/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ /* * 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 * * Authors: Joe Kopena * * This program conducts a simple experiment: It places two nodes at a * parameterized distance apart. One node generates packets and the * other node receives. The stat framework collects data on packet * loss. Outside of this program, a control script uses that data to * produce graphs presenting performance at the varying distances. * This isn't a typical simulation but is a common "experiment" * performed in real life and serves as an accessible exemplar for the * stat framework. It also gives some intuition on the behavior and * basic reasonability of the NS-3 WiFi models. * * Applications used by this program are in test02-apps.h and * test02-apps.cc, which should be in the same place as this file. * */ #include #include #include "ns3/core-module.h" #include "ns3/network-module.h" #include "ns3/mobility-module.h" #include "ns3/internet-module.h" #include "ns3/stats-module.h" #include "ns3/yans-wifi-helper.h" #include "wifi-example-apps.h" using namespace ns3; using namespace std; NS_LOG_COMPONENT_DEFINE ("WiFiDistanceExperiment"); void TxCallback (Ptr > datac, std::string path, Ptr packet) { NS_LOG_INFO ("Sent frame counted in " << datac->GetKey ()); datac->Update (); // end TxCallback } //---------------------------------------------------------------------- //-- main //---------------------------------------------- int main (int argc, char *argv[]) { double distance = 50.0; string format ("omnet"); string experiment ("wifi-distance-test"); string strategy ("wifi-default"); string input; string runID; { stringstream sstr; sstr << "run-" << time (NULL); runID = sstr.str (); } // Set up command line parameters used to control the experiment. CommandLine cmd (__FILE__); cmd.AddValue ("distance", "Distance apart to place nodes (in meters).", distance); cmd.AddValue ("format", "Format to use for data output.", format); cmd.AddValue ("experiment", "Identifier for experiment.", experiment); cmd.AddValue ("strategy", "Identifier for strategy.", strategy); cmd.AddValue ("run", "Identifier for run.", runID); cmd.Parse (argc, argv); if (format != "omnet" && format != "db") { NS_LOG_ERROR ("Unknown output format '" << format << "'"); return -1; } #ifndef STATS_HAS_SQLITE3 if (format == "db") { NS_LOG_ERROR ("sqlite support not compiled in."); return -1; } #endif { stringstream sstr (""); sstr << distance; input = sstr.str (); } //------------------------------------------------------------ //-- Create nodes and network stacks //-------------------------------------------- NS_LOG_INFO ("Creating nodes."); NodeContainer nodes; nodes.Create (2); NS_LOG_INFO ("Installing WiFi and Internet stack."); WifiHelper wifi; WifiMacHelper wifiMac; wifiMac.SetType ("ns3::AdhocWifiMac"); YansWifiPhyHelper wifiPhy = YansWifiPhyHelper::Default (); YansWifiChannelHelper wifiChannel = YansWifiChannelHelper::Default (); wifiPhy.SetChannel (wifiChannel.Create ()); NetDeviceContainer nodeDevices = wifi.Install (wifiPhy, wifiMac, nodes); InternetStackHelper internet; internet.Install (nodes); Ipv4AddressHelper ipAddrs; ipAddrs.SetBase ("192.168.0.0", "255.255.255.0"); ipAddrs.Assign (nodeDevices); //------------------------------------------------------------ //-- Setup physical layout //-------------------------------------------- NS_LOG_INFO ("Installing static mobility; distance " << distance << " ."); MobilityHelper mobility; Ptr positionAlloc = CreateObject(); positionAlloc->Add (Vector (0.0, 0.0, 0.0)); positionAlloc->Add (Vector (0.0, distance, 0.0)); mobility.SetPositionAllocator (positionAlloc); mobility.Install (nodes); //------------------------------------------------------------ //-- Create a custom traffic source and sink //-------------------------------------------- NS_LOG_INFO ("Create traffic source & sink."); Ptr appSource = NodeList::GetNode (0); Ptr sender = CreateObject(); appSource->AddApplication (sender); sender->SetStartTime (Seconds (1)); Ptr appSink = NodeList::GetNode (1); Ptr receiver = CreateObject(); appSink->AddApplication (receiver); receiver->SetStartTime (Seconds (0)); Config::Set ("/NodeList/*/ApplicationList/*/$Sender/Destination", Ipv4AddressValue ("192.168.0.2")); //------------------------------------------------------------ //-- Setup stats and data collection //-------------------------------------------- // Create a DataCollector object to hold information about this run. DataCollector data; data.DescribeRun (experiment, strategy, input, runID); // Add any information we wish to record about this run. data.AddMetadata ("author", "tjkopena"); // Create a counter to track how many frames are generated. Updates // are triggered by the trace signal generated by the WiFi MAC model // object. Here we connect the counter to the signal via the simple // TxCallback() glue function defined above. Ptr > totalTx = CreateObject >(); totalTx->SetKey ("wifi-tx-frames"); totalTx->SetContext ("node[0]"); Config::Connect ("/NodeList/0/DeviceList/*/$ns3::WifiNetDevice/Mac/MacTx", MakeBoundCallback (&TxCallback, totalTx)); data.AddDataCalculator (totalTx); // This is similar, but creates a counter to track how many frames // are received. Instead of our own glue function, this uses a // method of an adapter class to connect a counter directly to the // trace signal generated by the WiFi MAC. Ptr totalRx = CreateObject(); totalRx->SetKey ("wifi-rx-frames"); totalRx->SetContext ("node[1]"); Config::Connect ("/NodeList/1/DeviceList/*/$ns3::WifiNetDevice/Mac/MacRx", MakeCallback (&PacketCounterCalculator::PacketUpdate, totalRx)); data.AddDataCalculator (totalRx); // This counter tracks how many packets---as opposed to frames---are // generated. This is connected directly to a trace signal provided // by our Sender class. Ptr appTx = CreateObject(); appTx->SetKey ("sender-tx-packets"); appTx->SetContext ("node[0]"); Config::Connect ("/NodeList/0/ApplicationList/*/$Sender/Tx", MakeCallback (&PacketCounterCalculator::PacketUpdate, appTx)); data.AddDataCalculator (appTx); // Here a counter for received packets is directly manipulated by // one of the custom objects in our simulation, the Receiver // Application. The Receiver object is given a pointer to the // counter and calls its Update() method whenever a packet arrives. Ptr > appRx = CreateObject >(); appRx->SetKey ("receiver-rx-packets"); appRx->SetContext ("node[1]"); receiver->SetCounter (appRx); data.AddDataCalculator (appRx); /** * Just to show this is here... Ptr > test = CreateObject >(); test->SetKey("test-dc"); data.AddDataCalculator(test); test->Update(4); test->Update(8); test->Update(24); test->Update(12); **/ // This DataCalculator connects directly to the transmit trace // provided by our Sender Application. It records some basic // statistics about the sizes of the packets received (min, max, // avg, total # bytes), although in this scenaro they're fixed. Ptr appTxPkts = CreateObject(); appTxPkts->SetKey ("tx-pkt-size"); appTxPkts->SetContext ("node[0]"); Config::Connect ("/NodeList/0/ApplicationList/*/$Sender/Tx", MakeCallback (&PacketSizeMinMaxAvgTotalCalculator::PacketUpdate, appTxPkts)); data.AddDataCalculator (appTxPkts); // Here we directly manipulate another DataCollector tracking min, // max, total, and average propagation delays. Check out the Sender // and Receiver classes to see how packets are tagged with // timestamps to do this. Ptr delayStat = CreateObject(); delayStat->SetKey ("delay"); delayStat->SetContext ("."); receiver->SetDelayTracker (delayStat); data.AddDataCalculator (delayStat); //------------------------------------------------------------ //-- Run the simulation //-------------------------------------------- NS_LOG_INFO ("Run Simulation."); Simulator::Run (); //------------------------------------------------------------ //-- Generate statistics output. //-------------------------------------------- // Pick an output writer based in the requested format. Ptr output = 0; if (format == "omnet") { NS_LOG_INFO ("Creating omnet formatted data output."); output = CreateObject(); } else if (format == "db") { #ifdef STATS_HAS_SQLITE3 NS_LOG_INFO ("Creating sqlite formatted data output."); output = CreateObject(); #endif } else { NS_LOG_ERROR ("Unknown output format " << format); } // Finally, have that writer interrogate the DataCollector and save // the results. if (output != 0) output->Output (data); // Free any memory here at the end of this example. Simulator::Destroy (); // end main }