doc: remove space before paren in code samples

This commit is contained in:
Peter D. Barnes, Jr
2022-11-21 13:01:52 -08:00
committed by Peter Barnes
parent 820c029e8b
commit 700543b01a
69 changed files with 2589 additions and 2612 deletions

View File

@@ -326,8 +326,8 @@ Indent constructor's initialization list with 4 spaces.
.. sourcecode:: cpp
MyClass::MyClass(int x, int y)
: m_x (x),
m_y (y)
: m_x(x),
m_y(y)
{
}
@@ -837,7 +837,7 @@ Casts
=====
Where casts are necessary, use the Google C++ guidance: "Use C++-style casts
like ``static_cast<float> (double_value)``, or brace initialization for
like ``static_cast<float>(double_value)``, or brace initialization for
conversion of arithmetic types like ``int64 y = int64{1} << 42``."
Do not use C-style casts, since they can be unsafe.
@@ -1047,13 +1047,13 @@ the |ns3| smart pointer class ``Ptr`` should be used in boolean comparisons as f
if (p == NULL) {...}
if (p == 0) {...}
NS_ASSERT... (p != nullptr, ...) NS_ASSERT... (p, ...)
NS_ABORT... (p != nullptr, ...) NS_ABORT... (p, ...)
NS_ASSERT...(p != nullptr, ...) NS_ASSERT...(p, ...)
NS_ABORT... (p != nullptr, ...) NS_ABORT... (p, ...)
NS_ASSERT... (p == nullptr, ...) NS_ASSERT... (!p, ...)
NS_ABORT... (p == nullptr, ...) NS_ABORT... (!p, ...)
NS_ASSERT...(p == nullptr, ...) NS_ASSERT...(!p, ...)
NS_ABORT... (p == nullptr, ...) NS_ABORT... (!p, ...)
NS_TEST... (p, nullptr, ...) NS_TEST... (p, nullptr, ...)
NS_TEST... (p, nullptr, ...) NS_TEST... (p, nullptr, ...)
C++ standard
============
@@ -1069,9 +1069,9 @@ Miscellaneous items
===================
- ``NS_LOG_COMPONENT_DEFINE("log-component-name");`` statements should be
placed within namespace ns3 (for module code) and after the
placed within ``namespace ns3`` (for module code) and after the
``using namespace ns3;``. In examples,
``NS_OBJECT_ENSURE_REGISTERED()`` should also be placed within namespace ``ns3``.
``NS_OBJECT_ENSURE_REGISTERED()`` should also be placed within ``namespace ns3``.
- Pointers and references are left-aligned:

View File

