diff --git a/samples/main-random-walk.cc b/samples/main-random-walk.cc new file mode 100644 index 000000000..cccd64936 --- /dev/null +++ b/samples/main-random-walk.cc @@ -0,0 +1,61 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ + +#include + +#include "ns3/ptr.h" +#include "ns3/mobility-model.h" +#include "ns3/mobility-model-notifier.h" +#include "ns3/random-topology.h" +#include "ns3/default-value.h" +#include "ns3/command-line.h" +#include "ns3/simulator.h" +#include "ns3/nstime.h" +#include "ns3/node.h" +#include "ns3/node-list.h" + +using namespace ns3; + +static void +CourseChange (ns3::TraceContext const&, Ptr mobility) +{ + Position pos = mobility->Get (); + Speed vel = mobility->GetSpeed (); + std::cout << Simulator::Now () << ", model=" << mobility << ", POS: x=" << pos.x << ", y=" << pos.y + << ", z=" << pos.z << "; VEL:" << vel.dx << ", y=" << vel.dy + << ", z=" << vel.dz << std::endl; +} + +int main (int argc, char *argv[]) +{ + DefaultValue::Bind ("RandomWalk2dMode", "Time"); + DefaultValue::Bind ("RandomWalk2dTime", "2s"); + DefaultValue::Bind ("RandomWalk2dSpeed", "Constant:1.0"); + DefaultValue::Bind ("RandomWalk2dBounds", "0:200:0:100"); + + DefaultValue::Bind ("RandomDiscPositionX", "100"); + DefaultValue::Bind ("RandomDiscPositionY", "50"); + DefaultValue::Bind ("RandomDiscPositionRho", "Uniform:0:30"); + + DefaultValue::Bind ("RandomTopologyPositionType", "RandomDiscPosition"); + DefaultValue::Bind ("RandomTopologyMobilityType", "RandomWalk2dMobilityModel"); + + CommandLine::Parse (argc, argv); + + RandomTopology topology; + + for (uint32_t i = 0; i < 100; i++) + { + Ptr node = Create (); + node->AddInterface (Create ()); + } + + topology.Layout (NodeList::Begin (), NodeList::End ()); + NodeList::Connect ("/nodes/*/$MobilityModelNotifier/course-change", + MakeCallback (&CourseChange)); + + Simulator::StopAt (Seconds (100.0)); + + Simulator::Run (); + + return 0; +} diff --git a/samples/wscript b/samples/wscript index e89fbe9b8..73f694ed1 100644 --- a/samples/wscript +++ b/samples/wscript @@ -41,3 +41,6 @@ def build(bld): ['core', 'simulator', 'mobility']) obj.source = 'main-random-topology.cc' + obj = bld.create_ns3_program('main-random-walk', + ['core', 'simulator', 'mobility']) + obj.source = 'main-random-walk.cc' diff --git a/src/core/int-to-type.h b/src/core/int-to-type.h new file mode 100644 index 000000000..240fe8a71 --- /dev/null +++ b/src/core/int-to-type.h @@ -0,0 +1,19 @@ +#ifndef INT_TO_TYPE_H +#define INT_TO_TYPE_H + +namespace ns3 { + +/** + * This trivial template is extremely useful, as explained in + * "Modern C++ Design", p29, section 2.4, + * "Mapping Integral Constants to Types" + */ +template +struct IntToType +{ + enum {value = v}; +}; + +} // namespace ns3 + +#endif /* INT_TO_TYPE_H */ diff --git a/src/core/type-traits-test.cc b/src/core/type-traits-test.cc new file mode 100644 index 000000000..93e310bf4 --- /dev/null +++ b/src/core/type-traits-test.cc @@ -0,0 +1,40 @@ +#include "type-traits.h" +#include "test.h" + +#ifdef RUN_SELF_TESTS + +namespace ns3 { + +class TypeTraitsTest : public Test +{ +public: + TypeTraitsTest (); + virtual bool RunTests (void); +}; + +TypeTraitsTest::TypeTraitsTest () + : Test ("TypeTraits") +{} +bool +TypeTraitsTest::RunTests (void) +{ + bool result = true; + + //TypeTraits::ReferencedType ir; + //TypeTraits::NonConstType uci; + NS_TEST_ASSERT_EQUAL (TypeTraits::IsPointerToMember, 1); + NS_TEST_ASSERT_EQUAL (TypeTraits::IsPointerToMember, 1); + NS_TEST_ASSERT_EQUAL (TypeTraits::IsPointerToMember, 1); + NS_TEST_ASSERT_EQUAL (TypeTraits::IsPointerToMember, 1); + NS_TEST_ASSERT_EQUAL (TypeTraits::PointerToMemberTraits::nArgs, 0); + NS_TEST_ASSERT_EQUAL (TypeTraits::PointerToMemberTraits::nArgs, 1); + + return result; +} + +static TypeTraitsTest g_typeTraitsTest; + +} // namespace ns3 + +#endif /* RUN_SELF_TESTS */ + diff --git a/src/core/type-traits.h b/src/core/type-traits.h index 4a65404ad..54c550e10 100644 --- a/src/core/type-traits.h +++ b/src/core/type-traits.h @@ -1,25 +1,294 @@ #ifndef TYPE_TRAITS_H #define TYPE_TRAITS_H -template -struct TypeTraits; - template struct TypeTraits { - typedef T ReferencedType; -}; +private: + struct NullType {}; + template struct UnConst + { + typedef U Result; + }; + template struct UnConst + { + typedef U Result; + }; + template struct ReferenceTraits + { + enum {IsReference = 0}; + typedef U ReferencedType; + }; + template struct ReferenceTraits + { + enum {IsReference = 1}; + typedef U ReferencedType; + }; + template struct PointerTraits + { + enum {IsPointer = 0}; + typedef U PointeeType; + }; + template struct PointerTraits + { + enum {IsPointer = 1}; + typedef U PointeeType; + }; + template struct FunctionPtrTraits + { + enum {IsFunctionPointer = 0}; + }; + template + struct FunctionPtrTraits + { + enum {IsFunctionPointer = 1}; + enum {nArgs = 0}; + typedef U ReturnType; + }; + template + struct FunctionPtrTraits + { + enum {IsFunctionPointer = 1}; + enum {nArgs = 1}; + typedef U ReturnType; + typedef V1 Arg1Type; + }; + template + struct FunctionPtrTraits + { + enum {IsFunctionPointer = 1}; + enum {nArgs = 2}; + typedef U ReturnType; + typedef V1 Arg1Type; + typedef V2 Arg2Type; + }; + template + struct FunctionPtrTraits + { + enum {IsFunctionPointer = 1}; + enum {nArgs = 3}; + typedef U ReturnType; + typedef V1 Arg1Type; + typedef V2 Arg2Type; + typedef V3 Arg3Type; + }; + template + struct FunctionPtrTraits + { + enum {IsFunctionPointer = 1}; + enum {nArgs = 4}; + typedef U ReturnType; + typedef V1 Arg1Type; + typedef V2 Arg2Type; + typedef V3 Arg3Type; + typedef V4 Arg4Type; + }; + template + struct FunctionPtrTraits + { + enum {IsFunctionPointer = 1}; + enum {nArgs = 5}; + typedef U ReturnType; + typedef V1 Arg1Type; + typedef V2 Arg2Type; + typedef V3 Arg3Type; + typedef V4 Arg4Type; + typedef V5 Arg5Type; + }; + template + struct FunctionPtrTraits + { + enum {IsFunctionPointer = 1}; + enum {nArgs = 6}; + typedef U ReturnType; + typedef V1 Arg1Type; + typedef V2 Arg2Type; + typedef V3 Arg3Type; + typedef V4 Arg4Type; + typedef V5 Arg5Type; + typedef V6 Arg6Type; + }; + template struct PtrToMemberTraits + { + enum {IsPointerToMember = 0}; + }; + template + struct PtrToMemberTraits + { + enum {IsPointerToMember = 1}; + enum {nArgs = 0}; + typedef U ReturnType; + }; + template + struct PtrToMemberTraits + { + enum {IsPointerToMember = 1}; + enum {nArgs = 0}; + typedef U ReturnType; + }; + template + struct PtrToMemberTraits + { + enum {IsPointerToMember = 1}; + enum {nArgs = 1}; + typedef U ReturnType; + typedef W1 Arg1Type; + }; + template + struct PtrToMemberTraits + { + enum {IsPointerToMember = 1}; + enum {nArgs = 1}; + typedef U ReturnType; + typedef W1 Arg1Type; + }; + template + struct PtrToMemberTraits + { + enum {IsPointerToMember = 1}; + enum {nArgs = 2}; + typedef U ReturnType; + typedef W1 Arg1Type; + typedef W2 Arg2Type; + }; + template + struct PtrToMemberTraits + { + enum {IsPointerToMember = 1}; + enum {nArgs = 2}; + typedef U ReturnType; + typedef W1 Arg1Type; + typedef W2 Arg2Type; + }; + template + struct PtrToMemberTraits + { + enum {IsPointerToMember = 1}; + enum {nArgs = 3}; + typedef U ReturnType; + typedef W1 Arg1Type; + typedef W2 Arg2Type; + typedef W3 Arg3Type; + }; + template + struct PtrToMemberTraits + { + enum {IsPointerToMember = 1}; + enum {nArgs = 3}; + typedef U ReturnType; + typedef W1 Arg1Type; + typedef W2 Arg2Type; + typedef W3 Arg3Type; + }; + template + struct PtrToMemberTraits + { + enum {IsPointerToMember = 1}; + enum {nArgs = 4}; + typedef U ReturnType; + typedef W1 Arg1Type; + typedef W2 Arg2Type; + typedef W3 Arg3Type; + typedef W4 Arg4Type; + }; + template + struct PtrToMemberTraits + { + enum {IsPointerToMember = 1}; + enum {nArgs = 4}; + typedef U ReturnType; + typedef W1 Arg1Type; + typedef W2 Arg2Type; + typedef W3 Arg3Type; + typedef W4 Arg4Type; + }; + template + struct PtrToMemberTraits + { + enum {IsPointerToMember = 1}; + enum {nArgs = 5}; + typedef U ReturnType; + typedef W1 Arg1Type; + typedef W2 Arg2Type; + typedef W3 Arg3Type; + typedef W4 Arg4Type; + typedef W5 Arg5Type; + }; + template + struct PtrToMemberTraits + { + enum {IsPointerToMember = 1}; + enum {nArgs = 5}; + typedef U ReturnType; + typedef W1 Arg1Type; + typedef W2 Arg2Type; + typedef W3 Arg3Type; + typedef W4 Arg4Type; + typedef W5 Arg5Type; + }; + template + struct PtrToMemberTraits + { + enum {IsPointerToMember = 1}; + enum {nArgs = 6}; + typedef U ReturnType; + typedef W1 Arg1Type; + typedef W2 Arg2Type; + typedef W3 Arg3Type; + typedef W4 Arg4Type; + typedef W5 Arg5Type; + typedef W6 Arg6Type; + }; + template + struct PtrToMemberTraits + { + enum {IsPointerToMember = 1}; + enum {nArgs = 6}; + typedef U ReturnType; + typedef W1 Arg1Type; + typedef W2 Arg2Type; + typedef W3 Arg3Type; + typedef W4 Arg4Type; + typedef W5 Arg5Type; + typedef W6 Arg6Type; + }; -template -struct TypeTraits -{ - typedef T ReferencedType; -}; - -template -struct TypeTraits -{ - typedef T ReferencedType; +public: + typedef typename UnConst::Result NonConstType; + typedef typename ReferenceTraits::ReferencedType ReferencedType; + typedef typename PointerTraits::PointeeType PointeeType; + enum {IsPointerToMember = PtrToMemberTraits::IsPointerToMember}; + enum {IsPointer = PointerTraits::IsPointer}; + enum {IsReference = ReferenceTraits::IsReference}; + enum {IsFunctionPointer = FunctionPtrTraits::IsFunctionPointer}; + typedef PtrToMemberTraits PointerToMemberTraits; + typedef FunctionPtrTraits FunctionPointerTraits; }; diff --git a/src/core/wscript b/src/core/wscript index 5806f254b..bfb784825 100644 --- a/src/core/wscript +++ b/src/core/wscript @@ -51,6 +51,7 @@ def build(bld): 'composite-trace-resolver.cc', 'trace-doc.cc', 'trace-source.cc', + 'type-traits-test.cc', ] if sys.platform == 'win32': @@ -94,5 +95,6 @@ def build(bld): 'composite-trace-resolver.h', 'array-trace-resolver.h', 'trace-doc.h', + 'int-to-type.h', ] diff --git a/src/mobility/ns2-mobility-file-topology.cc b/src/mobility/ns2-mobility-file-topology.cc new file mode 100644 index 000000000..7d0b8c915 --- /dev/null +++ b/src/mobility/ns2-mobility-file-topology.cc @@ -0,0 +1,145 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2007 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ +#include +#include +#include "ns3/debug.h" +#include "ns3/simulator.h" +#include "ns3/node-list.h" +#include "ns3/node.h" +#include "ns2-mobility-file-topology.h" +#include "static-speed-mobility-model.h" + +NS_DEBUG_COMPONENT_DEFINE ("Ns2MobilityFileTopology"); + +namespace ns3 { + + +Ns2MobilityFileTopology::Ns2MobilityFileTopology (std::string filename) + : m_filename (filename) +{} + + +Ptr +Ns2MobilityFileTopology::GetMobilityModel (std::string idString, const ObjectStore &store) const +{ + std::istringstream iss; + iss.str (idString); + uint32_t id; + iss >> id; + Ptr object = store.Get (id); + if (object == 0) + { + return 0; + } + Ptr model = + object->QueryInterface (StaticSpeedMobilityModel::iid); + if (model == 0) + { + model = Create (); + object->AddInterface (model); + } + return model; +} + +double +Ns2MobilityFileTopology::ReadDouble (std::string valueString) const +{ + std::istringstream iss; + iss.str (valueString); + double value; + iss >> value; + return value; +} + +void +Ns2MobilityFileTopology::LayoutObjectStore (const ObjectStore &store) const +{ + std::ifstream file (m_filename.c_str (), std::ios::in); + if (file.is_open()) + { + while (!file.eof() ) + { + std::string line; + getline (file, line); + std::string::size_type startNodeId = line.find_first_of ("("); + std::string::size_type endNodeId = line.find_first_of (")"); + if (startNodeId == std::string::npos || + endNodeId == std::string::npos) + { + continue; + } + Ptr model = GetMobilityModel (line.substr (startNodeId + 1, + endNodeId - startNodeId), + store); + if (model == 0) + { + continue; + } + if (startNodeId == 6) + { + double value = ReadDouble (line.substr (endNodeId + 9, std::string::npos)); + std::string coordinate = line.substr (endNodeId + 6, 1); + Position position = model->Get (); + if (coordinate == "X") + { + position.x = value; + NS_DEBUG ("X=" << value); + } + else if (coordinate == "Y") + { + position.y = value; + NS_DEBUG ("Y=" << value); + } + else if (coordinate == "Z") + { + position.z = value; + NS_DEBUG ("Z=" << value); + } + else + { + continue; + } + model->Set (position); + } + else + { + double at = ReadDouble (line.substr (8, startNodeId - 17)); + std::string::size_type xSpeedEnd = line.find_first_of (" ", endNodeId + 10); + std::string::size_type ySpeedEnd = line.find_first_of (" ", xSpeedEnd + 1); + double xSpeed = ReadDouble (line.substr (endNodeId + 10, xSpeedEnd - endNodeId - 10)); + double ySpeed = ReadDouble (line.substr (xSpeedEnd + 1, ySpeedEnd - xSpeedEnd - 1)); + double zSpeed = ReadDouble (line.substr (ySpeedEnd + 1, std::string::npos)); + NS_DEBUG ("at=" << at << "xSpeed=" << xSpeed << ", ySpeed=" << ySpeed << ", zSpeed=" << zSpeed); + Simulator::Schedule (Seconds (at), &StaticSpeedMobilityModel::SetSpeed, model, + Speed (xSpeed, ySpeed, zSpeed)); + } + } + file.close(); + } +} + +void +Ns2MobilityFileTopology::Layout (void) const +{ + Layout (NodeList::Begin (), NodeList::End ()); +} + +} // namespace ns3 diff --git a/src/mobility/ns2-mobility-file-topology.h b/src/mobility/ns2-mobility-file-topology.h new file mode 100644 index 000000000..1bcc1a5fe --- /dev/null +++ b/src/mobility/ns2-mobility-file-topology.h @@ -0,0 +1,113 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2007 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ +#ifndef NS2_MOBILITY_FILE_TOPOLOGY_H +#define NS2_MOBILITY_FILE_TOPOLOGY_H + +#include +#include +#include "ns3/ptr.h" +#include "ns3/object.h" +#include "static-speed-mobility-model.h" + +namespace ns3 { + +/** + * \brief a topology object which can read ns2's movement files + * generated by the CMU setdest tool. + */ +class Ns2MobilityFileTopology +{ +public: + /** + * \param filename filename of file which contains the + * ns2 movement trace. + */ + Ns2MobilityFileTopology (std::string filename); + + /** + * Read the ns2 trace file and configure the movement + * patterns of all nodes contained in the global ns3::NodeList + * whose nodeId is matches the nodeId of the nodes in the trace + * file. + */ + void Layout (void) const; + + /** + * \param begin an iterator which points to the start of the input + * object array. + * \param end an iterator which points to the end of the input + * object array. + * + * Read the ns2 trace file and configure the movement + * patterns of all input objects. Each input object + * is identified by a unique node id which reflects + * the index of the object in the input array. + */ + template + void Layout (T begin, T end) const; +private: + class ObjectStore + { + public: + virtual ~ObjectStore () {} + virtual Ptr Get (uint32_t i) const = 0; + }; + void LayoutObjectStore (const ObjectStore &store) const; + Ptr GetMobilityModel (std::string idString, const ObjectStore &store) const; + double ReadDouble (std::string valueString) const; + std::string m_filename; +}; + +} // namespace ns3 + +namespace ns3 { + +template +void +Ns2MobilityFileTopology::Layout (T begin, T end) const +{ + class MyObjectStore : public ObjectStore + { + public: + MyObjectStore (T begin, T end) + : m_begin (begin), + m_end (end) + {} + virtual Ptr Get (uint32_t i) const { + T iterator = m_begin; + iterator += i; + if (iterator >= m_end) + { + return 0; + } + return *iterator; + } + private: + T m_begin; + T m_end; + }; + LayoutObjectStore (MyObjectStore (begin, end)); +} + + +} // namespace ns3 + +#endif /* NS2_MOBILITY_FILE_TOPOLOGY_H */ diff --git a/src/mobility/random-direction-2d-mobility-model.cc b/src/mobility/random-direction-2d-mobility-model.cc new file mode 100644 index 000000000..9df80874c --- /dev/null +++ b/src/mobility/random-direction-2d-mobility-model.cc @@ -0,0 +1,210 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2007 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ +#include "ns3/random-variable-default-value.h" +#include "ns3/rectangle-default-value.h" +#include "ns3/simulator.h" +#include +#include +#include "random-direction-2d-mobility-model.h" +#include "ns3/log.h" + +NS_LOG_COMPONENT_DEFINE ("RandomDirection2dMobilityModel"); + +namespace ns3 { + +const double RandomDirection2dMobilityModel::PI = 3.14159265358979323846; +const ClassId RandomDirection2dMobilityModel::cid = + MakeClassId ("RandomDirection2dMobilityModel", + MobilityModel::iid); + + +static RandomVariableDefaultValue + g_speedVariable ("RandomDirection2dSpeed", + "A random variable to control the speed of a RandomDirection2d mobility model.", + "Uniform:1:2"); + +static RandomVariableDefaultValue + g_pauseVariable ("RandomDirection2dPause", + "A random variable to control the duration " + "of the pause of a RandomDiretion mobility model.", + "Constant:2"); + +static RectangleDefaultValue + g_bounds ("RandomDirection2dArea", + "The bounding area for the RandomDirection2d model.", + -100, 100, -100, 100); + + +RandomDirection2dMobilityModelParameters::RandomDirection2dMobilityModelParameters () + : m_bounds (g_bounds.GetValue ()), + m_speedVariable (g_speedVariable.GetCopy ()), + m_pauseVariable (g_pauseVariable.GetCopy ()) + +{} +RandomDirection2dMobilityModelParameters::RandomDirection2dMobilityModelParameters +(const Rectangle &bounds, + const RandomVariable &speedVariable, + const RandomVariable &pauseVariable) + : m_bounds (bounds), + m_speedVariable (speedVariable.Copy ()), + m_pauseVariable (pauseVariable.Copy ()) +{} + +RandomDirection2dMobilityModelParameters::~RandomDirection2dMobilityModelParameters () +{ + delete m_speedVariable; + delete m_pauseVariable; + m_speedVariable = 0; + m_pauseVariable = 0; +} + +void +RandomDirection2dMobilityModelParameters::SetSpeed (const RandomVariable &speedVariable) +{ + delete m_speedVariable; + m_speedVariable = speedVariable.Copy (); +} +void +RandomDirection2dMobilityModelParameters::SetPause (const RandomVariable &pauseVariable) +{ + delete m_pauseVariable; + m_pauseVariable = pauseVariable.Copy (); +} +void +RandomDirection2dMobilityModelParameters::SetBounds (const Rectangle &bounds) +{ + m_bounds = bounds; +} + +Ptr +RandomDirection2dMobilityModelParameters::GetCurrent (void) +{ + static Ptr parameters = 0; + if (parameters == 0 || + g_bounds.IsDirty () || + g_speedVariable.IsDirty () || + g_pauseVariable.IsDirty ()) + { + parameters = Create (); + g_bounds.ClearDirtyFlag (); + g_speedVariable.ClearDirtyFlag (); + g_pauseVariable.ClearDirtyFlag (); + } + return parameters; +} + + +RandomDirection2dMobilityModel::RandomDirection2dMobilityModel () + : m_parameters (RandomDirection2dMobilityModelParameters::GetCurrent ()) +{ + SetInterfaceId (RandomDirection2dMobilityModel::iid); + m_event = Simulator::ScheduleNow (&RandomDirection2dMobilityModel::Start, this); +} +RandomDirection2dMobilityModel::RandomDirection2dMobilityModel +(Ptr parameters) + : m_parameters (parameters) +{ + SetInterfaceId (RandomDirection2dMobilityModel::iid); + m_event = Simulator::ScheduleNow (&RandomDirection2dMobilityModel::Start, this); +} +void +RandomDirection2dMobilityModel::DoDispose (void) +{ + m_parameters = 0; + // chain up. + MobilityModel::DoDispose (); +} +void +RandomDirection2dMobilityModel::Start (void) +{ + double direction = UniformVariable::GetSingleValue (0, 2 * PI); + SetDirectionAndSpeed (direction); +} + +void +RandomDirection2dMobilityModel::BeginPause (void) +{ + Time pause = Seconds (m_parameters->m_pauseVariable->GetValue ()); + m_helper.Pause (); + m_event = Simulator::Schedule (pause, &RandomDirection2dMobilityModel::ResetDirectionAndSpeed, this); + NotifyCourseChange (); +} + +void +RandomDirection2dMobilityModel::SetDirectionAndSpeed (double direction) +{ + NS_LOG_FUNCTION; + double speed = m_parameters->m_speedVariable->GetValue (); + const Speed vector (std::cos (direction) * speed, + std::sin (direction) * speed, + 0.0); + Position position = m_helper.GetCurrentPosition (m_parameters->m_bounds); + m_helper.Reset (vector); + Position next = m_parameters->m_bounds.CalculateIntersection (position, vector); + Time delay = Seconds (CalculateDistance (position, next) / speed); + m_event = Simulator::Schedule (delay, + &RandomDirection2dMobilityModel::BeginPause, this); + NotifyCourseChange (); +} +void +RandomDirection2dMobilityModel::ResetDirectionAndSpeed (void) +{ + double direction = UniformVariable::GetSingleValue (0, PI); + + Position position = m_helper.GetCurrentPosition (m_parameters->m_bounds); + switch (m_parameters->m_bounds.GetClosestSide (position)) + { + case Rectangle::RIGHT: + direction += PI / 2; + break; + case Rectangle::LEFT: + direction += - PI / 2; + break; + case Rectangle::TOP: + direction += PI; + break; + case Rectangle::BOTTOM: + direction += 0.0; + break; + } + SetDirectionAndSpeed (direction); +} +Position +RandomDirection2dMobilityModel::DoGet (void) const +{ + return m_helper.GetCurrentPosition (m_parameters->m_bounds); +} +void +RandomDirection2dMobilityModel::DoSet (const Position &position) +{ + m_helper.InitializePosition (position); + Simulator::Remove (m_event); + m_event = Simulator::ScheduleNow (&RandomDirection2dMobilityModel::Start, this); +} +Speed +RandomDirection2dMobilityModel::DoGetSpeed (void) const +{ + return m_helper.GetSpeed (); +} + + + +} // namespace ns3 diff --git a/src/mobility/random-direction-2d-mobility-model.h b/src/mobility/random-direction-2d-mobility-model.h new file mode 100644 index 000000000..6dce660a1 --- /dev/null +++ b/src/mobility/random-direction-2d-mobility-model.h @@ -0,0 +1,121 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2007 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ +#ifndef RANDOM_DIRECTION_MOBILITY_MODEL_H +#define RANDOM_DIRECTION_MOBILITY_MODEL_H + +#include "ns3/object.h" +#include "ns3/ptr.h" +#include "ns3/nstime.h" +#include "ns3/event-id.h" +#include "ns3/component-manager.h" +#include "ns3/rectangle.h" +#include "mobility-model.h" +#include "static-speed-helper.h" + +namespace ns3 { + +class RandomVariable; + +/** + * \brief the parameters to control a RandomDirection mobility model. + */ +class RandomDirection2dMobilityModelParameters : public Object +{ + public: + /** + * Create a default parameter object from Bind default values. + */ + RandomDirection2dMobilityModelParameters (); + /** + * \param bounds the 2d bounds of the mobility model + * \param speedVariable the random variable used to pick a random speed + * \param pauseVariable the random variable used to pick a random pause delay + */ + RandomDirection2dMobilityModelParameters (const Rectangle &bounds, + const RandomVariable &speedVariable, + const RandomVariable &pauseVariable); + virtual ~RandomDirection2dMobilityModelParameters (); + + /** + * \param speedVariable the random variable used to pick a random speed. + */ + void SetSpeed (const RandomVariable &speedVariable); + /** + * \param pauseVariable the random variable used to pick a random pause delay. + */ + void SetPause (const RandomVariable &pauseVariable); + /** + * \param bounds the 2d bounds of the mobility model. + */ + void SetBounds (const Rectangle &bounds); + private: + friend class RandomDirection2dMobilityModel; + + static Ptr GetCurrent (void); + + Rectangle m_bounds; + RandomVariable *m_speedVariable; + RandomVariable *m_pauseVariable; +}; + +/** + * \brief a RandomDirection mobility model + * + * The movement of objects is based on random directions: each object + * pauses for a specific delay, chooses a random direction and speed and + * then travels in the specific direction until it reaches one of + * the boundaries of the model. When it reaches the boundary, it pauses, + * selects a new direction and speed, aso. + */ +class RandomDirection2dMobilityModel : public MobilityModel +{ + public: + static const ClassId cid; + + /** + * Create a RandomDirection model from the default Bind values. + */ + RandomDirection2dMobilityModel (); + /** + * \param parameters the parameters which control the behavior of the model. + * Create a RandomDirection model using the parameters specified. + */ + RandomDirection2dMobilityModel (Ptr parameters); + private: + void Start (void); + void ResetDirectionAndSpeed (void); + void BeginPause (void); + void SetDirectionAndSpeed (double direction); + void InitializeDirectionAndSpeed (void); + virtual void DoDispose (void); + virtual Position DoGet (void) const; + virtual void DoSet (const Position &position); + virtual Speed DoGetSpeed (void) const; + + static const double PI; + Ptr m_parameters; + EventId m_event; + StaticSpeedHelper m_helper; +}; + +} // namespace ns3 + +#endif /* RANDOM_DIRECTION_MOBILITY_MODEL_H */ diff --git a/src/mobility/random-walk-2d-mobility-model.cc b/src/mobility/random-walk-2d-mobility-model.cc new file mode 100644 index 000000000..b6db1b5fa --- /dev/null +++ b/src/mobility/random-walk-2d-mobility-model.cc @@ -0,0 +1,233 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2006,2007 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ +#include "random-walk-2d-mobility-model.h" +#include "ns3/default-value.h" +#include "ns3/time-default-value.h" +#include "ns3/rectangle-default-value.h" +#include "ns3/random-variable-default-value.h" +#include "ns3/simulator.h" +#include "ns3/debug.h" +#include + +NS_DEBUG_COMPONENT_DEFINE ("RandomWalk2d"); + +namespace ns3 { + +const ClassId RandomWalk2dMobilityModel::cid = + MakeClassId ("RandomWalk2dMobilityModel", RandomWalk2dMobilityModel::iid); + + +static EnumDefaultValue +g_mode ("RandomWalk2dMode", + "The mode indicates the condition used to " + "change the current speed and direction", + RandomWalk2dMobilityModelParameters::MODE_DISTANCE, "Distance", + RandomWalk2dMobilityModelParameters::MODE_TIME, "Time", + 0, (void*)0); + +static NumericDefaultValue +g_modeDistance ("RandomWalk2dDistance", + "Change current direction and speed after moving this distance.", + 2.0); + +static TimeDefaultValue +g_modeTime ("RandomWalk2dTime", + "Change current direction and speed after moving for this delay.", + Seconds (1.0)); + +static RandomVariableDefaultValue +g_speed ("RandomWalk2dSpeed", + "A random variable used to pick the speed.", + "Uniform:2:4"); +static RandomVariableDefaultValue +g_direction ("RandomWalk2dDirection", + "A random variable used to pick the direction (gradients).", + "Uniform:0.0:6.283184"); + +static RectangleDefaultValue +g_rectangle ("RandomWalk2dBounds", + "Bounds of the area to cruise.", + 0.0, 0.0, 100.0, 100.0); + +RandomWalk2dMobilityModelParameters::RandomWalk2dMobilityModelParameters () + : m_mode (g_mode.GetValue ()), + m_modeDistance (g_modeDistance.GetValue ()), + m_modeTime (g_modeTime.GetValue ()), + m_speed (g_speed.GetCopy ()), + m_direction (g_direction.GetCopy ()), + m_bounds (g_rectangle.GetValue ()) +{} + +RandomWalk2dMobilityModelParameters::~RandomWalk2dMobilityModelParameters () +{ + delete m_speed; + delete m_direction; + m_speed = 0; + m_direction = 0; +} + +void +RandomWalk2dMobilityModelParameters::SetSpeed (const RandomVariable &speed) +{ + delete m_speed; + m_speed = speed.Copy (); +} +void +RandomWalk2dMobilityModelParameters::SetDirection (const RandomVariable &direction) +{ + delete m_direction; + m_direction = direction.Copy (); +} +void +RandomWalk2dMobilityModelParameters::SetModeDistance (double distance) +{ + m_mode = RandomWalk2dMobilityModelParameters::MODE_DISTANCE; + m_modeDistance = distance; +} +void +RandomWalk2dMobilityModelParameters::SetModeTime (Time time) +{ + m_mode = RandomWalk2dMobilityModelParameters::MODE_TIME; + m_modeTime = time; +} +void +RandomWalk2dMobilityModelParameters::SetBounds (const Rectangle &bounds) +{ + m_bounds = bounds; +} + +Ptr +RandomWalk2dMobilityModelParameters::GetCurrent (void) +{ + static Ptr parameters = 0; + if (parameters == 0 || + g_speed.IsDirty () || + g_direction.IsDirty () || + g_mode.IsDirty () || + g_modeDistance.IsDirty () || + g_modeTime.IsDirty () || + g_rectangle.IsDirty ()) + { + parameters = Create (); + } + return parameters; +} + +RandomWalk2dMobilityModel::RandomWalk2dMobilityModel () + : m_parameters (RandomWalk2dMobilityModelParameters::GetCurrent ()) +{ + SetInterfaceId (RandomWalk2dMobilityModel::iid); + m_event = Simulator::ScheduleNow (&RandomWalk2dMobilityModel::Start, this); +} + +void +RandomWalk2dMobilityModel::Start (void) +{ + double speed = m_parameters->m_speed->GetValue (); + double direction = m_parameters->m_direction->GetValue (); + Speed vector (std::cos (direction) * speed, + std::sin (direction) * speed, + 0.0); + m_helper.Reset (vector); + + Time delayLeft; + if (m_parameters->m_mode == RandomWalk2dMobilityModelParameters::MODE_TIME) + { + delayLeft = m_parameters->m_modeTime; + } + else + { + delayLeft = Seconds (m_parameters->m_modeDistance / speed); + } + DoWalk (delayLeft); +} + +void +RandomWalk2dMobilityModel::DoWalk (Time delayLeft) +{ + Position position = m_helper.GetCurrentPosition (); + Speed speed = m_helper.GetSpeed (); + Position nextPosition = position; + nextPosition.x += speed.dx * delayLeft.GetSeconds (); + nextPosition.y += speed.dy * delayLeft.GetSeconds (); + if (m_parameters->m_bounds.IsInside (nextPosition)) + { + m_event = Simulator::Schedule (delayLeft, &RandomWalk2dMobilityModel::Start, this); + } + else + { + nextPosition = m_parameters->m_bounds.CalculateIntersection (position, speed); + Time delay = Seconds ((nextPosition.x - position.x) / speed.dx); + m_event = Simulator::Schedule (delay, &RandomWalk2dMobilityModel::Rebound, this, + delayLeft - delay); + } + NotifyCourseChange (); +} + +void +RandomWalk2dMobilityModel::Rebound (Time delayLeft) +{ + Position position = m_helper.GetCurrentPosition (m_parameters->m_bounds); + Speed speed = m_helper.GetSpeed (); + switch (m_parameters->m_bounds.GetClosestSide (position)) + { + case Rectangle::RIGHT: + case Rectangle::LEFT: + speed.dx = - speed.dx; + break; + case Rectangle::TOP: + case Rectangle::BOTTOM: + speed.dy = - speed.dy; + break; + } + m_helper.Reset (speed); + DoWalk (delayLeft); +} + +void +RandomWalk2dMobilityModel::DoDispose (void) +{ + m_parameters = 0; + // chain up + MobilityModel::DoDispose (); +} +Position +RandomWalk2dMobilityModel::DoGet (void) const +{ + return m_helper.GetCurrentPosition (m_parameters->m_bounds); +} +void +RandomWalk2dMobilityModel::DoSet (const Position &position) +{ + NS_ASSERT (m_parameters->m_bounds.IsInside (position)); + m_helper.InitializePosition (position); + Simulator::Remove (m_event); + m_event = Simulator::ScheduleNow (&RandomWalk2dMobilityModel::Start, this); +} +Speed +RandomWalk2dMobilityModel::DoGetSpeed (void) const +{ + return m_helper.GetSpeed (); +} + + + +} // namespace ns3 diff --git a/src/mobility/random-walk-2d-mobility-model.h b/src/mobility/random-walk-2d-mobility-model.h new file mode 100644 index 000000000..2e921216b --- /dev/null +++ b/src/mobility/random-walk-2d-mobility-model.h @@ -0,0 +1,147 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2006,2007 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ +#ifndef RANDOM_WALK_2D_MOBILITY_MODEL_H +#define RANDOM_WALK_2D_MOBILITY_MODEL_H + +#include "ns3/object.h" +#include "ns3/nstime.h" +#include "ns3/component-manager.h" +#include "ns3/event-id.h" +#include "ns3/rectangle.h" +#include "mobility-model.h" +#include "static-speed-helper.h" + +namespace ns3 { + +class RandomVariable; + +/** + * \brief parameters to control a random walk 2d model + * + * A single parameter object can be shared by multiple random + * walk models. + */ +class RandomWalk2dMobilityModelParameters : public Object +{ + public: + /** + * Instantiate a set of RandomWalk parameters initialized + * with the Bind default values. + */ + RandomWalk2dMobilityModelParameters (); + virtual ~RandomWalk2dMobilityModelParameters (); + /** + * \param speed the random variable used to pick a new + * speed when the direction is changed. + * + */ + void SetSpeed (const RandomVariable &speed); + /** + * \param direction the random variable used to pick a new + * direction. + */ + void SetDirection (const RandomVariable &direction); + /** + * \param distance the distance before a direction change + * + * Unit is meters. + * "time" mode is incompatible with "distance" mode. + */ + void SetModeDistance (double distance); + /** + * \param time the delay before a direction change. + * + * "time" mode is incompatible with "distance" mode. + */ + void SetModeTime (Time time); + + /** + * \param bounds the bounds of the random walk + */ + void SetBounds (const Rectangle &bounds); + + + // needed public for internal default value code. + enum Mode { + MODE_DISTANCE, + MODE_TIME + }; + private: + friend class RandomWalk2dMobilityModel; + static Ptr GetCurrent (void); + + enum Mode m_mode; + double m_modeDistance; + Time m_modeTime; + RandomVariable *m_speed; + RandomVariable *m_direction; + Rectangle m_bounds; +}; + +/** + * \brief a 2D random walk position model + * + * Each instance moves with a speed and direction choosen at random + * with the user-provided random variables until + * either a fixed distance has been walked or until a fixed amount + * of time. + * + * The parameters of the model can be specified either with the ns3::Bind + * function and the variables "RandomWalk2dSpeed", "RandomWalk2dMode", + * "RandomWalk2dDistance", "RandomWalk2dTime", and, "RandomWalk2dBounds" or + * with an instance of the RandomWalk2dMobilityModelParameters class which + * must be fed to the RandomWalk2dMobilityModel constructors. + */ +class RandomWalk2dMobilityModel : public MobilityModel +{ + public: + static const ClassId cid; + /** + * Create a new position object located at position (0,0,0) + */ + RandomWalk2dMobilityModel (); + /** + * \param parameters the parameters to use to control + * the movement of this mobile object. + * + * Create a new position object located at position (0,0,0) with + * the specified parameters. + */ + RandomWalk2dMobilityModel (Ptr parameters); + + private: + void Start (void); + void Rebound (Time timeLeft); + void DoWalk (Time timeLeft); + virtual void DoDispose (void); + virtual Position DoGet (void) const; + virtual void DoSet (const Position &position); + virtual Speed DoGetSpeed (void) const; + + StaticSpeedHelper m_helper; + EventId m_event; + Ptr m_parameters; +}; + + +} // namespace ns3 + +#endif /* RANDOM_WALK_2D_MOBILITY_MODEL_H */ diff --git a/src/mobility/random-waypoint-mobility-model.cc b/src/mobility/random-waypoint-mobility-model.cc new file mode 100644 index 000000000..0078a35c2 --- /dev/null +++ b/src/mobility/random-waypoint-mobility-model.cc @@ -0,0 +1,163 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2007 INRIA + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ +#include +#include "ns3/simulator.h" +#include "ns3/random-variable.h" +#include "ns3/random-variable-default-value.h" +#include "ns3/component-manager.h" +#include "random-waypoint-mobility-model.h" +#include "random-position.h" + +namespace ns3 { + +static RandomVariableDefaultValue +g_speed ("RandomWaypointSpeed", + "A random variable used to pick the speed of a random waypoint model.", + "Uniform:0.3:0.7"); + +static RandomVariableDefaultValue +g_pause ("RandomWaypointPause", + "A random variable used to pick the pause of a random waypoint model.", + "Constant:2"); + +static ClassIdDefaultValue +g_position ("RandomWaypointPosition", + "A random position model used to pick the next waypoint position.", + RandomPosition::iid, + "RandomRectanglePosition"); + +const ClassId RandomWaypointMobilityModel::cid = + MakeClassId ("RandomWaypointMobilityModel", MobilityModel::iid); + +RandomWaypointMobilityModelParameters::RandomWaypointMobilityModelParameters () + : m_speed (g_speed.GetCopy ()), + m_pause (g_pause.GetCopy ()) +{ + m_position = ComponentManager::Create (g_position.GetValue (), + RandomPosition::iid); +} +RandomWaypointMobilityModelParameters::RandomWaypointMobilityModelParameters (Ptr randomPosition, + const RandomVariable &speed, + const RandomVariable &pause) + : m_speed (speed.Copy ()), + m_pause (pause.Copy ()), + m_position (randomPosition) +{} +void +RandomWaypointMobilityModelParameters::SetWaypointPositionModel (Ptr randomPosition) +{ + m_position = randomPosition; +} +void +RandomWaypointMobilityModelParameters::SetSpeed (const RandomVariable &speed) +{ + delete m_speed; + m_speed = speed.Copy (); +} +void +RandomWaypointMobilityModelParameters::SetPause (const RandomVariable &pause) +{ + delete m_pause; + m_pause = pause.Copy (); +} +void +RandomWaypointMobilityModelParameters::DoDispose (void) +{ + m_position = 0; + delete m_pause; + delete m_speed; + m_pause = 0; + m_speed = 0; +} + +Ptr +RandomWaypointMobilityModelParameters::GetCurrent (void) +{ + static Ptr parameters = 0; + if (parameters == 0 || + g_position.IsDirty () || + g_pause.IsDirty () || + g_speed.IsDirty ()) + { + parameters = Create (); + } + return parameters; +} + +RandomWaypointMobilityModel::RandomWaypointMobilityModel () + : m_parameters (RandomWaypointMobilityModelParameters::GetCurrent ()) +{ + Simulator::ScheduleNow (&RandomWaypointMobilityModel::Start, this); +} + +RandomWaypointMobilityModel::RandomWaypointMobilityModel (Ptr parameters) + : m_parameters (parameters) +{ + Simulator::ScheduleNow (&RandomWaypointMobilityModel::Start, this); + NotifyCourseChange (); +} + +void +RandomWaypointMobilityModel::BeginWalk (void) +{ + Position m_current = m_helper.GetCurrentPosition (); + Position destination = m_parameters->m_position->Get (); + double speed = m_parameters->m_speed->GetValue (); + double dx = (destination.x - m_current.x); + double dy = (destination.y - m_current.y); + double dz = (destination.z - m_current.z); + double k = speed / std::sqrt (dx*dx + dy*dy + dz*dz); + + m_helper.Reset (Speed (k*dx, k*dy, k*dz)); + Time travelDelay = Seconds (CalculateDistance (destination, m_current) / speed); + m_event = Simulator::Schedule (travelDelay, + &RandomWaypointMobilityModel::Start, this); + NotifyCourseChange (); +} + +void +RandomWaypointMobilityModel::Start (void) +{ + Time pause = Seconds (m_parameters->m_pause->GetValue ()); + m_helper.Pause (); + NotifyCourseChange (); + m_event = Simulator::Schedule (pause, &RandomWaypointMobilityModel::BeginWalk, this); +} + +Position +RandomWaypointMobilityModel::DoGet (void) const +{ + return m_helper.GetCurrentPosition (); +} +void +RandomWaypointMobilityModel::DoSet (const Position &position) +{ + m_helper.InitializePosition (position); + Simulator::Remove (m_event); + Simulator::ScheduleNow (&RandomWaypointMobilityModel::Start, this); +} +Speed +RandomWaypointMobilityModel::DoGetSpeed (void) const +{ + return m_helper.GetSpeed (); +} + + +} // namespace ns3 diff --git a/src/mobility/random-waypoint-mobility-model.h b/src/mobility/random-waypoint-mobility-model.h new file mode 100644 index 000000000..72aef43b3 --- /dev/null +++ b/src/mobility/random-waypoint-mobility-model.h @@ -0,0 +1,112 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2007 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ +#ifndef RANDOM_WAYPOINT_MOBILITY_MODEL_H +#define RANDOM_WAYPOINT_MOBILITY_MODEL_H + +#include "static-speed-helper.h" +#include "mobility-model.h" +#include "random-position.h" +#include "ns3/ptr.h" + +namespace ns3 { + +class RandomVariable; + +/** + * \brief the parameters which control the behavior of a random waypoint + * mobility model. + */ +class RandomWaypointMobilityModelParameters : public Object +{ +public: + /** + * Defaults parameters based on the Bind values. + */ + RandomWaypointMobilityModelParameters (); + /** + * \param randomPosition a random position model to choose the position of waypoints. + * \param speed a random variable to choose the speed + * \param pause a random variable to choose the pause delay + */ + RandomWaypointMobilityModelParameters (Ptr randomPosition, + const RandomVariable &speed, + const RandomVariable &pause); + /** + * \param randomPosition a random position model to choose the position of waypoints. + */ + void SetWaypointPositionModel (Ptr randomPosition); + /** + * \param speed a random variable to choose the speed + */ + void SetSpeed (const RandomVariable &speed); + /** + * \param pause a random variable to choose the pause delay + */ + void SetPause (const RandomVariable &pause); +private: + friend class RandomWaypointMobilityModel; + static Ptr GetCurrent (void); + virtual void DoDispose (void); + RandomVariable *m_speed; + RandomVariable *m_pause; + Ptr m_position; +}; + +/** + * \brief a random waypoint mobility model + * + * Each object chooses a random destination "waypoint", a random speed, + * and a random pause time: it then pauses for the specified pause time, + * and starts moving towards the specified destination with the specified + * speed. Once the destination is reached the process starts again. + * + * The implementation of this model is not 2d-specific. i.e. if you provide + * a 3d random waypoint position model to this mobility model, the model + * will still work. + */ +class RandomWaypointMobilityModel : public MobilityModel +{ +public: + static const ClassId cid; + + /** + * Create a waypoint mobility model from the Bind default values. + */ + RandomWaypointMobilityModel (); + /** + * \param parameters the parameters which control the behavior of this model. + */ + RandomWaypointMobilityModel (Ptr parameters); +private: + void Start (void); + void BeginWalk (void); + virtual Position DoGet (void) const; + virtual void DoSet (const Position &position); + virtual Speed DoGetSpeed (void) const; + + StaticSpeedHelper m_helper; + Ptr m_parameters; + EventId m_event; +}; + +} // namespace ns3 + +#endif /* RANDOM_WAYPOINT_MOBILITY_MODEL_H */ diff --git a/src/mobility/rectangle.cc b/src/mobility/rectangle.cc index 5ae589b8c..2f10a7d43 100644 --- a/src/mobility/rectangle.cc +++ b/src/mobility/rectangle.cc @@ -45,17 +45,17 @@ bool Rectangle::IsInside (const Position &position) const { return - position.x <= xMax && position.x >= xMin && - position.y <= yMax && position.y >= yMin; + position.x <= this->xMax && position.x >= this->xMin && + position.y <= this->yMax && position.y >= this->yMin; } Rectangle::Side Rectangle::GetClosestSide (const Position &position) const { - double xMinDist = std::abs (position.x - xMin); - double xMaxDist = std::abs (xMax - position.x); - double yMinDist = std::abs (position.y - yMin); - double yMaxDist = std::abs (yMax - position.y); + double xMinDist = std::abs (position.x - this->xMin); + double xMaxDist = std::abs (this->xMax - position.x); + double yMinDist = std::abs (position.y - this->yMin); + double yMaxDist = std::abs (this->yMax - position.y); double minX = std::min (xMinDist, xMaxDist); double minY = std::min (yMinDist, yMaxDist); if (minX < minY) @@ -85,29 +85,29 @@ Rectangle::GetClosestSide (const Position &position) const Position Rectangle::CalculateIntersection (const Position ¤t, const Speed &speed) const { - double xMaxY = current.y + (xMax - current.x) / speed.dx * speed.dy; - double xMinY = current.y + (xMin - current.x) / speed.dx * speed.dy; - double yMaxX = current.x + (yMax - current.y) / speed.dy * speed.dx; - double yMinX = current.x + (yMin - current.y) / speed.dy * speed.dx; - bool xMaxOk = xMaxY <= yMax && xMaxY >= yMin; - bool xMinOk = xMinY <= yMax && xMinY >= yMin; - bool yMaxOk = yMaxX <= xMax && yMaxX >= xMin; - bool yMinOk = yMinX <= xMax && yMinX >= xMin; - if (xMaxOk && speed.dx >= 0) + double xMaxY = current.y + (this->xMax - current.x) / speed.dx * speed.dy; + double xMinY = current.y + (this->xMin - current.x) / speed.dx * speed.dy; + double yMaxX = current.x + (this->yMax - current.y) / speed.dy * speed.dx; + double yMinX = current.x + (this->yMin - current.y) / speed.dy * speed.dx; + bool xMaxYOk = (xMaxY <= this->yMax && xMaxY >= this->yMin); + bool xMinYOk = (xMinY <= this->yMax && xMinY >= this->yMin); + bool yMaxXOk = (yMaxX <= this->xMax && yMaxX >= this->xMin); + bool yMinXOk = (yMinX <= this->xMax && yMinX >= this->xMin); + if (xMaxYOk && speed.dx >= 0) { - return Position (xMax, xMaxY, 0.0); + return Position (this->xMax, xMaxY, 0.0); } - else if (xMinOk && speed.dx <= 0) + else if (xMinYOk && speed.dx <= 0) { - return Position (xMin, xMinY, 0.0); + return Position (this->xMin, xMinY, 0.0); } - else if (yMaxOk && speed.dy >= 0) + else if (yMaxXOk && speed.dy >= 0) { - return Position (yMaxX, yMax, 0.0); + return Position (yMaxX, this->yMax, 0.0); } - else if (yMinOk && speed.dy <= 0) + else if (yMinXOk && speed.dy <= 0) { - return Position (yMinX, yMin, 0.0); + return Position (yMinX, this->yMin, 0.0); } else { diff --git a/src/mobility/static-speed-helper.cc b/src/mobility/static-speed-helper.cc index 82a3dd029..b2d806ab8 100644 --- a/src/mobility/static-speed-helper.cc +++ b/src/mobility/static-speed-helper.cc @@ -31,7 +31,8 @@ StaticSpeedHelper::StaticSpeedHelper (const Position &position) StaticSpeedHelper::StaticSpeedHelper (const Position &position, const Speed &speed) : m_position (position), - m_speed (speed) + m_speed (speed), + m_paused (true) {} void StaticSpeedHelper::InitializePosition (const Position &position) @@ -41,14 +42,7 @@ StaticSpeedHelper::InitializePosition (const Position &position) m_speed.dy = 0.0; m_speed.dz = 0.0; m_lastUpdate = Simulator::Now (); - m_pauseEnd = Simulator::Now (); -} - -void -StaticSpeedHelper::Reset (const Speed &speed, const Time &pauseDelay) -{ - Reset (speed); - m_pauseEnd = Simulator::Now () + pauseDelay; + m_paused = true; } Position @@ -61,7 +55,7 @@ StaticSpeedHelper::GetCurrentPosition (void) const Speed StaticSpeedHelper::GetSpeed (void) const { - return m_speed; + return m_paused? Speed (0, 0, 0) : m_speed; } void StaticSpeedHelper::SetSpeed (const Speed &speed) @@ -73,17 +67,13 @@ StaticSpeedHelper::SetSpeed (const Speed &speed) void StaticSpeedHelper::Update (void) const { + if (m_paused) + { + return; + } Time now = Simulator::Now (); - if (m_pauseEnd > now) - { - return; - } - Time last = std::max (now, m_pauseEnd); - if (m_lastUpdate >= last) - { - return; - } - Time deltaTime = now - last; + NS_ASSERT (m_lastUpdate <= now); + Time deltaTime = now - m_lastUpdate; m_lastUpdate = now; double deltaS = deltaTime.GetSeconds (); m_position.x += m_speed.dx * deltaS; @@ -96,7 +86,7 @@ StaticSpeedHelper::Reset (const Speed &speed) { Update (); m_speed = speed; - m_pauseEnd = Simulator::Now (); + Unpause (); } void StaticSpeedHelper::UpdateFull (const Rectangle &bounds) const @@ -115,5 +105,21 @@ StaticSpeedHelper::GetCurrentPosition (const Rectangle &bounds) const return m_position; } +void +StaticSpeedHelper::Pause (void) +{ + Update (); + m_paused = true; +} + +void +StaticSpeedHelper::Unpause (void) +{ + if (m_paused) + { + m_lastUpdate = Simulator::Now (); + m_paused = false; + } +} } // namespace ns3 diff --git a/src/mobility/static-speed-helper.h b/src/mobility/static-speed-helper.h index 24e1c6237..343898f22 100644 --- a/src/mobility/static-speed-helper.h +++ b/src/mobility/static-speed-helper.h @@ -37,12 +37,13 @@ class StaticSpeedHelper const Speed &speed); void InitializePosition (const Position &position); - void Reset (const Speed &speed, const Time &pauseDelay); void Reset (const Speed &speed); Position GetCurrentPosition (const Rectangle &bounds) const; Position GetCurrentPosition (void) const; Speed GetSpeed (void) const; void SetSpeed (const Speed &speed); + void Pause (void); + void Unpause (void); private: void Update (void) const; @@ -50,7 +51,7 @@ class StaticSpeedHelper mutable Time m_lastUpdate; mutable Position m_position; Speed m_speed; - Time m_pauseEnd; + bool m_paused; }; } // namespace ns3 diff --git a/src/mobility/wscript b/src/mobility/wscript index 66d9dfb4f..f630a4b71 100644 --- a/src/mobility/wscript +++ b/src/mobility/wscript @@ -16,6 +16,10 @@ def build(bld): 'static-mobility-model.cc', 'static-speed-helper.cc', 'static-speed-mobility-model.cc', + 'random-waypoint-mobility-model.cc', + 'random-walk-2d-mobility-model.cc', + 'random-direction-2d-mobility-model.cc', + 'ns2-mobility-file-topology.cc', ] headers = bld.create_obj('ns3header') @@ -33,4 +37,8 @@ def build(bld): 'static-mobility-model.h', 'static-speed-helper.h', 'static-speed-mobility-model.h', + 'random-waypoint-mobility-model.h', + 'random-walk-2d-mobility-model.h', + 'random-direction-2d-mobility-model.h', + 'ns2-mobility-file-topology.h', ] diff --git a/src/simulator/event-garbage-collector.cc b/src/simulator/event-garbage-collector.cc new file mode 100644 index 000000000..776f2a999 --- /dev/null +++ b/src/simulator/event-garbage-collector.cc @@ -0,0 +1,152 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2007 INESC Porto + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Gustavo J. A. M. Carneiro + */ +#include "event-garbage-collector.h" + +#define CLEANUP_CHUNK_MIN_SIZE 8 +#define CLEANUP_CHUNK_MAX_SIZE 128 + + +namespace ns3 { + + +EventGarbageCollector::EventGarbageCollector () : + m_nextCleanupSize (CLEANUP_CHUNK_MIN_SIZE) +{} + +void +EventGarbageCollector::Track (EventId event) +{ + m_events.push_back (event); + if (m_events.size () >= m_nextCleanupSize) + Cleanup (); +} + +inline bool +EventExpiredPredicate (const EventId &event) +{ + return event.IsExpired (); +} + +void +EventGarbageCollector::Grow () +{ + m_nextCleanupSize += (m_nextCleanupSize < CLEANUP_CHUNK_MAX_SIZE? + m_nextCleanupSize : CLEANUP_CHUNK_MAX_SIZE); +} + +void +EventGarbageCollector::Shrink () +{ + while (m_nextCleanupSize > m_events.size ()) + m_nextCleanupSize >>= 1; + Grow (); +} + +// Called when a new event was added and the cleanup limit was exceeded in consequence. +void +EventGarbageCollector::Cleanup () +{ + m_events.remove_if (EventExpiredPredicate); + + // If after cleanup we are still over the limit, increase the limit. + if (m_events.size () >= m_nextCleanupSize) + Grow (); + else + Shrink (); +} + + +EventGarbageCollector::~EventGarbageCollector () +{ + for (std::list::iterator event = m_events.begin (); + event != m_events.end (); event++) + { + Simulator::Cancel (*event); + } +} + +}; // namespace ns3 + + + +#ifdef RUN_SELF_TESTS + +#include "ns3/test.h" + +namespace ns3 { + +class EventGarbageCollectorTests : public Test +{ + int m_counter; + EventGarbageCollector *m_events; + + void EventGarbageCollectorCallback (); + +public: + + EventGarbageCollectorTests (); + virtual ~EventGarbageCollectorTests (); + virtual bool RunTests (void); +}; + +EventGarbageCollectorTests::EventGarbageCollectorTests () + : Test ("EventGarbageCollector"), m_counter (0), m_events (0) +{} + +EventGarbageCollectorTests::~EventGarbageCollectorTests () +{} + +void +EventGarbageCollectorTests::EventGarbageCollectorCallback () +{ + m_counter++; + if (m_counter == 50) + { + // this should cause the remaining (50) events to be cancelled + delete m_events; + m_events = 0; + } +} + +bool EventGarbageCollectorTests::RunTests (void) +{ + bool result = true; + + m_events = new EventGarbageCollector (); + + for (int n = 0; n < 100; n++) + { + m_events->Track (Simulator::Schedule + (Simulator::Now (), + &EventGarbageCollectorTests::EventGarbageCollectorCallback, + this)); + } + Simulator::Run (); + NS_TEST_ASSERT_EQUAL (m_events, 0); + NS_TEST_ASSERT_EQUAL (m_counter, 50); + return result; +} + +static EventGarbageCollectorTests g_eventCollectorTests; + +}; + +#endif /* RUN_SELF_TESTS */ diff --git a/src/simulator/event-garbage-collector.h b/src/simulator/event-garbage-collector.h new file mode 100644 index 000000000..b03b86322 --- /dev/null +++ b/src/simulator/event-garbage-collector.h @@ -0,0 +1,62 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2007 INESC Porto + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Gustavo J. A. M. Carneiro + */ +#ifndef EVENT_GARBAGE_COLLECTOR_H +#define EVENT_GARBAGE_COLLECTOR_H + +#include +#include "event-id.h" +#include "simulator.h" + +namespace ns3 { + +/** + * \brief An object that tracks scheduled events and automatically + * cancels them when it is destroyed. It is useful in situations + * where multiple instances of the same type of event can + * simultaneously be scheduled, and when the events should be limited + * to the lifetime of a container object. + */ +class EventGarbageCollector +{ +public: + + EventGarbageCollector (); + + /** + * \brief Tracks a new event + */ + void Track (EventId event); + + ~EventGarbageCollector (); + +private: + + std::list::size_type m_nextCleanupSize; + std::list m_events; + + void Cleanup (); + void Grow (); + void Shrink (); +}; + +}; // namespace ns3 + +#endif /* EVENT_GARBAGE_COLLECTOR_H */ diff --git a/src/simulator/simulator.cc b/src/simulator/simulator.cc index e00f548b5..5e6d3bad4 100644 --- a/src/simulator/simulator.cc +++ b/src/simulator/simulator.cc @@ -67,9 +67,10 @@ public: EventId ScheduleDestroy (const Ptr &event); void Remove (const EventId &ev); void Cancel (const EventId &ev); - bool IsExpired (const EventId &ev); + bool IsExpired (const EventId &ev) const; void Run (void); Time Now (void) const; + Time GetDelayLeft (const EventId &id) const; private: void ProcessOneEvent (void); @@ -251,6 +252,18 @@ SimulatorPrivate::Now (void) const { return TimeStep (m_currentTs); } +Time +SimulatorPrivate::GetDelayLeft (const EventId &id) const +{ + if (IsExpired (id)) + { + return TimeStep (0); + } + else + { + return TimeStep (id.GetTs () - m_currentTs); + } +} void SimulatorPrivate::Remove (const EventId &ev) @@ -293,12 +306,12 @@ SimulatorPrivate::Cancel (const EventId &id) } bool -SimulatorPrivate::IsExpired (const EventId &ev) +SimulatorPrivate::IsExpired (const EventId &ev) const { if (ev.GetUid () == 2) { // destroy events. - for (DestroyEvents::iterator i = m_destroyEvents.begin (); i != m_destroyEvents.end (); i++) + for (DestroyEvents::const_iterator i = m_destroyEvents.begin (); i != m_destroyEvents.end (); i++) { if (*i == ev) { @@ -411,6 +424,11 @@ Simulator::Now (void) { return GetPriv ()->Now (); } +Time +Simulator::GetDelayLeft (const EventId &id) +{ + return GetPriv ()->GetDelayLeft (id); +} Ptr Simulator::MakeEvent (void (*f) (void)) diff --git a/src/simulator/simulator.h b/src/simulator/simulator.h index cdf2f8b4e..0d48b2990 100644 --- a/src/simulator/simulator.h +++ b/src/simulator/simulator.h @@ -552,6 +552,13 @@ public: * Return the "current simulation time". */ static Time Now (void); + /** + * \param id the event id to analyse + * \returns the delay left until the input event id expires. + * if the event is not running, this method returns + * zero. + */ + static Time GetDelayLeft (const EventId &id); private: Simulator (); ~Simulator (); diff --git a/src/simulator/timer.cc b/src/simulator/timer.cc new file mode 100644 index 000000000..d3c09a0c8 --- /dev/null +++ b/src/simulator/timer.cc @@ -0,0 +1,325 @@ +#include "timer.h" +#include "simulator.h" +#include "simulation-singleton.h" +#include "event-garbage-collector.h" + +namespace ns3 { + +Timer::Timer () + : m_flags (0), + m_delay (FemtoSeconds (0)), + m_event (), + m_impl (0) +{} + +Timer::Timer (enum SchedulePolicy schedulePolicy, + enum DestroyPolicy destroyPolicy) + : m_flags (schedulePolicy | destroyPolicy), + m_delay (FemtoSeconds (0)), + m_event (), + m_impl (0) +{} + +Timer::Timer (enum GarbageCollectPolicy policy) + : m_flags (GARBAGE_COLLECT), + m_delay (FemtoSeconds (0)), + m_event (), + m_impl (0) +{} + +Timer::~Timer () +{ + if (m_flags & CHECK_ON_DESTROY) + { + if (m_event.IsRunning ()) + { + NS_FATAL_ERROR ("Event is still running while destroying."); + } + } + else if (m_flags & CANCEL_ON_DESTROY) + { + m_event.Cancel (); + } + else if (m_flags & REMOVE_ON_DESTROY) + { + Simulator::Remove (m_event); + } + delete m_impl; +} + +void +Timer::SetDelay (const Time &time) +{ + m_delay = time; +} +Time +Timer::GetDelay (void) const +{ + return m_delay; +} +Time +Timer::GetDelayLeft (void) const +{ + switch (GetState ()) { + case Timer::RUNNING: + return Simulator::GetDelayLeft (m_event); + break; + case Timer::EXPIRED: + return TimeStep (0); + break; + case Timer::SUSPENDED: + return m_delayLeft; + break; + default: + NS_ASSERT (false); + return TimeStep (0); + break; + } +} + +void +Timer::Cancel (void) +{ + Simulator::Cancel (m_event); +} +void +Timer::Remove (void) +{ + Simulator::Remove (m_event); +} +bool +Timer::IsExpired (void) const +{ + return !IsSuspended () && m_event.IsExpired (); +} +bool +Timer::IsRunning (void) const +{ + return !IsSuspended () && m_event.IsRunning (); +} +bool +Timer::IsSuspended (void) const +{ + return (m_flags & TIMER_SUSPENDED) == TIMER_SUSPENDED; +} +enum Timer::State +Timer::GetState (void) const +{ + if (IsRunning ()) + { + return Timer::RUNNING; + } + else if (IsExpired ()) + { + return Timer::EXPIRED; + } + else + { + NS_ASSERT (IsSuspended ()); + return Timer::SUSPENDED; + } +} + +void +Timer::Schedule (void) +{ + Schedule (m_delay); +} + +void +Timer::Schedule (Time delay) +{ + NS_ASSERT (m_impl != 0); + if (m_flags & CHECK_ON_SCHEDULE) + { + if (m_event.IsRunning ()) + { + NS_FATAL_ERROR ("Event is still running while re-scheduling."); + } + } + else if (m_flags & CANCEL_ON_SCHEDULE) + { + m_event.Cancel (); + } + else if (m_flags & REMOVE_ON_SCHEDULE) + { + Simulator::Remove (m_event); + } + m_event = m_impl->Schedule (delay); + if (m_flags & GARBAGE_COLLECT) + { + SimulationSingleton::Get ()->Track (m_event); + } +} + +void +Timer::Suspend (void) +{ + NS_ASSERT (IsRunning ()); + m_delayLeft = Simulator::GetDelayLeft (m_event); + Simulator::Remove (m_event); + m_flags |= TIMER_SUSPENDED; +} + +void +Timer::Resume (void) +{ + NS_ASSERT (m_flags & TIMER_SUSPENDED); + m_event = m_impl->Schedule (m_delayLeft); + m_flags &= ~TIMER_SUSPENDED; +} + + +} // namespace ns3 + + +#ifdef RUN_SELF_TESTS +#include "ns3/test.h" + +namespace { +void bari (int) +{} +void bar2i (int, int) +{} +void bar3i (int, int, int) +{} +void bar4i (int, int, int, int) +{} +void bar5i (int, int, int, int, int) +{} +void bar6i (int, int, int, int, int, int) +{} +void barcir (const int &) +{} +void barir (int &) +{} +void barip (int *) +{} +void barcip (const int *) +{} +} + +namespace ns3 { + +class TimerTests : public Test +{ +public: + TimerTests (); + virtual bool RunTests (void); + void bazi (int) {} + void baz2i (int, int) {} + void baz3i (int, int, int) {} + void baz4i (int, int, int, int) {} + void baz5i (int, int, int, int, int) {} + void baz6i (int, int, int, int, int, int) {} + void bazcir (const int&) {} + void bazir (int&) {} + void bazip (int *) {} + void bazcip (const int *) {} +}; + +TimerTests::TimerTests () + : Test ("Timer") +{} + +bool +TimerTests::RunTests (void) +{ + bool result = true; + + Timer timer; + + timer.SetFunction (&bari); + timer.SetArguments (1); + timer.SetDelay (Seconds (10.0)); + NS_TEST_ASSERT (!timer.IsRunning ()); + NS_TEST_ASSERT (timer.IsExpired ()); + NS_TEST_ASSERT (!timer.IsSuspended ()); + NS_TEST_ASSERT_EQUAL (timer.GetState (), Timer::EXPIRED); + timer.Schedule (); + NS_TEST_ASSERT (timer.IsRunning ()); + NS_TEST_ASSERT (!timer.IsExpired ()); + NS_TEST_ASSERT (!timer.IsSuspended ()); + NS_TEST_ASSERT_EQUAL (timer.GetState (), Timer::RUNNING); + timer.Suspend (); + NS_TEST_ASSERT (!timer.IsRunning ()); + NS_TEST_ASSERT (!timer.IsExpired ()); + NS_TEST_ASSERT (timer.IsSuspended ()); + NS_TEST_ASSERT_EQUAL (timer.GetState (), Timer::SUSPENDED); + timer.Resume (); + NS_TEST_ASSERT (timer.IsRunning ()); + NS_TEST_ASSERT (!timer.IsExpired ()); + NS_TEST_ASSERT (!timer.IsSuspended ()); + NS_TEST_ASSERT_EQUAL (timer.GetState (), Timer::RUNNING); + timer.Cancel (); + NS_TEST_ASSERT (!timer.IsRunning ()); + NS_TEST_ASSERT (timer.IsExpired ()); + NS_TEST_ASSERT (!timer.IsSuspended ()); + NS_TEST_ASSERT_EQUAL (timer.GetState (), Timer::EXPIRED); + + int a = 0; + int &b = a; + const int &c = a; + + timer.SetFunction (&bari); + timer.SetArguments (2); + timer.SetArguments (a); + timer.SetArguments (b); + timer.SetArguments (c); + timer.SetFunction (&barir); + timer.SetArguments (2); + timer.SetArguments (a); + timer.SetArguments (b); + timer.SetArguments (c); + timer.SetFunction (&barcir); + timer.SetArguments (2); + timer.SetArguments (a); + timer.SetArguments (b); + timer.SetArguments (c); + // the following call cannot possibly work and is flagged by + // a runtime error. + //timer.SetArguments (0.0); + timer.SetDelay (Seconds (1.0)); + timer.Schedule (); + + timer.SetFunction (&TimerTests::bazi, this); + timer.SetArguments (3); + timer.SetFunction (&TimerTests::bazir, this); + timer.SetArguments (3); + timer.SetFunction (&TimerTests::bazcir, this); + timer.SetArguments (3); + + timer.SetFunction (&bar2i); + timer.SetArguments (1, 1); + timer.SetFunction (&bar3i); + timer.SetArguments (1, 1, 1); + timer.SetFunction (&bar4i); + timer.SetArguments (1, 1, 1, 1); + timer.SetFunction (&bar5i); + timer.SetArguments (1, 1, 1, 1, 1); + //timer.SetFunction (&bar6i); + //timer.SetArguments (1, 1, 1, 1, 1, 1); + + timer.SetFunction (&TimerTests::baz2i, this); + timer.SetArguments (1, 1); + timer.SetFunction (&TimerTests::baz3i, this); + timer.SetArguments (1, 1, 1); + timer.SetFunction (&TimerTests::baz4i, this); + timer.SetArguments (1, 1, 1, 1); + timer.SetFunction (&TimerTests::baz5i, this); + timer.SetArguments (1, 1, 1, 1, 1); + //timer.SetFunction (&TimerTests::baz6i, this); + //timer.SetArguments (1, 1, 1, 1, 1, 1); + + + Simulator::Run (); + Simulator::Destroy (); + + return result; +} + +TimerTests g_tests; + +} // namespace ns3 + +#endif /* RUN_SELF_TESTS */ diff --git a/src/simulator/timer.h b/src/simulator/timer.h new file mode 100644 index 000000000..5087db294 --- /dev/null +++ b/src/simulator/timer.h @@ -0,0 +1,991 @@ +#ifndef TIMER_H +#define TIMER_H + +#include "ns3/fatal-error.h" +#include "nstime.h" +#include "event-id.h" +#include "ns3/int-to-type.h" + +namespace ns3 { + +class TimerImpl; + +/** + * \brief a simple Timer class + * + * A timer is used to hold together a delay, a function to invoke + * when the delay expires, and a set of arguments to pass to the function + * when the delay expires. + * + * A timer can also be used to enforce a set of predefined event lifetime + * management policies. These policies are specified at construction time + * and cannot be changed after. + */ +class Timer +{ +public: + enum SchedulePolicy { + /** + * This policy cancels the event before scheduling a new event + * for each call to Timer::Schedule. + */ + CANCEL_ON_SCHEDULE = (1<<0), + /** + * This policy removes the event from the simulation event list + * before scheduling a new event for each call to Timer::Schedule. + */ + REMOVE_ON_SCHEDULE = (1<<1), + /** + * This policy enforces a check before each call to Timer::Schedule + * to verify that the timer has already expired. + */ + CHECK_ON_SCHEDULE = (1<<2), + }; + enum DestroyPolicy { + /** + * This policy cancels the event from the destructor of the Timer + * to verify that the event has already expired. + */ + CANCEL_ON_DESTROY = (1<<3), + /** + * This policy removes the event from the simulation event list + * when the destructor of the Timer is invoked. + */ + REMOVE_ON_DESTROY = (1<<4), + /** + * This policy enforces a check from the destructor of the Timer + * to verify that the timer has already expired. + */ + CHECK_ON_DESTROY = (1<<5) + }; + enum GarbageCollectPolicy { + /** + * Every event scheduled with this policy is kept track of by an + * event garbage collector which makes sure that all events + * of timers with a GARBAGE_COLLECT policy are cancelled at the + * end of the simulation. + */ + GARBAGE_COLLECT = (1<<6) + }; + enum State { + RUNNING, + EXPIRED, + SUSPENDED, + }; + /** + * create a timer with a default event lifetime management policy: + * - CHECK_ON_SCHEDULE + * - CHECK_ON_DESTROY + */ + Timer (); + /** + * \param scheduleFlags the event lifetime management policies to use for schedule events + * \param destroyFlags the event lifetime management policies to use for destroy events + */ + Timer (enum SchedulePolicy schedulePolicy, + enum DestroyPolicy destroyPolicy); + /** + * \param policy the garbage collect policy. Only one + * value is possible. + */ + Timer (enum GarbageCollectPolicy policy); + ~Timer (); + + /** + * \param fn the function + * + * Store this function in this Timer for later use by Timer::Schedule. + */ + template + void SetFunction (FN fn); + + /** + * \param memPtr the member function pointer + * \param objPtr the pointer to object + * + * Store this function and object in this Timer for later use by Timer::Schedule. + */ + template + void SetFunction (MEM_PTR memPtr, OBJ_PTR objPtr); + + + /** + * \param a1 the first argument + * + * Store this argument in this Timer for later use by Timer::Schedule. + */ + template + void SetArguments (T1 a1); + /** + * \param a1 the first argument + * \param a2 the second argument + * + * Store these arguments in this Timer for later use by Timer::Schedule. + */ + template + void SetArguments (T1 a1, T2 a2); + /** + * \param a1 the first argument + * \param a2 the second argument + * \param a3 the third argument + * + * Store these arguments in this Timer for later use by Timer::Schedule. + */ + template + void SetArguments (T1 a1, T2 a2, T3 a3); + /** + * \param a1 the first argument + * \param a2 the second argument + * \param a3 the third argument + * \param a4 the fourth argument + * + * Store these arguments in this Timer for later use by Timer::Schedule. + */ + template + void SetArguments (T1 a1, T2 a2, T3 a3, T4 a4); + /** + * \param a1 the first argument + * \param a2 the second argument + * \param a3 the third argument + * \param a4 the fourth argument + * \param a5 the fifth argument + * + * Store these arguments in this Timer for later use by Timer::Schedule. + */ + template + void SetArguments (T1 a1, T2 a2, T3 a3, T4 a4, T5 a5); + /** + * \param a1 the first argument + * \param a2 the second argument + * \param a3 the third argument + * \param a4 the fourth argument + * \param a5 the fifth argument + * \param a6 the sixth argument + * + * Store these arguments in this Timer for later use by Timer::Schedule. + */ + template + void SetArguments (T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6); + + /** + * \param delay the delay + * + * The next call to Schedule will schedule the timer with this delay. + */ + void SetDelay (const Time &delay); + /** + * \returns the currently-configured delay for the next Schedule. + */ + Time GetDelay (void) const; + /** + * \returns the amount of time left until this timer expires. + * + * This method returns zero if the timer is in EXPIRED state. + */ + Time GetDelayLeft (void) const; + /** + * Cancel the currently-running event if there is one. Do nothing + * otherwise. + */ + void Cancel (void); + /** + * Remove from the simulation event-list the currently-running event + * if there is one. Do nothing otherwise. + */ + void Remove (void); + /** + * \return true if there is no currently-running event, false otherwise. + */ + bool IsExpired (void) const; + /** + * \return true if there is a currently-running event, false otherwise. + */ + bool IsRunning (void) const; + /** + * \returns true if this timer was suspended and not yet resumed, false + * otherwise. + */ + bool IsSuspended (void) const; + /** + * \returns the current state of the timer. + */ + enum Timer::State GetState (void) const; + /** + * Schedule a new event using the currently-configured delay, function, + * and arguments. + */ + void Schedule (void); + /** + * \param delay the delay to use + * + * Schedule a new event using the specified delay (ignore the delay set by + * Timer::SetDelay), function, and arguments. + */ + void Schedule (Time delay); + + /** + * Cancel the timer and save the amount of time left until it was + * set to expire. + * Calling Suspend on a non-running timer is an error. + */ + void Suspend (void); + /** + * Restart the timer to expire within the amount of time left saved + * during Suspend. + * Calling Resume without a prior call to Suspend is an error. + */ + void Resume (void); + +private: + template + void DoSetFunction (IntToType<0>, FN fn); + template + void DoSetFunction (IntToType<1>, FN fn); + template + void DoSetFunction (IntToType<2>, FN fn); + template + void DoSetFunction (IntToType<3>, FN fn); + template + void DoSetFunction (IntToType<4>, FN fn); + template + void DoSetFunction (IntToType<5>, FN fn); + template + void DoSetFunction (IntToType<6>, FN fn); + + template + void DoSetFunction (IntToType<0>, MEM_PTR memPtr, OBJ_PTR objPtr); + template + void DoSetFunction (IntToType<1>, MEM_PTR memPtr, OBJ_PTR objPtr); + template + void DoSetFunction (IntToType<2>, MEM_PTR memPtr, OBJ_PTR objPtr); + template + void DoSetFunction (IntToType<3>, MEM_PTR memPtr, OBJ_PTR objPtr); + template + void DoSetFunction (IntToType<4>, MEM_PTR memPtr, OBJ_PTR objPtr); + template + void DoSetFunction (IntToType<5>, MEM_PTR memPtr, OBJ_PTR objPtr); + template + void DoSetFunction (IntToType<6>, MEM_PTR memPtr, OBJ_PTR objPtr); + + enum { + TIMER_SUSPENDED = (1<<7) + }; + + int m_flags; + Time m_delay; + EventId m_event; + TimerImpl *m_impl; + Time m_delayLeft; +}; + +} // namespace ns3 + + +// The actual implementation. +#include "simulator.h" +#include "ns3/type-traits.h" + +namespace ns3 { + + +template +struct TimerTraits +{ + typedef typename TypeTraits::ReferencedType>::NonConstType StoredType; + typedef const StoredType &ParameterType; +}; + +class TimerImpl +{ +public: + virtual ~TimerImpl () {} + virtual EventId Schedule (const Time &delay) = 0; +}; + + +template +struct TimerImplOne : public TimerImpl +{ + virtual void SetArguments (T1 a1) = 0; +}; +template +struct TimerImplTwo : public TimerImpl +{ + virtual void SetArguments (T1 a1,T2 a2) = 0; +}; +template +struct TimerImplThree : public TimerImpl +{ + virtual void SetArguments (T1 a1,T2 a2,T3 a3) = 0; +}; +template +struct TimerImplFour : public TimerImpl +{ + virtual void SetArguments (T1 a1,T2 a2,T3 a3, T4 a4) = 0; +}; +template +struct TimerImplFive : public TimerImpl +{ + virtual void SetArguments (T1 a1,T2 a2,T3 a3, T4 a4, T5 a5) = 0; +}; +template +struct TimerImplSix : public TimerImpl +{ + virtual void SetArguments (T1 a1,T2 a2,T3 a3, T4 a4, T5 a5, T6 a6) = 0; +}; + + +template +void +Timer::SetFunction (FN fn) +{ + NS_ASSERT (TypeTraits::IsFunctionPointer); + DoSetFunction (IntToType::FunctionPointerTraits::nArgs> (), fn); +} + +template +void +Timer::DoSetFunction (IntToType<0>, FN fn) +{ + struct FnTimerImplZero : public TimerImpl + { + FnTimerImplZero (FN fn) + : m_fn (fn) {} + virtual EventId Schedule (const Time &delay) { + return Simulator::Schedule (delay, m_fn); + } + FN m_fn; + } *function = new FnTimerImplZero (fn); + delete m_impl; + m_impl = function; +} + +template +void +Timer::DoSetFunction (IntToType<1>, FN fn) +{ + typedef typename TypeTraits::FunctionPointerTraits::Arg1Type T1; + typedef typename TimerTraits::ParameterType T1Parameter; + typedef typename TimerTraits::StoredType T1Stored; + + struct FnTimerImplOne : public TimerImplOne + { + FnTimerImplOne (FN fn) + : m_fn (fn) {} + virtual void SetArguments (T1Parameter a1) { + m_a1 = a1; + } + virtual EventId Schedule (const Time &delay) { + return Simulator::Schedule (delay, m_fn, m_a1); + } + FN m_fn; + T1Stored m_a1; + } *function = new FnTimerImplOne (fn); + delete m_impl; + m_impl = function; +} + +template +void +Timer::DoSetFunction (IntToType<2>, FN fn) +{ + typedef typename TypeTraits::FunctionPointerTraits::Arg1Type T1; + typedef typename TimerTraits::ParameterType T1Parameter; + typedef typename TimerTraits::StoredType T1Stored; + typedef typename TypeTraits::FunctionPointerTraits::Arg2Type T2; + typedef typename TimerTraits::ParameterType T2Parameter; + typedef typename TimerTraits::StoredType T2Stored; + + struct FnTimerImplTwo : public TimerImplTwo + { + FnTimerImplTwo (FN fn) + : m_fn (fn) {} + virtual void SetArguments (T1Parameter a1, T2Parameter a2) { + m_a1 = a1; + m_a2 = a2; + } + virtual EventId Schedule (const Time &delay) { + return Simulator::Schedule (delay, m_fn, m_a1, m_a2); + } + FN m_fn; + T1Stored m_a1; + T2Stored m_a2; + } *function = new FnTimerImplTwo (fn); + delete m_impl; + m_impl = function; +} + +template +void +Timer::DoSetFunction (IntToType<3>, FN fn) +{ + typedef typename TypeTraits::FunctionPointerTraits::Arg1Type T1; + typedef typename TimerTraits::ParameterType T1Parameter; + typedef typename TimerTraits::StoredType T1Stored; + typedef typename TypeTraits::FunctionPointerTraits::Arg2Type T2; + typedef typename TimerTraits::ParameterType T2Parameter; + typedef typename TimerTraits::StoredType T2Stored; + typedef typename TypeTraits::FunctionPointerTraits::Arg3Type T3; + typedef typename TimerTraits::ParameterType T3Parameter; + typedef typename TimerTraits::StoredType T3Stored; + + struct FnTimerImplThree : public TimerImplThree + { + FnTimerImplThree (FN fn) + : m_fn (fn) {} + virtual void SetArguments (T1Parameter a1, T2Parameter a2, T3Parameter a3) { + m_a1 = a1; + m_a2 = a2; + m_a3 = a3; + } + virtual EventId Schedule (const Time &delay) { + return Simulator::Schedule (delay, m_fn, m_a1, m_a2, m_a3); + } + FN m_fn; + T1Stored m_a1; + T2Stored m_a2; + T3Stored m_a3; + } *function = new FnTimerImplThree (fn); + delete m_impl; + m_impl = function; +} + +template +void +Timer::DoSetFunction (IntToType<4>, FN fn) +{ + typedef typename TypeTraits::FunctionPointerTraits::Arg1Type T1; + typedef typename TimerTraits::ParameterType T1Parameter; + typedef typename TimerTraits::StoredType T1Stored; + typedef typename TypeTraits::FunctionPointerTraits::Arg2Type T2; + typedef typename TimerTraits::ParameterType T2Parameter; + typedef typename TimerTraits::StoredType T2Stored; + typedef typename TypeTraits::FunctionPointerTraits::Arg3Type T3; + typedef typename TimerTraits::ParameterType T3Parameter; + typedef typename TimerTraits::StoredType T3Stored; + typedef typename TypeTraits::FunctionPointerTraits::Arg4Type T4; + typedef typename TimerTraits::ParameterType T4Parameter; + typedef typename TimerTraits::StoredType T4Stored; + + struct FnTimerImplFour : public TimerImplFour + { + FnTimerImplFour (FN fn) + : m_fn (fn) {} + virtual void SetArguments (T1Parameter a1, T2Parameter a2, T3Parameter a3, T4Parameter a4) { + m_a1 = a1; + m_a2 = a2; + m_a3 = a3; + m_a4 = a4; + } + virtual EventId Schedule (const Time &delay) { + return Simulator::Schedule (delay, m_fn, m_a1, m_a2, m_a3, m_a4); + } + FN m_fn; + T1Stored m_a1; + T2Stored m_a2; + T3Stored m_a3; + T4Stored m_a4; + } *function = new FnTimerImplFour (fn); + delete m_impl; + m_impl = function; +} + +template +void +Timer::DoSetFunction (IntToType<5>, FN fn) +{ + typedef typename TypeTraits::FunctionPointerTraits::Arg1Type T1; + typedef typename TimerTraits::ParameterType T1Parameter; + typedef typename TimerTraits::StoredType T1Stored; + typedef typename TypeTraits::FunctionPointerTraits::Arg2Type T2; + typedef typename TimerTraits::ParameterType T2Parameter; + typedef typename TimerTraits::StoredType T2Stored; + typedef typename TypeTraits::FunctionPointerTraits::Arg3Type T3; + typedef typename TimerTraits::ParameterType T3Parameter; + typedef typename TimerTraits::StoredType T3Stored; + typedef typename TypeTraits::FunctionPointerTraits::Arg4Type T4; + typedef typename TimerTraits::ParameterType T4Parameter; + typedef typename TimerTraits::StoredType T4Stored; + typedef typename TypeTraits::FunctionPointerTraits::Arg5Type T5; + typedef typename TimerTraits::ParameterType T5Parameter; + typedef typename TimerTraits::StoredType T5Stored; + + struct FnTimerImplFive : public TimerImplFive + { + FnTimerImplFive (FN fn) + : m_fn (fn) {} + virtual void SetArguments (T1Parameter a1, T2Parameter a2, T3Parameter a3, T4Parameter a4, T5Parameter a5) { + m_a1 = a1; + m_a2 = a2; + m_a3 = a3; + m_a4 = a4; + m_a5 = a5; + } + virtual EventId Schedule (const Time &delay) { + return Simulator::Schedule (delay, m_fn, m_a1, m_a2, m_a3, m_a4, m_a5); + } + FN m_fn; + T1Stored m_a1; + T2Stored m_a2; + T3Stored m_a3; + T4Stored m_a4; + T5Stored m_a5; + } *function = new FnTimerImplFive (fn); + delete m_impl; + m_impl = function; +} + +template +void +Timer::DoSetFunction (IntToType<6>, FN fn) +{ + typedef typename TypeTraits::FunctionPointerTraits::Arg1Type T1; + typedef typename TimerTraits::ParameterType T1Parameter; + typedef typename TimerTraits::StoredType T1Stored; + typedef typename TypeTraits::FunctionPointerTraits::Arg2Type T2; + typedef typename TimerTraits::ParameterType T2Parameter; + typedef typename TimerTraits::StoredType T2Stored; + typedef typename TypeTraits::FunctionPointerTraits::Arg3Type T3; + typedef typename TimerTraits::ParameterType T3Parameter; + typedef typename TimerTraits::StoredType T3Stored; + typedef typename TypeTraits::FunctionPointerTraits::Arg4Type T4; + typedef typename TimerTraits::ParameterType T4Parameter; + typedef typename TimerTraits::StoredType T4Stored; + typedef typename TypeTraits::FunctionPointerTraits::Arg5Type T5; + typedef typename TimerTraits::ParameterType T5Parameter; + typedef typename TimerTraits::StoredType T5Stored; + typedef typename TypeTraits::FunctionPointerTraits::Arg6Type T6; + typedef typename TimerTraits::ParameterType T6Parameter; + typedef typename TimerTraits::StoredType T6Stored; + + struct FnTimerImplSix : public TimerImplSix + { + FnTimerImplSix (FN fn) + : m_fn (fn) {} + virtual void SetArguments (T1Parameter a1, T2Parameter a2, T3Parameter a3, T4Parameter a4, T5Parameter a5, T6Parameter a6) { + m_a1 = a1; + m_a2 = a2; + m_a3 = a3; + m_a4 = a4; + m_a5 = a5; + m_a6 = a6; + } + virtual EventId Schedule (const Time &delay) { + return Simulator::Schedule (delay, m_fn, m_a1, m_a2, m_a3, m_a4, m_a5, m_a6); + } + FN m_fn; + T1Stored m_a1; + T2Stored m_a2; + T3Stored m_a3; + T4Stored m_a4; + T5Stored m_a5; + T6Stored m_a6; + } *function = new FnTimerImplSix (fn); + delete m_impl; + m_impl = function; +} + +template +void +Timer::SetFunction (MEM_PTR memPtr, OBJ_PTR objPtr) +{ + NS_ASSERT (TypeTraits::IsPointerToMember); + DoSetFunction (IntToType::PointerToMemberTraits::nArgs> () , memPtr, objPtr); +} + +template +void +Timer::DoSetFunction (IntToType<0>, MEM_PTR memPtr, OBJ_PTR objPtr) +{ + struct MemFnTimerImplZero : public TimerImpl + { + MemFnTimerImplZero (MEM_PTR memPtr, OBJ_PTR objPtr) + : m_memPtr (memPtr), m_objPtr (objPtr) {} + virtual EventId Schedule (const Time &delay) { + return Simulator::Schedule (delay, m_memPtr, m_objPtr); + } + MEM_PTR m_memPtr; + OBJ_PTR m_objPtr; + } *function = new MemFnTimerImplZero (memPtr, objPtr); + delete m_impl; + m_impl = function; +} + +template +void +Timer::DoSetFunction (IntToType<1>, MEM_PTR memPtr, OBJ_PTR objPtr) +{ + typedef typename TypeTraits::PointerToMemberTraits::Arg1Type T1; + typedef typename TimerTraits::ParameterType T1Parameter; + typedef typename TimerTraits::StoredType T1Stored; + + struct MemFnTimerImplOne : public TimerImplOne + { + MemFnTimerImplOne (MEM_PTR memPtr, OBJ_PTR objPtr) + : m_memPtr (memPtr), m_objPtr (objPtr) {} + virtual void SetArguments (T1Parameter a1) { + m_a1 = a1; + } + virtual EventId Schedule (const Time &delay) { + return Simulator::Schedule (delay, m_memPtr, m_objPtr, m_a1); + } + MEM_PTR m_memPtr; + OBJ_PTR m_objPtr; + T1Stored m_a1; + } *function = new MemFnTimerImplOne (memPtr, objPtr); + delete m_impl; + m_impl = function; +} + +template +void +Timer::DoSetFunction (IntToType<2>, MEM_PTR memPtr, OBJ_PTR objPtr) +{ + typedef typename TypeTraits::PointerToMemberTraits::Arg1Type T1; + typedef typename TimerTraits::ParameterType T1Parameter; + typedef typename TimerTraits::StoredType T1Stored; + typedef typename TypeTraits::PointerToMemberTraits::Arg2Type T2; + typedef typename TimerTraits::ParameterType T2Parameter; + typedef typename TimerTraits::StoredType T2Stored; + + struct MemFnTimerImplTwo : public TimerImplTwo + { + MemFnTimerImplTwo (MEM_PTR memPtr, OBJ_PTR objPtr) + : m_memPtr (memPtr), m_objPtr (objPtr) {} + virtual void SetArguments (T1Parameter a1, T2Parameter a2) { + m_a1 = a1; + m_a2 = a2; + } + virtual EventId Schedule (const Time &delay) { + return Simulator::Schedule (delay, m_memPtr, m_objPtr, m_a1, m_a2); + } + MEM_PTR m_memPtr; + OBJ_PTR m_objPtr; + T1Stored m_a1; + T2Stored m_a2; + } *function = new MemFnTimerImplTwo (memPtr, objPtr); + delete m_impl; + m_impl = function; +} + +template +void +Timer::DoSetFunction (IntToType<3>, MEM_PTR memPtr, OBJ_PTR objPtr) +{ + typedef typename TypeTraits::PointerToMemberTraits::Arg1Type T1; + typedef typename TimerTraits::ParameterType T1Parameter; + typedef typename TimerTraits::StoredType T1Stored; + typedef typename TypeTraits::PointerToMemberTraits::Arg2Type T2; + typedef typename TimerTraits::ParameterType T2Parameter; + typedef typename TimerTraits::StoredType T2Stored; + typedef typename TypeTraits::PointerToMemberTraits::Arg3Type T3; + typedef typename TimerTraits::ParameterType T3Parameter; + typedef typename TimerTraits::StoredType T3Stored; + + struct MemFnTimerImplThree : public TimerImplThree + { + MemFnTimerImplThree (MEM_PTR memPtr, OBJ_PTR objPtr) + : m_memPtr (memPtr), m_objPtr (objPtr) {} + virtual void SetArguments (T1Parameter a1, T2Parameter a2, T3Parameter a3) { + m_a1 = a1; + m_a2 = a2; + m_a3 = a3; + } + virtual EventId Schedule (const Time &delay) { + return Simulator::Schedule (delay, m_memPtr, m_objPtr, m_a1, m_a2, m_a3); + } + MEM_PTR m_memPtr; + OBJ_PTR m_objPtr; + T1Stored m_a1; + T2Stored m_a2; + T3Stored m_a3; + } *function = new MemFnTimerImplThree (memPtr, objPtr); + delete m_impl; + m_impl = function; +} + +template +void +Timer::DoSetFunction (IntToType<4>, MEM_PTR memPtr, OBJ_PTR objPtr) +{ + typedef typename TypeTraits::PointerToMemberTraits::Arg1Type T1; + typedef typename TimerTraits::ParameterType T1Parameter; + typedef typename TimerTraits::StoredType T1Stored; + typedef typename TypeTraits::PointerToMemberTraits::Arg2Type T2; + typedef typename TimerTraits::ParameterType T2Parameter; + typedef typename TimerTraits::StoredType T2Stored; + typedef typename TypeTraits::PointerToMemberTraits::Arg3Type T3; + typedef typename TimerTraits::ParameterType T3Parameter; + typedef typename TimerTraits::StoredType T3Stored; + typedef typename TypeTraits::PointerToMemberTraits::Arg4Type T4; + typedef typename TimerTraits::ParameterType T4Parameter; + typedef typename TimerTraits::StoredType T4Stored; + + struct MemFnTimerImplFour : public TimerImplFour + { + MemFnTimerImplFour (MEM_PTR memPtr, OBJ_PTR objPtr) + : m_memPtr (memPtr), m_objPtr (objPtr) {} + virtual void SetArguments (T1Parameter a1, T2Parameter a2, T3Parameter a3, T4Parameter a4) { + m_a1 = a1; + m_a2 = a2; + m_a3 = a3; + m_a4 = a4; + } + virtual EventId Schedule (const Time &delay) { + return Simulator::Schedule (delay, m_memPtr, m_objPtr, m_a1, m_a2, m_a3, m_a4); + } + MEM_PTR m_memPtr; + OBJ_PTR m_objPtr; + T1Stored m_a1; + T2Stored m_a2; + T3Stored m_a3; + T4Stored m_a4; + } *function = new MemFnTimerImplFour (memPtr, objPtr); + delete m_impl; + m_impl = function; +} + +template +void +Timer::DoSetFunction (IntToType<5>, MEM_PTR memPtr, OBJ_PTR objPtr) +{ + typedef typename TypeTraits::PointerToMemberTraits::Arg1Type T1; + typedef typename TimerTraits::ParameterType T1Parameter; + typedef typename TimerTraits::StoredType T1Stored; + typedef typename TypeTraits::PointerToMemberTraits::Arg2Type T2; + typedef typename TimerTraits::ParameterType T2Parameter; + typedef typename TimerTraits::StoredType T2Stored; + typedef typename TypeTraits::PointerToMemberTraits::Arg3Type T3; + typedef typename TimerTraits::ParameterType T3Parameter; + typedef typename TimerTraits::StoredType T3Stored; + typedef typename TypeTraits::PointerToMemberTraits::Arg4Type T4; + typedef typename TimerTraits::ParameterType T4Parameter; + typedef typename TimerTraits::StoredType T4Stored; + typedef typename TypeTraits::PointerToMemberTraits::Arg5Type T5; + typedef typename TimerTraits::ParameterType T5Parameter; + typedef typename TimerTraits::StoredType T5Stored; + + struct MemFnTimerImplFive : public TimerImplFive + { + MemFnTimerImplFive (MEM_PTR memPtr, OBJ_PTR objPtr) + : m_memPtr (memPtr), m_objPtr (objPtr) {} + virtual void SetArguments (T1Parameter a1, T2Parameter a2, T3Parameter a3, T4Parameter a4,T5Parameter a5) { + m_a1 = a1; + m_a2 = a2; + m_a3 = a3; + m_a4 = a4; + m_a5 = a5; + } + virtual EventId Schedule (const Time &delay) { + return Simulator::Schedule (delay, m_memPtr, m_objPtr, m_a1, m_a2, m_a3, m_a4, m_a5); + } + MEM_PTR m_memPtr; + OBJ_PTR m_objPtr; + T1Stored m_a1; + T2Stored m_a2; + T3Stored m_a3; + T4Stored m_a4; + T5Stored m_a5; + } *function = new MemFnTimerImplFive (memPtr, objPtr); + delete m_impl; + m_impl = function; +} + +template +void +Timer::DoSetFunction (IntToType<6>, MEM_PTR memPtr, OBJ_PTR objPtr) +{ + typedef typename TypeTraits::PointerToMemberTraits::Arg1Type T1; + typedef typename TimerTraits::ParameterType T1Parameter; + typedef typename TimerTraits::StoredType T1Stored; + typedef typename TypeTraits::PointerToMemberTraits::Arg2Type T2; + typedef typename TimerTraits::ParameterType T2Parameter; + typedef typename TimerTraits::StoredType T2Stored; + typedef typename TypeTraits::PointerToMemberTraits::Arg3Type T3; + typedef typename TimerTraits::ParameterType T3Parameter; + typedef typename TimerTraits::StoredType T3Stored; + typedef typename TypeTraits::PointerToMemberTraits::Arg4Type T4; + typedef typename TimerTraits::ParameterType T4Parameter; + typedef typename TimerTraits::StoredType T4Stored; + typedef typename TypeTraits::PointerToMemberTraits::Arg5Type T5; + typedef typename TimerTraits::ParameterType T5Parameter; + typedef typename TimerTraits::StoredType T5Stored; + typedef typename TypeTraits::PointerToMemberTraits::Arg6Type T6; + typedef typename TimerTraits::ParameterType T6Parameter; + typedef typename TimerTraits::StoredType T6Stored; + + struct MemFnTimerImplSix : public TimerImplSix + { + MemFnTimerImplSix (MEM_PTR memPtr, OBJ_PTR objPtr) + : m_memPtr (memPtr), m_objPtr (objPtr) {} + virtual void SetArguments (T1Parameter a1, T2Parameter a2, T3Parameter a3, T4Parameter a4,T5Parameter a5,T6Parameter a6) { + m_a1 = a1; + m_a2 = a2; + m_a3 = a3; + m_a4 = a4; + m_a5 = a5; + m_a6 = a6; + } + virtual EventId Schedule (const Time &delay) { + return Simulator::Schedule (delay, m_memPtr, m_objPtr, m_a1, m_a2, m_a3, m_a4, m_a5, m_a6); + } + MEM_PTR m_memPtr; + OBJ_PTR m_objPtr; + T1Stored m_a1; + T2Stored m_a2; + T3Stored m_a3; + T4Stored m_a4; + T5Stored m_a5; + T6Stored m_a6; + } *function = new MemFnTimerImplSix (memPtr, objPtr); + delete m_impl; + m_impl = function; +} + + +template +void +Timer::SetArguments (T1 a1) +{ + if (m_impl == 0) + { + NS_FATAL_ERROR ("You cannot set the arguments of a Timer before setting its function."); + return; + } + typedef struct TimerImplOne< + typename TimerTraits::ParameterType + > TimerImplBase; + TimerImplBase *impl = dynamic_cast (m_impl); + if (impl == 0) + { + NS_FATAL_ERROR ("You tried to set Timer arguments incompatible with its function."); + return; + } + impl->SetArguments (a1); +} + +template +void +Timer::SetArguments (T1 a1, T2 a2) +{ + if (m_impl == 0) + { + NS_FATAL_ERROR ("You cannot set the arguments of a Timer before setting its function."); + return; + } + typedef struct TimerImplTwo< + typename TimerTraits::ParameterType, + typename TimerTraits::ParameterType + > TimerImplBase; + TimerImplBase *impl = dynamic_cast (m_impl); + if (impl == 0) + { + NS_FATAL_ERROR ("You tried to set Timer arguments incompatible with its function."); + return; + } + impl->SetArguments (a1, a2); +} + +template +void +Timer::SetArguments (T1 a1, T2 a2, T3 a3) +{ + if (m_impl == 0) + { + NS_FATAL_ERROR ("You cannot set the arguments of a Timer before setting its function."); + return; + } + typedef struct TimerImplThree< + typename TimerTraits::ParameterType, + typename TimerTraits::ParameterType, + typename TimerTraits::ParameterType + > TimerImplBase; + TimerImplBase *impl = dynamic_cast (m_impl); + if (impl == 0) + { + NS_FATAL_ERROR ("You tried to set Timer arguments incompatible with its function."); + return; + } + impl->SetArguments (a1, a2, a3); +} + +template +void +Timer::SetArguments (T1 a1, T2 a2, T3 a3, T4 a4) +{ + if (m_impl == 0) + { + NS_FATAL_ERROR ("You cannot set the arguments of a Timer before setting its function."); + return; + } + typedef struct TimerImplFour< + typename TimerTraits::ParameterType, + typename TimerTraits::ParameterType, + typename TimerTraits::ParameterType, + typename TimerTraits::ParameterType + > TimerImplBase; + TimerImplBase *impl = dynamic_cast (m_impl); + if (impl == 0) + { + NS_FATAL_ERROR ("You tried to set Timer arguments incompatible with its function."); + return; + } + impl->SetArguments (a1, a2, a3, a4); +} + +template +void +Timer::SetArguments (T1 a1, T2 a2, T3 a3, T4 a4, T5 a5) +{ + if (m_impl == 0) + { + NS_FATAL_ERROR ("You cannot set the arguments of a Timer before setting its function."); + return; + } + typedef struct TimerImplFive< + typename TimerTraits::ParameterType, + typename TimerTraits::ParameterType, + typename TimerTraits::ParameterType, + typename TimerTraits::ParameterType, + typename TimerTraits::ParameterType + > TimerImplBase; + TimerImplBase *impl = dynamic_cast (m_impl); + if (impl == 0) + { + NS_FATAL_ERROR ("You tried to set Timer arguments incompatible with its function."); + return; + } + impl->SetArguments (a1, a2, a3, a4, a5); +} + +template +void +Timer::SetArguments (T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6) +{ + if (m_impl == 0) + { + NS_FATAL_ERROR ("You cannot set the arguments of a Timer before setting its function."); + return; + } + typedef struct TimerImplSix< + typename TimerTraits::ParameterType, + typename TimerTraits::ParameterType, + typename TimerTraits::ParameterType, + typename TimerTraits::ParameterType, + typename TimerTraits::ParameterType, + typename TimerTraits::ParameterType + > TimerImplBase; + TimerImplBase *impl = dynamic_cast (m_impl); + if (impl == 0) + { + NS_FATAL_ERROR ("You tried to set Timer arguments incompatible with its function."); + return; + } + impl->SetArguments (a1, a2, a3, a4, a5, a6); +} + + + +} // namespace ns3 + +#endif /* TIMER_H */ diff --git a/src/simulator/wscript b/src/simulator/wscript index 970a43aea..68279c9e3 100644 --- a/src/simulator/wscript +++ b/src/simulator/wscript @@ -60,6 +60,8 @@ def build(bld): 'event-impl.cc', 'simulator.cc', 'time-default-value.cc', + 'timer.cc', + 'event-garbage-collector.cc', ] headers = bld.create_obj('ns3header') @@ -73,6 +75,7 @@ def build(bld): 'scheduler-factory.h', 'simulation-singleton.h', 'time-default-value.h', + 'timer.h' ] env = bld.env_of_name('default') diff --git a/utils/mobility-generator.cc b/utils/mobility-generator.cc new file mode 100644 index 000000000..7c7a7159c --- /dev/null +++ b/utils/mobility-generator.cc @@ -0,0 +1,67 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2007 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ + +#include "ns3/ns2-mobility-file-topology.h" +#include "ns3/object.h" +#include "ns3/simulator.h" +#include "ns3/mobility-model-notifier.h" +#include + +using namespace ns3; + +static void +CourseChange (Ptr position) +{ + Position pos = position->Get (); + std::cout << Simulator::Now () << ", pos=" << position << ", x=" << pos.x << ", y=" << pos.y + << ", z=" << pos.z << std::endl; +} + +int main (int argc, char *argv[]) +{ + std::vector > objects; + while (argc > 0) + { + if (strncmp (*argv, "--n=", strlen ("--n=")) == 0) + { + uint32_t n = atoi (*argv + strlen ("--n=")); + for (uint32_t i = 0; i < n; i++) + { + Ptr notifier = Create (); + notifier->RegisterListener (MakeCallback (&CourseChange)); + objects.push_back (notifier); + } + } + else if (strncmp (*argv, "--ns2-topology=", + strlen ("--ns2-topology=")) == 0) + { + const char *filename = *argv + strlen ("--ns2-topology="); + Ns2MobilityFileTopology topology (filename); + topology.Layout (objects.begin (), objects.end ()); + } + argc--; + argv++; + } + + Simulator::Run (); + Simulator::Destroy (); + return 0; +} diff --git a/utils/mobility-visualizer-model.cc b/utils/mobility-visualizer-model.cc new file mode 100644 index 000000000..21cb007e4 --- /dev/null +++ b/utils/mobility-visualizer-model.cc @@ -0,0 +1,137 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ + +#include + +#include "ns3/ptr.h" +#include "ns3/mobility-model.h" +#include "ns3/mobility-model-notifier.h" +#include "ns3/random-topology.h" +#include "ns3/default-value.h" +#include "ns3/command-line.h" +#include "ns3/command-line.h" +#include "ns3/simulator.h" +#include "ns3/nstime.h" +#include "ns3/node.h" +#include "ns3/node-list.h" +#include "ns3/rectangle-default-value.h" + +#include "mobility-visualizer.h" + +using namespace ns3; + +static Time g_sampleInterval = Seconds (SAMPLE_INTERVAL); +static uint32_t g_numNodes = 10; + +template +static const T* DefaultValueListGet (const std::string &name) +{ + for (DefaultValueList::Iterator iter = DefaultValueList::Begin (); + iter != DefaultValueList::End (); iter++) + { + const DefaultValueBase *value = *iter; + if (value->GetName () == name) + { + return dynamic_cast (value); + } + } + return NULL; +} + + + +static void +Sample () +{ + + ViewUpdateData *data = new ViewUpdateData; + for (NodeList::Iterator nodeIter = NodeList::Begin (); nodeIter != NodeList::End (); nodeIter++) + { + Ptr node = *nodeIter; + Ptr mobility = node->QueryInterface (MobilityModel::iid); + Position pos = mobility->Get (); + Speed vel = mobility->GetSpeed (); + + NodeUpdate update; + update.node = PeekPointer (node); + update.x = pos.x; + update.y = pos.y; + update.vx = vel.dx; + update.vy = vel.dy; + data->updateList.push_back (update); + } + data->time = Simulator::Now ().GetSeconds (); + view_update (data); + Simulator::Schedule (g_sampleInterval, Sample); +} + + + +int model_init (int argc, char *argv[], double *x1, double *y1, double *x2, double *y2) +{ + DefaultValue::Bind ("RandomWalk2dMode", "Time"); + DefaultValue::Bind ("RandomWalk2dTime", "5s"); + DefaultValue::Bind ("RandomWalk2dSpeed", "Constant:20.0"); + DefaultValue::Bind ("RandomDirection2dSpeed", "Uniform:10.0:20.0"); + DefaultValue::Bind ("RandomWalk2dBounds", "0:400:0:300"); + DefaultValue::Bind ("RandomDirection2dArea", "0:400:0:300"); + DefaultValue::Bind ("RandomWaypointSpeed", "Uniform:10:30"); + +// DefaultValue::Bind ("RandomDiscPositionX", "100"); +// DefaultValue::Bind ("RandomDiscPositionY", "50"); +// DefaultValue::Bind ("RandomDiscPositionRho", "Uniform:0:30"); + + DefaultValue::Bind ("RandomTopologyPositionType", "RandomRectanglePosition"); + DefaultValue::Bind ("RandomTopologyMobilityType", "RandomWalk2dMobilityModel"); + +// CommandLine::AddArgValue ("sample-interval","sample interval", g_sampleInterval); +// CommandLine::AddArgValue ("num-nodes","number of nodes", g_numNodes); + + CommandLine::Parse (argc, argv); + + RandomTopology topology; + + for (uint32_t i = 0; i < g_numNodes; i++) + { + Ptr node = Create (); + node->AddInterface (Create ()); + } + + topology.Layout (NodeList::Begin (), NodeList::End ()); + + Simulator::Schedule (g_sampleInterval, Sample); + + ClassId mobType = DefaultValueListGet ("RandomTopologyMobilityType")->GetValue (); + if (mobType.GetName () == "RandomWalk2dMobilityModel") + { + Rectangle bounds = DefaultValueListGet ("RandomWalk2dBounds")->GetValue (); + *x1 = bounds.xMin; + *y1 = bounds.yMin; + *x2 = bounds.xMax; + *y2 = bounds.yMax; + std::cout << "RECT " << bounds.xMin << " " << bounds.xMax << " " + << bounds.yMin << " " << bounds.yMax << std::endl; + } + else if (mobType.GetName () == "RandomDirection2dMobilityModel") + { + Rectangle bounds = DefaultValueListGet ("RandomDirection2dArea")->GetValue (); + *x1 = bounds.xMin; + *y1 = bounds.yMin; + *x2 = bounds.xMax; + *y2 = bounds.yMax; + std::cout << "RECT " << bounds.xMin << " " << bounds.xMax << " " + << bounds.yMin << " " << bounds.yMax << std::endl; + } + else if (mobType.GetName () == "RandomWaypointMobilityModel") + { + std::cerr << "bounds for RandomWaypointMobilityModel not implemented" << std::endl; + //ClassId posType = DefaultValueList::Get ("RandomWaypointPosition")->GetValue (); + std::cout << "?" << std::endl; // too hard to represent an abstract/probabilistic model graphically + } + else + { + NS_FATAL_ERROR ("mobility type " << mobType.GetName () << " not supported"); + } + + std::cerr << g_sampleInterval << std::endl; + return 0; +} diff --git a/utils/mobility-visualizer-view.cc b/utils/mobility-visualizer-view.cc new file mode 100644 index 000000000..c1370856b --- /dev/null +++ b/utils/mobility-visualizer-view.cc @@ -0,0 +1,218 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ + +#include + +#include +#include + +#include "mobility-visualizer.h" +#include +#include "ns3/simulator.h" + +#define MAX_QUEUE_LENGTH 100 +#define MAX_EVENTS 20 +#define LOOKAHEAD_SECONDS 10 + +GtkWidget *g_canvas; + +int model_init (int argc, char *argv[]); + +struct Node +{ + GooCanvasItem *m_item; + GooCanvasItem *m_vector; + void create () + { + GooCanvasItem *root = goo_canvas_get_root_item (GOO_CANVAS (g_canvas)); + m_item = goo_canvas_ellipse_new (root, 0, 0, 2.0, 2.0, + "line_width", 0.5, + "stroke_color", "black", + "fill_color", "red", + NULL); + + m_vector = goo_canvas_polyline_new (root, FALSE, 0, + "line_width", 0.3, + "stroke_color", "black", + "end-arrow", TRUE, + "arrow-length", 10.0, + "arrow-width", 10.0, + NULL); + + } + + + void update (double x, double y, double vx, double vy) + { + g_object_set (m_item, "center_x", x, "center_y", y, NULL); + + if (vx == 0 && vy == 0) + { + GooCanvasPoints *points = goo_canvas_points_new (0); + g_object_set (m_vector, "points", points, NULL); + goo_canvas_points_unref (points); + } + else + { + GooCanvasPoints *points = goo_canvas_points_new (2); + + points->coords[0] = x; + points->coords[1] = y; + points->coords[2] = x + vx; + points->coords[3] = y + vy; + + g_object_set (m_vector, "points", points, NULL); + goo_canvas_points_unref (points); + } + } +}; + +std::map g_nodes; + +GTimeVal initialTime = {-1, -1}; +gboolean firstTime = TRUE; +double g_lookaheadTime = 0; +GStaticMutex g_lookaheadTimeMux = G_STATIC_MUTEX_INIT; +ViewUpdateData *g_nextData = NULL; + + +GAsyncQueue *queue; + +#define TIME_SCALE 1 + +double get_current_time () +{ + GTimeVal currTime; + g_get_current_time (&currTime); + GTimeVal relativeTime; + relativeTime.tv_sec = currTime.tv_sec - initialTime.tv_sec + LOOKAHEAD_SECONDS; + relativeTime.tv_usec = currTime.tv_usec; + g_time_val_add (&relativeTime, -initialTime.tv_usec); + return (relativeTime.tv_sec + 1.0e-6*relativeTime.tv_usec)*TIME_SCALE; +} + +// called from the simulation thread +void view_update (ViewUpdateData *updateData) +{ + while ((g_static_mutex_lock (&g_lookaheadTimeMux), g_lookaheadTime) != 0 and updateData->time >= g_lookaheadTime) + { + g_static_mutex_unlock (&g_lookaheadTimeMux); + g_usleep ((gulong) 10e3); + } + g_static_mutex_unlock (&g_lookaheadTimeMux); + g_async_queue_push (queue, updateData); +} + +void view_update_process (ViewUpdateData *updateData) +{ + for (std::vector::const_iterator update + = updateData->updateList.begin (); + update != updateData->updateList.end (); + update++) + { + if (g_nodes.find (update->node) == g_nodes.end ()) + { + g_nodes[update->node].create (); + } + g_nodes[update->node].update (update->x, update->y, update->vx, update->vy); + } + delete updateData; +} + +gboolean view_update_consumer () +{ + if (firstTime) + { + firstTime = FALSE; + g_get_current_time (&initialTime); + } + + double now = get_current_time (); + g_static_mutex_lock (&g_lookaheadTimeMux); + g_lookaheadTime = now + LOOKAHEAD_SECONDS; + g_static_mutex_unlock (&g_lookaheadTimeMux); + + if (!g_nextData) + g_nextData = (ViewUpdateData *) g_async_queue_try_pop (queue); + + if (!g_nextData) + return TRUE; + + if (g_nextData->time > now) + return TRUE; + + do + { + view_update_process (g_nextData); + g_nextData = (ViewUpdateData *) g_async_queue_try_pop (queue); + } + while (g_nextData && g_nextData->time <= now); + + return TRUE; +} + +void zoom_changed (GtkAdjustment *adj) +{ + goo_canvas_set_scale (GOO_CANVAS (g_canvas), gtk_adjustment_get_value (adj)); +} + +int main (int argc, char *argv[]) +{ + g_thread_init (NULL); + gtk_init (&argc, &argv); + double x1 = 0, y1 = 0, x2 = 0, y2 = 0; + + model_init (argc, argv, &x1, &y1, &x2, &y2); + + GtkWidget *window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_default_size (GTK_WINDOW (window), 640, 600); + gtk_widget_show (window); + g_signal_connect (window, "destroy", G_CALLBACK (gtk_main_quit), NULL); + + GtkWidget *scrolled_win = gtk_scrolled_window_new (NULL, NULL); + gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_win), GTK_SHADOW_IN); + gtk_widget_show (scrolled_win); + + GtkWidget *vbox = gtk_vbox_new (FALSE, 4); + gtk_widget_show (vbox); + gtk_box_pack_start (GTK_BOX (vbox), scrolled_win, 1, 1, 4); + gtk_container_add (GTK_CONTAINER (window), vbox); + + GtkWidget *hbox = gtk_hbox_new (FALSE, 4); + gtk_widget_show (hbox); + gtk_box_pack_start (GTK_BOX (vbox), hbox, false, false, 4); + + GtkObject *zoom = gtk_adjustment_new (3.0, 0.1, 10.0, 0.2, 1.0, 1.0); + gtk_box_pack_start(GTK_BOX (hbox), + GTK_WIDGET (g_object_new (GTK_TYPE_SPIN_BUTTON, "adjustment", zoom, + "visible", true, "digits", 2, NULL)), + false, false, 4); + + g_canvas = goo_canvas_new (); + gtk_widget_set_size_request (GTK_WIDGET (g_canvas), 600, 450); + goo_canvas_set_bounds (GOO_CANVAS (g_canvas), -500, -500, 500, 500); + g_signal_connect (zoom, "value-changed", G_CALLBACK (zoom_changed), NULL); + gtk_adjustment_value_changed (GTK_ADJUSTMENT (zoom)); + gtk_widget_show (g_canvas); + gtk_container_add (GTK_CONTAINER (scrolled_win), g_canvas); + + goo_canvas_scroll_to (GOO_CANVAS (g_canvas), 0, 0); + + // create the bounds rectangle + if (x1 != x2) + { + GooCanvasItem *item = + goo_canvas_rect_new (goo_canvas_get_root_item (GOO_CANVAS (g_canvas)), + x1, y1, x2-x1, y2-y1, NULL); + g_object_set (item, "line-width", 1.0, "stroke-color", "grey", NULL); + } + + queue = g_async_queue_new (); + + g_timeout_add ((guint) (SAMPLE_INTERVAL*1000), (GSourceFunc) view_update_consumer, NULL); + + g_thread_create (GThreadFunc (ns3::Simulator::Run), NULL, FALSE, NULL); + + gtk_main (); + + return 0; +} diff --git a/utils/mobility-visualizer.h b/utils/mobility-visualizer.h new file mode 100644 index 000000000..634847c3c --- /dev/null +++ b/utils/mobility-visualizer.h @@ -0,0 +1,23 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +#include + +int model_init (int argc, char *argv[], double *x1, double *y1, double *x2, double *y2); + +struct NodeUpdate +{ + void *node; + double x; + double y; + double vx; + double vy; +}; + +struct ViewUpdateData +{ + std::vector updateList; + double time; +}; + +void view_update (ViewUpdateData *updateData); + +#define SAMPLE_INTERVAL (1.0/30) diff --git a/utils/wscript b/utils/wscript index 15fbfa512..390508478 100644 --- a/utils/wscript +++ b/utils/wscript @@ -1,5 +1,13 @@ ## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*- +import os.path +def configure(conf): + check = conf.create_pkgconfig_configurator() + check.name = 'goocanvas gthread-2.0' + check.uselib = 'MOBILITY_VISUALIZER' + check.mandatory = False + conf.env['ENABLE_MOBILITY_VISUALIZER'] = check.run() + def build(bld): env = bld.env_of_name('default') @@ -23,3 +31,12 @@ def build(bld): obj = bld.create_ns3_program('print-trace-sources', ['internet-node', 'csma-cd', 'point-to-point']) obj.source = 'print-trace-sources.cc' + + if env['ENABLE_MOBILITY_VISUALIZER']: + obj = bld.create_ns3_program('mobility-visualizer', + ['internet-node', 'mobility']) + obj.source = ['mobility-visualizer-model.cc', 'mobility-visualizer-view.cc'] + obj.uselib = 'MOBILITY_VISUALIZER' + if os.path.basename(obj.env['CXX']).startswith("g++"): + obj.env.append_value('CXXFLAGS', '-fno-strict-aliasing') + diff --git a/wscript b/wscript index 77562417d..430675d1f 100644 --- a/wscript +++ b/wscript @@ -143,6 +143,7 @@ def configure(conf): variant_env.append_value("LINKFLAGS", "-Wl,--enable-runtime-pseudo-reloc") conf.sub_config('src') + conf.sub_config('utils') def create_ns3_program(bld, name, dependencies=('simulator',)):