@@ -32,7 +32,7 @@ specificity, these are:
+=====================================+====================================+
| Default Attribute values set when | Affect all instances of the class. |
| Attributes are defined in | |
| :cpp:func:`GetTypeId ()`. | |
| :cpp:func:`GetTypeId()`. | |
+-------------------------------------+------------------------------------+
| :cpp:class:`CommandLine` | Affect all future instances. |
| :cpp:func:`Config::SetDefault()` | |
@@ -44,8 +44,8 @@ specificity, these are:
| Helper methods with (string/ | Affects all instances created by |
| AttributeValue) parameter pairs | the helper. |
+-------------------------------------+------------------------------------+
| :cpp:func:`MyClass::SetX ()` | Alters this particular instance. |
| :cpp:func:`Object::SetAttribute ()` | Generally this is the only form |
| :cpp:func:`MyClass::SetX()` | Alters this particular instance. |
| :cpp:func:`Object::SetAttribute()` | Generally this is the only form |
| :cpp:func:`Config::Set()` | which can be scheduled to alter |
| | an instance once the simulation |
| | is running. |
@@ -99,7 +99,7 @@ references to heap-allocated objects that may cause memory leaks.
For most basic usage (syntax), treat a smart pointer like a regular pointer::
Ptr<WifiNetDevice> nd = ...;
nd->CallSomeFunction ();
nd->CallSomeFunction();
// etc.
So how do you get a smart pointer to an object, as in the first line
@@ -111,24 +111,24 @@ CreateObject
As we discussed above in :ref:`Memory-management-and-class-Ptr`, at the
lowest-level API, objects of type :cpp:class:`Object` are not instantiated
using ``operator new`` as usual but instead by a templated function called
:cpp:func:`CreateObject ()`.
:cpp:func:`CreateObject()`.
A typical way to create such an object is as follows::
Ptr<WifiNetDevice> nd = CreateObject<WifiNetDevice> ();
Ptr<WifiNetDevice> nd = CreateObject<WifiNetDevice>();
You can think of this as being functionally equivalent to::
WifiNetDevice* nd = new WifiNetDevice ();
WifiNetDevice* nd = new WifiNetDevice();
Objects that derive from :cpp:class:`Object` must be allocated on the heap
using :cpp:func:`CreateObject ()`. Those deriving from :cpp:class:`ObjectBase`,
using :cpp:func:`CreateObject()`. Those deriving from :cpp:class:`ObjectBase`,
such as |ns3| helper functions and packet headers and trailers,
can be allocated on the stack.
In some scripts, you may not see a lot of :cpp:func:`CreateObject ()` calls
In some scripts, you may not see a lot of :cpp:func:`CreateObject()` calls
in the code; this is because there are some helper objects in effect
that are doing the :cpp:func:`CreateObject ()` calls for you.
that are doing the :cpp:func:`CreateObject()` calls for you.
TypeId
++++++
@@ -150,39 +150,39 @@ Putting all of these concepts together, let's look at a specific
example: class :cpp:class:`Node`.
The public header file ``node.h`` has a declaration that includes
a static :cpp:func:`GetTypeId ()` function call::
a static :cpp:func:`GetTypeId()` function call::
class Node : public Object
{
public:
static TypeId GetTypeId ();
static TypeId GetTypeId();
...
This is defined in the ``node.cc`` file as follows::
TypeId
Node::GetTypeId ()
Node::GetTypeId()
{
static TypeId tid = TypeId ("ns3::Node")
.SetParent<Object> ()
.SetGroupName ("Network")
.AddConstructor<Node> ()
.AddAttribute ("DeviceList",
"The list of devices associated to this Node.",
ObjectVectorValue (),
MakeObjectVectorAccessor (&Node::m_devices),
MakeObjectVectorChecker<NetDevice> ())
.AddAttribute ("ApplicationList",
"The list of applications associated to this Node.",
ObjectVectorValue (),
MakeObjectVectorAccessor (&Node::m_applications),
MakeObjectVectorChecker<Application> ())
.AddAttribute ("Id",
"The id (unique integer) of this Node.",
TypeId::ATTR_GET, // allow only getting it.
UintegerValue (0),
MakeUintegerAccessor (&Node::m_id),
MakeUintegerChecker<uint32_t> ())
static TypeId tid = TypeId("ns3::Node")
.SetParent<Object>()
.SetGroupName("Network")
.AddConstructor<Node>()
.AddAttribute("DeviceList",
"The list of devices associated to this Node.",
ObjectVectorValue(),
MakeObjectVectorAccessor(&Node::m_devices),
MakeObjectVectorChecker<NetDevice>())
.AddAttribute("ApplicationList",
"The list of applications associated to this Node.",
ObjectVectorValue(),
MakeObjectVectorAccessor(&Node::m_applications),
MakeObjectVectorChecker<Application>())
.AddAttribute("Id",
"The id(unique integer) of this Node.",
TypeId::ATTR_GET, // allow only getting it.
UintegerValue(0),
MakeUintegerAccessor(&Node::m_id),
MakeUintegerChecker<uint32_t>())
;
return tid;
}
@@ -192,38 +192,38 @@ as an extended form of run time type information (RTTI). The C++ language
includes a simple kind of RTTI in order to support ``dynamic_cast`` and
``typeid`` operators.
The :cpp:func:`SetParent<Object> ()` call in the definition above is used in
The :cpp:func:`SetParent<Object>()` call in the definition above is used in
conjunction with our object aggregation mechanisms to allow safe up- and
down-casting in inheritance trees during :cpp:func:`GetObject ()`.
down-casting in inheritance trees during :cpp:func:`GetObject()`.
It also enables subclasses to inherit the Attributes of their parent class.
The :cpp:func:`AddConstructor<Node> ()` call is used in conjunction
The :cpp:func:`AddConstructor<Node>()` call is used in conjunction
with our abstract object factory mechanisms to allow us to construct
C++ objects without forcing a user to know the concrete class of
the object she is building.
The three calls to :cpp:func:`AddAttribute ()` associate a given string
The three calls to :cpp:func:`AddAttribute()` associate a given string
with a strongly typed value in the class. Notice that you must provide
a help string which may be displayed, for example, *via* command line
processors. Each :cpp:class:`Attribute` is associated with mechanisms
for accessing the underlying member variable in the object (for example,
:cpp:func:`MakeUintegerAccessor ()` tells the generic :cpp:class:`Attribute`
:cpp:func:`MakeUintegerAccessor()` tells the generic :cpp:class:`Attribute`
code how to get to the node ID above). There are also "Checker" methods which
are used to validate values against range limitations, such as maximum
and minimum allowed values.
When users want to create Nodes, they will usually call some form of
:cpp:func:`CreateObject ()`,::
:cpp:func:`CreateObject()`,::
Ptr<Node> n = CreateObject<Node> ();
Ptr<Node> n = CreateObject<Node>();
or more abstractly, using an object factory, you can create a
:cpp:class:`Node` object without even knowing the concrete C++ type::
ObjectFactory factory;
const std::string typeId = "ns3::Node'';
factory.SetTypeId (typeId);
Ptr<Object> node = factory.Create <Object> ();
factory.SetTypeId(typeId);
Ptr<Object> node = factory.Create <Object>();
Both of these methods result in fully initialized attributes being available
in the resulting :cpp:class:`Object` instances.
@@ -359,7 +359,7 @@ the following::
class QueueBase : public Object {
public:
static TypeId GetTypeId ();
static TypeId GetTypeId();
...
private:
@@ -408,34 +408,34 @@ Let's consider things that a user may want to do with the value of
to that default.
* Set or get the value on an already instantiated queue.
The above things typically require providing ``Set ()`` and ``Get ()``
The above things typically require providing ``Set()`` and ``Get()``
functions, and some type of global default value.
In the |ns3| attribute system, these value definitions and accessor function
registrations are moved into the :cpp:class:`TypeId` class; *e.g*.::
NS_OBJECT_ENSURE_REGISTERED (QueueBase);
NS_OBJECT_ENSURE_REGISTERED(QueueBase);
TypeId
QueueBase::GetTypeId ()
QueueBase::GetTypeId()
{
static TypeId tid = TypeId ("ns3::DropTailQueue")
.SetParent<Queue> ()
.SetGroupName ("Network")
static TypeId tid = TypeId("ns3::DropTailQueue")
.SetParent<Queue>()
.SetGroupName("Network")
...
.AddAttribute ("MaxSize",
"The max queue size",
QueueSizeValue (QueueSize ("100p")),
MakeQueueSizeAccessor (&QueueBase::SetMaxSize,
&QueueBase::GetMaxSize),
MakeQueueSizeChecker ())
.AddAttribute("MaxSize",
"The max queue size",
QueueSizeValue(QueueSize("100p")),
MakeQueueSizeAccessor(&QueueBase::SetMaxSize,
&QueueBase::GetMaxSize),
MakeQueueSizeChecker())
...
;
return tid;
}
The :cpp:func:`AddAttribute ()` method is performing a number of things for the
The :cpp:func:`AddAttribute()` method is performing a number of things for the
:cpp:member:`m_maxSize` value:
* Binding the (usually private) member variable :cpp:member:`m_maxSize`
@@ -452,7 +452,7 @@ we will provide an example script that shows how users may manipulate
these values.
Note that initialization of the attribute relies on the macro
``NS_OBJECT_ENSURE_REGISTERED (QueueBase)`` being called; if you leave this
``NS_OBJECT_ENSURE_REGISTERED(QueueBase)`` being called; if you leave this
out of your new class implementation, your attributes will not be initialized
correctly.
@@ -486,13 +486,13 @@ function begins::
//
int
main (int argc, char *argv[])
main(int argc, char *argv[])
{
// Queues in ns-3 are objects that hold items (other objects) in
// a queue structure. The C++ implementation uses templates to
// allow queues to hold various types of items, but the most
// common is a pointer to a packet (Ptr<Packet>).
// common is a pointer to a packet(Ptr<Packet>).
//
// The maximum queue size can either be enforced in bytes ('b') or
// packets ('p'). A special type called the ns3::QueueSize can
@@ -505,12 +505,12 @@ function begins::
//
// Here, we set it to 80 packets. We could use one of two value types:
// a string-based value or a QueueSizeValue value
Config::SetDefault ("ns3::QueueBase::MaxSize", StringValue ("80p"));
Config::SetDefault("ns3::QueueBase::MaxSize", StringValue("80p"));
// The below function call is redundant
Config::SetDefault ("ns3::QueueBase::MaxSize", QueueSizeValue (QueueSize (QueueSizeUnit::PACKETS, 80)));
Config::SetDefault("ns3::QueueBase::MaxSize", QueueSizeValue(QueueSize(QueueSizeUnit::PACKETS, 80)));
The main thing to notice in the above are the two equivalent calls to
:cpp:func:`Config::SetDefault ()`. This is how we set the default value
:cpp:func:`Config::SetDefault()`. This is how we set the default value
for all subsequently instantiated :cpp:class:`DropTailQueue`\s. We illustrate
that two types of ``Value`` classes, a :cpp:class:`StringValue` and
a :cpp:class:`QueueSizeValue` class, can be used to assign the value
@@ -532,21 +532,21 @@ the :cpp:class:`CommandLine` API documentation.
// For example, via "--ns3::QueueBase::MaxSize=80p"
CommandLine cmd;
// This provides yet another way to set the value from the command line:
cmd.AddValue ("maxSize", "ns3::QueueBase::MaxSize");
cmd.Parse (argc, argv);
cmd.AddValue("maxSize", "ns3::QueueBase::MaxSize");
cmd.Parse(argc, argv);
Now, we will create a few objects using the low-level API. Our
newly created queues will not have :cpp:member:`m_maxSize` initialized to
0 packets, as defined in the :cpp:func:`QueueBase::GetTypeId ()`
0 packets, as defined in the :cpp:func:`QueueBase::GetTypeId()`
function, but to 80 packets, because of what we did above with
default values.::
Ptr<Node> n0 = CreateObject<Node> ();
Ptr<Node> n0 = CreateObject<Node>();
Ptr<PointToPointNetDevice> net0 = CreateObject<PointToPointNetDevice> ();
n0->AddDevice (net0);
Ptr<PointToPointNetDevice> net0 = CreateObject<PointToPointNetDevice>();
n0->AddDevice(net0);
Ptr<Queue<Packet> > q = CreateObject<DropTailQueue<Packet> > ();
Ptr<Queue<Packet> > q = CreateObject<DropTailQueue<Packet> >();
net0->AddQueue(q);
At this point, we have created a single :cpp:class:`Node` (``n0``)
@@ -569,23 +569,23 @@ the helper and low-level APIs; either from the constructors themselves::
Ptr<GridPositionAllocator> p =
CreateObjectWithAttributes<GridPositionAllocator>
("MinX", DoubleValue (-100.0),
"MinY", DoubleValue (-100.0),
"DeltaX", DoubleValue (5.0),
"DeltaY", DoubleValue (20.0),
"GridWidth", UintegerValue (20),
"LayoutType", StringValue ("RowFirst"));
("MinX", DoubleValue(-100.0),
"MinY", DoubleValue(-100.0),
"DeltaX", DoubleValue(5.0),
"DeltaY", DoubleValue(20.0),
"GridWidth", UintegerValue(20),
"LayoutType", StringValue("RowFirst"));
or from the higher-level helper APIs, such as::
mobility.SetPositionAllocator
("ns3::GridPositionAllocator",
"MinX", DoubleValue (-100.0),
"MinY", DoubleValue (-100.0),
"DeltaX", DoubleValue (5.0),
"DeltaY", DoubleValue (20.0),
"GridWidth", UintegerValue (20),
"LayoutType", StringValue ("RowFirst"));
("ns3::GridPositionAllocator",
"MinX", DoubleValue(-100.0),
"MinY", DoubleValue(-100.0),
"DeltaX", DoubleValue(5.0),
"DeltaY", DoubleValue(20.0),
"GridWidth", UintegerValue(20),
"LayoutType", StringValue("RowFirst"));
We don't illustrate it here, but you can also configure an
:cpp:class:`ObjectFactory` with new values for specific attributes.
@@ -596,9 +596,9 @@ one of the helper APIs for the class.
To review, there are several ways to set values for attributes for
class instances *to be created in the future:*
* :cpp:func:`Config::SetDefault ()`
* :cpp:func:`CommandLine::AddValue ()`
* :cpp:func:`CreateObjectWithAttributes<> ()`
* :cpp:func:`Config::SetDefault()`
* :cpp:func:`CommandLine::AddValue()`
* :cpp:func:`CreateObjectWithAttributes<>()`
* Various helper APIs
But what if you've already created an instance, and you want
@@ -624,35 +624,35 @@ First, we observe that we can get a pointer to the (base class)
``"TxQueue"``::
PointerValue ptr;
net0->GetAttribute ("TxQueue", ptr);
Ptr<Queue<Packet> > txQueue = ptr.Get<Queue<Packet> > ();
net0->GetAttribute("TxQueue", ptr);
Ptr<Queue<Packet> > txQueue = ptr.Get<Queue<Packet> >();
Using the :cpp:func:`GetObject ()` function, we can perform a safe downcast
Using the :cpp:func:`GetObject()` function, we can perform a safe downcast
to a :cpp:class:`DropTailQueue`. The `NS_ASSERT` checks that the pointer is
valid.
::
Ptr<DropTailQueue<Packet> > dtq = txQueue->GetObject <DropTailQueue<Packet> > ();
NS_ASSERT (dtq != 0);
Ptr<DropTailQueue<Packet> > dtq = txQueue->GetObject <DropTailQueue<Packet> >();
NS_ASSERT(dtq);
Next, we can get the value of an attribute on this queue. We have introduced
wrapper ``Value`` classes for the underlying data types, similar
to Java wrappers around these types, since the attribute system stores values
serialized to strings, and not disparate types. Here, the attribute value
is assigned to a :cpp:class:`QueueSizeValue`, and the :cpp:func:`Get ()`
method on this value produces the (unwrapped) ``QueueSize``. That is,
is assigned to a :cpp:class:`QueueSizeValue`, and the :cpp:func:`Get()`
the variable `limit` is written into by the GetAttribute method.::
QueueSizeValue limit;
dtq->GetAttribute ("MaxSize", limit);
NS_LOG_INFO ("1. dtq limit: " << limit.Get ());
dtq->GetAttribute("MaxSize", limit);
NS_LOG_INFO("1. dtq limit: " << limit.Get());
Note that the above downcast is not really needed; we could have gotten
the attribute value directly from ``txQueue``::
txQueue->GetAttribute ("MaxSize", limit);
NS_LOG_INFO ("2. txQueue limit: " << limit.Get ());
txQueue->GetAttribute("MaxSize", limit);
NS_LOG_INFO("2. txQueue limit: " << limit.Get());
Now, let's set it to another value (60 packets). Let's also make
use of the StringValue shorthand notation to set the size by
@@ -661,9 +661,9 @@ by either the `p` or `b` character).
::
txQueue->SetAttribute ("MaxSize", StringValue ("60p"));
txQueue->GetAttribute ("MaxSize", limit);
NS_LOG_INFO ("3. txQueue limit changed: " << limit.Get ());
txQueue->SetAttribute("MaxSize", StringValue("60p"));
txQueue->GetAttribute("MaxSize", limit);
NS_LOG_INFO("3. txQueue limit changed: " << limit.Get());
Config Namespace Path
=====================
@@ -675,11 +675,11 @@ would like to configure a specific attribute with a single statement.
::
Config::Set ("/NodeList/0/DeviceList/0/TxQueue/MaxSize",
StringValue ("25p"));
txQueue->GetAttribute ("MaxSize", limit);
NS_LOG_INFO ("4. txQueue limit changed through namespace: "
<< limit.Get ());
Config::Set("/NodeList/0/DeviceList/0/TxQueue/MaxSize",
StringValue("25p"));
txQueue->GetAttribute("MaxSize", limit);
NS_LOG_INFO("4. txQueue limit changed through namespace: "
<< limit.Get());
The configuration path often has the form of
``".../<container name>/<index>/.../<attribute>/<attribute>"``
@@ -691,14 +691,14 @@ ends with a succession of member attributes, in this case the ``"MaxSize"``
attribute of the ``"TxQueue"`` of the chosen :cpp:class:`NetDevice`.
We could have also used wildcards to set this value for all nodes and all net
devices (which in this simple example has the same effect as the previous
:cpp:func:`Config::Set ()`)::
devices(which in this simple example has the same effect as the previous
:cpp:func:`Config::Set()`)::
Config::Set ("/NodeList/*/DeviceList/*/TxQueue/MaxSize",
StringValue ("15p"));
txQueue->GetAttribute ("MaxSize", limit);
NS_LOG_INFO ("5. txQueue limit changed through wildcarded namespace: "
<< limit.Get ());
Config::Set("/NodeList/*/DeviceList/*/TxQueue/MaxSize",
StringValue("15p"));
txQueue->GetAttribute("MaxSize", limit);
NS_LOG_INFO("5. txQueue limit changed through wildcarded namespace: "
<< limit.Get());
If you run this program from the command line, you should see the following
output corresponding to the steps we took above:
@@ -724,12 +724,12 @@ namespace path.
::
Names::Add ("server", n0);
Names::Add ("server/eth0", net0);
Names::Add("server", n0);
Names::Add("server/eth0", net0);
...
Config::Set ("/Names/server/eth0/TxQueue/MaxPackets", UintegerValue (25));
Config::Set("/Names/server/eth0/TxQueue/MaxPackets", UintegerValue(25));
Here we've added the path elements ``"server"`` and ``"eth0"`` under
the ``"/Names/"`` namespace, then used the resulting configuration path
@@ -755,8 +755,8 @@ or *via* strings. Direct implicit conversion of types to
:cpp:class:`AttributeValue` is not really practical.
So in the above, users have a choice of using strings or values::
p->Set ("cwnd", StringValue ("100")); // string-based setter
p->Set ("cwnd", IntegerValue (100)); // integer-based setter
p->Set("cwnd", StringValue("100")); // string-based setter
p->Set("cwnd", IntegerValue(100)); // integer-based setter
The system provides some macros that help users declare and define
new AttributeValue subclasses for new types that they want to introduce into
@@ -792,18 +792,18 @@ In general, the attribute code to assign values to the underlying class member
variables is executed after an object is constructed. But what if you need the
values assigned before the constructor body executes, because you need them in
the logic of the constructor? There is a way to do this, used for example in the
class :cpp:class:`ConfigStore`: call :cpp:func:`ObjectBase::ConstructSelf ()` as
class :cpp:class:`ConfigStore`: call :cpp:func:`ObjectBase::ConstructSelf()` as
follows::
ConfigStore::ConfigStore ()
ConfigStore::ConfigStore()
{
ObjectBase::ConstructSelf (AttributeConstructionList ());
ObjectBase::ConstructSelf(AttributeConstructionList());
// continue on with constructor.
}
Beware that the object and all its derived classes must also implement
a :cpp:func:`GetInstanceTypeId ()` method. Otherwise
the :cpp:func:`ObjectBase::ConstructSelf ()` will not be able to read
a :cpp:func:`GetInstanceTypeId()` method. Otherwise
the :cpp:func:`ObjectBase::ConstructSelf()` will not be able to read
the attributes.
Adding Attributes
@@ -834,11 +834,11 @@ variable using the metadata system. If it were not already provided by |ns3|,
the user could declare the following addition in the runtime metadata system (to
the :cpp:func:`GetTypeId` definition for :cpp:class:`TcpSocket`)::
.AddAttribute ("Congestion window",
"Tcp congestion window (bytes)",
UintegerValue (1),
MakeUintegerAccessor (&TcpSocket::m_cWnd),
MakeUintegerChecker<uint16_t> ())
.AddAttribute("Congestion window",
"Tcp congestion window(bytes)",
UintegerValue(1),
MakeUintegerAccessor(&TcpSocket::m_cWnd),
MakeUintegerChecker<uint16_t>())
Now, the user with a pointer to a :cpp:class:`TcpSocket` instance
can perform operations such as
@@ -863,7 +863,7 @@ In the ``my-mobility.h`` header file::
class MyMobility : public MobilityModel
{
This requires we declare the :cpp:func:`GetTypeId ()` function.
This requires we declare the :cpp:func:`GetTypeId()` function.
This is a one-line public function declaration::
public:
@@ -871,31 +871,31 @@ This is a one-line public function declaration::
* Register this type.
* \return The object TypeId.
*/
static TypeId GetTypeId ();
static TypeId GetTypeId();
We've already introduced what a :cpp:class:`TypeId` definition will look like
in the ``my-mobility.cc`` implementation file::
NS_OBJECT_ENSURE_REGISTERED (MyMobility);
NS_OBJECT_ENSURE_REGISTERED(MyMobility);
TypeId
MyMobility::GetTypeId ()
MyMobility::GetTypeId()
{
static TypeId tid = TypeId ("ns3::MyMobility")
.SetParent<MobilityModel> ()
.SetGroupName ("Mobility")
.AddConstructor<MyMobility> ()
.AddAttribute ("Bounds",
"Bounds of the area to cruise.",
RectangleValue (Rectangle (0.0, 0.0, 100.0, 100.0)),
MakeRectangleAccessor (&MyMobility::m_bounds),
MakeRectangleChecker ())
.AddAttribute ("Time",
"Change current direction and speed after moving for this delay.",
TimeValue (Seconds (1.0)),
MakeTimeAccessor (&MyMobility::m_modeTime),
MakeTimeChecker ())
// etc (more parameters).
static TypeId tid = TypeId("ns3::MyMobility")
.SetParent<MobilityModel>()
.SetGroupName("Mobility")
.AddConstructor<MyMobility>()
.AddAttribute("Bounds",
"Bounds of the area to cruise.",
RectangleValue(Rectangle(0.0, 0.0, 100.0, 100.0)),
MakeRectangleAccessor(&MyMobility::m_bounds),
MakeRectangleChecker())
.AddAttribute("Time",
"Change current direction and speed after moving for this delay.",
// etc (more parameters).
TimeValue(Seconds(1.0)),
MakeTimeAccessor(&MyMobility::m_modeTime),
MakeTimeChecker())
;
return tid;
}
@@ -903,14 +903,14 @@ in the ``my-mobility.cc`` implementation file::
If we don't want to subclass from an existing class, in the header file
we just inherit from :cpp:class:`ns3::Object`, and in the object file
we set the parent class to :cpp:class:`ns3::Object` with
``.SetParent<Object> ()``.
``.SetParent<Object>()``.
Typical mistakes here involve:
* Not calling ``NS_OBJECT_ENSURE_REGISTERED ()``
* Not calling the :cpp:func:`SetParent ()` method,
* Not calling ``NS_OBJECT_ENSURE_REGISTERED()``
* Not calling the :cpp:func:`SetParent()` method,
or calling it with the wrong type.
* Not calling the :cpp:func:`AddConstructor ()` method,
* Not calling the :cpp:func:`AddConstructor()` method,
or calling it with the wrong type.
* Introducing a typographical error in the name of the :cpp:class:`TypeId`
in its constructor.
@@ -950,27 +950,27 @@ Header File
One macro call and two operators, must be added below the class declaration in
order to turn a Rectangle into a value usable by the ``Attribute`` system::
std::ostream &operator << (std::ostream &os, const Rectangle &rectangle);
std::istream &operator >> (std::istream &is, Rectangle &rectangle);
std::ostream &operator <<(std::ostream &os, const Rectangle &rectangle);
std::istream &operator >>(std::istream &is, Rectangle &rectangle);
ATTRIBUTE_HELPER_HEADER (Rectangle);
ATTRIBUTE_HELPER_HEADER(Rectangle);
Implementation File
~~~~~~~~~~~~~~~~~~~
In the class definition (``.cc`` file), the code looks like this::
ATTRIBUTE_HELPER_CPP (Rectangle);
ATTRIBUTE_HELPER_CPP(Rectangle);
std::ostream &
operator << (std::ostream &os, const Rectangle &rectangle)
operator <<(std::ostream &os, const Rectangle &rectangle)
{
os << rectangle.xMin << "|" << rectangle.xMax << "|" << rectangle.yMin << "|"
<< rectangle.yMax;
return os;
}
std::istream &
operator >> (std::istream &is, Rectangle &rectangle)
operator >>(std::istream &is, Rectangle &rectangle)
{
char c1, c2, c3;
is >> rectangle.xMin >> c1 >> rectangle.xMax >> c2 >> rectangle.yMin >> c3
@@ -979,13 +979,13 @@ In the class definition (``.cc`` file), the code looks like this::
c2 != '|' ||
c3 != '|')
{
is.setstate (std::ios_base::failbit);
is.setstate(std::ios_base::failbit);
}
return is;
}
These stream operators simply convert from a string representation of the
Rectangle (``"xMin|xMax|yMin|yMax"``) to the underlying Rectangle. The modeler
Rectangle(``"xMin|xMax|yMin|yMax"``) to the underlying Rectangle. The modeler
must specify these operators and the string syntactical representation of an
instance of the new class.
@@ -1014,36 +1014,36 @@ to show how the system is extended::
class ConfigExample : public Object
{
public:
static TypeId GetTypeId () {
static TypeId tid = TypeId ("ns3::A")
.SetParent<Object> ()
.AddAttribute ("TestInt16", "help text",
IntegerValue (-2),
MakeIntegerAccessor (&A::m_int16),
MakeIntegerChecker<int16_t> ())
static TypeId GetTypeId() {
static TypeId tid = TypeId("ns3::A")
.SetParent<Object>()
.AddAttribute("TestInt16", "help text",
IntegerValue(-2),
MakeIntegerAccessor(&A::m_int16),
MakeIntegerChecker<int16_t>())
;
return tid;
}
int16_t m_int16;
};
NS_OBJECT_ENSURE_REGISTERED (ConfigExample);
NS_OBJECT_ENSURE_REGISTERED(ConfigExample);
Next, we use the Config subsystem to override the defaults in a couple of
ways::
Config::SetDefault ("ns3::ConfigExample::TestInt16", IntegerValue (-5));
Config::SetDefault("ns3::ConfigExample::TestInt16", IntegerValue(-5));
Ptr<ConfigExample> a_obj = CreateObject<ConfigExample> ();
NS_ABORT_MSG_UNLESS (a_obj->m_int16 == -5,
"Cannot set ConfigExample's integer attribute via Config::SetDefault");
Ptr<ConfigExample> a_obj = CreateObject<ConfigExample>();
NS_ABORT_MSG_UNLESS(a_obj->m_int16 == -5,
"Cannot set ConfigExample's integer attribute via Config::SetDefault");
Ptr<ConfigExample> a2_obj = CreateObject<ConfigExample> ();
a2_obj->SetAttribute ("TestInt16", IntegerValue (-3));
Ptr<ConfigExample> a2_obj = CreateObject<ConfigExample>();
a2_obj->SetAttribute("TestInt16", IntegerValue(-3));
IntegerValue iv;
a2_obj->GetAttribute ("TestInt16", iv);
NS_ABORT_MSG_UNLESS (iv.Get () == -3,
"Cannot set ConfigExample's integer attribute via SetAttribute");
a2_obj->GetAttribute("TestInt16", iv);
NS_ABORT_MSG_UNLESS(iv.Get() == -3,
"Cannot set ConfigExample's integer attribute via SetAttribute");
The next statement is necessary to make sure that (one of) the objects
created is rooted in the configuration namespace as an object instance.
@@ -1052,14 +1052,14 @@ or :cpp:class:`ns3::Channel` instance,
but here, since we are working at the core level, we need to create a
new root namespace object::
Config::RegisterRootNamespaceObject (a2_obj);
Config::RegisterRootNamespaceObject(a2_obj);
Writing
+++++++
Next, we want to output the configuration store. The examples show how
to do it in two formats, XML and raw text. In practice, one should perform
this step just before calling :cpp:func:`Simulator::Run ()` to save the
this step just before calling :cpp:func:`Simulator::Run()` to save the
final configuration just before running the simulation.
There are three Attributes that govern the behavior of the ConfigStore:
@@ -1072,27 +1072,26 @@ the ConfigStore format is plain text or Xml (``"FileFormat=Xml"``)
The example shows::
Config::SetDefault ("ns3::ConfigStore::Filename", StringValue ("output-attributes.xml"));
Config::SetDefault ("ns3::ConfigStore::FileFormat", StringValue ("Xml"));
Config::SetDefault ("ns3::ConfigStore::Mode", StringValue ("Save"));
Config::SetDefault("ns3::ConfigStore::Filename", StringValue("output-attributes.xml"));
Config::SetDefault("ns3::ConfigStore::FileFormat", StringValue("Xml"));
Config::SetDefault("ns3::ConfigStore::Mode", StringValue("Save"));
ConfigStore outputConfig;
outputConfig.ConfigureDefaults ();
outputConfig.ConfigureAttributes ();
outputConfig.ConfigureDefaults();
outputConfig.ConfigureAttributes();
// Output config store to txt format
Config::SetDefault ("ns3::ConfigStore::Filename", StringValue ("output-attributes.txt"));
Config::SetDefault ("ns3::ConfigStore::FileFormat", StringValue ("RawText"));
Config::SetDefault ("ns3::ConfigStore::Mode", StringValue ("Save"));
Config::SetDefault("ns3::ConfigStore::Filename", StringValue("output-attributes.txt"));
Config::SetDefault("ns3::ConfigStore::FileFormat", StringValue("RawText"));
Config::SetDefault("ns3::ConfigStore::Mode", StringValue("Save"));
ConfigStore outputConfig2;
outputConfig2.ConfigureDefaults ();
outputConfig2.ConfigureAttributes ();
outputConfig2.ConfigureDefaults();
outputConfig2.ConfigureAttributes();
Simulator::Run ();
Simulator::Run();
Simulator::Destroy ();
Simulator::Destroy();
Note the placement of these statements just prior to the
:cpp:func:`Simulator::Run ()` statement. This output logs all of the
values in place just prior to starting the simulation (*i.e*. after
all of the configuration has taken place).
@@ -1184,11 +1183,11 @@ are registered before being used in object construction).
::
Config::SetDefault ("ns3::ConfigStore::Filename", StringValue ("input-defaults.xml"));
Config::SetDefault ("ns3::ConfigStore::Mode", StringValue ("Load"));
Config::SetDefault ("ns3::ConfigStore::FileFormat", StringValue ("Xml"));
Config::SetDefault("ns3::ConfigStore::Filename", StringValue("input-defaults.xml"));
Config::SetDefault("ns3::ConfigStore::Mode", StringValue("Load"));
Config::SetDefault("ns3::ConfigStore::FileFormat", StringValue("Xml"));
ConfigStore inputConfig;
inputConfig.ConfigureDefaults ();
inputConfig.ConfigureDefaults();
Next, note that loading of input configuration data is limited to Attribute
default (*i.e*. not instance) values, and global values. Attribute instance
@@ -1219,31 +1218,31 @@ write out the resulting attributes to a separate file called
#include "ns3/config-store-module.h"
...
int main (...)
int main(...)
{
Config::SetDefault ("ns3::ConfigStore::Filename", StringValue ("input-defaults.xml"));
Config::SetDefault ("ns3::ConfigStore::Mode", StringValue ("Load"));
Config::SetDefault ("ns3::ConfigStore::FileFormat", StringValue ("Xml"));
Config::SetDefault("ns3::ConfigStore::Filename", StringValue("input-defaults.xml"));
Config::SetDefault("ns3::ConfigStore::Mode", StringValue("Load"));
Config::SetDefault("ns3::ConfigStore::FileFormat", StringValue("Xml"));
ConfigStore inputConfig;
inputConfig.ConfigureDefaults ();
inputConfig.ConfigureDefaults();
//
// Allow the user to override any of the defaults and the above Bind () at
// Allow the user to override any of the defaults and the above Bind() at
// run-time, viacommand-line arguments
//
CommandLine cmd;
cmd.Parse (argc, argv);
cmd.Parse(argc, argv);
// setup topology
...
// Invoke just before entering Simulator::Run ()
Config::SetDefault ("ns3::ConfigStore::Filename", StringValue ("output-attributes.xml"));
Config::SetDefault ("ns3::ConfigStore::Mode", StringValue ("Save"));
// Invoke just before entering Simulator::Run()
Config::SetDefault("ns3::ConfigStore::Filename", StringValue("output-attributes.xml"));
Config::SetDefault("ns3::ConfigStore::Mode", StringValue("Save"));
ConfigStore outputConfig;
outputConfig.ConfigureAttributes ();
Simulator::Run ();
outputConfig.ConfigureAttributes();
Simulator::Run();
}
ConfigStore use cases (pre- and post-simulation)
@@ -1262,13 +1261,13 @@ As a matter of fact, some Objects might be created when the simulation starts.
Hence, ConfigStore will not "report" their attributes if invoked earlier in the code.
A typical workflow might involve running the simulation, calling ConfigStore
at the end of the simulation (after ``Simulator::Run ()`` and before ``Simulator::Destroy ()``)
at the end of the simulation (after ``Simulator::Run()`` and before ``Simulator::Destroy()``)
This will show all the attributes in the Objects, both those with default values, and those
with values changed during the simulation execution.
To change these values, you'll need to either change the default (class-wide) attribute values
(in this case call ConfigStore before the Object creation), or specific object attribute
(in this case call ConfigStore after the Object creation, typically just before ``Simulator::Run ()``.
(in this case call ConfigStore after the Object creation, typically just before ``Simulator::Run()``.
ConfigStore GUI
@@ -1278,7 +1277,7 @@ There is a GTK-based front end for the ConfigStore. This allows users to use a
GUI to access and change variables.
Some screenshots are presented here. They are the result of using GtkConfig on
``src/lte/examples/lena-dual-stripe.cc`` after ``Simulator::Run ()``.
``src/lte/examples/lena-dual-stripe.cc`` after ``Simulator::Run()``.
.. _GtkConfig:
@@ -1327,15 +1326,15 @@ is rerun.
Usage is almost the same as the non-GTK-based version, but there
are no :cpp:class:`ConfigStore` attributes involved::
// Invoke just before entering Simulator::Run ()
// Invoke just before entering Simulator::Run()
GtkConfigStore config;
config.ConfigureDefaults ();
config.ConfigureAttributes ();
config.ConfigureDefaults();
config.ConfigureAttributes();
Now, when you run the script, a GUI should pop up, allowing you to open menus of
attributes on different nodes/objects, and then launch the simulation execution
when you are done.
Note that "launch the simulation" means to proceed with the simulation script.
If GtkConfigStore has been called after ``Simulator::Run ()`` the simulation will
If GtkConfigStore has been called after ``Simulator::Run()`` the simulation will
not be started again - it will just end.

View File

@@ -19,15 +19,15 @@ so that they can invoke methods on each other::
class A {
public:
void ReceiveInput ( // parameters );
void ReceiveInput( /* parameters */ );
...
}
(in another source file:)
and in another source file::
class B {
public:
void DoSomething ();
void DoSomething();
...
private:
@@ -38,7 +38,7 @@ so that they can invoke methods on each other::
B::DoSomething()
{
// Tell a_instance that something happened
a_instance->ReceiveInput ( // parameters);
a_instance->ReceiveInput( /* parameters */ );
...
}
@@ -58,7 +58,9 @@ This is not an abstract problem for network simulation research, but rather it
has been a source of problems in previous simulators, when researchers want to
extend or modify the system to do different things (as they are apt to do in
research). Consider, for example, a user who wants to add an IPsec security
protocol sublayer between TCP and IP::
protocol sublayer between TCP and IP:
.. code-block::text
------------ -----------
| TCP | | TCP |
@@ -104,7 +106,7 @@ What you get from this is a variable named simply ``pfi`` that is initialized to
the value 0. If you want to initialize this pointer to something meaningful, you
have to have a function with a matching signature. In this case::
int MyFunction (int arg) {}
int MyFunction(int arg) {}
If you have this target, you can initialize the variable to point to your
function like::
@@ -114,14 +116,14 @@ function like::
You can then call MyFunction indirectly using the more suggestive form of the
call::
int result = (*pfi) (1234);
int result = (*pfi)(1234);
This is suggestive since it looks like you are dereferencing the function
pointer just like you would dereference any pointer. Typically, however, people
take advantage of the fact that the compiler knows what is going on and will
just use a shorter form::
int result = pfi (1234);
int result = pfi(1234);
Notice that the function pointer obeys value semantics, so you can pass it
around like any other value. Typically, when you use an asynchronous interface
@@ -136,7 +138,7 @@ the pointer to function returning an int (PFI).
The declaration of the variable providing the indirection looks only slightly
different::
int (MyClass::*pmi) (int arg) = 0;
int (MyClass::*pmi)(int arg) = 0;
This declares a variable named ``pmi`` just as the previous example declared a
variable named ``pfi``. Since the will be to call a method of an instance of a
@@ -144,7 +146,7 @@ particular class, one must declare that method in a class::
class MyClass {
public:
int MyMethod (int arg);
int MyMethod(int arg);
};
Given this class declaration, one would then initialize that variable like
@@ -158,18 +160,18 @@ pointer. This, in turn, means there must be an object of MyClass to refer to. A
simplistic example of this is just calling a method indirectly (think virtual
function)::
int (MyClass::*pmi) (int arg) = 0; // Declare a PMI
int (MyClass::*pmi)(int arg) = 0; // Declare a PMI
pmi = &MyClass::MyMethod; // Point at the implementation code
MyClass myClass; // Need an instance of the class
(myClass.*pmi) (1234); // Call the method with an object ptr
(myClass.*pmi)(1234); // Call the method with an object ptr
Just like in the C example, you can use this in an asynchronous call to another
module which will *call back* using a method and an object pointer. The
straightforward extension one might consider is to pass a pointer to the object
and the PMI variable. The module would just do::
(*objectPtr.*pmi) (1234);
(*objectPtr.*pmi)(1234);
to execute the callback on the desired object.
@@ -186,12 +188,12 @@ It is basically just a packaged-up function call, possibly with some state.
A functor has two parts, a specific part and a generic part, related through
inheritance. The calling code (the code that executes the callback) will execute
a generic overloaded ``operator ()`` of a generic functor to cause the callback
a generic overloaded ``operator()`` of a generic functor to cause the callback
to be called. The called code (the code that wants to be called back) will have
to provide a specialized implementation of the ``operator ()`` that performs the
to provide a specialized implementation of the ``operator()`` that performs the
class-specific work that caused the close-coupling problem above.
With the specific functor and its overloaded ``operator ()`` created, the called
With the specific functor and its overloaded ``operator()`` created, the called
code then gives the specialized code to the module that will execute the
callback (the calling code).
@@ -210,7 +212,7 @@ of the functor::
class Functor
{
public:
virtual int operator() (T arg) = 0;
virtual int operator()(T arg) = 0;
};
The caller defines a specific part of the functor that really is just there to
@@ -226,7 +228,7 @@ implement the specific ``operator()`` method::
m_pmi = _pmi;
}
virtual int operator() (ARG arg)
virtual int operator()(ARG arg)
{
(*m_p.*m_pmi)(arg);
}
@@ -240,8 +242,8 @@ Here is an example of the usage::
class A
{
public:
A (int a0) : a (a0) {}
int Hello (int b0)
A(int a0) : a(a0) {}
int Hello(int b0)
{
std::cout << "Hello from A, a = " << a << " b0 = " << b0 << std::endl;
}
@@ -269,19 +271,19 @@ with the object pointer using the C++ PMI syntax.
To use this, one could then declare some model code that takes a generic functor
as a parameter::
void LibraryFunction (Functor functor);
void LibraryFunction(Functor functor);
The code that will talk to the model would build a specific functor and pass it to ``LibraryFunction``::
MyClass myClass;
SpecificFunctor<MyClass, int> functor (&myclass, MyClass::MyMethod);
SpecificFunctor<MyClass, int> functor(&myclass, MyClass::MyMethod);
When ``LibraryFunction`` is done, it executes the callback using the
``operator()`` on the generic functor it was passed, and in this particular
case, provides the integer argument::
void
LibraryFunction (Functor functor)
LibraryFunction(Functor functor)
{
// Execute the library function
functor(1234);
@@ -319,7 +321,7 @@ Using the Callback API with static functions
Consider a function::
static double
CbOne (double a, double b)
CbOne(double a, double b)
{
std::cout << "invoke cbOne a=" << a << ", b=" << b << std::endl;
return a;
@@ -327,7 +329,7 @@ Consider a function::
Consider also the following main program snippet::
int main (int argc, char *argv[])
int main(int argc, char *argv[])
{
// return type: double
// first arg type: double
@@ -365,7 +367,7 @@ Now, we need to tie together this callback instance and the actual target functi
callback-- this is important. We can pass in any such properly-typed function
to this callback. Let's look at this more closely::
static double CbOne (double a, double b) {}
static double CbOne(double a, double b) {}
^ ^ ^
| | |
| | |
@@ -378,21 +380,21 @@ arguments are the types of the arguments of the function signature.
Now, let's bind our callback "one" to the function that matches its signature::
// build callback instance which points to cbOne function
one = MakeCallback (&CbOne);
one = MakeCallback(&CbOne);
This call to ``MakeCallback`` is, in essence, creating one of the specialized
functors mentioned above. The variable declared using the ``Callback``
template function is going to be playing the part of the generic functor. The
assignment ``one = MakeCallback (&CbOne)`` is the cast that converts the
assignment ``one = MakeCallback(&CbOne)`` is the cast that converts the
specialized functor known to the callee to a generic functor known to the caller.
Then, later in the program, if the callback is needed, it can be used as follows::
NS_ASSERT (!one.IsNull ());
NS_ASSERT(!one.IsNull());
// invoke cbOne function through callback instance
double retOne;
retOne = one (10.0, 20.0);
retOne = one(10.0, 20.0);
The check for ``IsNull()`` ensures that the callback is not null -- that there
is a function to call behind this callback. Then, ``one()`` executes the
@@ -410,13 +412,13 @@ invoked. Consider this example, also from main-callback.cc::
class MyCb {
public:
int CbTwo (double a) {
int CbTwo(double a) {
std::cout << "invoke cbTwo a=" << a << std::endl;
return -5;
}
};
int main ()
int main()
{
...
// return type: int
@@ -424,7 +426,7 @@ invoked. Consider this example, also from main-callback.cc::
Callback<int, double> two;
MyCb cb;
// build callback instance which points to MyCb::cbTwo
two = MakeCallback (&MyCb::CbTwo, &cb);
two = MakeCallback(&MyCb::CbTwo, &cb);
...
}
@@ -432,7 +434,7 @@ Here, we pass an additional object pointer to the ``MakeCallback<>`` function.
Recall from the background section above that ``Operator()`` will use the pointer to
member syntax when it executes on an object::
virtual int operator() (ARG arg)
virtual int operator()(ARG arg)
{
(*m_p.*m_pmi)(arg);
}
@@ -440,11 +442,11 @@ member syntax when it executes on an object::
And so we needed to provide the two variables (``m_p`` and ``m_pmi``) when
we made the specific functor. The line::
two = MakeCallback (&MyCb::CbTwo, &cb);
two = MakeCallback(&MyCb::CbTwo, &cb);
does precisely that. In this case, when ``two ()`` is invoked::
does precisely that. In this case, when ``two()`` is invoked::
int result = two (1.0);
int result = two(1.0);
will result in a call to the ``CbTwo`` member function (method) on the object
pointed to by ``&cb``.
@@ -457,8 +459,8 @@ check before using them. There is a special construct for a null
callback, which is preferable to simply passing "0" as an argument;
it is the ``MakeNullCallback<>`` construct::
two = MakeNullCallback<int, double> ();
NS_ASSERT (two.IsNull ());
two = MakeNullCallback<int, double>();
NS_ASSERT(two.IsNull());
Invoking a null callback is just like invoking a null function pointer: it will
crash at runtime.
@@ -484,14 +486,14 @@ function that needs to be called whenever a packet is received. This function
calls an object that actually writes the packet to disk in the pcap file
format. The signature of one of these functions will be::
static void DefaultSink (Ptr<PcapFileWrapper> file, Ptr<const Packet> p);
static void DefaultSink(Ptr<PcapFileWrapper> file, Ptr<const Packet> p);
The static keyword means this is a static function which does not need a
``this`` pointer, so it will be using C-style callbacks. We don't want the
calling code to have to know about anything but the Packet. What we want in
the calling code is just a call that looks like::
m_promiscSnifferTrace (m_currentPkt);
m_promiscSnifferTrace(m_currentPkt);
What we want to do is to *bind* the ``Ptr<PcapFileWriter> file`` to the
specific callback implementation when it is created and arrange for the
@@ -501,7 +503,7 @@ We provide the ``MakeBoundCallback`` template function for that purpose. It
takes the same parameters as the ``MakeCallback`` template function but also
takes the parameters to be bound. In the case of the example above::
MakeBoundCallback (&DefaultSink, file);
MakeBoundCallback(&DefaultSink, file);
will create a specific callback implementation that knows to add in the extra
bound arguments. Conceptually, it extends the specific functor described above
@@ -518,7 +520,7 @@ with one or more bound arguments::
m_boundArg = boundArg;
}
virtual int operator() (ARG arg)
virtual int operator()(ARG arg)
{
(*m_p.*m_pmi)(m_boundArg, arg);
}
@@ -532,7 +534,7 @@ You can see that when the specific functor is created, the bound argument is sav
in the functor / callback object itself. When the ``operator()`` is invoked with
the single parameter, as in::
m_promiscSnifferTrace (m_currentPkt);
m_promiscSnifferTrace(m_currentPkt);
the implementation of ``operator()`` adds the bound parameter into the actual
function call::
@@ -542,20 +544,20 @@ function call::
It's possible to bind two or three arguments as well. Say we have a function with
signature::
static void NotifyEvent (Ptr<A> a, Ptr<B> b, MyEventType e);
static void NotifyEvent(Ptr<A> a, Ptr<B> b, MyEventType e);
One can create bound callback binding first two arguments like::
MakeBoundCallback (&NotifyEvent, a1, b1);
MakeBoundCallback(&NotifyEvent, a1, b1);
assuming `a1` and `b1` are objects of type `A` and `B` respectively. Similarly for
three arguments one would have function with a signature::
static void NotifyEvent (Ptr<A> a, Ptr<B> b, MyEventType e);
static void NotifyEvent(Ptr<A> a, Ptr<B> b, MyEventType e);
Binding three arguments in done with::
MakeBoundCallback (&NotifyEvent, a1, b1, c1);
MakeBoundCallback(&NotifyEvent, a1, b1, c1);
again assuming `a1`, `b1` and `c1` are objects of type `A`, `B` and `C` respectively.

View File

@@ -213,7 +213,7 @@ the basics here, instead focusing on preferred usage for |ns3|.
| The ``Frobnitz`` is accessed by:: | The ``Frobnitz`` is accessed by:: |
| | |
| Foo::Frobnitz frob; | Foo::Frobnitz frob; |
| frob.Set (...); | frob.Set (...); |
| frob.Set(...); | frob.Set(...); |
+--------------------------------------+------------------------------------+
To use a specific syntax highlighter, for example, ``bash`` shell commands:
@@ -315,7 +315,7 @@ The preferred style for Doxygen comments is the JavaDoc style::
* Understanding this material shouldn't be necessary to using
* the class or method.
*/
void ExampleFunction (const int foo, double & bar, const bool baz);
void ExampleFunction(const int foo, double & bar, const bool baz);
In this style the Doxygen comment block begins with two \`*' characters:
``/**``, and precedes the item being documented.
@@ -324,7 +324,7 @@ For items needing only a brief description, either of these short forms
is appropriate::
/** Destructor implementation. */
void DoDispose ();
void DoDispose();
int m_count; //!< Count of ...
@@ -355,8 +355,8 @@ Useful Features
#. In the sub class mark inherited functions with an ordinary comment::
// Inherited methods
virtual void FooBar ();
virtual int BarFoo (double baz);
virtual void FooBar();
virtual int BarFoo(double baz);
This doesn't work for static functions; see ``GetTypeId``, below, for an
example.
@@ -596,7 +596,7 @@ usage for |ns3|.
* \tparam U \deduced The argument type.
* \param [in] a The argument.
*/
template <typename T, typename U> T Function (U a);
template <typename T, typename U> T Function(U a);
* Use ``\tparam U \deduced`` because the type ``U`` can be deduced at
the site where the template is invoked. Basically deduction can only
@@ -604,7 +604,7 @@ usage for |ns3|.
* Use ``\tparam T \explicit`` because the type ``T`` can't be deduced;
it must be given explicitly at the invocation site, as in
``Create<MyObject> (...)``
``Create<MyObject>(...)``
* ``\internal`` should be used only to set off a discussion of implementation
details, not to mark ``private`` functions (they are already marked,
@@ -621,16 +621,16 @@ cases is:
* Default constructor/destructor::
MyClass (); //!< Default constructor
~MyClass (); //!< Destructor
MyClass(); //!< Default constructor
~MyClass(); //!< Destructor
* Dummy destructor and DoDispose::
/** Dummy destructor, see DoDispose. */
~MyClass ();
~MyClass();
/** Destructor implementation */
virtual void DoDispose ();
virtual void DoDispose();
* GetTypeId::
@@ -638,4 +638,4 @@ cases is:
* Register this type.
* \return The object TypeId.
*/
static TypeId GetTypeId ();
static TypeId GetTypeId();

View File

@@ -62,7 +62,7 @@ might write this:
::
void handler (int arg0, int arg1)
void handler(int arg0, int arg1)
{
std::cout << "handler called with argument arg0=" << arg0 << " and
arg1=" << arg1 << std::endl;
@@ -115,13 +115,13 @@ What does this mean?
::
Simulator::Schedule (Time const &time, MEM mem_ptr, OBJ obj);
Simulator::Schedule(Time const &time, MEM mem_ptr, OBJ obj);
vs.
::
Simulator::ScheduleWithContext (uint32_t context, Time const &time, MEM mem_ptr, OBJ obj);
Simulator::ScheduleWithContext(uint32_t context, Time const &time, MEM mem_ptr, OBJ obj);
Readers who invest time and effort in developing or using a non-trivial
simulation model will know the value of the |ns3| logging framework to
@@ -212,8 +212,8 @@ event execution. These are derived from the abstract base class `SimulatorImpl`
You can choose which simulator engine to use by setting a global variable,
for example::
GlobalValue::Bind ("SimulatorImplementationType",
StringValue ("ns3::DistributedSimulatorImpl"));
GlobalValue::Bind("SimulatorImplementationType",
StringValue("ns3::DistributedSimulatorImpl"));
or by using a command line argument::
@@ -306,8 +306,8 @@ The main job of the `Scheduler` classes is to maintain the priority queue of
future events. The scheduler can be set with a global variable,
similar to choosing the `SimulatorImpl`::
GlobalValue::Bind ("SchedulerType",
StringValue ("ns3::DistributedSimulatorImpl"));
GlobalValue::Bind("SchedulerType",
StringValue("ns3::DistributedSimulatorImpl"));
The scheduler can be changed at any time via `Simulator::SetScheduler()`.
The default scheduler is `MapScheduler` which uses a `std::map<>` to
@@ -343,6 +343,3 @@ complexity of the other API calls.
+-----------------------+-------------------------------------+-------------+--------------+----------+--------------+
| PriorityQueueSchduler | `std::priority_queue<,std::vector>` | Logarithimc | Logarithims | 24 bytes | 0 |
+-----------------------+-------------------------------------+-------------+--------------+----------+--------------+

View File

@@ -88,24 +88,24 @@ was created using the following code from gnuplot-example.cc: ::
std::string dataTitle = "2-D Data";
// Instantiate the plot and set its title.
Gnuplot plot (graphicsFileName);
plot.SetTitle (plotTitle);
Gnuplot plot(graphicsFileName);
plot.SetTitle(plotTitle);
// Make the graphics file, which the plot file will create when it
// is used with Gnuplot, be a PNG file.
plot.SetTerminal ("png");
plot.SetTerminal("png");
// Set the labels for each axis.
plot.SetLegend ("X Values", "Y Values");
plot.SetLegend("X Values", "Y Values");
// Set the range for the x axis.
plot.AppendExtra ("set xrange [-6:+6]");
plot.AppendExtra("set xrange [-6:+6]");
// Instantiate the dataset, set its title, and make the points be
// plotted along with connecting lines.
Gnuplot2dDataset dataset;
dataset.SetTitle (dataTitle);
dataset.SetStyle (Gnuplot2dDataset::LINES_POINTS);
dataset.SetTitle(dataTitle);
dataset.SetStyle(Gnuplot2dDataset::LINES_POINTS);
double x;
double y;
@@ -121,20 +121,20 @@ was created using the following code from gnuplot-example.cc: ::
y = x * x;
// Add this point.
dataset.Add (x, y);
dataset.Add(x, y);
}
// Add the dataset to the plot.
plot.AddDataset (dataset);
plot.AddDataset(dataset);
// Open the plot file.
std::ofstream plotFile (plotFileName.c_str());
std::ofstream plotFile(plotFileName.c_str());
// Write the plot file.
plot.GenerateOutput (plotFile);
plot.GenerateOutput(plotFile);
// Close the plot file.
plotFile.close ();
plotFile.close();
An Example 2-Dimensional Plot with Error Bars
*********************************************
@@ -154,27 +154,27 @@ was created using the following code from gnuplot-example.cc: ::
std::string dataTitle = "2-D Data With Error Bars";
// Instantiate the plot and set its title.
Gnuplot plot (graphicsFileName);
plot.SetTitle (plotTitle);
Gnuplot plot(graphicsFileName);
plot.SetTitle(plotTitle);
// Make the graphics file, which the plot file will create when it
// is used with Gnuplot, be a PNG file.
plot.SetTerminal ("png");
plot.SetTerminal("png");
// Set the labels for each axis.
plot.SetLegend ("X Values", "Y Values");
plot.SetLegend("X Values", "Y Values");
// Set the range for the x axis.
plot.AppendExtra ("set xrange [-6:+6]");
plot.AppendExtra("set xrange [-6:+6]");
// Instantiate the dataset, set its title, and make the points be
// plotted with no connecting lines.
Gnuplot2dDataset dataset;
dataset.SetTitle (dataTitle);
dataset.SetStyle (Gnuplot2dDataset::POINTS);
dataset.SetTitle(dataTitle);
dataset.SetStyle(Gnuplot2dDataset::POINTS);
// Make the dataset have error bars in both the x and y directions.
dataset.SetErrorBars (Gnuplot2dDataset::XY);
dataset.SetErrorBars(Gnuplot2dDataset::XY);
double x;
double xErrorDelta;
@@ -199,20 +199,20 @@ was created using the following code from gnuplot-example.cc: ::
// Add this point with uncertainties in both the x and y
// direction.
dataset.Add (x, y, xErrorDelta, yErrorDelta);
dataset.Add(x, y, xErrorDelta, yErrorDelta);
}
// Add the dataset to the plot.
plot.AddDataset (dataset);
plot.AddDataset(dataset);
// Open the plot file.
std::ofstream plotFile (plotFileName.c_str());
std::ofstream plotFile(plotFileName.c_str());
// Write the plot file.
plot.GenerateOutput (plotFile);
plot.GenerateOutput(plotFile);
// Close the plot file.
plotFile.close ();
plotFile.close();
An Example 3-Dimensional Plot
*****************************
@@ -232,34 +232,34 @@ was created using the following code from gnuplot-example.cc: ::
std::string dataTitle = "3-D Data";
// Instantiate the plot and set its title.
Gnuplot plot (graphicsFileName);
plot.SetTitle (plotTitle);
Gnuplot plot(graphicsFileName);
plot.SetTitle(plotTitle);
// Make the graphics file, which the plot file will create when it
// is used with Gnuplot, be a PNG file.
plot.SetTerminal ("png");
plot.SetTerminal("png");
// Rotate the plot 30 degrees around the x axis and then rotate the
// plot 120 degrees around the new z axis.
plot.AppendExtra ("set view 30, 120, 1.0, 1.0");
plot.AppendExtra("set view 30, 120, 1.0, 1.0");
// Make the zero for the z-axis be in the x-axis and y-axis plane.
plot.AppendExtra ("set ticslevel 0");
plot.AppendExtra("set ticslevel 0");
// Set the labels for each axis.
plot.AppendExtra ("set xlabel 'X Values'");
plot.AppendExtra ("set ylabel 'Y Values'");
plot.AppendExtra ("set zlabel 'Z Values'");
plot.AppendExtra("set xlabel 'X Values'");
plot.AppendExtra("set ylabel 'Y Values'");
plot.AppendExtra("set zlabel 'Z Values'");
// Set the ranges for the x and y axis.
plot.AppendExtra ("set xrange [-5:+5]");
plot.AppendExtra ("set yrange [-5:+5]");
plot.AppendExtra("set xrange [-5:+5]");
plot.AppendExtra("set yrange [-5:+5]");
// Instantiate the dataset, set its title, and make the points be
// connected by lines.
Gnuplot3dDataset dataset;
dataset.SetTitle (dataTitle);
dataset.SetStyle ("with lines");
dataset.SetTitle(dataTitle);
dataset.SetStyle("with lines");
double x;
double y;
@@ -278,22 +278,22 @@ was created using the following code from gnuplot-example.cc: ::
z = x * x * y * y;
// Add this point.
dataset.Add (x, y, z);
dataset.Add(x, y, z);
}
// The blank line is necessary at the end of each x value's data
// points for the 3-D surface grid to work.
dataset.AddEmptyLine ();
dataset.AddEmptyLine();
}
// Add the dataset to the plot.
plot.AddDataset (dataset);
plot.AddDataset(dataset);
// Open the plot file.
std::ofstream plotFile (plotFileName.c_str());
std::ofstream plotFile(plotFileName.c_str());
// Write the plot file.
plot.GenerateOutput (plotFile);
plot.GenerateOutput(plotFile);
// Close the plot file.
plotFile.close ();
plotFile.close();

View File

@@ -99,7 +99,7 @@ To add the hash function ``foo``, follow the ``hash-murmur3.h``/``.cc`` pattern:
* ``include`` the declaration in ``hash.h`` (at the point where
``hash-murmur3.h`` is included.
* In your own code, instantiate a ``Hasher`` object via the constructor
``Hasher (Ptr<Hash::Function::Foo> ())``
``Hasher(Ptr<Hash::Function::Foo>())``
If your hash function is a single function, e.g. ``hashf``, you don't

View File

@@ -60,8 +60,8 @@ is called "router" such as here:
::
RouterTestSuite::RouterTestSuite ()
: TestSuite ("router", UNIT)
RouterTestSuite::RouterTestSuite()
: TestSuite("router", UNIT)
Try this command:
@@ -154,8 +154,8 @@ which looks like this:
::
#include "ns3/example-as-test.h"
static ns3::ExampleAsTestSuite g_modExampleOne ("mymodule-example-mod-example-one", "mod-example", NS_TEST_SOURCEDIR, "--arg-one");
static ns3::ExampleAsTestSuite g_modExampleTwo ("mymodule-example-mod-example-two", "mod-example", NS_TEST_SOURCEDIR, "--arg-two");
static ns3::ExampleAsTestSuite g_modExampleOne("mymodule-example-mod-example-one", "mod-example", NS_TEST_SOURCEDIR, "--arg-one");
static ns3::ExampleAsTestSuite g_modExampleTwo("mymodule-example-mod-example-two", "mod-example", NS_TEST_SOURCEDIR, "--arg-two");
The arguments to the constructor are the name of the test suite, the
example to run, the directory that contains the "good" reference file
@@ -240,11 +240,11 @@ the wifi Information Elements.
...
};
void
BasicMultiLinkElementTest::DoRun ()
BasicMultiLinkElementTest::DoRun()
{
MultiLinkElement mle (WIFI_MAC_MGT_BEACON);
MultiLinkElement mle(WIFI_MAC_MGT_BEACON);
// Fill in the Multi-Link Element
TestHeaderSerialization (mle, WIFI_MAC_MGT_BEACON);
TestHeaderSerialization(mle, WIFI_MAC_MGT_BEACON);
}
Examples of this approach are found, e.g., in ``src/wifi/test/wifi-eht-info-elems-test.cc``

View File

@@ -31,9 +31,9 @@ use of a particular function.
For example, this code snippet is from ``Ipv4L3Protocol::IsDestinationAddress()``::
if (address == iaddr.GetBroadcast ())
if (address == iaddr.GetBroadcast())
{
NS_LOG_LOGIC ("For me (interface broadcast address)");
NS_LOG_LOGIC("For me (interface broadcast address)");
return true;
}
@@ -66,10 +66,10 @@ The second way to enable logging is to use explicit statements in your
program, such as in the ``first`` tutorial program::
int
main (int argc, char *argv[])
main(int argc, char *argv[])
{
LogComponentEnable ("UdpEchoClientApplication", LOG_LEVEL_INFO);
LogComponentEnable ("UdpEchoServerApplication", LOG_LEVEL_INFO);
LogComponentEnable("UdpEchoClientApplication", LOG_LEVEL_INFO);
LogComponentEnable("UdpEchoServerApplication", LOG_LEVEL_INFO);
...
(The meaning of ``LOG_LEVEL_INFO``, and other possible values,
@@ -107,7 +107,7 @@ in a module, spanning different compilation units, but logically grouped
together, such as the |ns3| wifi code::
WifiHelper wifiHelper;
wifiHelper.EnableLogComponents ();
wifiHelper.EnableLogComponents();
The ``NS_LOG`` log component wildcard \`*' will enable all components.
@@ -319,7 +319,7 @@ How to add logging to your code
Adding logging to your code is very simple:
1. Invoke the ``NS_LOG_COMPONENT_DEFINE (...);`` macro
1. Invoke the ``NS_LOG_COMPONENT_DEFINE(...);`` macro
inside of ``namespace ns3``.
Create a unique string identifier (usually based on the name of the file
@@ -330,7 +330,7 @@ Adding logging to your code is very simple:
namespace ns3 {
NS_LOG_COMPONENT_DEFINE ("Ipv4L3Protocol");
NS_LOG_COMPONENT_DEFINE("Ipv4L3Protocol");
...
This registers ``Ipv4L3Protocol`` as a log component.
@@ -361,15 +361,15 @@ In case you want to add logging statements to the methods of your template class
This requires you to perform these steps for all the subclasses of your class.
2. Invoke the ``NS_LOG_TEMPLATE_DEFINE (...);`` macro in the constructor of
2. Invoke the ``NS_LOG_TEMPLATE_DEFINE(...);`` macro in the constructor of
your class by providing the name of a log component registered by calling
the ``NS_LOG_COMPONENT_DEFINE (...);`` macro in some module. For instance:
the ``NS_LOG_COMPONENT_DEFINE(...);`` macro in some module. For instance:
::
template <typename Item>
Queue<Item>::Queue ()
: NS_LOG_TEMPLATE_DEFINE ("Queue")
Queue<Item>::Queue()
: NS_LOG_TEMPLATE_DEFINE("Queue")
{
}
@@ -380,18 +380,18 @@ In case you want to add logging statements to a static member template
1. Invoke the ``NS_LOG_STATIC_TEMPLATE_DEFINE (...);`` macro in your static
method by providing the name of a log component registered by calling
the ``NS_LOG_COMPONENT_DEFINE (...);`` macro in some module. For instance:
the ``NS_LOG_COMPONENT_DEFINE(...);`` macro in some module. For instance:
::
template <typename Item>
void
NetDeviceQueue::PacketEnqueued (Ptr<Queue<Item> > queue,
Ptr<NetDeviceQueueInterface> ndqi,
uint8_t txq, Ptr<const Item> item)
NetDeviceQueue::PacketEnqueued(Ptr<Queue<Item> > queue,
Ptr<NetDeviceQueueInterface> ndqi,
uint8_t txq, Ptr<const Item> item)
{
NS_LOG_STATIC_TEMPLATE_DEFINE ("NetDeviceQueueInterface");
NS_LOG_STATIC_TEMPLATE_DEFINE("NetDeviceQueueInterface");
...
2. Add logging statements (macro calls) to your static method.
@@ -433,24 +433,24 @@ Logging Macros
Severity Class Macro
================ ==========================
``LOG_NONE`` (none needed)
``LOG_ERROR`` ``NS_LOG_ERROR (...);``
``LOG_WARN`` ``NS_LOG_WARN (...);``
``LOG_DEBUG`` ``NS_LOG_DEBUG (...);``
``LOG_INFO`` ``NS_LOG_INFO (...);``
``LOG_FUNCTION`` ``NS_LOG_FUNCTION (...);``
``LOG_LOGIC`` ``NS_LOG_LOGIC (...);``
``LOG_ERROR`` ``NS_LOG_ERROR(...);``
``LOG_WARN`` ``NS_LOG_WARN(...);``
``LOG_DEBUG`` ``NS_LOG_DEBUG(...);``
``LOG_INFO`` ``NS_LOG_INFO(...);``
``LOG_FUNCTION`` ``NS_LOG_FUNCTION(...);``
``LOG_LOGIC`` ``NS_LOG_LOGIC(...);``
================ ==========================
The macros function as output streamers, so anything you can send to
``std::cout``, joined by ``<<`` operators, is allowed::
void MyClass::Check (int value, char * item)
void MyClass::Check(int value, char * item)
{
NS_LOG_FUNCTION (this << arg << item);
NS_LOG_FUNCTION(this << arg << item);
if (arg > 10)
{
NS_LOG_ERROR ("encountered bad value " << value <<
" while checking " << name << "!");
NS_LOG_ERROR("encountered bad value " << value <<
" while checking " << name << "!");
}
...
}
@@ -463,7 +463,7 @@ Logging Macros
Unconditional Logging
=====================
As a convenience, the ``NS_LOG_UNCOND (...);`` macro will always log its
As a convenience, the ``NS_LOG_UNCOND(...);`` macro will always log its
arguments, even if the associated log-component is not enabled at any
severity. This macro does not use any of the prefix options. Note that
logging is only enabled in debug builds; this macro won't produce
@@ -473,19 +473,19 @@ output in optimized builds.
Guidelines
==========
* Start every class method with ``NS_LOG_FUNCTION (this << args...);``
* Start every class method with ``NS_LOG_FUNCTION(this << args...);``
This enables easy function call tracing.
* Except: don't log operators or explicit copy constructors,
since these will cause infinite recursion and stack overflow.
* For methods without arguments use the same form:
``NS_LOG_FUNCTION (this);``
``NS_LOG_FUNCTION(this);``
* For static functions:
* With arguments use ``NS_LOG_FUNCTION (...);`` as normal.
* Without arguments use ``NS_LOG_FUNCTION_NOARGS ();``
* With arguments use ``NS_LOG_FUNCTION(...);`` as normal.
* Without arguments use ``NS_LOG_FUNCTION_NOARGS();``
* Use ``NS_LOG_ERROR`` for serious error conditions that probably
invalidate the simulation execution.
@@ -507,10 +507,7 @@ Guidelines
``NS_LOG="***"``).
* Use an explicit cast for any variable of type uint8_t or int8_t,
e.g., ``NS_LOG_LOGIC ("Variable i is " << static_cast<int> (i));``.
e.g., ``NS_LOG_LOGIC("Variable i is " << static_cast<int>(i));``.
Without the cast, the integer is interpreted as a char, and the result
will be most likely not in line with the expectations.
This is a well documented C++ 'feature'.

View File

@@ -62,7 +62,7 @@ So far, in our design, we have::
* \returns true if the Packet is to be considered as errored/corrupted
* \param pkt Packet to apply error model to
*/
bool IsCorrupt (Ptr<Packet> pkt);
bool IsCorrupt(Ptr<Packet> pkt);
};
Note that we do not pass a const pointer, thereby allowing the function to
@@ -109,16 +109,16 @@ a base class and first subclass that could be posted for initial review::
class ErrorModel
{
public:
ErrorModel ();
virtual ~ErrorModel ();
bool IsCorrupt (Ptr<Packet> pkt);
void Reset ();
void Enable ();
void Disable ();
bool IsEnabled () const;
ErrorModel();
virtual ~ErrorModel();
bool IsCorrupt(Ptr<Packet> pkt);
void Reset();
void Enable();
void Disable();
bool IsEnabled() const;
private:
virtual bool DoCorrupt (Ptr<Packet> pkt) = 0;
virtual void DoReset () = 0;
virtual bool DoCorrupt(Ptr<Packet> pkt) = 0;
virtual void DoReset() = 0;
};
enum ErrorUnit
@@ -133,16 +133,16 @@ a base class and first subclass that could be posted for initial review::
class RateErrorModel : public ErrorModel
{
public:
RateErrorModel ();
virtual ~RateErrorModel ();
enum ErrorUnit GetUnit () const;
void SetUnit (enum ErrorUnit error_unit);
double GetRate () const;
void SetRate (double rate);
void SetRandomVariable (const RandomVariable &ranvar);
RateErrorModel();
virtual ~RateErrorModel();
enum ErrorUnit GetUnit() const;
void SetUnit(enum ErrorUnit error_unit);
double GetRate() const;
void SetRate(double rate);
void SetRandomVariable(const RandomVariable &ranvar);
private:
virtual bool DoCorrupt (Ptr<Packet> pkt);
virtual void DoReset ();
virtual bool DoCorrupt(Ptr<Packet> pkt);
virtual void DoReset();
};
@@ -294,19 +294,19 @@ from class Object.::
class ErrorModel : public Object
{
public:
static TypeId GetTypeId ();
static TypeId GetTypeId();
ErrorModel ();
virtual ~ErrorModel ();
ErrorModel();
virtual ~ErrorModel();
};
class RateErrorModel : public ErrorModel
{
public:
static TypeId GetTypeId ();
static TypeId GetTypeId();
RateErrorModel ();
virtual ~RateErrorModel ();
RateErrorModel();
virtual ~RateErrorModel();
};
#endif
@@ -319,7 +319,7 @@ But we are in ``src/network/model``, so we must include it as "``#include
"ns3/object.h"``". Note also that this goes outside the namespace declaration.
Second, each class must implement a static public member function called
``GetTypeId ()``.
``GetTypeId()``.
Third, it is a good idea to implement constructors and destructors rather than
to let the compiler generate them, and to make the destructor virtual. In C++,
@@ -335,52 +335,52 @@ file.::
namespace ns3 {
NS_OBJECT_ENSURE_REGISTERED (ErrorModel);
NS_OBJECT_ENSURE_REGISTERED(ErrorModel);
TypeId ErrorModel::GetTypeId ()
TypeId ErrorModel::GetTypeId()
{
static TypeId tid = TypeId ("ns3::ErrorModel")
.SetParent<Object> ()
.SetGroupName ("Network")
static TypeId tid = TypeId("ns3::ErrorModel")
.SetParent<Object>()
.SetGroupName("Network")
;
return tid;
}
ErrorModel::ErrorModel ()
ErrorModel::ErrorModel()
{
}
ErrorModel::~ErrorModel ()
ErrorModel::~ErrorModel()
{
}
NS_OBJECT_ENSURE_REGISTERED (RateErrorModel);
NS_OBJECT_ENSURE_REGISTERED(RateErrorModel);
TypeId RateErrorModel::GetTypeId ()
TypeId RateErrorModel::GetTypeId()
{
static TypeId tid = TypeId ("ns3::RateErrorModel")
.SetParent<ErrorModel> ()
.SetGroupName ("Network")
.AddConstructor<RateErrorModel> ()
static TypeId tid = TypeId("ns3::RateErrorModel")
.SetParent<ErrorModel>()
.SetGroupName("Network")
.AddConstructor<RateErrorModel>()
;
return tid;
}
RateErrorModel::RateErrorModel ()
RateErrorModel::RateErrorModel()
{
}
RateErrorModel::~RateErrorModel ()
RateErrorModel::~RateErrorModel()
{
}
What is the ``GetTypeId ()`` function? This function does a few things. It
What is the ``GetTypeId()`` function? This function does a few things. It
registers a unique string into the TypeId system. It establishes the hierarchy
of objects in the attribute system (via ``SetParent``). It also declares that
certain objects can be created via the object creation framework
(``AddConstructor``).
The macro ``NS_OBJECT_ENSURE_REGISTERED (classname)`` is needed also once for
The macro ``NS_OBJECT_ENSURE_REGISTERED(classname)`` is needed also once for
every class that defines a new GetTypeId method, and it does the actual
registration of the class into the system. The :ref:`Object-model` chapter
discusses this in more detail.
@@ -434,35 +434,35 @@ Add Accessor
::
void
PointToPointNetDevice::SetReceiveErrorModel (Ptr<ErrorModel> em)
PointToPointNetDevice::SetReceiveErrorModel(Ptr<ErrorModel> em)
{
NS_LOG_FUNCTION (this << em);
NS_LOG_FUNCTION(this << em);
m_receiveErrorModel = em;
}
.AddAttribute ("ReceiveErrorModel",
.AddAttribute("ReceiveErrorModel",
"The receiver error model used to simulate packet loss",
PointerValue (),
MakePointerAccessor (&PointToPointNetDevice::m_receiveErrorModel),
MakePointerChecker<ErrorModel> ())
PointerValue(),
MakePointerAccessor(&PointToPointNetDevice::m_receiveErrorModel),
MakePointerChecker<ErrorModel>())
Plumb Into the System
+++++++++++++++++++++
::
void PointToPointNetDevice::Receive (Ptr<Packet> packet)
void PointToPointNetDevice::Receive(Ptr<Packet> packet)
{
NS_LOG_FUNCTION (this << packet);
NS_LOG_FUNCTION(this << packet);
uint16_t protocol = 0;
if (m_receiveErrorModel && m_receiveErrorModel->IsCorrupt (packet) )
if(m_receiveErrorModel && m_receiveErrorModel->IsCorrupt(packet) )
{
//
// If we have an error model and it indicates that it is time to lose a
// corrupted packet, don't forward this packet up, let it go.
//
m_dropTrace (packet);
m_dropTrace(packet);
}
else
{
@@ -470,12 +470,12 @@ Plumb Into the System
// Hit the receive trace hook, strip off the point-to-point protocol header
// and forward this packet up the protocol stack.
//
m_rxTrace (packet);
m_rxTrace(packet);
ProcessHeader(packet, protocol);
m_rxCallback (this, packet, protocol, GetRemote ());
if (!m_promiscCallback.IsNull ())
{ m_promiscCallback (this, packet, protocol, GetRemote (),
GetAddress (), NetDevice::PACKET_HOST);
m_rxCallback(this, packet, protocol, GetRemote());
if(!m_promiscCallback.IsNull())
{ m_promiscCallback(this, packet, protocol, GetRemote(),
GetAddress(), NetDevice::PACKET_HOST);
}
}
}
@@ -492,13 +492,13 @@ Create Null Functional Script
// We can obtain a handle to the NetDevice via the channel and node
// pointers
Ptr<PointToPointNetDevice> nd3 = PointToPointTopology::GetNetDevice
(n3, channel2);
Ptr<ErrorModel> em = Create<ErrorModel> ();
nd3->SetReceiveErrorModel (em);
(n3, channel2);
Ptr<ErrorModel> em = Create<ErrorModel>();
nd3->SetReceiveErrorModel(em);
bool
ErrorModel::DoCorrupt (Packet& p)
ErrorModel::DoCorrupt(Packet& p)
{
NS_LOG_FUNCTION;
NS_LOG_UNCOND("Corrupt!");
@@ -514,7 +514,7 @@ Add a Subclass
**************
The trivial base class ErrorModel does not do anything interesting, but it
provides a useful base class interface (Corrupt () and Reset ()), forwarded to
provides a useful base class interface (``Corrupt()`` and ``Reset()``), forwarded to
virtual functions that can be subclassed. Let's next consider what we call a
BasicErrorModel which is based on the |ns2| ErrorModel class (in
``ns-2/queue/errmodel.{cc,h}``).
@@ -542,24 +542,24 @@ We declare BasicErrorModel to be a subclass of ErrorModel as follows,::
class BasicErrorModel : public ErrorModel
{
public:
static TypeId GetTypeId ();
static TypeId GetTypeId();
...
private:
// Implement base class pure virtual functions
virtual bool DoCorrupt (Ptr<Packet> p);
virtual bool DoReset ();
virtual bool DoCorrupt(Ptr<Packet> p);
virtual bool DoReset();
...
}
and configure the subclass GetTypeId function by setting a unique TypeId string
and setting the Parent to ErrorModel::
TypeId RateErrorModel::GetTypeId ()
TypeId RateErrorModel::GetTypeId()
{
static TypeId tid = TypeId ("ns3::RateErrorModel")
.SetParent<ErrorModel> ()
.SetGroupName ("Network")
.AddConstructor<RateErrorModel> ()
static TypeId tid = TypeId("ns3::RateErrorModel")
.SetParent<ErrorModel>()
.SetGroupName("Network")
.AddConstructor<RateErrorModel>()
...
Build Core Functions and Unit Tests

View File

@@ -161,10 +161,10 @@ The skeleton test suite will contain the below constructor,
which declares a new unit test named ``new-module``,
with a single test case consisting of the class ``NewModuleTestCase1``::
NewModuleTestSuite::NewModuleTestSuite ()
: TestSuite ("new-module", UNIT)
NewModuleTestSuite::NewModuleTestSuite()
: TestSuite("new-module", UNIT)
{
AddTestCase (new NewModuleTestCase1);
AddTestCase(new NewModuleTestCase1);
}
Step 3 - Declare Source Files

View File

@@ -32,10 +32,10 @@ properties; for instance::
class Address
{
public:
Address ();
Address (uint8_t type, const uint8_t *buffer, uint8_t len);
Address (const Address & address);
Address &operator = (const Address &address);
Address();
Address(uint8_t type, const uint8_t *buffer, uint8_t len);
Address(const Address & address);
Address &operator=(const Address &address);
...
private:
uint8_t m_type;
@@ -132,7 +132,7 @@ allocated using a templated Create or CreateObject method, as follows.
For objects deriving from class :cpp:class:`Object`::
Ptr<WifiNetDevice> device = CreateObject<WifiNetDevice> ();
Ptr<WifiNetDevice> device = CreateObject<WifiNetDevice>();
Please do not create such objects using ``operator new``; create them using
:cpp:func:`CreateObject()` instead.
@@ -141,7 +141,7 @@ For objects deriving from class :cpp:class:`SimpleRefCount`, or other objects
that support usage of the smart pointer class, a templated helper function is
available and recommended to be used::
Ptr<B> b = Create<B> ();
Ptr<B> b = Create<B>();
This is simply a wrapper around operator new that correctly handles the
reference counting system.
@@ -190,12 +190,12 @@ node. Let's look at how some Ipv4 protocols are added to a node.::
static void
AddIpv4Stack(Ptr<Node> node)
{
Ptr<Ipv4L3Protocol> ipv4 = CreateObject<Ipv4L3Protocol> ();
ipv4->SetNode (node);
node->AggregateObject (ipv4);
Ptr<Ipv4Impl> ipv4Impl = CreateObject<Ipv4Impl> ();
ipv4Impl->SetIpv4 (ipv4);
node->AggregateObject (ipv4Impl);
Ptr<Ipv4L3Protocol> ipv4 = CreateObject<Ipv4L3Protocol>();
ipv4->SetNode(node);
node->AggregateObject(ipv4);
Ptr<Ipv4Impl> ipv4Impl = CreateObject<Ipv4Impl>();
ipv4Impl->SetIpv4(ipv4);
node->AggregateObject(ipv4Impl);
}
Note that the Ipv4 protocols are created using :cpp:func:`CreateObject()`.
@@ -220,7 +220,7 @@ configure a default route. To do so, it must access an object within the node
that has an interface to the IP forwarding configuration. It performs the
following::
Ptr<Ipv4> ipv4 = m_node->GetObject<Ipv4> ();
Ptr<Ipv4> ipv4 = m_node->GetObject<Ipv4>();
If the node in fact does not have an Ipv4 object aggregated to it, then the
method will return null. Therefore, it is good practice to check the return
@@ -248,9 +248,9 @@ pattern in use in the |ns3| system. It is heavily used in the "helper" API.
Class :cpp:class:`ObjectFactory` can be used to instantiate objects and to
configure the attributes on those objects::
void SetTypeId (TypeId tid);
void Set (std::string name, const AttributeValue &value);
Ptr<T> Create () const;
void SetTypeId(TypeId tid);
void Set(std::string name, const AttributeValue &value);
Ptr<T> Create() const;
The first method allows one to use the |ns3| TypeId system to specify the type
of objects created. The second allows one to set attributes on the objects to be
@@ -260,15 +260,15 @@ For example: ::
ObjectFactory factory;
// Make this factory create objects of type FriisPropagationLossModel
factory.SetTypeId ("ns3::FriisPropagationLossModel")
factory.SetTypeId("ns3::FriisPropagationLossModel")
// Make this factory object change a default value of an attribute, for
// subsequently created objects
factory.Set ("SystemLoss", DoubleValue (2.0));
factory.Set("SystemLoss", DoubleValue(2.0));
// Create one such object
Ptr<Object> object = factory.Create ();
factory.Set ("SystemLoss", DoubleValue (3.0));
Ptr<Object> object = factory.Create();
factory.Set("SystemLoss", DoubleValue(3.0));
// Create another object with a different SystemLoss
Ptr<Object> object = factory.Create ();
Ptr<Object> object = factory.Create();
Downcasting
***********
@@ -285,9 +285,9 @@ dynamic casting much more user friendly::
template <typename T1, typename T2>
Ptr<T1>
DynamicCast (Ptr<T2> const&p)
DynamicCast(Ptr<T2> const&p)
{
return Ptr<T1> (dynamic_cast<T1 *> (PeekPointer (p)));
return Ptr<T1>(dynamic_cast<T1 *>(PeekPointer(p)));
}
DynamicCast works when the programmer has a base type pointer and is testing

View File

@@ -117,20 +117,20 @@ The correct way to create these objects is to use the templated
::
Ptr<UniformRandomVariable> x = CreateObject<UniformRandomVariable> ();
Ptr<UniformRandomVariable> x = CreateObject<UniformRandomVariable>();
then you can access values by calling methods on the object such as:
::
myRandomNo = x->GetInteger ();
myRandomNo = x->GetInteger();
If you try to instead do something like this:
::
myRandomNo = UniformRandomVariable().GetInteger ();
myRandomNo = UniformRandomVariable().GetInteger();
your program will encounter a segmentation fault, because the implementation
relies on some attribute construction that occurs only when `CreateObject`
@@ -160,11 +160,11 @@ A class :cpp:class:`ns3::RngSeedManager` provides an API to control the seeding
run number behavior. This seeding and substream state setting must be called
before any random variables are created; e.g::
RngSeedManager::SetSeed (3); // Changes seed from default of 1 to 3
RngSeedManager::SetRun (7); // Changes run number from default of 1 to 7
RngSeedManager::SetSeed(3); // Changes seed from default of 1 to 3
RngSeedManager::SetRun(7); // Changes run number from default of 1 to 7
// Now, create random variables
Ptr<UniformRandomVariable> x = CreateObject<UniformRandomVariable> ();
Ptr<ExponentialRandomVariable> y = CreateObject<ExponentialRandomVarlable> ();
Ptr<UniformRandomVariable> x = CreateObject<UniformRandomVariable>();
Ptr<ExponentialRandomVariable> y = CreateObject<ExponentialRandomVarlable>();
...
Which is better, setting a new seed or advancing the substream state? There is
@@ -227,13 +227,13 @@ that access the next value in the substream.
* \brief Returns a random double from the underlying distribution
* \return A floating point random value
*/
double GetValue () const;
double GetValue() const;
/**
* \brief Returns a random integer from the underlying distribution
* \return Integer cast of ::GetValue()
*/
uint32_t GetInteger () const;
uint32_t GetInteger() const;
We have already described the seeding configuration above. Different
RandomVariable subclasses may have additional API.
@@ -273,17 +273,17 @@ that values can be set for them through the |ns3| attribute system.
An example is in the propagation models for WifiNetDevice::
TypeId
RandomPropagationDelayModel::GetTypeId ()
RandomPropagationDelayModel::GetTypeId()
{
static TypeId tid = TypeId ("ns3::RandomPropagationDelayModel")
.SetParent<PropagationDelayModel> ()
.SetGroupName ("Propagation")
.AddConstructor<RandomPropagationDelayModel> ()
.AddAttribute ("Variable",
"The random variable which generates random delays (s).",
StringValue ("ns3::UniformRandomVariable"),
MakePointerAccessor (&RandomPropagationDelayModel::m_variable),
MakePointerChecker<RandomVariableStream> ())
static TypeId tid = TypeId("ns3::RandomPropagationDelayModel")
.SetParent<PropagationDelayModel>()
.SetGroupName("Propagation")
.AddConstructor<RandomPropagationDelayModel>()
.AddAttribute("Variable",
"The random variable which generates random delays (s).",
StringValue("ns3::UniformRandomVariable"),
MakePointerAccessor(&RandomPropagationDelayModel::m_variable),
MakePointerChecker<RandomVariableStream>())
;
return tid;
}

View File

@@ -58,8 +58,8 @@ The usage of the realtime simulator is straightforward, from a scripting
perspective. Users just need to set the attribute
``SimulatorImplementationType`` to the Realtime simulator, such as follows: ::
GlobalValue::Bind ("SimulatorImplementationType",
StringValue ("ns3::RealtimeSimulatorImpl"));
GlobalValue::Bind("SimulatorImplementationType",
StringValue("ns3::RealtimeSimulatorImpl"));
There is a script in ``examples/realtime/realtime-udp-echo.cc`` that
has an example of how to configure the realtime behavior. Try:

View File

@@ -707,7 +707,7 @@ arguments as needed, but basedir is the minimum needed)::
(gdb) r --suite=
Starting program: <..>/build/utils/ns3-dev-test-runner-debug --suite=wifi-interference
[Thread debugging using libthread_db enabled]
assert failed. file=../src/core/model/type-id.cc, line=138, cond="uid <= m_information.size () && uid != 0"
assert failed. file=../src/core/model/type-id.cc, line=138, cond="uid <= m_information.size() && uid != 0"
...
Here is another example of how to use valgrind to debug a memory problem
@@ -757,13 +757,13 @@ as a ''unit'' test with the display name, ``my-test-suite-name``.
class MySuite : public TestSuite
{
public:
MyTestSuite ();
MyTestSuite();
};
MyTestSuite::MyTestSuite ()
: TestSuite ("my-test-suite-name", UNIT)
MyTestSuite::MyTestSuite()
: TestSuite("my-test-suite-name", UNIT)
{
AddTestCase (new MyTestCase, TestCase::QUICK);
AddTestCase(new MyTestCase, TestCase::QUICK);
}
static MyTestSuite myTestSuite;
@@ -794,20 +794,20 @@ override also the ``DoSetup`` method.
class MyTestCase : public TestCase
{
MyTestCase ();
virtual void DoSetup ();
virtual void DoRun ();
MyTestCase();
virtual void DoSetup();
virtual void DoRun();
};
MyTestCase::MyTestCase ()
: TestCase ("Check some bit of functionality")
MyTestCase::MyTestCase()
: TestCase("Check some bit of functionality")
{
}
void
MyTestCase::DoRun ()
MyTestCase::DoRun()
{
NS_TEST_ASSERT_MSG_EQ (true, true, "Some failure message");
NS_TEST_ASSERT_MSG_EQ(true, true, "Some failure message");
}
Utilities

View File

@@ -24,7 +24,7 @@ output, as in, ::
#include <iostream>
...
int main ()
int main()
{
...
std::cout << "The value of x is " << x << std::endl;
@@ -139,19 +139,19 @@ made using those operators.::
class MyObject : public Object
{
public:
static TypeId GetTypeId ()
static TypeId GetTypeId()
{
static TypeId tid = TypeId ("MyObject")
.SetParent (Object::GetTypeId ())
.AddConstructor<MyObject> ()
.AddTraceSource ("MyInteger",
"An integer value to trace.",
MakeTraceSourceAccessor (&MyObject::m_myInt))
static TypeId tid = TypeId("MyObject")
.SetParent(Object::GetTypeId())
.AddConstructor<MyObject>()
.AddTraceSource("MyInteger",
"An integer value to trace.",
MakeTraceSourceAccessor(&MyObject::m_myInt))
;
return tid;
}
MyObject () {}
MyObject() {}
TracedValue<uint32_t> m_myInt;
};
@@ -166,7 +166,7 @@ infrastructure that overloads the operators mentioned above and drives the
callback process.::
void
IntTrace (Int oldValue, Int newValue)
IntTrace(Int oldValue, Int newValue)
{
std::cout << "Traced " << oldValue << " to " << newValue << std::endl;
}
@@ -176,11 +176,11 @@ function. This function will be called whenever one of the operators of the
``TracedValue`` is executed.::
int
main (int argc, char *argv[])
main(int argc, char *argv[])
{
Ptr<MyObject> myObject = CreateObject<MyObject> ();
Ptr<MyObject> myObject = CreateObject<MyObject>();
myObject->TraceConnectWithoutContext ("MyInteger", MakeCallback(&IntTrace));
myObject->TraceConnectWithoutContext("MyInteger", MakeCallback(&IntTrace));
myObject->m_myInt = 1234;
}
@@ -228,13 +228,13 @@ called a *config path*.
For example, one might find something that looks like the following in the
system (taken from ``examples/tcp-large-transfer.cc``)::
void CwndTracer (uint32_t oldval, uint32_t newval) {}
void CwndTracer(uint32_t oldval, uint32_t newval) {}
...
Config::ConnectWithoutContext (
"/NodeList/0/$ns3::TcpL4Protocol/SocketList/0/CongestionWindow",
MakeCallback (&CwndTracer));
Config::ConnectWithoutContext(
"/NodeList/0/$ns3::TcpL4Protocol/SocketList/0/CongestionWindow",
MakeCallback(&CwndTracer));
This should look very familiar. It is the same thing as the previous example,
except that a static member function of class ``Config`` is being called instead
@@ -246,11 +246,11 @@ must be an ``Attribute`` of an ``Object``. In fact, if you had a pointer to the
``Object`` that has the "CongestionWindow" ``Attribute`` handy (call it
``theObject``), you could write this just like the previous example::
void CwndTracer (uint32_t oldval, uint32_t newval) {}
void CwndTracer(uint32_t oldval, uint32_t newval) {}
...
theObject->TraceConnectWithoutContext ("CongestionWindow", MakeCallback (&CwndTracer));
theObject->TraceConnectWithoutContext("CongestionWindow", MakeCallback(&CwndTracer));
It turns out that the code for ``Config::ConnectWithoutContext`` does exactly
that. This function takes a path that represents a chain of ``Object`` pointers
@@ -284,7 +284,7 @@ This socket, the type of which turns out to be an ``ns3::TcpSocketImpl`` defines
an attribute called "CongestionWindow" which is a ``TracedValue<uint32_t>``.
The ``Config::ConnectWithoutContext`` now does a,::
object->TraceConnectWithoutContext ("CongestionWindow", MakeCallback (&CwndTracer));
object->TraceConnectWithoutContext("CongestionWindow", MakeCallback(&CwndTracer));
using the object pointer from "SocketList/0" which makes the connection between
the trace source defined in the socket to the callback -- ``CwndTracer``.
@@ -323,10 +323,10 @@ helper methods designed for use inside other (device) helpers.
Perhaps you will recall seeing some of these variations::
pointToPoint.EnablePcapAll ("second");
pointToPoint.EnablePcap ("second", p2pNodes.Get (0)->GetId (), 0);
csma.EnablePcap ("third", csmaDevices.Get (0), true);
pointToPoint.EnableAsciiAll (ascii.CreateFileStream ("myfirst.tr"));
pointToPoint.EnablePcapAll("second");
pointToPoint.EnablePcap("second", p2pNodes.Get(0)->GetId(), 0);
csma.EnablePcap("third", csmaDevices.Get(0), true);
pointToPoint.EnableAsciiAll(ascii.CreateFileStream("myfirst.tr"));
What may not be obvious, though, is that there is a consistent model for all of
the trace-related methods found in the system. We will now take a little time
@@ -381,14 +381,14 @@ The class ``PcapHelperForDevice`` is a ``mixin`` provides the high level
functionality for using pcap tracing in an |ns3| device. Every device must
implement a single virtual method inherited from this class.::
virtual void EnablePcapInternal (std::string prefix, Ptr<NetDevice> nd, bool promiscuous) = 0;
virtual void EnablePcapInternal(std::string prefix, Ptr<NetDevice> nd, bool promiscuous) = 0;
The signature of this method reflects the device-centric view of the situation
at this level. All of the public methods inherited from class
``PcapUserHelperForDevice`` reduce to calling this single device-dependent
implementation method. For example, the lowest level pcap method,::
void EnablePcap (std::string prefix, Ptr<NetDevice> nd, bool promiscuous = false, bool explicitFilename = false);
void EnablePcap(std::string prefix, Ptr<NetDevice> nd, bool promiscuous = false, bool explicitFilename = false);
will call the device implementation of ``EnablePcapInternal`` directly. All
other public pcap tracing methods build on this implementation to provide
@@ -402,17 +402,17 @@ Pcap Tracing Device Helper Methods
::
void EnablePcap (std::string prefix, Ptr<NetDevice> nd,
bool promiscuous = false, bool explicitFilename = false);
void EnablePcap (std::string prefix, std::string ndName,
bool promiscuous = false, bool explicitFilename = false);
void EnablePcap (std::string prefix, NetDeviceContainer d,
bool promiscuous = false);
void EnablePcap (std::string prefix, NodeContainer n,
bool promiscuous = false);
void EnablePcap (std::string prefix, uint32_t nodeid, uint32_t deviceid,
bool promiscuous = false);
void EnablePcapAll (std::string prefix, bool promiscuous = false);
void EnablePcap(std::string prefix, Ptr<NetDevice> nd,
bool promiscuous = false, bool explicitFilename = false);
void EnablePcap(std::string prefix, std::string ndName,
bool promiscuous = false, bool explicitFilename = false);
void EnablePcap(std::string prefix, NetDeviceContainer d,
bool promiscuous = false);
void EnablePcap(std::string prefix, NodeContainer n,
bool promiscuous = false);
void EnablePcap(std::string prefix, uint32_t nodeid, uint32_t deviceid,
bool promiscuous = false);
void EnablePcapAll(std::string prefix, bool promiscuous = false);
In each of the methods shown above, there is a default parameter called
``promiscuous`` that defaults to false. This parameter indicates that the trace
@@ -422,7 +422,7 @@ mode) simply add a true parameter to any of the calls above. For example,::
Ptr<NetDevice> nd;
...
helper.EnablePcap ("prefix", nd, true);
helper.EnablePcap("prefix", nd, true);
will enable promiscuous mode captures on the ``NetDevice`` specified by ``nd``.
@@ -438,7 +438,7 @@ since the net device must belong to exactly one ``Node``. For example,::
Ptr<NetDevice> nd;
...
helper.EnablePcap ("prefix", nd);
helper.EnablePcap("prefix", nd);
You can enable pcap tracing on a particular node/net-device pair by providing a
``std::string`` representing an object name service string to an ``EnablePcap``
@@ -446,10 +446,10 @@ method. The ``Ptr<NetDevice>`` is looked up from the name string. Again, the
``<Node>`` is implicit since the named net device must belong to exactly one
``Node``. For example,::
Names::Add ("server" ...);
Names::Add ("server/eth0" ...);
Names::Add("server" ...);
Names::Add("server/eth0" ...);
...
helper.EnablePcap ("prefix", "server/ath0");
helper.EnablePcap("prefix", "server/ath0");
You can enable pcap tracing on a collection of node/net-device pairs by
providing a ``NetDeviceContainer``. For each ``NetDevice`` in the container the
@@ -460,7 +460,7 @@ example,::
NetDeviceContainer d = ...;
...
helper.EnablePcap ("prefix", d);
helper.EnablePcap("prefix", d);
You can enable pcap tracing on a collection of node/net-device pairs by
providing a ``NodeContainer``. For each ``Node`` in the ``NodeContainer`` its
@@ -471,18 +471,18 @@ enabled.::
NodeContainer n;
...
helper.EnablePcap ("prefix", n);
helper.EnablePcap("prefix", n);
You can enable pcap tracing on the basis of node ID and device ID as well as
with explicit ``Ptr``. Each ``Node`` in the system has an integer node ID and
each device connected to a node has an integer device ID.::
helper.EnablePcap ("prefix", 21, 1);
helper.EnablePcap("prefix", 21, 1);
Finally, you can enable pcap tracing for all devices in the system, with the
same type as that managed by the device helper.::
helper.EnablePcapAll ("prefix");
helper.EnablePcapAll("prefix");
Pcap Tracing Device Helper Filename Selection
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -506,8 +506,8 @@ your pcap file name will automatically pick this up and be called
Finally, two of the methods shown above,::
void EnablePcap (std::string prefix, Ptr<NetDevice> nd, bool promiscuous = false, bool explicitFilename = false);
void EnablePcap (std::string prefix, std::string ndName, bool promiscuous = false, bool explicitFilename = false);
void EnablePcap(std::string prefix, Ptr<NetDevice> nd, bool promiscuous = false, bool explicitFilename = false);
void EnablePcap(std::string prefix, std::string ndName, bool promiscuous = false, bool explicitFilename = false);
have a default parameter called ``explicitFilename``. When set to true, this
parameter disables the automatic filename completion mechanism and allows you to
@@ -520,7 +520,7 @@ given device, one could::
Ptr<NetDevice> nd;
...
helper.EnablePcap ("my-pcap-file.pcap", nd, true, true);
helper.EnablePcap("my-pcap-file.pcap", nd, true, true);
The first ``true`` parameter enables promiscuous mode traces and the second
tells the helper to interpret the ``prefix`` parameter as a complete filename.
@@ -537,7 +537,7 @@ using ASCII tracing to a device helper class. As in the pcap case, every device
must implement a single virtual method inherited from the ASCII trace
``mixin``.::
virtual void EnableAsciiInternal (Ptr<OutputStreamWrapper> stream, std::string prefix, Ptr<NetDevice> nd) = 0;
virtual void EnableAsciiInternal(Ptr<OutputStreamWrapper> stream, std::string prefix, Ptr<NetDevice> nd) = 0;
The signature of this method reflects the device-centric view of the situation
at this level; and also the fact that the helper may be writing to a shared
@@ -546,8 +546,8 @@ class ``AsciiTraceHelperForDevice`` reduce to calling this single device-
dependent implementation method. For example, the lowest level ASCII trace
methods,::
void EnableAscii (std::string prefix, Ptr<NetDevice> nd);
void EnableAscii (Ptr<OutputStreamWrapper> stream, Ptr<NetDevice> nd);
void EnableAscii(std::string prefix, Ptr<NetDevice> nd);
void EnableAscii(Ptr<OutputStreamWrapper> stream, Ptr<NetDevice> nd);
will call the device implementation of ``EnableAsciiInternal`` directly,
providing either a valid prefix or stream. All other public ASCII tracing
@@ -562,23 +562,23 @@ Ascii Tracing Device Helper Methods
::
void EnableAscii (std::string prefix, Ptr<NetDevice> nd);
void EnableAscii (Ptr<OutputStreamWrapper> stream, Ptr<NetDevice> nd);
void EnableAscii(std::string prefix, Ptr<NetDevice> nd);
void EnableAscii(Ptr<OutputStreamWrapper> stream, Ptr<NetDevice> nd);
void EnableAscii (std::string prefix, std::string ndName);
void EnableAscii (Ptr<OutputStreamWrapper> stream, std::string ndName);
void EnableAscii(std::string prefix, std::string ndName);
void EnableAscii(Ptr<OutputStreamWrapper> stream, std::string ndName);
void EnableAscii (std::string prefix, NetDeviceContainer d);
void EnableAscii (Ptr<OutputStreamWrapper> stream, NetDeviceContainer d);
void EnableAscii(std::string prefix, NetDeviceContainer d);
void EnableAscii(Ptr<OutputStreamWrapper> stream, NetDeviceContainer d);
void EnableAscii (std::string prefix, NodeContainer n);
void EnableAscii (Ptr<OutputStreamWrapper> stream, NodeContainer n);
void EnableAscii(std::string prefix, NodeContainer n);
void EnableAscii(Ptr<OutputStreamWrapper> stream, NodeContainer n);
void EnableAscii (std::string prefix, uint32_t nodeid, uint32_t deviceid);
void EnableAscii (Ptr<OutputStreamWrapper> stream, uint32_t nodeid, uint32_t deviceid);
void EnableAscii(std::string prefix, uint32_t nodeid, uint32_t deviceid);
void EnableAscii(Ptr<OutputStreamWrapper> stream, uint32_t nodeid, uint32_t deviceid);
void EnableAsciiAll (std::string prefix);
void EnableAsciiAll (Ptr<OutputStreamWrapper> stream);
void EnableAsciiAll(std::string prefix);
void EnableAsciiAll(Ptr<OutputStreamWrapper> stream);
You are encouraged to peruse the Doxygen for class ``TraceHelperForDevice`` to
find the details of these methods; but to summarize ...
@@ -598,7 +598,7 @@ exactly one ``Node``. For example,::
Ptr<NetDevice> nd;
...
helper.EnableAscii ("prefix", nd);
helper.EnableAscii("prefix", nd);
In this case, no trace contexts are written to the ASCII trace file since they
would be redundant. The system will pick the file name to be created using the
@@ -612,10 +612,10 @@ refer to a single file::
Ptr<NetDevice> nd1;
Ptr<NetDevice> nd2;
...
Ptr<OutputStreamWrapper> stream = asciiTraceHelper.CreateFileStream ("trace-file-name.tr");
Ptr<OutputStreamWrapper> stream = asciiTraceHelper.CreateFileStream("trace-file-name.tr");
...
helper.EnableAscii (stream, nd1);
helper.EnableAscii (stream, nd2);
helper.EnableAscii(stream, nd1);
helper.EnableAscii(stream, nd2);
In this case, trace contexts are written to the ASCII trace file since they
are required to disambiguate traces from the two devices. Note that since the
@@ -628,28 +628,28 @@ You can enable ASCII tracing on a particular node/net-device pair by providing a
string. Again, the ``<Node>`` is implicit since the named net device must
belong to exactly one ``Node``. For example,::
Names::Add ("client" ...);
Names::Add ("client/eth0" ...);
Names::Add ("server" ...);
Names::Add ("server/eth0" ...);
Names::Add("client" ...);
Names::Add("client/eth0" ...);
Names::Add("server" ...);
Names::Add("server/eth0" ...);
...
helper.EnableAscii ("prefix", "client/eth0");
helper.EnableAscii ("prefix", "server/eth0");
helper.EnableAscii("prefix", "client/eth0");
helper.EnableAscii("prefix", "server/eth0");
This would result in two files named ``prefix-client-eth0.tr`` and
``prefix-server-eth0.tr`` with traces for each device in the respective trace
file. Since all of the EnableAscii functions are overloaded to take a stream
wrapper, you can use that form as well::
Names::Add ("client" ...);
Names::Add ("client/eth0" ...);
Names::Add ("server" ...);
Names::Add ("server/eth0" ...);
Names::Add("client" ...);
Names::Add("client/eth0" ...);
Names::Add("server" ...);
Names::Add("server/eth0" ...);
...
Ptr<OutputStreamWrapper> stream = asciiTraceHelper.CreateFileStream ("trace-file-name.tr");
Ptr<OutputStreamWrapper> stream = asciiTraceHelper.CreateFileStream("trace-file-name.tr");
...
helper.EnableAscii (stream, "client/eth0");
helper.EnableAscii (stream, "server/eth0");
helper.EnableAscii(stream, "client/eth0");
helper.EnableAscii(stream, "server/eth0");
This would result in a single trace file called ``trace-file-name.tr`` that
contains all of the trace events for both devices. The events would be
@@ -663,7 +663,7 @@ since the found net device must belong to exactly one ``Node``. For example,::
NetDeviceContainer d = ...;
...
helper.EnableAscii ("prefix", d);
helper.EnableAscii("prefix", d);
This would result in a number of ASCII trace files being created, each of which
follows the <prefix>-<node id>-<device id>.tr convention. Combining all of the
@@ -671,9 +671,9 @@ traces into a single file is accomplished similarly to the examples above::
NetDeviceContainer d = ...;
...
Ptr<OutputStreamWrapper> stream = asciiTraceHelper.CreateFileStream ("trace-file-name.tr");
Ptr<OutputStreamWrapper> stream = asciiTraceHelper.CreateFileStream("trace-file-name.tr");
...
helper.EnableAscii (stream, d);
helper.EnableAscii(stream, d);
You can enable ascii tracing on a collection of node/net-device pairs by
providing a ``NodeContainer``. For each ``Node`` in the ``NodeContainer`` its
@@ -684,7 +684,7 @@ enabled.::
NodeContainer n;
...
helper.EnableAscii ("prefix", n);
helper.EnableAscii("prefix", n);
This would result in a number of ASCII trace files being created, each of which
follows the <prefix>-<node id>-<device id>.tr convention. Combining all of the
@@ -694,14 +694,14 @@ You can enable pcap tracing on the basis of node ID and device ID as well as
with explicit ``Ptr``. Each ``Node`` in the system has an integer node ID and
each device connected to a node has an integer device ID.::
helper.EnableAscii ("prefix", 21, 1);
helper.EnableAscii("prefix", 21, 1);
Of course, the traces can be combined into a single file as shown above.
Finally, you can enable pcap tracing for all devices in the system, with the
same type as that managed by the device helper.::
helper.EnableAsciiAll ("prefix");
helper.EnableAsciiAll("prefix");
This would result in a number of ASCII trace files being created, one for
every device in the system of the type managed by the helper. All of these
@@ -751,14 +751,14 @@ difference will be in the method names and signatures. Different method names
are required to disambiguate class ``Ipv4`` from ``Ipv6`` which are both derived
from class ``Object``, and methods that share the same signature.::
virtual void EnablePcapIpv4Internal (std::string prefix, Ptr<Ipv4> ipv4, uint32_t interface) = 0;
virtual void EnablePcapIpv4Internal(std::string prefix, Ptr<Ipv4> ipv4, uint32_t interface) = 0;
The signature of this method reflects the protocol and interface-centric view of
the situation at this level. All of the public methods inherited from class
``PcapHelperForIpv4`` reduce to calling this single device-dependent
implementation method. For example, the lowest level pcap method,::
void EnablePcapIpv4 (std::string prefix, Ptr<Ipv4> ipv4, uint32_t interface);
void EnablePcapIpv4(std::string prefix, Ptr<Ipv4> ipv4, uint32_t interface);
will call the device implementation of ``EnablePcapIpv4Internal`` directly. All
other public pcap tracing methods build on this implementation to provide
@@ -777,12 +777,12 @@ constraints.
Note that just like in the device version, there are six methods::
void EnablePcapIpv4 (std::string prefix, Ptr<Ipv4> ipv4, uint32_t interface);
void EnablePcapIpv4 (std::string prefix, std::string ipv4Name, uint32_t interface);
void EnablePcapIpv4 (std::string prefix, Ipv4InterfaceContainer c);
void EnablePcapIpv4 (std::string prefix, NodeContainer n);
void EnablePcapIpv4 (std::string prefix, uint32_t nodeid, uint32_t interface);
void EnablePcapIpv4All (std::string prefix);
void EnablePcapIpv4(std::string prefix, Ptr<Ipv4> ipv4, uint32_t interface);
void EnablePcapIpv4(std::string prefix, std::string ipv4Name, uint32_t interface);
void EnablePcapIpv4(std::string prefix, Ipv4InterfaceContainer c);
void EnablePcapIpv4(std::string prefix, NodeContainer n);
void EnablePcapIpv4(std::string prefix, uint32_t nodeid, uint32_t interface);
void EnablePcapIpv4All(std::string prefix);
You are encouraged to peruse the Doxygen for class ``PcapHelperForIpv4`` to find
the details of these methods; but to summarize ...
@@ -790,17 +790,17 @@ the details of these methods; but to summarize ...
You can enable pcap tracing on a particular protocol/interface pair by providing
a ``Ptr<Ipv4>`` and ``interface`` to an ``EnablePcap`` method. For example,::
Ptr<Ipv4> ipv4 = node->GetObject<Ipv4> ();
Ptr<Ipv4> ipv4 = node->GetObject<Ipv4>();
...
helper.EnablePcapIpv4 ("prefix", ipv4, 0);
helper.EnablePcapIpv4("prefix", ipv4, 0);
You can enable pcap tracing on a particular node/net-device pair by providing a
``std::string`` representing an object name service string to an ``EnablePcap``
method. The ``Ptr<Ipv4>`` is looked up from the name string. For example,::
Names::Add ("serverIPv4" ...);
Names::Add("serverIPv4" ...);
...
helper.EnablePcapIpv4 ("prefix", "serverIpv4", 1);
helper.EnablePcapIpv4("prefix", "serverIpv4", 1);
You can enable pcap tracing on a collection of protocol/interface pairs by
providing an ``Ipv4InterfaceContainer``. For each ``Ipv4`` / interface pair in
@@ -810,13 +810,13 @@ corresponding interface. For example,::
NodeContainer nodes;
...
NetDeviceContainer devices = deviceHelper.Install (nodes);
NetDeviceContainer devices = deviceHelper.Install(nodes);
...
Ipv4AddressHelper ipv4;
ipv4.SetBase ("10.1.1.0", "255.255.255.0");
Ipv4InterfaceContainer interfaces = ipv4.Assign (devices);
ipv4.SetBase("10.1.1.0", "255.255.255.0");
Ipv4InterfaceContainer interfaces = ipv4.Assign(devices);
...
helper.EnablePcapIpv4 ("prefix", interfaces);
helper.EnablePcapIpv4("prefix", interfaces);
You can enable pcap tracing on a collection of protocol/interface pairs by
providing a ``NodeContainer``. For each ``Node`` in the ``NodeContainer`` the
@@ -825,19 +825,19 @@ and tracing is enabled on the resulting pairs. For example,::
NodeContainer n;
...
helper.EnablePcapIpv4 ("prefix", n);
helper.EnablePcapIpv4("prefix", n);
You can enable pcap tracing on the basis of node ID and interface as well. In
this case, the node-id is translated to a ``Ptr<Node>`` and the appropriate
protocol is looked up in the node. The resulting protocol and interface are used
to specify the resulting trace source.::
helper.EnablePcapIpv4 ("prefix", 21, 1);
helper.EnablePcapIpv4("prefix", 21, 1);
Finally, you can enable pcap tracing for all interfaces in the system, with
associated protocol being the same type as that managed by the device helper.::
helper.EnablePcapIpv4All ("prefix");
helper.EnablePcapIpv4All("prefix");
Pcap Tracing Protocol Helper Filename Selection
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -884,8 +884,8 @@ The class ``AsciiTraceHelperForIpv4`` adds the high level functionality for
using ASCII tracing to a protocol helper. Each protocol that enables these
methods must implement a single virtual method inherited from this class.::
virtual void EnableAsciiIpv4Internal (Ptr<OutputStreamWrapper> stream, std::string prefix,
Ptr<Ipv4> ipv4, uint32_t interface) = 0;
virtual void EnableAsciiIpv4Internal(Ptr<OutputStreamWrapper> stream, std::string prefix,
Ptr<Ipv4> ipv4, uint32_t interface) = 0;
The signature of this method reflects the protocol- and interface-centric view
of the situation at this level; and also the fact that the helper may be writing
@@ -894,8 +894,8 @@ to a shared output stream. All of the public methods inherited from class
dependent implementation method. For example, the lowest level ascii trace
methods,::
void EnableAsciiIpv4 (std::string prefix, Ptr<Ipv4> ipv4, uint32_t interface);
void EnableAsciiIpv4 (Ptr<OutputStreamWrapper> stream, Ptr<Ipv4> ipv4, uint32_t interface);
void EnableAsciiIpv4(std::string prefix, Ptr<Ipv4> ipv4, uint32_t interface);
void EnableAsciiIpv4(Ptr<OutputStreamWrapper> stream, Ptr<Ipv4> ipv4, uint32_t interface);
will call the device implementation of ``EnableAsciiIpv4Internal`` directly,
providing either the prefix or the stream. All other public ascii tracing
@@ -910,23 +910,23 @@ Ascii Tracing Device Helper Methods
::
void EnableAsciiIpv4 (std::string prefix, Ptr<Ipv4> ipv4, uint32_t interface);
void EnableAsciiIpv4 (Ptr<OutputStreamWrapper> stream, Ptr<Ipv4> ipv4, uint32_t interface);
void EnableAsciiIpv4(std::string prefix, Ptr<Ipv4> ipv4, uint32_t interface);
void EnableAsciiIpv4(Ptr<OutputStreamWrapper> stream, Ptr<Ipv4> ipv4, uint32_t interface);
void EnableAsciiIpv4 (std::string prefix, std::string ipv4Name, uint32_t interface);
void EnableAsciiIpv4 (Ptr<OutputStreamWrapper> stream, std::string ipv4Name, uint32_t interface);
void EnableAsciiIpv4(std::string prefix, std::string ipv4Name, uint32_t interface);
void EnableAsciiIpv4(Ptr<OutputStreamWrapper> stream, std::string ipv4Name, uint32_t interface);
void EnableAsciiIpv4 (std::string prefix, Ipv4InterfaceContainer c);
void EnableAsciiIpv4 (Ptr<OutputStreamWrapper> stream, Ipv4InterfaceContainer c);
void EnableAsciiIpv4(std::string prefix, Ipv4InterfaceContainer c);
void EnableAsciiIpv4(Ptr<OutputStreamWrapper> stream, Ipv4InterfaceContainer c);
void EnableAsciiIpv4 (std::string prefix, NodeContainer n);
void EnableAsciiIpv4 (Ptr<OutputStreamWrapper> stream, NodeContainer n);
void EnableAsciiIpv4(std::string prefix, NodeContainer n);
void EnableAsciiIpv4(Ptr<OutputStreamWrapper> stream, NodeContainer n);
void EnableAsciiIpv4 (std::string prefix, uint32_t nodeid, uint32_t deviceid);
void EnableAsciiIpv4 (Ptr<OutputStreamWrapper> stream, uint32_t nodeid, uint32_t interface);
void EnableAsciiIpv4(std::string prefix, uint32_t nodeid, uint32_t deviceid);
void EnableAsciiIpv4(Ptr<OutputStreamWrapper> stream, uint32_t nodeid, uint32_t interface);
void EnableAsciiIpv4All (std::string prefix);
void EnableAsciiIpv4All (Ptr<OutputStreamWrapper> stream);
void EnableAsciiIpv4All(std::string prefix);
void EnableAsciiIpv4All(Ptr<OutputStreamWrapper> stream);
You are encouraged to peruse the Doxygen for class ``PcapAndAsciiHelperForIpv4``
to find the details of these methods; but to summarize ...
@@ -945,7 +945,7 @@ protocol/interface pair by providing a ``Ptr<Ipv4>`` and an ``interface`` to an
Ptr<Ipv4> ipv4;
...
helper.EnableAsciiIpv4 ("prefix", ipv4, 1);
helper.EnableAsciiIpv4("prefix", ipv4, 1);
In this case, no trace contexts are written to the ASCII trace file since they
would be redundant. The system will pick the file name to be created using the
@@ -957,13 +957,13 @@ traces sent to a single file, you can do that as well by using an object to
refer to a single file. We have already something similar to this in the "cwnd"
example above::
Ptr<Ipv4> protocol1 = node1->GetObject<Ipv4> ();
Ptr<Ipv4> protocol2 = node2->GetObject<Ipv4> ();
Ptr<Ipv4> protocol1 = node1->GetObject<Ipv4>();
Ptr<Ipv4> protocol2 = node2->GetObject<Ipv4>();
...
Ptr<OutputStreamWrapper> stream = asciiTraceHelper.CreateFileStream ("trace-file-name.tr");
Ptr<OutputStreamWrapper> stream = asciiTraceHelper.CreateFileStream("trace-file-name.tr");
...
helper.EnableAsciiIpv4 (stream, protocol1, 1);
helper.EnableAsciiIpv4 (stream, protocol2, 1);
helper.EnableAsciiIpv4(stream, protocol1, 1);
helper.EnableAsciiIpv4(stream, protocol2, 1);
In this case, trace contexts are written to the ASCII trace file since they are
required to disambiguate traces from the two interfaces. Note that since the
@@ -976,24 +976,24 @@ method. The ``Ptr<Ipv4>`` is looked up from the name string. The ``<Node>`` in
the resulting filenames is implicit since there is a one-to-one correspondence
between protocol instances and nodes, For example,::
Names::Add ("node1Ipv4" ...);
Names::Add ("node2Ipv4" ...);
Names::Add("node1Ipv4" ...);
Names::Add("node2Ipv4" ...);
...
helper.EnableAsciiIpv4 ("prefix", "node1Ipv4", 1);
helper.EnableAsciiIpv4 ("prefix", "node2Ipv4", 1);
helper.EnableAsciiIpv4("prefix", "node1Ipv4", 1);
helper.EnableAsciiIpv4("prefix", "node2Ipv4", 1);
This would result in two files named "prefix-nnode1Ipv4-i1.tr" and
"prefix-nnode2Ipv4-i1.tr" with traces for each interface in the respective
trace file. Since all of the EnableAscii functions are overloaded to take a
stream wrapper, you can use that form as well::
Names::Add ("node1Ipv4" ...);
Names::Add ("node2Ipv4" ...);
Names::Add("node1Ipv4" ...);
Names::Add("node2Ipv4" ...);
...
Ptr<OutputStreamWrapper> stream = asciiTraceHelper.CreateFileStream ("trace-file-name.tr");
Ptr<OutputStreamWrapper> stream = asciiTraceHelper.CreateFileStream("trace-file-name.tr");
...
helper.EnableAsciiIpv4 (stream, "node1Ipv4", 1);
helper.EnableAsciiIpv4 (stream, "node2Ipv4", 1);
helper.EnableAsciiIpv4(stream, "node1Ipv4", 1);
helper.EnableAsciiIpv4(stream, "node2Ipv4", 1);
This would result in a single trace file called "trace-file-name.tr" that
contains all of the trace events for both interfaces. The events would be
@@ -1007,14 +1007,14 @@ one-to-one correspondence between each protocol and its node. For example,::
NodeContainer nodes;
...
NetDeviceContainer devices = deviceHelper.Install (nodes);
NetDeviceContainer devices = deviceHelper.Install(nodes);
...
Ipv4AddressHelper ipv4;
ipv4.SetBase ("10.1.1.0", "255.255.255.0");
Ipv4InterfaceContainer interfaces = ipv4.Assign (devices);
ipv4.SetBase("10.1.1.0", "255.255.255.0");
Ipv4InterfaceContainer interfaces = ipv4.Assign(devices);
...
...
helper.EnableAsciiIpv4 ("prefix", interfaces);
helper.EnableAsciiIpv4("prefix", interfaces);
This would result in a number of ASCII trace files being created, each of which
follows the <prefix>-n<node id>-i<interface>.tr convention. Combining all of the
@@ -1022,15 +1022,15 @@ traces into a single file is accomplished similarly to the examples above::
NodeContainer nodes;
...
NetDeviceContainer devices = deviceHelper.Install (nodes);
NetDeviceContainer devices = deviceHelper.Install(nodes);
...
Ipv4AddressHelper ipv4;
ipv4.SetBase ("10.1.1.0", "255.255.255.0");
Ipv4InterfaceContainer interfaces = ipv4.Assign (devices);
ipv4.SetBase("10.1.1.0", "255.255.255.0");
Ipv4InterfaceContainer interfaces = ipv4.Assign(devices);
...
Ptr<OutputStreamWrapper> stream = asciiTraceHelper.CreateFileStream ("trace-file-name.tr");
Ptr<OutputStreamWrapper> stream = asciiTraceHelper.CreateFileStream("trace-file-name.tr");
...
helper.EnableAsciiIpv4 (stream, interfaces);
helper.EnableAsciiIpv4(stream, interfaces);
You can enable ASCII tracing on a collection of protocol/interface pairs by
providing a ``NodeContainer``. For each ``Node`` in the ``NodeContainer`` the
@@ -1039,7 +1039,7 @@ and tracing is enabled on the resulting pairs. For example,::
NodeContainer n;
...
helper.EnableAsciiIpv4 ("prefix", n);
helper.EnableAsciiIpv4("prefix", n);
This would result in a number of ASCII trace files being created, each of which
follows the <prefix>-<node id>-<device id>.tr convention. Combining all of the
@@ -1050,14 +1050,14 @@ this case, the node-id is translated to a ``Ptr<Node>`` and the appropriate
protocol is looked up in the node. The resulting protocol and interface are
used to specify the resulting trace source.::
helper.EnableAsciiIpv4 ("prefix", 21, 1);
helper.EnableAsciiIpv4("prefix", 21, 1);
Of course, the traces can be combined into a single file as shown above.
Finally, you can enable ASCII tracing for all interfaces in the system, with
associated protocol being the same type as that managed by the device helper.::
helper.EnableAsciiIpv4All ("prefix");
helper.EnableAsciiIpv4All("prefix");
This would result in a number of ASCII trace files being created, one for
every interface in the system related to a protocol of the type managed by the

View File

@@ -55,7 +55,7 @@ closely, try running it under the `gdb debugger
Program received signal SIGSEGV, Segmentation fault.
0x0804aa12 in main (argc=1, argv=0xbfdfefa4)
at ../examples/tcp-point-to-point.cc:136
136 Ptr<Socket> localSocket = socketFactory->CreateSocket ();
136 Ptr<Socket> localSocket = socketFactory->CreateSocket();
(gdb) p localSocket
$1 = {m_ptr = 0x3c5d65}
(gdb) p socketFactory
@@ -73,9 +73,9 @@ Let's look around line 136 of tcp-point-to-point, as gdb suggests:
.. sourcecode:: cpp
Ptr<SocketFactory> socketFactory = n2->GetObject<SocketFactory> (Tcp::iid);
Ptr<Socket> localSocket = socketFactory->CreateSocket ();
localSocket->Bind ();
Ptr<SocketFactory> socketFactory = n2->GetObject<SocketFactory>(Tcp::iid);
Ptr<Socket> localSocket = socketFactory->CreateSocket();
localSocket->Bind();
The culprit here is that the return value of GetObject is not being checked and
may be null.

View File

@@ -76,7 +76,7 @@ This is all just as it was in ``first.cc``, so there is nothing new yet.
using namespace ns3;
NS_LOG_COMPONENT_DEFINE ("SecondScriptExample");
NS_LOG_COMPONENT_DEFINE("SecondScriptExample");
The main program begins with a slightly different twist. We use a verbose
flag to determine whether or not the ``UdpEchoClientApplication`` and
@@ -99,10 +99,10 @@ entirely comfortable with the following code at this point in the tutorial.
uint32_t nCsma = 3;
CommandLine cmd;
cmd.AddValue ("nCsma", "Number of \"extra\" CSMA nodes/devices", nCsma);
cmd.AddValue ("verbose", "Tell echo applications to log if true", verbose);
cmd.AddValue("nCsma", "Number of \"extra\" CSMA nodes/devices", nCsma);
cmd.AddValue("verbose", "Tell echo applications to log if true", verbose);
cmd.Parse (argc, argv);
cmd.Parse(argc, argv);
if (verbose)
{
@@ -119,7 +119,7 @@ done in ``first.cc``.
::
NodeContainer p2pNodes;
p2pNodes.Create (2);
p2pNodes.Create(2);
Next, we declare another ``NodeContainer`` to hold the nodes that will be
part of the bus (CSMA) network. First, we just instantiate the container
@@ -128,8 +128,8 @@ object itself.
::
NodeContainer csmaNodes;
csmaNodes.Add (p2pNodes.Get (1));
csmaNodes.Create (nCsma);
csmaNodes.Add(p2pNodes.Get(1));
csmaNodes.Create(nCsma);
The next line of code ``Gets`` the first node (as in having an index of one)
from the point-to-point node container and adds it to the container of nodes
@@ -148,11 +148,11 @@ the helper and a two millisecond delay on channels created by the helper.
::
PointToPointHelper pointToPoint;
pointToPoint.SetDeviceAttribute ("DataRate", StringValue ("5Mbps"));
pointToPoint.SetChannelAttribute ("Delay", StringValue ("2ms"));
pointToPoint.SetDeviceAttribute("DataRate", StringValue("5Mbps"));
pointToPoint.SetChannelAttribute("Delay", StringValue("2ms"));
NetDeviceContainer p2pDevices;
p2pDevices = pointToPoint.Install (p2pNodes);
p2pDevices = pointToPoint.Install(p2pNodes);
We then instantiate a ``NetDeviceContainer`` to keep track of the
point-to-point net devices and we ``Install`` devices on the
@@ -173,11 +173,11 @@ its native data type.
::
CsmaHelper csma;
csma.SetChannelAttribute ("DataRate", StringValue ("100Mbps"));
csma.SetChannelAttribute ("Delay", TimeValue (NanoSeconds (6560)));
csma.SetChannelAttribute("DataRate", StringValue("100Mbps"));
csma.SetChannelAttribute("Delay", TimeValue(NanoSeconds(6560)));
NetDeviceContainer csmaDevices;
csmaDevices = csma.Install (csmaNodes);
csmaDevices = csma.Install(csmaNodes);
Just as we created a ``NetDeviceContainer`` to hold the devices created by
the ``PointToPointHelper`` we create a ``NetDeviceContainer`` to hold
@@ -192,8 +192,8 @@ stacks present. Just as in the ``first.cc`` script, we will use the
::
InternetStackHelper stack;
stack.Install (p2pNodes.Get (0));
stack.Install (csmaNodes);
stack.Install(p2pNodes.Get(0));
stack.Install(csmaNodes);
Recall that we took one of the nodes from the ``p2pNodes`` container and
added it to the ``csmaNodes`` container. Thus we only need to install
@@ -208,9 +208,9 @@ two point-to-point devices.
::
Ipv4AddressHelper address;
address.SetBase ("10.1.1.0", "255.255.255.0");
address.SetBase("10.1.1.0", "255.255.255.0");
Ipv4InterfaceContainer p2pInterfaces;
p2pInterfaces = address.Assign (p2pDevices);
p2pInterfaces = address.Assign(p2pDevices);
Recall that we save the created interfaces in a container to make it easy to
pull out addressing information later for use in setting up the applications.
@@ -224,9 +224,9 @@ from network number 10.1.2.0 in this case, as seen below.
::
address.SetBase ("10.1.2.0", "255.255.255.0");
address.SetBase("10.1.2.0", "255.255.255.0");
Ipv4InterfaceContainer csmaInterfaces;
csmaInterfaces = address.Assign (csmaDevices);
csmaInterfaces = address.Assign(csmaDevices);
Now we have a topology built, but we need applications. This section is
going to be fundamentally similar to the applications section of
@@ -242,11 +242,11 @@ the constructor.
::
UdpEchoServerHelper echoServer (9);
UdpEchoServerHelper echoServer(9);
ApplicationContainer serverApps = echoServer.Install (csmaNodes.Get (nCsma));
serverApps.Start (Seconds (1.0));
serverApps.Stop (Seconds (10.0));
ApplicationContainer serverApps = echoServer.Install(csmaNodes.Get(nCsma));
serverApps.Start(Seconds(1.0));
serverApps.Stop(Seconds(10.0));
Recall that the ``csmaNodes NodeContainer`` contains one of the
nodes created for the point-to-point network and ``nCsma`` "extra" nodes.
@@ -267,14 +267,14 @@ leftmost point-to-point node seen in the topology illustration.
::
UdpEchoClientHelper echoClient (csmaInterfaces.GetAddress (nCsma), 9);
echoClient.SetAttribute ("MaxPackets", UintegerValue (1));
echoClient.SetAttribute ("Interval", TimeValue (Seconds (1.0)));
echoClient.SetAttribute ("PacketSize", UintegerValue (1024));
UdpEchoClientHelper echoClient(csmaInterfaces.GetAddress(nCsma), 9);
echoClient.SetAttribute("MaxPackets", UintegerValue(1));
echoClient.SetAttribute("Interval", TimeValue(Seconds(1.0)));
echoClient.SetAttribute("PacketSize", UintegerValue(1024));
ApplicationContainer clientApps = echoClient.Install (p2pNodes.Get (0));
clientApps.Start (Seconds (2.0));
clientApps.Stop (Seconds (10.0));
ApplicationContainer clientApps = echoClient.Install(p2pNodes.Get(0));
clientApps.Start(Seconds(2.0));
clientApps.Stop(Seconds(10.0));
Since we have actually built an internetwork here, we need some form of
internetwork routing. |ns3| provides what we call global routing to
@@ -292,7 +292,7 @@ is a one-liner:
::
Ipv4GlobalRoutingHelper::PopulateRoutingTables ();
Ipv4GlobalRoutingHelper::PopulateRoutingTables();
Next we enable pcap tracing. The first line of code to enable pcap tracing
in the point-to-point helper should be familiar to you by now. The second
@@ -301,8 +301,8 @@ you haven't encountered yet.
::
pointToPoint.EnablePcapAll ("second");
csma.EnablePcap ("second", csmaDevices.Get (1), true);
pointToPoint.EnablePcapAll("second");
csma.EnablePcap("second", csmaDevices.Get(1), true);
The CSMA network is a multi-point-to-point network. This means that there
can (and are in this case) multiple endpoints on a shared medium. Each of
@@ -329,8 +329,8 @@ the ``first.cc`` example.
::
Simulator::Run ();
Simulator::Destroy ();
Simulator::Run();
Simulator::Destroy();
return 0;
}
@@ -564,9 +564,9 @@ number and device number as parameters. Go ahead and replace the
::
pointToPoint.EnablePcap ("second", p2pNodes.Get (0)->GetId (), 0);
csma.EnablePcap ("second", csmaNodes.Get (nCsma)->GetId (), 0, false);
csma.EnablePcap ("second", csmaNodes.Get (nCsma-1)->GetId (), 0, false);
pointToPoint.EnablePcap("second", p2pNodes.Get(0)->GetId(), 0);
csma.EnablePcap("second", csmaNodes.Get(nCsma)->GetId(), 0, false);
csma.EnablePcap("second", csmaNodes.Get(nCsma-1)->GetId(), 0, false);
We know that we want to create a pcap file with the base name "second" and
we also know that the device of interest in both cases is going to be zero,
@@ -610,14 +610,14 @@ On line 110, notice the following command to enable tracing on one node
.. sourcecode:: bash
csma.EnablePcap ("second", csmaDevices.Get (1), true);
csma.EnablePcap("second", csmaDevices.Get(1), true);
Change the index to the quantity ``nCsma``, corresponding to the last
node in the topology-- the node that contains the echo server:
.. sourcecode:: bash
csma.EnablePcap ("second", csmaDevices.Get (nCsma), true);
csma.EnablePcap("second", csmaDevices.Get(nCsma), true);
If you build the new script and run the simulation setting ``nCsma`` to 100,
@@ -657,7 +657,7 @@ argument of ``false`` indicates that you would like a non-promiscuous trace:
.. sourcecode:: bash
csma.EnablePcap ("second", csmaDevices.Get (nCsma - 1), false);
csma.EnablePcap("second", csmaDevices.Get(nCsma - 1), false);
Now build and run as before:
@@ -872,7 +872,7 @@ component is defined. This should all be quite familiar by now.
using namespace ns3;
NS_LOG_COMPONENT_DEFINE ("ThirdScriptExample");
NS_LOG_COMPONENT_DEFINE("ThirdScriptExample");
The main program begins just like ``second.cc`` by adding some command line
parameters for enabling or disabling logging components and for changing the
@@ -885,11 +885,11 @@ number of devices created.
uint32_t nWifi = 3;
CommandLine cmd;
cmd.AddValue ("nCsma", "Number of \"extra\" CSMA nodes/devices", nCsma);
cmd.AddValue ("nWifi", "Number of wifi STA devices", nWifi);
cmd.AddValue ("verbose", "Tell echo applications to log if true", verbose);
cmd.AddValue("nCsma", "Number of \"extra\" CSMA nodes/devices", nCsma);
cmd.AddValue("nWifi", "Number of wifi STA devices", nWifi);
cmd.AddValue("verbose", "Tell echo applications to log if true", verbose);
cmd.Parse (argc,argv);
cmd.Parse(argc,argv);
if (verbose)
{
@@ -903,7 +903,7 @@ that we will connect via the point-to-point link.
::
NodeContainer p2pNodes;
p2pNodes.Create (2);
p2pNodes.Create(2);
Next, we see an old friend. We instantiate a ``PointToPointHelper`` and
set the associated default ``Attributes`` so that we create a five megabit
@@ -914,11 +914,11 @@ on the nodes and the channel between them.
::
PointToPointHelper pointToPoint;
pointToPoint.SetDeviceAttribute ("DataRate", StringValue ("5Mbps"));
pointToPoint.SetChannelAttribute ("Delay", StringValue ("2ms"));
pointToPoint.SetDeviceAttribute("DataRate", StringValue("5Mbps"));
pointToPoint.SetChannelAttribute("Delay", StringValue("2ms"));
NetDeviceContainer p2pDevices;
p2pDevices = pointToPoint.Install (p2pNodes);
p2pDevices = pointToPoint.Install(p2pNodes);
Next, we declare another ``NodeContainer`` to hold the nodes that will be
part of the bus (CSMA) network.
@@ -926,8 +926,8 @@ part of the bus (CSMA) network.
::
NodeContainer csmaNodes;
csmaNodes.Add (p2pNodes.Get (1));
csmaNodes.Create (nCsma);
csmaNodes.Add(p2pNodes.Get(1));
csmaNodes.Create(nCsma);
The next line of code ``Gets`` the first node (as in having an index of one)
from the point-to-point node container and adds it to the container of nodes
@@ -943,11 +943,11 @@ selected nodes.
::
CsmaHelper csma;
csma.SetChannelAttribute ("DataRate", StringValue ("100Mbps"));
csma.SetChannelAttribute ("Delay", TimeValue (NanoSeconds (6560)));
csma.SetChannelAttribute("DataRate", StringValue("100Mbps"));
csma.SetChannelAttribute("Delay", TimeValue(NanoSeconds(6560)));
NetDeviceContainer csmaDevices;
csmaDevices = csma.Install (csmaNodes);
csmaDevices = csma.Install(csmaNodes);
Next, we are going to create the nodes that will be part of the Wi-Fi network.
We are going to create a number of "station" nodes as specified by the
@@ -957,8 +957,8 @@ point-to-point link as the node for the access point.
::
NodeContainer wifiStaNodes;
wifiStaNodes.Create (nWifi);
NodeContainer wifiApNode = p2pNodes.Get (0);
wifiStaNodes.Create(nWifi);
NodeContainer wifiApNode = p2pNodes.Get(0);
The next bit of code constructs the wifi devices and the interconnection
channel between these wifi nodes. First, we configure the PHY and channel
@@ -966,8 +966,8 @@ helpers:
::
YansWifiChannelHelper channel = YansWifiChannelHelper::Default ();
YansWifiPhyHelper phy = YansWifiPhyHelper::Default ();
YansWifiChannelHelper channel = YansWifiChannelHelper::Default();
YansWifiPhyHelper phy = YansWifiPhyHelper::Default();
For simplicity, this code uses the default PHY layer configuration and
channel models which are documented in the API doxygen documentation for
@@ -980,7 +980,7 @@ wireless medium and can communicate and interfere:
::
phy.SetChannel (channel.Create ());
phy.SetChannel(channel.Create());
Once the PHY helper is configured, we can focus on the MAC layer. The
WifiMacHelper object is used to set MAC parameters.
@@ -992,7 +992,7 @@ the MAC layer implementation.
::
WifiMacHelper mac;
Ssid ssid = Ssid ("ns-3-ssid");
Ssid ssid = Ssid("ns-3-ssid");
WifiHelper will, by default, configure
the standard in use to be 802.11ax (known commercially as Wi-Fi 6) and configure
@@ -1013,9 +1013,9 @@ the WifiNetDevice objects that the helper create.
::
NetDeviceContainer staDevices
mac.SetType ("ns3::StaWifiMac",
"Ssid", SsidValue (ssid),
"ActiveProbing", BooleanValue (false));
mac.SetType("ns3::StaWifiMac",
"Ssid", SsidValue(ssid),
"ActiveProbing", BooleanValue(false));
In the above code, the specific kind of MAC layer that
will be created by the helper is specified by the TypeId value
@@ -1035,7 +1035,7 @@ create the Wi-Fi devices of these stations:
::
NetDeviceContainer staDevices;
staDevices = wifi.Install (phy, mac, wifiStaNodes);
staDevices = wifi.Install(phy, mac, wifiStaNodes);
We have configured Wi-Fi for all of our STA nodes, and now we need to
configure the AP (access point) node. We begin this process by changing
@@ -1044,8 +1044,8 @@ requirements of the AP.
::
mac.SetType ("ns3::ApWifiMac",
"Ssid", SsidValue (ssid));
mac.SetType("ns3::ApWifiMac",
"Ssid", SsidValue(ssid));
In this case, the ``WifiMacHelper`` is going to create MAC
layers of the "ns3::ApWifiMac", the latter specifying that a MAC
@@ -1057,7 +1057,7 @@ The next lines create the single AP which shares the same set of PHY-level
::
NetDeviceContainer apDevices;
apDevices = wifi.Install (phy, mac, wifiApNode);
apDevices = wifi.Install(phy, mac, wifiApNode);
Now, we are going to add mobility models. We want the STA nodes to be mobile,
wandering around inside a bounding box, and we want to make the AP node
@@ -1069,13 +1069,13 @@ First, we instantiate a ``MobilityHelper`` object and set some
MobilityHelper mobility;
mobility.SetPositionAllocator ("ns3::GridPositionAllocator",
"MinX", DoubleValue (0.0),
"MinY", DoubleValue (0.0),
"DeltaX", DoubleValue (5.0),
"DeltaY", DoubleValue (10.0),
"GridWidth", UintegerValue (3),
"LayoutType", StringValue ("RowFirst"));
mobility.SetPositionAllocator("ns3::GridPositionAllocator",
"MinX", DoubleValue(0.0),
"MinY", DoubleValue(0.0),
"DeltaX", DoubleValue(5.0),
"DeltaY", DoubleValue(10.0),
"GridWidth", UintegerValue(3),
"LayoutType", StringValue("RowFirst"));
This code tells the mobility helper to use a two-dimensional grid to initially
place the STA nodes. Feel free to explore the Doxygen for class
@@ -1088,15 +1088,15 @@ box.
::
mobility.SetMobilityModel ("ns3::RandomWalk2dMobilityModel",
"Bounds", RectangleValue (Rectangle (-50, 50, -50, 50)));
mobility.SetMobilityModel("ns3::RandomWalk2dMobilityModel",
"Bounds", RectangleValue(Rectangle(-50, 50, -50, 50)));
We now tell the ``MobilityHelper`` to install the mobility models on the
STA nodes.
::
mobility.Install (wifiStaNodes);
mobility.Install(wifiStaNodes);
We want the access point to remain in a fixed position during the simulation.
We accomplish this by setting the mobility model for this node to be the
@@ -1104,8 +1104,8 @@ We accomplish this by setting the mobility model for this node to be the
::
mobility.SetMobilityModel ("ns3::ConstantPositionMobilityModel");
mobility.Install (wifiApNode);
mobility.SetMobilityModel("ns3::ConstantPositionMobilityModel");
mobility.Install(wifiApNode);
We now have our nodes, devices and channels created, and mobility models
chosen for the Wi-Fi nodes, but we have no protocol stacks present. Just as
@@ -1115,9 +1115,9 @@ to install these stacks.
::
InternetStackHelper stack;
stack.Install (csmaNodes);
stack.Install (wifiApNode);
stack.Install (wifiStaNodes);
stack.Install(csmaNodes);
stack.Install(wifiApNode);
stack.Install(wifiStaNodes);
Just as in the ``second.cc`` example script, we are going to use the
``Ipv4AddressHelper`` to assign IP addresses to our device interfaces.
@@ -1130,50 +1130,50 @@ both the STA devices and the AP on the wireless network.
Ipv4AddressHelper address;
address.SetBase ("10.1.1.0", "255.255.255.0");
address.SetBase("10.1.1.0", "255.255.255.0");
Ipv4InterfaceContainer p2pInterfaces;
p2pInterfaces = address.Assign (p2pDevices);
p2pInterfaces = address.Assign(p2pDevices);
address.SetBase ("10.1.2.0", "255.255.255.0");
address.SetBase("10.1.2.0", "255.255.255.0");
Ipv4InterfaceContainer csmaInterfaces;
csmaInterfaces = address.Assign (csmaDevices);
csmaInterfaces = address.Assign(csmaDevices);
address.SetBase ("10.1.3.0", "255.255.255.0");
address.Assign (staDevices);
address.Assign (apDevices);
address.SetBase("10.1.3.0", "255.255.255.0");
address.Assign(staDevices);
address.Assign(apDevices);
We put the echo server on the "rightmost" node in the illustration at the
start of the file. We have done this before.
::
UdpEchoServerHelper echoServer (9);
UdpEchoServerHelper echoServer(9);
ApplicationContainer serverApps = echoServer.Install (csmaNodes.Get (nCsma));
serverApps.Start (Seconds (1.0));
serverApps.Stop (Seconds (10.0));
ApplicationContainer serverApps = echoServer.Install(csmaNodes.Get(nCsma));
serverApps.Start(Seconds(1.0));
serverApps.Stop(Seconds(10.0));
And we put the echo client on the last STA node we created, pointing it to
the server on the CSMA network. We have also seen similar operations before.
::
UdpEchoClientHelper echoClient (csmaInterfaces.GetAddress (nCsma), 9);
echoClient.SetAttribute ("MaxPackets", UintegerValue (1));
echoClient.SetAttribute ("Interval", TimeValue (Seconds (1.0)));
echoClient.SetAttribute ("PacketSize", UintegerValue (1024));
UdpEchoClientHelper echoClient(csmaInterfaces.GetAddress(nCsma), 9);
echoClient.SetAttribute("MaxPackets", UintegerValue(1));
echoClient.SetAttribute("Interval", TimeValue(Seconds(1.0)));
echoClient.SetAttribute("PacketSize", UintegerValue(1024));
ApplicationContainer clientApps =
echoClient.Install (wifiStaNodes.Get (nWifi - 1));
clientApps.Start (Seconds (2.0));
clientApps.Stop (Seconds (10.0));
echoClient.Install(wifiStaNodes.Get(nWifi - 1));
clientApps.Start(Seconds(2.0));
clientApps.Stop(Seconds(10.0));
Since we have built an internetwork here, we need to enable internetwork routing
just as we did in the ``second.cc`` example script.
::
Ipv4GlobalRoutingHelper::PopulateRoutingTables ();
Ipv4GlobalRoutingHelper::PopulateRoutingTables();
One thing that can surprise some users is the fact that the simulation we just
created will never "naturally" stop. This is because we asked the wireless
@@ -1186,15 +1186,15 @@ loop.
::
Simulator::Stop (Seconds (10.0));
Simulator::Stop(Seconds(10.0));
We create just enough tracing to cover all three networks:
::
pointToPoint.EnablePcapAll ("third");
phy.EnablePcap ("third", apDevices.Get (0));
csma.EnablePcap ("third", csmaDevices.Get (0), true);
pointToPoint.EnablePcapAll("third");
phy.EnablePcap("third", apDevices.Get(0));
csma.EnablePcap("third", csmaDevices.Get(0), true);
These three lines of code will start pcap tracing on both of the point-to-point
nodes that serves as our backbone, will start a promiscuous (monitor) mode
@@ -1206,8 +1206,8 @@ Finally, we actually run the simulation, clean up and then exit the program.
::
Simulator::Run ();
Simulator::Destroy ();
Simulator::Run();
Simulator::Destroy();
return 0;
}
@@ -1357,11 +1357,11 @@ following function:
::
void
CourseChange (std::string context, Ptr<const MobilityModel> model)
CourseChange(std::string context, Ptr<const MobilityModel> model)
{
Vector position = model->GetPosition ();
NS_LOG_UNCOND (context <<
" x = " << position.x << ", y = " << position.y);
Vector position = model->GetPosition();
NS_LOG_UNCOND(context <<
" x = " << position.x << ", y = " << position.y);
}
This code just pulls the position information from the mobility model and
@@ -1374,11 +1374,10 @@ script just before the ``Simulator::Run`` call.
::
std::ostringstream oss;
oss <<
"/NodeList/" << wifiStaNodes.Get (nWifi - 1)->GetId () <<
"/$ns3::MobilityModel/CourseChange";
oss << "/NodeList/" << wifiStaNodes.Get(nWifi - 1)->GetId()
<< "/$ns3::MobilityModel/CourseChange";
Config::Connect (oss.str (), MakeCallback (&CourseChange));
Config::Connect(oss.str(), MakeCallback(&CourseChange));
What we do here is to create a string containing the tracing namespace path
of the event to which we want to connect. First, we have to figure out which
@@ -1535,29 +1534,29 @@ Changing from the defaults
* The type of queue used by a NetDevice can be usually modified through the device helper::
NodeContainer nodes;
nodes.Create (2);
nodes.Create(2);
PointToPointHelper p2p;
p2p.SetQueue ("ns3::DropTailQueue", "MaxSize", StringValue ("50p"));
p2p.SetQueue("ns3::DropTailQueue", "MaxSize", StringValue("50p"));
NetDeviceContainer devices = p2p.Install (nodes);
NetDeviceContainer devices = p2p.Install(nodes);
* The type of queue disc installed on a NetDevice can be modified through the
traffic control helper::
InternetStackHelper stack;
stack.Install (nodes);
stack.Install(nodes);
TrafficControlHelper tch;
tch.SetRootQueueDisc ("ns3::CoDelQueueDisc", "MaxSize", StringValue ("1000p"));
tch.Install (devices);
tch.SetRootQueueDisc("ns3::CoDelQueueDisc", "MaxSize", StringValue("1000p"));
tch.Install(devices);
* BQL can be enabled on a device that supports it through the traffic control helper::
InternetStackHelper stack;
stack.Install (nodes);
stack.Install(nodes);
TrafficControlHelper tch;
tch.SetRootQueueDisc ("ns3::CoDelQueueDisc", "MaxSize", StringValue ("1000p"));
tch.SetQueueLimits ("ns3::DynamicQueueLimits", "HoldTime", StringValue ("4ms"));
tch.Install (devices);
tch.SetRootQueueDisc("ns3::CoDelQueueDisc", "MaxSize", StringValue("1000p"));
tch.SetQueueLimits("ns3::DynamicQueueLimits", "HoldTime", StringValue("4ms"));
tch.Install(devices);

View File

@@ -292,7 +292,7 @@ The next line of the script is the following,
::
NS_LOG_COMPONENT_DEFINE ("FirstScriptExample");
NS_LOG_COMPONENT_DEFINE("FirstScriptExample");
We will use this statement as a convenient place to talk about our Doxygen
documentation system. If you look at the project web site,
@@ -334,7 +334,7 @@ The next lines of the script you will find are,
::
int
main (int argc, char *argv[])
main(int argc, char *argv[])
{
This is just the declaration of the main function of your program (script).
@@ -347,7 +347,7 @@ to be the default value:
::
Time::SetResolution (Time::NS);
Time::SetResolution(Time::NS);
The resolution is the smallest time value that can be represented (as well as
the smallest representable difference between two time values).
@@ -386,7 +386,7 @@ simulation.
::
NodeContainer nodes;
nodes.Create (2);
nodes.Create(2);
Let's find the documentation for the ``NodeContainer`` class before we
continue. Another way to get into the documentation for a given class is via
@@ -433,8 +433,8 @@ The next three lines in the script are,
::
PointToPointHelper pointToPoint;
pointToPoint.SetDeviceAttribute ("DataRate", StringValue ("5Mbps"));
pointToPoint.SetChannelAttribute ("Delay", StringValue ("2ms"));
pointToPoint.SetDeviceAttribute("DataRate", StringValue("5Mbps"));
pointToPoint.SetChannelAttribute("Delay", StringValue("2ms"));
The first line,
@@ -447,7 +447,7 @@ high-level perspective the next line,
::
pointToPoint.SetDeviceAttribute ("DataRate", StringValue ("5Mbps"));
pointToPoint.SetDeviceAttribute("DataRate", StringValue("5Mbps"));
tells the ``PointToPointHelper`` object to use the value "5Mbps"
(five megabits per second) as the "DataRate" when it creates a
@@ -468,7 +468,7 @@ final line,
::
pointToPoint.SetChannelAttribute ("Delay", StringValue ("2ms"));
pointToPoint.SetChannelAttribute("Delay", StringValue("2ms"));
tells the ``PointToPointHelper`` to use the value "2ms" (two milliseconds)
as the value of the propagation delay of every point to point channel it
@@ -490,7 +490,7 @@ following two lines of code,
::
NetDeviceContainer devices;
devices = pointToPoint.Install (nodes);
devices = pointToPoint.Install(nodes);
will finish configuring the devices and channel. The first line declares the
device container mentioned above and the second does the heavy lifting. The
@@ -504,7 +504,7 @@ by the ``PointToPointHelper``, the ``Attributes`` previously set in the
helper are used to initialize the corresponding ``Attributes`` in the
created objects.
After executing the ``pointToPoint.Install (nodes)`` call we will have
After executing the ``pointToPoint.Install(nodes)`` call we will have
two nodes, each with an installed point-to-point net device and a single
point-to-point channel between them. Both devices will be configured to
transmit data at five megabits per second over the channel which has a two
@@ -518,7 +518,7 @@ installed on our nodes. The next two lines of code will take care of that.
::
InternetStackHelper stack;
stack.Install (nodes);
stack.Install(nodes);
The ``InternetStackHelper`` is a topology helper that is to internet stacks
what the ``PointToPointHelper`` is to point-to-point net devices. The
@@ -539,7 +539,7 @@ The next two lines of code in our example script, ``first.cc``,
::
Ipv4AddressHelper address;
address.SetBase ("10.1.1.0", "255.255.255.0");
address.SetBase("10.1.1.0", "255.255.255.0");
declare an address helper object and tell it that it should begin allocating IP
addresses from the network 10.1.1.0 using the mask 255.255.255.0 to define
@@ -554,7 +554,7 @@ The next line of code,
::
Ipv4InterfaceContainer interfaces = address.Assign (devices);
Ipv4InterfaceContainer interfaces = address.Assign(devices);
performs the actual address assignment. In |ns3| we make the
association between an IP address and a device using an ``Ipv4Interface``
@@ -584,11 +584,11 @@ created.
::
UdpEchoServerHelper echoServer (9);
UdpEchoServerHelper echoServer(9);
ApplicationContainer serverApps = echoServer.Install (nodes.Get (1));
serverApps.Start (Seconds (1.0));
serverApps.Stop (Seconds (10.0));
ApplicationContainer serverApps = echoServer.Install(nodes.Get(1));
serverApps.Start(Seconds(1.0));
serverApps.Stop(Seconds(10.0));
The first line of code in the above snippet declares the
``UdpEchoServerHelper``. As usual, this isn't the application itself, it
@@ -608,7 +608,7 @@ to a node. Interestingly, the ``Install`` method takes a
``NodeContainter`` as a parameter just as the other ``Install`` methods
we have seen. This is actually what is passed to the method even though it
doesn't look so in this case. There is a C++ *implicit conversion* at
work here that takes the result of ``nodes.Get (1)`` (which returns a smart
work here that takes the result of ``nodes.Get(1)`` (which returns a smart
pointer to a node object --- ``Ptr<Node>``) and uses that in a constructor
for an unnamed ``NodeContainer`` that is then passed to ``Install``.
If you are ever at a loss to find a particular method signature in C++ code
@@ -633,8 +633,8 @@ converted for you. The two lines,
::
serverApps.Start (Seconds (1.0));
serverApps.Stop (Seconds (10.0));
serverApps.Start(Seconds(1.0));
serverApps.Stop(Seconds(10.0));
will cause the echo server application to ``Start`` (enable itself) at one
second into the simulation and to ``Stop`` (disable itself) at ten seconds
@@ -651,14 +651,14 @@ that is managed by an ``UdpEchoClientHelper``.
::
UdpEchoClientHelper echoClient (interfaces.GetAddress (1), 9);
echoClient.SetAttribute ("MaxPackets", UintegerValue (1));
echoClient.SetAttribute ("Interval", TimeValue (Seconds (1.0)));
echoClient.SetAttribute ("PacketSize", UintegerValue (1024));
UdpEchoClientHelper echoClient(interfaces.GetAddress(1), 9);
echoClient.SetAttribute("MaxPackets", UintegerValue(1));
echoClient.SetAttribute("Interval", TimeValue(Seconds(1.0)));
echoClient.SetAttribute("PacketSize", UintegerValue(1024));
ApplicationContainer clientApps = echoClient.Install (nodes.Get (0));
clientApps.Start (Seconds (2.0));
clientApps.Stop (Seconds (10.0));
ApplicationContainer clientApps = echoClient.Install(nodes.Get(0));
clientApps.Start(Seconds(2.0));
clientApps.Stop(Seconds(10.0));
For the echo client, however, we need to set five different ``Attributes``.
The first two ``Attributes`` are set during construction of the
@@ -695,17 +695,17 @@ done using the global function ``Simulator::Run``.
::
Simulator::Run ();
Simulator::Run();
When we previously called the methods,
::
serverApps.Start (Seconds (1.0));
serverApps.Stop (Seconds (10.0));
serverApps.Start(Seconds(1.0));
serverApps.Stop(Seconds(10.0));
...
clientApps.Start (Seconds (2.0));
clientApps.Stop (Seconds (10.0));
clientApps.Start(Seconds(2.0));
clientApps.Stop(Seconds(10.0));
we actually scheduled events in the simulator at 1.0 seconds, 2.0 seconds and
two events at 10.0 seconds. When ``Simulator::Run`` is called, the system
@@ -741,7 +741,7 @@ took care of the hard part for you. The remaining lines of our first
::
Simulator::Destroy ();
Simulator::Destroy();
return 0;
}
@@ -764,7 +764,7 @@ not) be generated.
The simulation will stop automatically when no further events are in the
event queue, or when a special Stop event is found. The Stop event is
created through the
``Simulator::Stop (stopTime);`` function.
``Simulator::Stop(stopTime);`` function.
There is a typical case where ``Simulator::Stop`` is absolutely necessary
to stop the simulation: when there is a self-sustaining event.
@@ -791,9 +791,9 @@ in the first example program will schedule an explicit stop at 11 seconds:
::
+ Simulator::Stop (Seconds (11.0));
Simulator::Run ();
Simulator::Destroy ();
+ Simulator::Stop(Seconds(11.0));
Simulator::Run();
Simulator::Destroy();
return 0;
}

View File

@@ -50,8 +50,8 @@ First, it has been enabled for IPv6 support with a command-line option:
::
CommandLine cmd;
cmd.AddValue ("useIpv6", "Use Ipv6", useV6);
cmd.Parse (argc, argv);
cmd.AddValue("useIpv6", "Use Ipv6", useV6);
cmd.Parse(argc, argv);
If the user specifies ``useIpv6``, option, the program will be run
using IPv6 instead of IPv4. The ``help`` option, available on all |ns3|
@@ -124,40 +124,40 @@ some of the new lines of this diff:
+ // Configure the plot. The first argument is the file name prefix
+ // for the output files generated. The second, third, and fourth
+ // arguments are, respectively, the plot title, x-axis, and y-axis labels
+ plotHelper.ConfigurePlot ("seventh-packet-byte-count",
+ "Packet Byte Count vs. Time",
+ "Time (Seconds)",
+ "Packet Byte Count");
+ plotHelper.ConfigurePlot("seventh-packet-byte-count",
+ "Packet Byte Count vs. Time",
+ "Time(Seconds)",
+ "Packet Byte Count");
+
+ // Specify the probe type, trace source path (in configuration namespace), and
+ // probe output trace source ("OutputBytes") to plot. The fourth argument
+ // specifies the name of the data series label on the plot. The last
+ // argument formats the plot by specifying where the key should be placed.
+ plotHelper.PlotProbe (probeType,
+ tracePath,
+ "OutputBytes",
+ "Packet Byte Count",
+ GnuplotAggregator::KEY_BELOW);
+ plotHelper.PlotProbe(probeType,
+ tracePath,
+ "OutputBytes",
+ "Packet Byte Count",
+ GnuplotAggregator::KEY_BELOW);
+
+ // Use FileHelper to write out the packet byte count over time
+ FileHelper fileHelper;
+
+ // Configure the file to be written, and the formatting of output data.
+ fileHelper.ConfigureFile ("seventh-packet-byte-count",
+ FileAggregator::FORMATTED);
+ fileHelper.ConfigureFile("seventh-packet-byte-count",
+ FileAggregator::FORMATTED);
+
+ // Set the labels for this formatted output file.
+ fileHelper.Set2dFormat ("Time (Seconds) = %.3e\tPacket Byte Count = %.0f");
+ fileHelper.Set2dFormat("Time (Seconds) = %.3e\tPacket Byte Count = %.0f");
+
+ // Specify the probe type, probe path (in configuration namespace), and
+ // probe output trace source ("OutputBytes") to write.
+ fileHelper.WriteProbe (probeType,
+ tracePath,
+ "OutputBytes");
+ fileHelper.WriteProbe(probeType,
+ tracePath,
+ "OutputBytes");
+
Simulator::Stop (Seconds (20));
Simulator::Run ();
Simulator::Destroy ();
Simulator::Stop(Seconds(20));
Simulator::Run();
Simulator::Destroy();
The careful reader will have noticed, when testing the IPv6 command
@@ -243,10 +243,10 @@ the GnuplotHelper object must be declared and configured:
+ // Configure the plot. The first argument is the file name prefix
+ // for the output files generated. The second, third, and fourth
+ // arguments are, respectively, the plot title, x-axis, and y-axis labels
+ plotHelper.ConfigurePlot ("seventh-packet-byte-count",
+ "Packet Byte Count vs. Time",
+ "Time (Seconds)",
+ "Packet Byte Count");
+ plotHelper.ConfigurePlot("seventh-packet-byte-count",
+ "Packet Byte Count vs. Time",
+ "Time (Seconds)",
+ "Packet Byte Count");
To this point, an empty plot has been configured. The filename prefix
@@ -272,11 +272,11 @@ We use them here:
+ // probe output trace source ("OutputBytes") to plot. The fourth argument
+ // specifies the name of the data series label on the plot. The last
+ // argument formats the plot by specifying where the key should be placed.
+ plotHelper.PlotProbe (probeType,
+ tracePath,
+ "OutputBytes",
+ "Packet Byte Count",
+ GnuplotAggregator::KEY_BELOW);
+ plotHelper.PlotProbe(probeType,
+ tracePath,
+ "OutputBytes",
+ "Packet Byte Count",
+ GnuplotAggregator::KEY_BELOW);
The first two arguments are the name of the probe type and the trace source path.
These two are probably the hardest to determine when you try to use
@@ -287,8 +287,8 @@ observe:
::
.AddTraceSource ("Tx", "Send IPv6 packet to outgoing interface.",
MakeTraceSourceAccessor (&Ipv6L3Protocol::m_txTrace))
.AddTraceSource("Tx", "Send IPv6 packet to outgoing interface.",
MakeTraceSourceAccessor(&Ipv6L3Protocol::m_txTrace))
This says that ``Tx`` is a name for variable ``m_txTrace``, which has
a declaration of:
@@ -317,18 +317,18 @@ the data out of the probed Packet object:
::
TypeId
Ipv6PacketProbe::GetTypeId ()
Ipv6PacketProbe::GetTypeId()
{
static TypeId tid = TypeId ("ns3::Ipv6PacketProbe")
.SetParent<Probe> ()
.SetGroupName ("Stats")
.AddConstructor<Ipv6PacketProbe> ()
.AddTraceSource ( "Output",
"The packet plus its IPv6 object and interface that serve as the output for this probe",
MakeTraceSourceAccessor (&Ipv6PacketProbe::m_output))
.AddTraceSource ( "OutputBytes",
"The number of bytes in the packet",
MakeTraceSourceAccessor (&Ipv6PacketProbe::m_outputBytes))
static TypeId tid = TypeId("ns3::Ipv6PacketProbe")
.SetParent<Probe>()
.SetGroupName("Stats")
.AddConstructor<Ipv6PacketProbe>()
.AddTraceSource("Output",
"The packet plus its IPv6 object and interface that serve as the output for this probe",
MakeTraceSourceAccessor(&Ipv6PacketProbe::m_output))
.AddTraceSource("OutputBytes",
"The number of bytes in the packet",
MakeTraceSourceAccessor(&Ipv6PacketProbe::m_outputBytes))
;
return tid;
}
@@ -407,8 +407,8 @@ be seen in the filenames. Let's look at the code piece-by-piece:
+ FileHelper fileHelper;
+
+ // Configure the file to be written, and the formatting of output data.
+ fileHelper.ConfigureFile ("seventh-packet-byte-count",
+ FileAggregator::FORMATTED);
+ fileHelper.ConfigureFile("seventh-packet-byte-count",
+ FileAggregator::FORMATTED);
The file helper file prefix is the first argument, and a format specifier
is next.
@@ -420,7 +420,7 @@ FORMATTED is specified) with a format string such as follows:
+
+ // Set the labels for this formatted output file.
+ fileHelper.Set2dFormat ("Time (Seconds) = %.3e\tPacket Byte Count = %.0f");
+ fileHelper.Set2dFormat("Time (Seconds) = %.3e\tPacket Byte Count = %.0f");
Finally, the trace source of interest must be hooked. Again, the probeType and
tracePath variables in this example are used, and the probe's output
@@ -431,9 +431,9 @@ trace source "OutputBytes" is hooked:
+
+ // Specify the probe type, trace source path (in configuration namespace), and
+ // probe output trace source ("OutputBytes") to write.
+ fileHelper.WriteProbe (probeType,
+ tracePath,
+ "OutputBytes");
+ fileHelper.WriteProbe(probeType,
+ tracePath,
+ "OutputBytes");
+
The wildcard fields in this trace source specifier match two trace sources.
@@ -448,4 +448,3 @@ providing time series output has been added. The basic pattern described
above may be replicated within the scope of support of the existing
probes and trace sources. More capabilities including statistics
processing will be added in future releases.

View File

@@ -822,9 +822,9 @@ use the indicated Code Wrapper macro:
.. sourcecode:: cpp
NS_BUILD_DEBUG (std::cout << "Part of an output line..." << std::flush; timer.Start ());
DoLongInvolvedComputation ();
NS_BUILD_DEBUG (timer.Stop (); std::cout << "Done: " << timer << std::endl;)
NS_BUILD_DEBUG(std::cout << "Part of an output line..." << std::flush; timer.Start());
DoLongInvolvedComputation();
NS_BUILD_DEBUG(timer.Stop(); std::cout << "Done: " << timer << std::endl;)
By default ns3 puts the build artifacts in the ``build`` directory.
You can specify a different output directory with the ``--out``
@@ -1626,4 +1626,3 @@ The resulting text file can then be saved with any corresponding
then
echo "$gitDiff" >> version.txt
fi

File diff suppressed because it is too large Load Diff

View File

@@ -350,7 +350,7 @@ Recall that we have defined a logging component in that script:
::
NS_LOG_COMPONENT_DEFINE ("FirstScriptExample");
NS_LOG_COMPONENT_DEFINE("FirstScriptExample");
You now know that you can enable all of the logging for this component by
setting the ``NS_LOG`` environment variable to the various levels. Let's
@@ -363,14 +363,14 @@ Open ``scratch/myfirst.cc`` in your favorite editor and add the line,
::
NS_LOG_INFO ("Creating Topology");
NS_LOG_INFO("Creating Topology");
right before the lines,
::
NodeContainer nodes;
nodes.Create (2);
nodes.Create(2);
Now build the script using ns3 and clear the ``NS_LOG`` variable to turn
off the torrent of logging we previously enabled:
@@ -426,12 +426,12 @@ in the following code,
::
int
main (int argc, char *argv[])
main(int argc, char *argv[])
{
...
CommandLine cmd;
cmd.Parse (argc, argv);
cmd.Parse(argc, argv);
...
}
@@ -470,8 +470,8 @@ at the |ns3| ``Attribute`` system while walking through the
::
PointToPointHelper pointToPoint;
pointToPoint.SetDeviceAttribute ("DataRate", StringValue ("5Mbps"));
pointToPoint.SetChannelAttribute ("Delay", StringValue ("2ms"));
pointToPoint.SetDeviceAttribute("DataRate", StringValue("5Mbps"));
pointToPoint.SetChannelAttribute("Delay", StringValue("2ms"));
and mentioned that ``DataRate`` was actually an ``Attribute`` of the
``PointToPointNetDevice``. Let's use the command line argument parser
@@ -507,12 +507,12 @@ any ``set`` operations as in the following example,
...
NodeContainer nodes;
nodes.Create (2);
nodes.Create(2);
PointToPointHelper pointToPoint;
NetDeviceContainer devices;
devices = pointToPoint.Install (nodes);
devices = pointToPoint.Install(nodes);
...
@@ -680,13 +680,13 @@ start with the following code,
::
int
main (int argc, char *argv[])
main(int argc, char *argv[])
{
uint32_t nPackets = 1;
CommandLine cmd;
cmd.AddValue("nPackets", "Number of packets to echo", nPackets);
cmd.Parse (argc, argv);
cmd.Parse(argc, argv);
...
@@ -696,7 +696,7 @@ instead of the constant ``1`` as is shown below.
::
echoClient.SetAttribute ("MaxPackets", UintegerValue (nPackets));
echoClient.SetAttribute("MaxPackets", UintegerValue(nPackets));
Now if you run the script and provide the ``--PrintHelp`` argument, you
should see your new ``User Argument`` listed in the help display.
@@ -778,7 +778,7 @@ from C++ programs could be used:
#include <iostream>
...
int main ()
int main()
{
...
std::cout << "The value of x is " << x << std::endl;
@@ -838,12 +838,12 @@ generated by many scripts.
Let's just jump right in and add some ASCII tracing output to our
``scratch/myfirst.cc`` script. Right before the call to
``Simulator::Run ()``, add the following lines of code:
``Simulator::Run()``, add the following lines of code:
::
AsciiTraceHelper ascii;
pointToPoint.EnableAsciiAll (ascii.CreateFileStream ("myfirst.tr"));
pointToPoint.EnableAsciiAll(ascii.CreateFileStream("myfirst.tr"));
Like in many other |ns3| idioms, this code uses a helper object to
help create ASCII traces. The second line contains two nested method calls.
@@ -998,7 +998,7 @@ The code used to enable pcap tracing is a one-liner.
::
pointToPoint.EnablePcapAll ("myfirst");
pointToPoint.EnablePcapAll("myfirst");
Go ahead and insert this line of code after the ASCII tracing code we just
added to ``scratch/myfirst.cc``. Notice that we only passed the string