├── .gitignore ├── CheatSheet └── ns3_cheatbook.pdf ├── IntroPresentation └── ns3_intro_slides.pdf ├── README.md ├── WScriptMaker ├── MakeWScript.py └── README.md ├── examples ├── AggregateExample │ ├── aggregate-test.cc │ ├── user-class.cc │ └── user-class.h ├── CustomApplicationExample │ ├── custom-application.cc │ ├── custom-application.h │ ├── custom-data-tag.cc │ ├── custom-data-tag.h │ ├── wave-project.cc │ ├── wave-setup.cc │ └── wave-setup.h ├── MobilityExample │ ├── custom-mobility-model.cc │ ├── custom-mobility-model.h │ └── mobility-test.cc ├── README.md ├── SUMOTraceExample │ ├── custom-application.cc │ ├── custom-application.h │ ├── custom-data-tag.cc │ ├── custom-data-tag.h │ ├── main-program.cc │ ├── ns2-node-utility.cc │ ├── ns2-node-utility.h │ ├── ns2mobility.tcl │ ├── wave-setup.cc │ └── wave-setup.h ├── SimpleUdpAppExample │ ├── simple-udp-application.cc │ ├── simple-udp-application.h │ └── udp-socket-example.cc ├── ThreeRouters │ └── three-routers-example.cc ├── TutorialLesson │ └── tutorial-lesson.cc └── WaveTest │ └── wave-test.cc └── ns3helpers ├── MyColor.py ├── README.md ├── __pycache__ ├── MyColor.cpython-37.pyc └── sort_dir.cpython-37.pyc ├── debug_ns3.py ├── gdb_ns3.py ├── llvm_ns3.py ├── ns3_most_recent.py ├── run_ns3.py ├── sort_dir.py └── vis_ns3.py /.gitignore: -------------------------------------------------------------------------------- 1 | .trash/ 2 | -------------------------------------------------------------------------------- /CheatSheet/ns3_cheatbook.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/addola/NS3-HelperScripts/903809295f93987eb284dc9c762a82ecff012aba/CheatSheet/ns3_cheatbook.pdf -------------------------------------------------------------------------------- /IntroPresentation/ns3_intro_slides.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/addola/NS3-HelperScripts/903809295f93987eb284dc9c762a82ecff012aba/IntroPresentation/ns3_intro_slides.pdf -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ns3 Shared Resource by Adil Alsuhaim 2 | This `git` repository contains `ns3` resources that I share publicly. The content is as follows: 3 | 4 | 1. **CheatSheet** A PDF document containing tips & tricks to use in `ns3` 5 | 2. **examples** `ns3` program examples. 6 | 3. **ns3helpers** Scripts written in `Python` that makes running & debugging `ns3` programs easier. 7 | 8 | ## CheatSheet 9 | I created a PDF document in `LaTeX` that contains tips & tricks on using `ns3`. I discuss many `ns3` topics including TraceSource, Attributes, creating modules and using packet tags. 10 | 11 | ## `ns3` Examples 12 | Under the `examples` directory we have `ns3` project directories that you can run by copying them to your `ns3`'s scratch directory. The examples were designed for `ns-3.30.1` 13 | 14 | ## NS3 Helper Scripts 15 | * You can find scripts I use to help me run my `ns3` simulations in the directory `ns3helpers` 16 | 17 | * There's a `README.md` under that directory with information on how to use the scripts. 18 | 19 | -------------------------------------------------------------------------------- /WScriptMaker/MakeWScript.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | ## @package wscript_builder 4 | # Builds a wscript python file from a $NS3_ROOT_DIR/contrib/name, where name is the name of the module specified 5 | # ./MakeWScript.py --name=user 6 | # 7 | # This will create wscript_name and wscript_name_examples 8 | # 9 | 10 | import os 11 | from os import walk 12 | import argparse 13 | import sys 14 | 15 | def PrintList(l): 16 | for item in l: 17 | print (item) 18 | 19 | def main(argv): 20 | 21 | parser = argparse.ArgumentParser(description='Makes wscript file for a given ns3 library. It requires that you define an environment variable $NS3_ROOT_DIR that points to the root ns3 directory.') 22 | parser.add_argument('--name', help="Name of ns3 module.", default='user') 23 | parser.add_argument('-v','--verbose', help="Verbatim output", action='store_true') 24 | parser.add_argument('-m', '--move', help='Move the created files over to overwrite the current wscript files',action='store_true') 25 | 26 | args = parser.parse_args() 27 | 28 | move_files = args.move 29 | 30 | 31 | 32 | log_details = args.verbose 33 | 34 | files = [] 35 | d = [] 36 | s = [] 37 | h = [] 38 | 39 | module_name = args.name 40 | 41 | ns3_root_dir = os.environ['NS3_ROOT_DIR'] 42 | ns3_source_path = ns3_root_dir+'/contrib/' 43 | 44 | module_path = ns3_source_path + module_name 45 | 46 | 47 | examples_source = [] 48 | #Read all Dirs 49 | is_example = True 50 | 51 | print("PATH : " + module_path) 52 | 53 | for (dirpath, dirnames, filenames) in walk(module_path): 54 | d.extend(dirnames) 55 | break 56 | #Process all subdirs 57 | for sub_dir in d: 58 | #Ignore certain directories such as .git, binding and docs 59 | if sub_dir == '.git' or sub_dir == 'trash' or sub_dir[0] == '.' or sub_dir == '.trash' or sub_dir == 'bindings' or sub_dir == 'doc': 60 | if log_details: 61 | print ("\tIgnored sub-dir: " + sub_dir) 62 | continue 63 | 64 | #if sub_dir == 'examples': 65 | 66 | #Get files for current sub_dir 67 | for (dirpath, dirnames, filenames) in walk(module_path + '/' + sub_dir): 68 | files.extend(filenames) 69 | break 70 | 71 | #Process all files 72 | for file_name in files: 73 | if log_details: 74 | print ("\tFile : " + sub_dir + '/' + file_name) 75 | #The 'examples' directory is treated diffrently, as we need to create its own wscript. 76 | if sub_dir == 'examples': 77 | if file_name.endswith('.cc'): 78 | examples_source.append(file_name) 79 | 80 | elif file_name.endswith('.h'): 81 | header_path = sub_dir + '/' + file_name 82 | h.append(header_path) 83 | elif file_name.endswith('.cc'): 84 | source_path = sub_dir + '/' + file_name 85 | s.append(source_path) 86 | else: 87 | pass 88 | #print file_name + " is neither header nor source!" 89 | 90 | files = [] #Reset the files 91 | 92 | dependency = ['core', 'network', 'wave', 'wifi', 'applications', 'internet', 'netanim'] 93 | 94 | if module_name != 'user': 95 | dependency.append ('user') 96 | 97 | #'buildings','spectrum', 'stats','wimax','point-to-point','csma' 98 | 99 | #file for wscript 100 | f = open('wscript_' + module_name, 'w') 101 | #file for examples if any 102 | fe = open('wscript_' + module_name + '_examples', 'w') 103 | 104 | 105 | if (log_details): 106 | print ("Created file : " + 'wscript_' + module_name) 107 | print ("Created file : " + 'wscript_' + module_name + '_examples') 108 | 109 | 110 | ######### Writing to the module's wscript ########### 111 | f.write("## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-\n") 112 | f.write("## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-\n") 113 | f.write("\n") 114 | f.write("def build(bld):\n") 115 | 116 | list_of_deps = '\tmodule_dependencies = ' + str(dependency) + '\n' 117 | #f.write("\tmodule_dependencies = ['wave', 'netanim']\n") 118 | f.write (list_of_deps) 119 | #'buildings', 'virtual-net-device','point-to-point' ,'spectrum','csma','core', 'network', 'netanim', 'stats','wifi', 'lte','applications','internet' 120 | f.write("\tmodule = bld.create_ns3_module('"+ module_name + "', module_dependencies)\n") 121 | 122 | ### Source files 123 | 124 | print ("# of Source files (.cc) : " + str(len(s)) + "\n# of Header files (.h) : " + str(len(h)) ) 125 | 126 | sanity_counter = 0 127 | f.write("\n#Source files\n\n") 128 | f.write("\tmodule.source = [\n") 129 | for i in range(len(s)): 130 | sanity_counter = sanity_counter + 1 131 | if(i == len(s)-1): #if last element... 132 | f.write("\t\t'" + s[i] + "'\n") 133 | else: 134 | f.write("\t\t'" + s[i] + "',\n") 135 | f.write("\t\t]\n") 136 | 137 | ### Header files 138 | f.write("\n#Header files\n\n") 139 | 140 | f.write("\theaders = bld(features='ns3header')\n") 141 | f.write("\theaders.module = '"+module_name+"'\n") 142 | f.write("\theaders.source = [\n") 143 | for i in range(len(h)): 144 | if(i == len(h)-1): #if last element... 145 | f.write("\t\t'" + h[i] + "'\n") 146 | else: 147 | f.write("\t\t'" + h[i] + "',\n") 148 | f.write("\t\t]\n") 149 | 150 | f.write("\n\n\tif (bld.env['ENABLE_EXAMPLES']):\n") 151 | f.write("\t\tbld.recurse('examples')\n") 152 | f.write("\n\t#bld.ns3_python_bindings()") 153 | f.close() 154 | 155 | ########### create wscript for Examples ########### 156 | 157 | fe.write("# -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-\n") 158 | fe.write('def build(bld):\n') 159 | 160 | for ex in examples_source: 161 | fe.write('\t') 162 | fe.write("obj = bld.create_ns3_program('" + ex[0:len(ex)-3] +"',\n") 163 | fe.write("\t\t['core', 'wave', 'applications', 'mobility', 'network', 'wifi',"+ "'" + module_name + "'])") 164 | fe.write('\n') 165 | fe.write("\tobj.source = '" + ex + "'\n\n") 166 | if len (examples_source) == 0: 167 | fe.write("\tpass") 168 | 169 | if move_files: #if user chose to move & overwrite the wscript files 170 | wscript_module = f.name 171 | wscript_example = fe.name 172 | #Actually move the generated wscript files to the proper directories. 173 | os.system ('mv ' + wscript_module + ' ' + module_path + '/wscript') 174 | os.system ('mv ' + wscript_example + ' ' + module_path + '/examples/wscript') 175 | 176 | 177 | if __name__ == "__main__": 178 | main(sys.argv[1:]) -------------------------------------------------------------------------------- /WScriptMaker/README.md: -------------------------------------------------------------------------------- 1 | Disclaimer 2 | ========== 3 | This code is provided as-is, with no guarantee. Try to understand the `python` code, and read these instructions carefully. 4 | 5 | Prerequisite 6 | ============ 7 | 1. Create an environment variable named `$NS3_ROOT_DIR` in your Linux operating system. The environment variable should point to your `ns-3` root directory. 8 | For example, on my computer, I created the environment variable as follows: 9 | ``` 10 | export NS3_ROOT_DIR="/home/adil/eclipse-workspace/ns-3.30.1-eclipse/ns-3.30.1" 11 | ``` 12 | 2. Your user-created modules should be created in a directory under `$NS3_ROOT_DIR/contrib` 13 | 14 | 15 | How it works 16 | ============ 17 | 1. Create a module as a folder under `$NS3_ROOT_DIR/contrib`, let's call it `user`. Do not place C++ header and code files directly under `user` directory, put them in subfolders. For example, create folders named `model`, `helper` and `examples`. This scripts scans those subfolder and generate a `wscript` file written in `python`. 18 | * If you have a folder named `examples`, it will treated differently. 19 | 20 | 2. Run this script with `--name=user` to scan the `$NS3_ROOT_DIR/contrib/user` folder. This will create two files named `wscript_user` and `wscript_user_examples`. 21 | ``` 22 | ./MakeWscript.py --name=user 23 | ``` 24 | 25 | 3. Copy the generated `wscript_user` to `$NS3_ROOT_DIR/contrib/user/wscript` and the `wscript_examples` to `$NS3_ROOT_DIR/contrib/user/wscript`. 26 | 27 | * Supplying the `--m` argument make it automatically copy the `wscript` files to their destination 28 | 29 | 4. You can modify the resulting `wscript` files by modifying the modules they depend on, or to comment out whether you want to build examples. 30 | 31 | 32 | Usage in your code 33 | =================== 34 | 1. In your `ns-3` you need to run `./waf --configure` to scan for changes under `contrib` directory. 35 | * This will create a `.h` file named `modulename-module.h`. For example, if our module is named `user`, it will create a file named `user-module.h` that includes all the header files in your module. 36 | 37 | 2. To include your modules from your `ns-3` simulations, simply perform an include of the `user-module.h` file 38 | ``` 39 | #include "ns3/user-module.h" 40 | ``` 41 | 42 | 43 | Questions 44 | ========= 45 | For any questions you can contact me `aalsuha@clemson.edu` or `adil.alsuhaim@gmail.com` -------------------------------------------------------------------------------- /examples/AggregateExample/aggregate-test.cc: -------------------------------------------------------------------------------- 1 | #include "ns3/core-module.h" 2 | #include "ns3/network-module.h" 3 | #include "user-class.h" 4 | 5 | using namespace ns3; 6 | 7 | class DummyClass : public ns3::Object 8 | { 9 | public: 10 | static TypeId GetTypeId(); 11 | DummyClass(); 12 | virtual ~DummyClass (); 13 | }; 14 | 15 | TypeId DummyClass::GetTypeId () 16 | { 17 | static TypeId tid = TypeId("ns3::DummyClass") 18 | .SetParent () 19 | .AddConstructor(); 20 | return tid; 21 | } 22 | 23 | DummyClass::DummyClass () 24 | { 25 | 26 | } 27 | DummyClass::~DummyClass () 28 | { 29 | 30 | } 31 | 32 | void Fun () 33 | { 34 | Ptr nnn = NodeList::GetNode (0); 35 | Ptr uuu = nnn->GetObject (); 36 | std::cout << Now() << "\tIn Fun(): " << uuu->GetValue() << std::endl; 37 | } 38 | 39 | int main (int argc, char* argv[]) 40 | { 41 | CommandLine cmd; 42 | cmd.Parse (argc, argv); 43 | 44 | NodeContainer nodes; 45 | nodes.Create (2); 46 | 47 | Ptr user = CreateObject (); 48 | user->SetValue (12); 49 | 50 | Ptr n0 = nodes.Get(0); 51 | n0->AggregateObject (user); 52 | 53 | Ptr new_copy = ns3::CopyObject (n0); 54 | std::cout << "Org Node:\t" << n0 << "\nCpy Node:\t" << new_copy << std::endl; 55 | 56 | //The copy doesn't have the aggregate 57 | Ptr obj = new_copy->GetObject (); 58 | //NULL 59 | std::cout << obj << std::endl; 60 | 61 | //We can only get the aggregated object from the original 62 | obj = n0->GetObject (); 63 | std::cout << obj << "\t" << obj->GetValue() << " user=" << user << std::endl; 64 | 65 | //We can also go the other way around 66 | Ptr ptr_to_original = user->GetObject (); 67 | std::cout << "Org Node:\t" << n0 << "\nPtr. Orig:\t" << ptr_to_original << std::endl; 68 | 69 | Ptr test2 = CreateObject (); 70 | n0->AggregateObject (test2); 71 | 72 | Ptr test2_ptr = test2->GetObject (); 73 | std::cout << "Test 2 Ptr:\t" << test2_ptr << std::endl; 74 | 75 | Ptr packet = Create (100); 76 | std::cout << "Packet Size:" << packet->GetSize() << std::endl; 77 | 78 | Simulator::Schedule (Seconds (5), &Fun); 79 | 80 | 81 | Simulator::Stop (Seconds (60)); 82 | Simulator::Run(); 83 | Simulator::Destroy (); 84 | 85 | 86 | } -------------------------------------------------------------------------------- /examples/AggregateExample/user-class.cc: -------------------------------------------------------------------------------- 1 | #include "user-class.h" 2 | 3 | namespace ns3 4 | { 5 | 6 | UserClass::UserClass() {} 7 | 8 | UserClass::~UserClass () {} 9 | 10 | TypeId UserClass::GetTypeId () 11 | { 12 | static TypeId tid = TypeId("ns3::UserClass") 13 | .SetParent () 14 | .AddConstructor () 15 | ; 16 | return tid; 17 | } 18 | 19 | double UserClass::GetValue() 20 | { 21 | return m_value; 22 | } 23 | 24 | void UserClass::SetValue (double val) 25 | { 26 | m_value = val; 27 | } 28 | 29 | 30 | } -------------------------------------------------------------------------------- /examples/AggregateExample/user-class.h: -------------------------------------------------------------------------------- 1 | #ifndef NS3_SCRATCH_AGGREGATE_EXAMPLE_USER_CLASS_H 2 | #define NS3_SCRATCH_AGGREGATE_EXAMPLE_USER_CLASS_H 3 | 4 | #include "ns3/object.h" 5 | #include "ns3/nstime.h" 6 | 7 | namespace ns3 8 | { 9 | class UserClass : public ns3::Object 10 | { 11 | public: 12 | static TypeId GetTypeId(); 13 | UserClass(); 14 | virtual ~UserClass(); 15 | 16 | void SetValue (double val); 17 | double GetValue (); 18 | 19 | private: 20 | double m_value; 21 | }; 22 | } 23 | 24 | #endif -------------------------------------------------------------------------------- /examples/CustomApplicationExample/custom-application.cc: -------------------------------------------------------------------------------- 1 | #include "ns3/mobility-model.h" 2 | #include "ns3/log.h" 3 | #include "ns3/simulator.h" 4 | #include "custom-application.h" 5 | #include "custom-data-tag.h" 6 | #include "ns3/random-variable-stream.h" 7 | 8 | #define RED_CODE "\033[91m" 9 | #define GREEN_CODE "\033[32m" 10 | #define END_CODE "\033[0m" 11 | 12 | 13 | namespace ns3 14 | { 15 | NS_LOG_COMPONENT_DEFINE("CustomApplication"); 16 | NS_OBJECT_ENSURE_REGISTERED(CustomApplication); 17 | 18 | TypeId CustomApplication::GetTypeId() 19 | { 20 | static TypeId tid = TypeId("ns3::CustomApplication") 21 | .SetParent () 22 | .AddConstructor () 23 | .AddAttribute ("Interval", "Broadcast Interval", 24 | TimeValue (MilliSeconds(100)), 25 | MakeTimeAccessor (&CustomApplication::m_broadcast_time), 26 | MakeTimeChecker() 27 | ) 28 | ; 29 | return tid; 30 | } 31 | 32 | TypeId CustomApplication::GetInstanceTypeId() const 33 | { 34 | return CustomApplication::GetTypeId(); 35 | } 36 | 37 | CustomApplication::CustomApplication() 38 | { 39 | m_broadcast_time = MilliSeconds (100); //every 100ms 40 | m_packetSize = 1000; //1000 bytes 41 | m_time_limit = Seconds (5); 42 | m_mode = WifiMode("OfdmRate6MbpsBW10MHz"); 43 | } 44 | CustomApplication::~CustomApplication() 45 | { 46 | 47 | } 48 | void 49 | CustomApplication::StartApplication() 50 | { 51 | NS_LOG_FUNCTION (this); 52 | //Set A Receive callback 53 | Ptr n = GetNode (); 54 | for (uint32_t i = 0; i < n->GetNDevices (); i++) 55 | { 56 | Ptr dev = n->GetDevice (i); 57 | if (dev->GetInstanceTypeId () == WaveNetDevice::GetTypeId()) 58 | { 59 | m_waveDevice = DynamicCast (dev); 60 | //ReceivePacket will be called when a packet is received 61 | dev->SetReceiveCallback (MakeCallback (&CustomApplication::ReceivePacket, this)); 62 | 63 | /* 64 | If you want promiscous receive callback, connect to this trace. 65 | For every packet received, both functions ReceivePacket & PromiscRx will be called. with PromicRx being called first! 66 | */ 67 | Ptr phy = m_waveDevice->GetPhys()[0]; //default, there's only one PHY in a WaveNetDevice 68 | phy->TraceConnectWithoutContext ("MonitorSnifferRx", MakeCallback(&CustomApplication::PromiscRx, this)); 69 | break; 70 | } 71 | } 72 | if (m_waveDevice) 73 | { 74 | //Let's create a bit of randomness with the first broadcast packet time to avoid collision 75 | Ptr rand = CreateObject (); 76 | Time random_offset = MicroSeconds (rand->GetValue(50,200)); 77 | 78 | Simulator::Schedule (m_broadcast_time+random_offset, &CustomApplication::BroadcastInformation, this); 79 | } 80 | else 81 | { 82 | NS_FATAL_ERROR ("There's no WaveNetDevice in your node"); 83 | } 84 | //We will periodically (every 1 second) check the list of neighbors, and remove old ones (older than 5 seconds) 85 | Simulator::Schedule (Seconds (1), &CustomApplication::RemoveOldNeighbors, this); 86 | 87 | } 88 | void 89 | CustomApplication::SetBroadcastInterval (Time interval) 90 | { 91 | NS_LOG_FUNCTION (this << interval); 92 | m_broadcast_time = interval; 93 | } 94 | void 95 | CustomApplication::SetWifiMode (WifiMode mode) 96 | { 97 | m_mode = mode; 98 | } 99 | 100 | void 101 | CustomApplication::BroadcastInformation() 102 | { 103 | NS_LOG_FUNCTION (this); 104 | //Setup transmission parameters 105 | TxInfo tx; 106 | tx.channelNumber = CCH; 107 | tx.preamble = WIFI_PREAMBLE_LONG; 108 | tx.priority = 7; //highest priority. 109 | tx.txPowerLevel = 7; 110 | tx.dataRate = m_mode; 111 | 112 | Ptr packet = Create (m_packetSize); 113 | 114 | //let's attach our custom data tag to it 115 | CustomDataTag tag; 116 | tag.SetNodeId ( GetNode()->GetId() ); 117 | tag.SetPosition ( GetNode()->GetObject()->GetPosition()); 118 | //timestamp is set in the default constructor of the CustomDataTag class as Simulator::Now() 119 | 120 | //attach the tag to the packet 121 | packet->AddPacketTag (tag); 122 | 123 | //Broadcast the packet as WSMP (0x88dc) 124 | m_waveDevice->SendX (packet, Mac48Address::GetBroadcast(), 0x88dc, tx); 125 | 126 | //Schedule next broadcast 127 | Simulator::Schedule (m_broadcast_time, &CustomApplication::BroadcastInformation, this); 128 | } 129 | 130 | bool 131 | CustomApplication::ReceivePacket (Ptr device, Ptr packet,uint16_t protocol, const Address &sender) 132 | { 133 | NS_LOG_FUNCTION (device << packet << protocol << sender); 134 | /* 135 | Packets received here only have Application data, no WifiMacHeader. 136 | We created packets with 1000 bytes payload, so we'll get 1000 bytes of payload. 137 | */ 138 | NS_LOG_INFO ("ReceivePacket() : Node " << GetNode()->GetId() << " : Received a packet from " << sender << " Size:" << packet->GetSize()); 139 | 140 | //Let's check if packet has a tag attached! 141 | CustomDataTag tag; 142 | if (packet->PeekPacketTag (tag)) 143 | { 144 | NS_LOG_INFO ("\tFrom Node Id: " << tag.GetNodeId() << " at " << tag.GetPosition() 145 | << "\tPacket Timestamp: " << tag.GetTimestamp() << " delay="<< Now()-tag.GetTimestamp()); 146 | } 147 | 148 | return true; 149 | } 150 | void 151 | CustomApplication::PromiscRx (Ptr packet, uint16_t channelFreq, WifiTxVector tx, MpduInfo mpdu, SignalNoiseDbm sn, uint16_t sta_id) 152 | { 153 | //This is a promiscous trace. It will pick broadcast packets, and packets not directed to this node's MAC address. 154 | /* 155 | Packets received here have MAC headers and payload. 156 | If packets are created with 1000 bytes payload, the size here is about 38 bytes larger. 157 | */ 158 | NS_LOG_DEBUG (Now () << " PromiscRx() : Node " << GetNode()->GetId() << " : ChannelFreq: " << channelFreq << " Mode: " << tx.GetMode() 159 | << " Signal: " << sn.signal << " Noise: " << sn.noise << " Size: " << packet->GetSize() 160 | << " Mode " << tx.GetMode () 161 | ); 162 | WifiMacHeader hdr; 163 | if (packet->PeekHeader (hdr)) 164 | { 165 | //Let's see if this packet is intended to this node 166 | Mac48Address destination = hdr.GetAddr1(); 167 | Mac48Address source = hdr.GetAddr2(); 168 | 169 | UpdateNeighbor (source); 170 | 171 | Mac48Address myMacAddress = m_waveDevice->GetMac(CCH)->GetAddress(); 172 | //A packet is intened to me if it targets my MAC address, or it's a broadcast message 173 | if ( destination==Mac48Address::GetBroadcast() || destination==myMacAddress) 174 | { 175 | NS_LOG_DEBUG ("\tFrom: " << source << "\n\tSeq. No. " << hdr.GetSequenceNumber() ); 176 | //Do something for this type of packets 177 | } 178 | else //Well, this packet is not intended for me 179 | { 180 | //Maybe record some information about neighbors 181 | } 182 | } 183 | } 184 | 185 | void CustomApplication::UpdateNeighbor (Mac48Address addr) 186 | { 187 | bool found = false; 188 | //Go over all neighbors, find one matching the address, and updates its 'last_beacon' time. 189 | for (std::vector::iterator it = m_neighbors.begin(); it != m_neighbors.end(); it++ ) 190 | { 191 | if (it->neighbor_mac == addr) 192 | { 193 | it->last_beacon = Now(); 194 | found = true; 195 | break; 196 | } 197 | } 198 | if (!found) //If no node with this address exist, add a new table entry 199 | { 200 | NS_LOG_INFO ( GREEN_CODE << Now() << " : Node " << GetNode()->GetId() << " is adding a neighbor with MAC="<GetId() << std::endl; 211 | for (std::vector::iterator it = m_neighbors.begin(); it != m_neighbors.end(); it++ ) 212 | { 213 | std::cout << "\tMAC: " << it->neighbor_mac << "\tLast Contact: " << it->last_beacon << std::endl; 214 | } 215 | } 216 | 217 | void CustomApplication::RemoveOldNeighbors () 218 | { 219 | //Go over the list of neighbors 220 | for (std::vector::iterator it = m_neighbors.begin(); it != m_neighbors.end(); it++ ) 221 | { 222 | //Get the time passed since the last time we heard from a node 223 | Time last_contact = Now () - it->last_beacon; 224 | 225 | if (last_contact >= Seconds (5)) //if it has been more than 5 seconds, we will remove it. You can change this to whatever value you want. 226 | { 227 | NS_LOG_INFO (RED_CODE << Now () << " Node " << GetNode()->GetId()<<" is removing old neighbor " << it->neighbor_mac < 7 | 8 | namespace ns3 9 | { 10 | /** \brief A struct to represent information about this node's neighbors. I chose MAC address and the time last message was received form that node 11 | * The time 'last_beacon' is used to determine whether we should remove the neighbor from the list. 12 | */ 13 | typedef struct 14 | { 15 | Mac48Address neighbor_mac; 16 | Time last_beacon; 17 | } NeighborInformation; 18 | 19 | class CustomApplication : public ns3::Application 20 | { 21 | public: 22 | 23 | static TypeId GetTypeId (void); 24 | virtual TypeId GetInstanceTypeId (void) const; 25 | 26 | CustomApplication(); 27 | ~CustomApplication(); 28 | 29 | /** \brief Broadcast some information 30 | */ 31 | void BroadcastInformation(); 32 | 33 | /** \brief This function is called when a net device receives a packet. 34 | * I connect to the callback in StartApplication. This matches the signiture of NetDevice receive. 35 | */ 36 | bool ReceivePacket (Ptr device,Ptr packet,uint16_t protocol, const Address &sender); 37 | 38 | void PromiscRx (Ptr packet, uint16_t channelFreq, WifiTxVector tx, MpduInfo mpdu, SignalNoiseDbm sn, uint16_t sta_id); 39 | 40 | void SetBroadcastInterval (Time interval); 41 | 42 | /** \brief Update a neighbor's last contact time, or add a new neighbor 43 | */ 44 | void UpdateNeighbor (Mac48Address addr); 45 | /** \brief Print a list of neighbors 46 | */ 47 | void PrintNeighbors (); 48 | 49 | /** \brief Change the data rate used for broadcasts. 50 | */ 51 | void SetWifiMode (WifiMode mode); 52 | 53 | /** \brief Remove neighbors you haven't heard from after some time. 54 | */ 55 | void RemoveOldNeighbors (); 56 | 57 | //You can create more functions like getters, setters, and others 58 | 59 | private: 60 | /** \brief This is an inherited function. Code that executes once the application starts 61 | */ 62 | void StartApplication(); 63 | Time m_broadcast_time; /**< How often do you broadcast messages */ 64 | uint32_t m_packetSize; /**< Packet size in bytes */ 65 | Ptr m_waveDevice; /**< A WaveNetDevice that is attached to this device */ 66 | 67 | std::vector m_neighbors; /**< A table representing neighbors of this node */ 68 | 69 | Time m_time_limit; /**< Time limit to keep neighbors in a list */ 70 | 71 | WifiMode m_mode; /**< data rate used for broadcasts */ 72 | //You can define more stuff to record statistics, etc. 73 | }; 74 | } 75 | 76 | #endif -------------------------------------------------------------------------------- /examples/CustomApplicationExample/custom-data-tag.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * cacc-data-tag.cc 3 | * 4 | * Created on: Oct 29, 2019 5 | * Author: adil 6 | */ 7 | #include "custom-data-tag.h" 8 | #include "ns3/log.h" 9 | #include "ns3/simulator.h" 10 | 11 | namespace ns3 { 12 | 13 | NS_LOG_COMPONENT_DEFINE("CustomDataTag"); 14 | NS_OBJECT_ENSURE_REGISTERED (CustomDataTag); 15 | 16 | CustomDataTag::CustomDataTag() { 17 | m_timestamp = Simulator::Now(); 18 | m_nodeId = -1; 19 | } 20 | CustomDataTag::CustomDataTag(uint32_t node_id) { 21 | m_timestamp = Simulator::Now(); 22 | m_nodeId = node_id; 23 | } 24 | 25 | CustomDataTag::~CustomDataTag() { 26 | } 27 | 28 | //Almost all custom tags will have similar implementation of GetTypeId and GetInstanceTypeId 29 | TypeId CustomDataTag::GetTypeId (void) 30 | { 31 | static TypeId tid = TypeId ("ns3::CustomDataTag") 32 | .SetParent () 33 | .AddConstructor (); 34 | return tid; 35 | } 36 | TypeId CustomDataTag::GetInstanceTypeId (void) const 37 | { 38 | return CustomDataTag::GetTypeId (); 39 | } 40 | 41 | /** The size required for the data contained within tag is: 42 | * size needed for a ns3::Vector for position + 43 | * size needed for a ns3::Time for timestamp + 44 | * size needed for a uint32_t for node id 45 | */ 46 | uint32_t CustomDataTag::GetSerializedSize (void) const 47 | { 48 | return sizeof(Vector) + sizeof (ns3::Time) + sizeof(uint32_t); 49 | } 50 | /** 51 | * The order of how you do Serialize() should match the order of Deserialize() 52 | */ 53 | void CustomDataTag::Serialize (TagBuffer i) const 54 | { 55 | //we store timestamp first 56 | i.WriteDouble(m_timestamp.GetDouble()); 57 | 58 | //then we store the position 59 | i.WriteDouble (m_currentPosition.x); 60 | i.WriteDouble (m_currentPosition.y); 61 | i.WriteDouble (m_currentPosition.z); 62 | 63 | //Then we store the node ID 64 | i.WriteU32(m_nodeId); 65 | } 66 | /** This function reads data from a buffer and store it in class's instance variables. 67 | */ 68 | void CustomDataTag::Deserialize (TagBuffer i) 69 | { 70 | //We extract what we stored first, so we extract the timestamp 71 | m_timestamp = Time::FromDouble (i.ReadDouble(), Time::NS);; 72 | 73 | //Then the position 74 | m_currentPosition.x = i.ReadDouble(); 75 | m_currentPosition.y = i.ReadDouble(); 76 | m_currentPosition.z = i.ReadDouble(); 77 | //Finally, we extract the node id 78 | m_nodeId = i.ReadU32(); 79 | 80 | } 81 | /** 82 | * This function can be used with ASCII traces if enabled. 83 | */ 84 | void CustomDataTag::Print (std::ostream &os) const 85 | { 86 | os << "Custom Data --- Node :" << m_nodeId << "\t(" << m_timestamp << ")" << " Pos (" << m_currentPosition << ")"; 87 | } 88 | 89 | //Your accessor and mutator functions 90 | uint32_t CustomDataTag::GetNodeId() { 91 | return m_nodeId; 92 | } 93 | 94 | void CustomDataTag::SetNodeId(uint32_t node_id) { 95 | m_nodeId = node_id; 96 | } 97 | Vector CustomDataTag::GetPosition(void) { 98 | return m_currentPosition; 99 | } 100 | 101 | Time CustomDataTag::GetTimestamp() { 102 | return m_timestamp; 103 | } 104 | 105 | void CustomDataTag::SetPosition(Vector pos) { 106 | m_currentPosition = pos; 107 | } 108 | 109 | void CustomDataTag::SetTimestamp(Time t) { 110 | m_timestamp = t; 111 | } 112 | 113 | } /* namespace ns3 */ 114 | 115 | 116 | -------------------------------------------------------------------------------- /examples/CustomApplicationExample/custom-data-tag.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This tag combines position, velocity, and acceleration in one tag. 3 | */ 4 | 5 | #ifndef CUSTOM_DATA_TAG_H 6 | #define CUSTOM_DATA_TAG_H 7 | 8 | #include "ns3/tag.h" 9 | #include "ns3/vector.h" 10 | #include "ns3/nstime.h" 11 | 12 | namespace ns3 13 | { 14 | /** We're creating a custom tag for simulation. A tag can be added to any packet, but you cannot add a tag of the same type twice. 15 | */ 16 | class CustomDataTag : public Tag { 17 | public: 18 | 19 | //Functions inherited from ns3::Tag that you have to implement. 20 | static TypeId GetTypeId(void); 21 | virtual TypeId GetInstanceTypeId(void) const; 22 | virtual uint32_t GetSerializedSize(void) const; 23 | virtual void Serialize (TagBuffer i) const; 24 | virtual void Deserialize (TagBuffer i); 25 | virtual void Print (std::ostream & os) const; 26 | 27 | //These are custom accessor & mutator functions 28 | Vector GetPosition(void); 29 | uint32_t GetNodeId(); 30 | Time GetTimestamp (); 31 | 32 | void SetPosition (Vector pos); 33 | void SetNodeId (uint32_t node_id); 34 | void SetTimestamp (Time t); 35 | 36 | 37 | 38 | CustomDataTag(); 39 | CustomDataTag(uint32_t node_id); 40 | virtual ~CustomDataTag(); 41 | private: 42 | 43 | uint32_t m_nodeId; 44 | /** Current position */ 45 | Vector m_currentPosition; 46 | /** Timestamp this tag was created */ 47 | Time m_timestamp; 48 | 49 | }; 50 | } 51 | 52 | #endif -------------------------------------------------------------------------------- /examples/CustomApplicationExample/wave-project.cc: -------------------------------------------------------------------------------- 1 | #include "ns3/wave-module.h" 2 | #include "ns3/wifi-module.h" 3 | #include "ns3/mobility-module.h" 4 | #include "ns3/core-module.h" 5 | #include "custom-application.h" 6 | #include "wave-setup.h" 7 | 8 | using namespace ns3; 9 | 10 | NS_LOG_COMPONENT_DEFINE ("CustomApplicationExample"); 11 | 12 | void SomeEvent () 13 | { 14 | for (uint32_t i=0 ; i n = NodeList::GetNode(i); 17 | Ptr c_app = DynamicCast (n->GetApplication(0)); 18 | c_app->SetWifiMode (WifiMode("OfdmRate3MbpsBW10MHz")); 19 | } 20 | std::cout << "******************" < cvmm = DynamicCast (nodes.Get(i)->GetObject()); 54 | cvmm->SetPosition ( Vector (20+i*5, 20+(i%2)*5, 0)); 55 | cvmm->SetVelocity ( Vector (10+((i+1)%2)*5,0,0) ); 56 | } 57 | 58 | WaveSetup wave; 59 | NetDeviceContainer devices = wave.ConfigureDevices(nodes); 60 | 61 | //Create Application in nodes 62 | 63 | //Method 1 64 | /* 65 | for (uint32_t i=0; i app_i = CreateObject(); 68 | app_i->SetBroadcastInterval (Seconds(interval)); 69 | app_i->SetStartTime (Seconds (0)); 70 | app_i->SetStopTime (Seconds (simTime)); 71 | nodes.Get(i)->AddApplication (app_i); 72 | } 73 | */ 74 | 75 | //Method 2 using ObjcetFactor. 76 | for (uint32_t i=0 ; i appI = fact.Create (); 82 | appI->SetStartTime(Seconds(0)); 83 | appI->SetStopTime (Seconds (0)); 84 | nodes.Get(i)->AddApplication(appI); 85 | } 86 | 87 | Simulator::Schedule (Seconds (30), &SomeEvent); 88 | 89 | Simulator::Stop(Seconds(simTime)); 90 | Simulator::Run(); 91 | std::cout << "Post Simulation: " << std::endl; 92 | 93 | for (uint32_t i=0 ; i appI = DynamicCast (nodes.Get(i)->GetApplication(0)); 96 | appI->PrintNeighbors (); 97 | } 98 | 99 | 100 | Simulator::Destroy(); 101 | 102 | } 103 | -------------------------------------------------------------------------------- /examples/CustomApplicationExample/wave-setup.cc: -------------------------------------------------------------------------------- 1 | #include "wave-setup.h" 2 | 3 | namespace ns3 4 | { 5 | 6 | WaveSetup::WaveSetup(){} 7 | WaveSetup::~WaveSetup () {} 8 | 9 | NetDeviceContainer WaveSetup::ConfigureDevices (NodeContainer& nodes) 10 | { 11 | /* 12 | Setting up WAVE devices. With PHY & MAC using default settings. 13 | */ 14 | YansWifiChannelHelper waveChannel = YansWifiChannelHelper::Default (); 15 | YansWavePhyHelper wavePhy = YansWavePhyHelper::Default (); 16 | wavePhy.SetChannel (waveChannel.Create ()); 17 | wavePhy.SetPcapDataLinkType (WifiPhyHelper::DLT_IEEE802_11_RADIO); 18 | wavePhy.Set ("TxPowerStart", DoubleValue (5) ); 19 | wavePhy.Set ("TxPowerEnd", DoubleValue (33) ); 20 | wavePhy.Set ("TxPowerLevels", UintegerValue (8)); 21 | //Setup up MAC 22 | QosWaveMacHelper waveMac = QosWaveMacHelper::Default (); 23 | WaveHelper waveHelper = WaveHelper::Default (); 24 | 25 | waveHelper.SetRemoteStationManager ("ns3::ConstantRateWifiManager", 26 | "DataMode", StringValue ("OfdmRate6MbpsBW10MHz" ), 27 | "ControlMode",StringValue ("OfdmRate6MbpsBW10MHz"), 28 | "NonUnicastMode", StringValue ("OfdmRate6MbpsBW10MHz")); 29 | 30 | NetDeviceContainer devices = waveHelper.Install (wavePhy, waveMac, nodes); 31 | 32 | 33 | //if you want PCAP trace, uncomment this! 34 | //wavePhy.EnablePcap ("custom-application", devices); //This generates *.pcap files 35 | 36 | return devices; 37 | } 38 | 39 | } -------------------------------------------------------------------------------- /examples/CustomApplicationExample/wave-setup.h: -------------------------------------------------------------------------------- 1 | #ifndef WAVE_SETUP_H 2 | #define WAVE_SETUP_H 3 | #include "ns3/core-module.h" 4 | #include "ns3/wave-module.h" 5 | #include "ns3/network-module.h" 6 | 7 | namespace ns3 8 | { 9 | /** \brief This is a "utility class". It does not an extension to ns3. 10 | */ 11 | class WaveSetup 12 | { 13 | public: 14 | WaveSetup (); 15 | virtual ~WaveSetup (); 16 | 17 | NetDeviceContainer ConfigureDevices (NodeContainer &n); 18 | }; 19 | } 20 | 21 | #endif -------------------------------------------------------------------------------- /examples/MobilityExample/custom-mobility-model.cc: -------------------------------------------------------------------------------- 1 | #include "custom-mobility-model.h" 2 | #include "ns3/simulator.h" 3 | #include "ns3/log.h" 4 | #include "ns3/console-color.h" 5 | #include // std::setprecision 6 | 7 | #include 8 | namespace ns3 9 | { 10 | NS_LOG_COMPONENT_DEFINE ("CustomMobilityModel"); 11 | NS_OBJECT_ENSURE_REGISTERED (CustomMobilityModel); 12 | 13 | TypeId ns3::CustomMobilityModel::GetTypeId(void) { 14 | static TypeId tid = TypeId("ns3::CustomMobilityModel") 15 | .SetParent() 16 | .SetGroupName ("caac") 17 | .AddConstructor() 18 | ; 19 | return tid; 20 | } 21 | TypeId ns3::CustomMobilityModel::GetInstanceTypeId() const 22 | { 23 | return CustomMobilityModel::GetTypeId(); 24 | } 25 | ns3::CustomMobilityModel::CustomMobilityModel() { 26 | m_theta =0 ; //heading is initialized to zero 27 | m_min_velocity = 0; //Cannot go backward. Minimum speed is stand still. 28 | m_max_velocity = 30; 29 | m_min_acceleration = -3.6576; // m/s^2 30 | m_max_acceleration = 3.6576; 31 | } 32 | ns3::CustomMobilityModel::~CustomMobilityModel() { 33 | } 34 | 35 | void CustomMobilityModel::SetAccelerationValue (double value) 36 | { 37 | double newValue; 38 | if (value>m_max_acceleration) 39 | { 40 | newValue = m_max_acceleration; 41 | } 42 | if (value m_max_acceleration) 110 | m_acceleration.x = m_max_acceleration; 111 | else if (m_acceleration.x < m_min_acceleration) 112 | m_acceleration.x = m_min_acceleration; 113 | 114 | 115 | //SanityCheck(); //Used this for debugging. 116 | 117 | NotifyCourseChange (); 118 | //Check if we're going to violate speed limits (0 to m_max_velocity) 119 | if (acceleration.x > 0 && m_baseVelocity.x == m_max_velocity) //trying to speedup when velocity is max 120 | { 121 | //Set acceleration to zero 122 | m_acceleration = Vector (0,0,0); 123 | NS_LOG_DEBUG ( BLUE ("\tSpeed limit hit!") ); 124 | // no further changes are needed. Change in acceleration has on effect on velocity 125 | 126 | return; 127 | } 128 | else if (acceleration.x < 0 && m_baseVelocity.x == 0) //Trying to slow down when velocity is zero 129 | { 130 | m_acceleration = Vector (0,0,0); 131 | NS_LOG_DEBUG ( BLUE ("\tZERO speed limit hit!") ); 132 | // no further changes are needed. Change in acceleration has on effect on velocity 133 | return; 134 | } 135 | if (acceleration.x == 0) 136 | { 137 | NS_LOG_DEBUG(YELLOW ("COURSE CHANGED ACCELERATION IS ZERO!")); 138 | //NotifyCourseChange(); 139 | return; 140 | } 141 | //Okay, so we are either "speedig up, but not at max speed" or "slowing down but not stand-still" 142 | /* 143 | A node maintains a certain acceleration until it hits top speed, when it hit top speed, acceleration is set to 0 144 | An event is created & sechudled to fire when max speed is reached to set the acceleration to 0. 145 | We're cancelling that event because acceleration has changed 146 | */ 147 | NS_LOG_DEBUG(Simulator::Now() << " : Cancelling speedlimit event. Vel=" << m_baseVelocity << " Acceleration=" << acceleration); 148 | m_limit_event.Cancel(); 149 | 150 | //If a node maintains this acceleration, when will it hit its speed limit? 151 | 152 | if (m_acceleration.x < 0) //we're slowing down, let's find the time it takes to reach 0 153 | { 154 | //Scheduling an event to set acceleration to zero 155 | m_timeToSpeedlimit = Seconds( m_baseVelocity.x / std::abs(m_acceleration.x) ); 156 | } 157 | else if (m_acceleration.x > 0) //We're speeding up, let's find the time it takes to reach max velocity 158 | { 159 | m_timeToSpeedlimit = Seconds( (m_max_velocity - m_baseVelocity.x) / m_acceleration.x ); 160 | } 161 | else 162 | { 163 | m_timeToSpeedlimit = Seconds(0); //for completion purposes 164 | } 165 | 166 | NS_LOG_DEBUG ("\tCurrent Velocity= " << m_baseVelocity); 167 | NS_LOG_DEBUG ("\tCurrent Acceleration= " << m_acceleration); 168 | NS_LOG_DEBUG ("\tLimit event in : " << m_timeToSpeedlimit); 169 | 170 | 171 | /* 172 | We will schedule an event for when will the velocity limit be reached 173 | */ 174 | //Let's check if the calculated time to reach the limit is not zero 175 | if (m_timeToSpeedlimit.GetSeconds() > 0 ) 176 | { 177 | NS_LOG_DEBUG (Simulator::Now() <<" -- Scheduled setting ACCELERATION to ZERO in " << m_timeToSpeedlimit ); 178 | //If we're speeding up... 179 | if (m_acceleration.x >0) 180 | m_limit_event = Simulator::Schedule(m_timeToSpeedlimit, &CustomMobilityModel::SetAccelerationToZeroMaxVelocity, this); 181 | else 182 | { //If we're slowing down... 183 | m_limit_event = Simulator::Schedule(m_timeToSpeedlimit, &CustomMobilityModel::SetAccelerationToZeroZeroVelocity, this); 184 | } 185 | 186 | } 187 | else //If the calculated time to speed limit is zero, set acceleration to zero. 188 | { 189 | //NS_LOG_LOGIC (Simulator::Now() << " Max Velocity reached. Setting Acceleration to ZERO"); 190 | m_acceleration = Vector (0,0,0); 191 | } 192 | 193 | //NotifyCourseChange (); 194 | } 195 | void CustomMobilityModel::SetAccelerationToZeroZeroVelocity() 196 | { 197 | NS_LOG_FUNCTION(this); 198 | SetVelocityAndAcceleration ( Vector(0,0,0) , Vector(0,0,0)); 199 | } 200 | /* 201 | Vector CustomMobilityModel::GetPosition (void) const 202 | { 203 | return DoGetPosition (); 204 | } 205 | */ 206 | void CustomMobilityModel::SetAccelerationToZeroMaxVelocity () 207 | { 208 | NS_LOG_FUNCTION (this); 209 | SetVelocityAndAcceleration ( Vector(m_max_velocity,0,0) , Vector(0,0,0)); 210 | 211 | } 212 | 213 | 214 | Vector ns3::CustomMobilityModel::GetAcceleration() { 215 | return m_acceleration; 216 | } 217 | 218 | void ns3::CustomMobilityModel::SetAccelerationLimits(double min, 219 | double max) { 220 | 221 | m_min_acceleration = min; 222 | m_max_acceleration = max; 223 | } 224 | 225 | void ns3::CustomMobilityModel::SetMaxVelocity(double max) { 226 | this->m_max_velocity = max; 227 | } 228 | 229 | double CustomMobilityModel::GetAccelerationValue () 230 | { 231 | return m_acceleration.x; 232 | } 233 | 234 | void CustomMobilityModel::SanityCheck() 235 | { 236 | //sanity check 237 | if (m_baseVelocity.x < 0) 238 | { 239 | std::cout << RED ("SPEED IS NEGATIVE! : ") << m_baseVelocity.x << std::endl; 240 | } 241 | if (m_baseVelocity.x > m_max_velocity) 242 | { 243 | std::cout << YELLOW ("SPEED LIMIT EXCEEDED : ") << m_baseVelocity.x << std::endl; 244 | } 245 | } 246 | 247 | } 248 | -------------------------------------------------------------------------------- /examples/MobilityExample/custom-mobility-model.h: -------------------------------------------------------------------------------- 1 | /* 2 | * NOTE : Using a custom Mobility Model works, but have issues working with PyViz due to lack of Python Bindings. 3 | * therefore, work on this is halted for now. 4 | */ 5 | 6 | #ifndef NS3_SCRATCH_CUSTOM_MOBILITY_MODEL_H 7 | #define NS3_SCRATCH_CUSTOM_MOBILITY_MODEL_H 8 | 9 | #include "ns3/constant-acceleration-mobility-model.h" 10 | #include "ns3/mobility-model.h" 11 | #include "ns3/nstime.h" 12 | #include "ns3/event-id.h" 13 | namespace ns3 14 | { 15 | /** \brief An implementation of longitudinal vehicular mobility on an x-axis only. This implementation is based on ns3::ConstantAccelerationMobilityModel, but it adds limits on velocity and acceleration. 16 | * 17 | * You can set an upper and lower limits for acceleration. The default values are 3.6576 & -3.6576 in m/s^2 18 | * You can also set the max velocity. Default value is 30 m/s. 19 | * 20 | * If you set the acceleration to a positive value, it calculates the time to reach the maximum velocity, and schedules an event to set the acceleration to zero at that time. 21 | * If acceleration is set to a negative value, it would calculate the time to reach zero velocity and schedule and event to set the acceleration to zero at that time. 22 | * 23 | * The event scheduled to set acceleration to zero is cancelled and replaced by another event everytime the accelration value is set again. 24 | * 25 | * 26 | */ 27 | class CustomMobilityModel : public MobilityModel 28 | { 29 | public: 30 | /** 31 | * Register this type with the TypeId system. 32 | * \return the object TypeId 33 | */ 34 | static TypeId GetTypeId (void); 35 | 36 | 37 | virtual TypeId GetInstanceTypeId() const; 38 | /** 39 | * Create position located at coordinates, velocity & acceleration set to (0,0,0) 40 | */ 41 | CustomMobilityModel (); 42 | virtual ~CustomMobilityModel (); 43 | /** 44 | * Set the model's velocity and acceleration 45 | * \param velocity the velocity (m/s) of type ns3::Vector 46 | * \param acceleration the acceleration (m/s^2) of type ns3::Vector 47 | */ 48 | void SetVelocityAndAcceleration (const Vector &velocity, const Vector &acceleration); 49 | /** \brief Change the acceleration. If the value is greater than the max limit, then it's set to that limit. If it's less than the lowest limit, it's set to the lower limit. 50 | */ 51 | void SetAccelerationValue (double value); 52 | 53 | /** \brief Returns the acceleration as a ns3::Vector form 54 | */ 55 | Vector GetAcceleration(); 56 | 57 | /** \brief Returns the acceleration as a double 58 | */ 59 | double GetAccelerationValue (); 60 | 61 | /** \brief Sets the minimum and maximum acceleration values in m/s^2. This depends on the vehicle. 62 | * \param min the minimum acceleration value. This is a negative value for deceleration. 63 | * \param max the maximum acceleration value. 64 | */ 65 | void SetAccelerationLimits (double min, double max); 66 | /** \brief Sets the maximum speed. This is usually the speed limit of the road. 67 | */ 68 | void SetMaxVelocity (double max); 69 | 70 | /** \brief Sanity check for debugging 71 | */ 72 | void SanityCheck (); 73 | 74 | private: 75 | 76 | /* \brief A function that is scheduled to set acceleration to zero when max velocity is reached. 77 | */ 78 | void SetAccelerationToZeroMaxVelocity (); 79 | /* \brief A function that is scheduled to set acceleration to zero when zero velocity is reached. 80 | */ 81 | void SetAccelerationToZeroZeroVelocity (); 82 | 83 | virtual Vector DoGetPosition (void) const; 84 | virtual void DoSetPosition (const Vector &position); 85 | virtual Vector DoGetVelocity (void) const; 86 | 87 | Time m_baseTime; //!< the base time 88 | Vector m_basePosition; //!< the base position 89 | Vector m_baseVelocity; //!< the base velocity 90 | Vector m_acceleration; //!< the acceleration 91 | 92 | Time m_updatePeriod; //!< How often to update 93 | Time m_timeToSpeedlimit; //!< When acceleration is adjusted, we compute the time at which the vehicle would reach max allowed velocity. We do this so that we would set the acceleration to 0 as vehicles must not exceed the speed limit 94 | 95 | 96 | EventId m_limit_event; //!< An event that's scheduled in anticipation of reaching max speed. If acceleration changes before then, it's cancelled, and a new one is scheduled 97 | double m_theta; //!< Heading angle. If vehicle is moving along x-axis, forward it would be 0, if opposite direction, it's PI (3.14) 98 | double m_max_velocity; 99 | double m_min_velocity; 100 | double m_min_acceleration; 101 | double m_max_acceleration; 102 | 103 | }; 104 | 105 | } 106 | 107 | 108 | #endif /* NS_3_30_1_CONTRIB_CACC_MOBILITY_VEHICULAR_MOBILITY_MODEL_H_ */ 109 | -------------------------------------------------------------------------------- /examples/MobilityExample/mobility-test.cc: -------------------------------------------------------------------------------- 1 | #include "ns3/mobility-module.h" 2 | #include "ns3/core-module.h" 3 | #include "ns3/network-module.h" 4 | #include "custom-mobility-model.h" 5 | using namespace ns3; 6 | void PrintInfo () 7 | { 8 | Ptr n0 = ns3::NodeList::GetNode(0); 9 | Ptr n1 = ns3::NodeList::GetNode(1); 10 | 11 | Ptr m0 = n0->GetObject (); 12 | Ptr m1 = n1->GetObject (); 13 | 14 | std::cout << "n0 Vel:" << m0->GetVelocity() << "\t\tn1 Vel: " << m1->GetVelocity() << std::endl; 15 | 16 | if (Now() == Seconds (3)) 17 | { 18 | Ptr cmm = DynamicCast (m0); 19 | cmm->SetAccelerationValue (0.5); 20 | } 21 | 22 | Simulator::Schedule (Seconds (1), &PrintInfo); 23 | 24 | } 25 | int main (int argc, char* argv[]) 26 | { 27 | CommandLine cmd; 28 | cmd.Parse (argc, argv); 29 | 30 | NodeContainer nodes; 31 | nodes.Create (2); 32 | 33 | MobilityHelper mob; 34 | mob.SetMobilityModel ("ns3::CustomMobilityModel"); 35 | mob.Install (nodes); 36 | 37 | Ptr m0 = DynamicCast(nodes.Get(0)->GetObject ()); 38 | Ptr m1 = DynamicCast(nodes.Get(1)->GetObject ()); 39 | 40 | //Initial positions 41 | m0->SetPosition (Vector (50,10,0)); 42 | m1->SetPosition (Vector (75,20,0)); 43 | 44 | m0->SetVelocityAndAcceleration (Vector (0,0,0), Vector (3,0,0)); 45 | m1->SetVelocityAndAcceleration (Vector (10,0,0), Vector (-3,0,0)); 46 | 47 | Simulator::Schedule (Seconds (1), &PrintInfo); 48 | Simulator::Stop (Seconds (60)); 49 | Simulator::Run(); 50 | Simulator::Destroy (); 51 | 52 | 53 | } -------------------------------------------------------------------------------- /examples/README.md: -------------------------------------------------------------------------------- 1 | # `ns-3` Example Projects 2 | 3 | This directory contains `ns-3` projects. Please note that all examples were run using 4 | 5 | * `ns3` version is now ns-3.35 6 | * Compiled using `gcc-7` on Ubuntu 18, and `clang11` on Mac OS. 7 | - Some examples may work on different versions of `ns3` and with older compilers. 8 | 9 | # How to use the projects 10 | Every project is placed in a separate directory. Simply copy the directory of the desired project to your `ns-3`'s scratch directory. 11 | 12 | 13 | -------------------------------------------------------------------------------- /examples/SUMOTraceExample/custom-application.cc: -------------------------------------------------------------------------------- 1 | #include "custom-application.h" 2 | #include "custom-data-tag.h" 3 | #include "ns3/mobility-model.h" 4 | #include "ns3/log.h" 5 | #include "ns3/simulator.h" 6 | 7 | #define RED_CODE "\033[91m" 8 | #define GREEN_CODE "\033[32m" 9 | #define END_CODE "\033[0m" 10 | 11 | 12 | namespace ns3 13 | { 14 | NS_LOG_COMPONENT_DEFINE("CustomApplication"); 15 | NS_OBJECT_ENSURE_REGISTERED(CustomApplication); 16 | 17 | TypeId CustomApplication::GetTypeId() 18 | { 19 | static TypeId tid = TypeId("ns3::CustomApplication") 20 | .SetParent () 21 | .AddConstructor () 22 | .AddAttribute ("Interval", "Broadcast Interval", 23 | TimeValue (MilliSeconds(100)), 24 | MakeTimeAccessor (&CustomApplication::m_broadcast_time), 25 | MakeTimeChecker() 26 | ) 27 | ; 28 | return tid; 29 | } 30 | 31 | TypeId CustomApplication::GetInstanceTypeId() const 32 | { 33 | return CustomApplication::GetTypeId(); 34 | } 35 | 36 | CustomApplication::CustomApplication() 37 | { 38 | NS_LOG_FUNCTION (this); 39 | m_broadcast_time = MilliSeconds (100); //every 100ms 40 | m_packetSize = 1000; //1000 bytes 41 | m_time_limit = Seconds (5); 42 | m_mode = WifiMode("OfdmRate6MbpsBW10MHz"); 43 | } 44 | CustomApplication::~CustomApplication() 45 | { 46 | 47 | } 48 | void 49 | CustomApplication::StartApplication() 50 | { 51 | NS_LOG_FUNCTION (this); 52 | std::cout << "Application at node " << GetNode()->GetId() << " has started!" << std::endl; 53 | 54 | //Set A Receive callback 55 | Ptr n = GetNode (); 56 | for (uint32_t i = 0; i < n->GetNDevices (); i++) 57 | { 58 | Ptr dev = n->GetDevice (i); 59 | if (dev->GetInstanceTypeId () == WaveNetDevice::GetTypeId()) 60 | { 61 | m_waveDevice = DynamicCast (dev); 62 | //ReceivePacket will be called when a packet is received 63 | dev->SetReceiveCallback (MakeCallback (&CustomApplication::ReceivePacket, this)); 64 | 65 | /* 66 | If you want promiscous receive callback, connect to this trace. 67 | For every packet received, both functions ReceivePacket & PromiscRx will be called. with PromicRx being called first! 68 | */ 69 | Ptr phy = m_waveDevice->GetPhys()[0]; //default, there's only one PHY in a WaveNetDevice 70 | phy->TraceConnectWithoutContext ("MonitorSnifferRx", MakeCallback(&CustomApplication::PromiscRx, this)); 71 | phy->TraceConnectWithoutContext ("MonitorSnifferTx", MakeCallback(&CustomApplication::MonitorTx, this)); 72 | phy->TraceConnectWithoutContext ("PhyTxDrop", MakeCallback(&CustomApplication::PhyTxDropTrace, this)); 73 | phy->TraceConnectWithoutContext ("PhyRxDrop", MakeCallback(&CustomApplication::PhyRxDropTrace, this)); 74 | 75 | break; 76 | } 77 | } 78 | if (m_waveDevice) 79 | { 80 | //Let's create a bit of randomness with the first broadcast packet time to avoid collision 81 | Ptr rand = CreateObject (); 82 | Time random_offset = MicroSeconds (rand->GetValue(50,200)); 83 | 84 | Simulator::Schedule (m_broadcast_time+random_offset, &CustomApplication::BroadcastInformation, this); 85 | } 86 | else 87 | { 88 | NS_FATAL_ERROR ("There's no WaveNetDevice in your node"); 89 | } 90 | //We will periodically (every 1 second) check the list of neighbors, and remove old ones (older than 5 seconds) 91 | Simulator::Schedule (Seconds (1), &CustomApplication::RemoveOldNeighbors, this); 92 | 93 | } 94 | void 95 | CustomApplication::SetBroadcastInterval (Time interval) 96 | { 97 | NS_LOG_FUNCTION (this << interval); 98 | m_broadcast_time = interval; 99 | } 100 | void 101 | CustomApplication::SetWifiMode (WifiMode mode) 102 | { 103 | m_mode = mode; 104 | } 105 | 106 | void 107 | CustomApplication::BroadcastInformation() 108 | { 109 | NS_LOG_FUNCTION (this); 110 | //Setup transmission parameters 111 | TxInfo tx; 112 | tx.channelNumber = CCH; 113 | tx.priority = 7; //highest priority. 114 | tx.txPowerLevel = 7; 115 | tx.dataRate = m_mode; 116 | 117 | Ptr packet = Create (m_packetSize); 118 | 119 | //let's attach our custom data tag to it 120 | CustomDataTag tag; 121 | tag.SetNodeId ( GetNode()->GetId() ); 122 | tag.SetPosition ( GetNode()->GetObject()->GetPosition()); 123 | //timestamp is set in the default constructor of the CustomDataTag class as Simulator::Now() 124 | 125 | //attach the tag to the packet 126 | packet->AddPacketTag (tag); 127 | 128 | //Broadcast the packet as WSMP (0x88dc) 129 | m_waveDevice->SendX (packet, Mac48Address::GetBroadcast(), 0x88dc, tx); 130 | 131 | //NS_LOG_DEBUG ("Node " << GetNode()->GetId() << " is BROADCASTING a packet. " << Now ()); 132 | //Schedule next broadcast 133 | Simulator::Schedule (m_broadcast_time, &CustomApplication::BroadcastInformation, this); 134 | } 135 | 136 | void 137 | CustomApplication::MonitorTx (const Ptr< const Packet > packet, uint16_t channelFreqMhz, WifiTxVector txVector, MpduInfo aMpdu, uint16_t sta_id) 138 | { 139 | NS_LOG_DEBUG (Now().GetSeconds() << GREEN_CODE << " >>>> Node " << GetNode()->GetId() << " transmitting : " << channelFreqMhz << END_CODE); 140 | } 141 | 142 | void 143 | CustomApplication::PhyRxDropTrace(Ptr packet, WifiPhyRxfailureReason reason) 144 | { 145 | NS_LOG_DEBUG (Now().GetSeconds() << RED_CODE << " Node " << GetNode()->GetId() << " RxDrop. " << END_CODE << "Reason: " << reason); 146 | } 147 | void 148 | CustomApplication::PhyTxDropTrace(Ptr packet) 149 | { 150 | NS_LOG_DEBUG (Now().GetSeconds() << RED_CODE << " Node " << GetNode()->GetId() << " TxDrop. " << END_CODE); 151 | } 152 | 153 | bool 154 | CustomApplication::ReceivePacket (Ptr device, Ptr packet,uint16_t protocol, const Address &sender) 155 | { 156 | NS_LOG_FUNCTION (device << packet << protocol << sender); 157 | /* 158 | Packets received here only have Application data, no WifiMacHeader. 159 | We created packets with 1000 bytes payload, so we'll get 1000 bytes of payload. 160 | */ 161 | NS_LOG_INFO ("ReceivePacket() : Node " << GetNode()->GetId() << " : Received a packet from " << sender << " Size:" << packet->GetSize()); 162 | 163 | //Let's check if packet has a tag attached! 164 | CustomDataTag tag; 165 | if (packet->PeekPacketTag (tag)) 166 | { 167 | NS_LOG_INFO ("\tFrom Node Id: " << tag.GetNodeId() << " at " << tag.GetPosition() 168 | << "\tPacket Timestamp: " << tag.GetTimestamp() << " delay="<< Now()-tag.GetTimestamp()); 169 | } 170 | 171 | return true; 172 | } 173 | void 174 | CustomApplication::PromiscRx (Ptr packet, uint16_t channelFreq, WifiTxVector tx, MpduInfo mpdu, SignalNoiseDbm sn, uint16_t sta_id) 175 | { 176 | //This is a promiscous trace. It will pick broadcast packets, and packets not directed to this node's MAC address. 177 | /* 178 | Packets received here have MAC headers and payload. 179 | If packets are created with 1000 bytes payload, the size here is about 38 bytes larger. 180 | */ 181 | NS_LOG_DEBUG (Now () << " PromiscRx() : Node " << GetNode()->GetId() << " : ChannelFreq: " << channelFreq << " Mode: " << tx.GetMode() 182 | << " Signal: " << sn.signal << " Noise: " << sn.noise << " Size: " << packet->GetSize() 183 | << " Mode " << tx.GetMode () 184 | ); 185 | WifiMacHeader hdr; 186 | if (packet->PeekHeader (hdr)) 187 | { 188 | //Let's see if this packet is intended to this node 189 | Mac48Address destination = hdr.GetAddr1(); 190 | Mac48Address source = hdr.GetAddr2(); 191 | 192 | //UpdateNeighbor (source); 193 | 194 | Mac48Address myMacAddress = m_waveDevice->GetMac(CCH)->GetAddress(); 195 | //A packet is intened to me if it targets my MAC address, or it's a broadcast message 196 | if ( destination==Mac48Address::GetBroadcast() || destination==myMacAddress) 197 | { 198 | NS_LOG_DEBUG ("\tFrom: " << source << "\n\tSeq. No. " << hdr.GetSequenceNumber() ); 199 | //Do something for this type of packets 200 | } 201 | else //Well, this packet is not intended for me 202 | { 203 | //Maybe record some information about neighbors 204 | } 205 | } 206 | } 207 | 208 | void CustomApplication::UpdateNeighbor (Mac48Address addr) 209 | { 210 | bool found = false; 211 | //Go over all neighbors, find one matching the address, and updates its 'last_beacon' time. 212 | for (std::vector::iterator it = m_neighbors.begin(); it != m_neighbors.end(); it++ ) 213 | { 214 | if (it->neighbor_mac == addr) 215 | { 216 | it->last_beacon = Now(); 217 | found = true; 218 | break; 219 | } 220 | } 221 | if (!found) //If no node with this address exist, add a new table entry 222 | { 223 | NS_LOG_INFO ( GREEN_CODE << Now() << " : Node " << GetNode()->GetId() << " is adding a neighbor with MAC="<GetId() << std::endl; 234 | for (std::vector::iterator it = m_neighbors.begin(); it != m_neighbors.end(); it++ ) 235 | { 236 | std::cout << "\tMAC: " << it->neighbor_mac << "\tLast Contact: " << it->last_beacon << std::endl; 237 | } 238 | } 239 | 240 | void CustomApplication::RemoveOldNeighbors () 241 | { 242 | //Go over the list of neighbors 243 | for (std::vector::iterator it = m_neighbors.begin(); it != m_neighbors.end(); it++ ) 244 | { 245 | //Get the time passed since the last time we heard from a node 246 | Time last_contact = Now () - it->last_beacon; 247 | 248 | if (last_contact >= Seconds (5)) //if it has been more than 5 seconds, we will remove it. You can change this to whatever value you want. 249 | { 250 | NS_LOG_INFO (RED_CODE << Now () << " Node " << GetNode()->GetId()<<" is removing old neighbor " << it->neighbor_mac < 7 | 8 | namespace ns3 9 | { 10 | /** \brief A struct to represent information about this node's neighbors. I chose MAC address and the time last message was received form that node 11 | * The time 'last_beacon' is used to determine whether we should remove the neighbor from the list. 12 | */ 13 | typedef struct 14 | { 15 | Mac48Address neighbor_mac; 16 | Time last_beacon; 17 | } NeighborInformation; 18 | 19 | class CustomApplication : public ns3::Application 20 | { 21 | public: 22 | 23 | static TypeId GetTypeId (void); 24 | virtual TypeId GetInstanceTypeId (void) const; 25 | 26 | CustomApplication(); 27 | ~CustomApplication(); 28 | 29 | /** \brief Broadcast some information 30 | */ 31 | void BroadcastInformation(); 32 | 33 | /** \brief This function is called when a net device receives a packet. 34 | * I connect to the callback in StartApplication. This matches the signiture of NetDevice receive. 35 | */ 36 | bool ReceivePacket (Ptr device,Ptr packet,uint16_t protocol, const Address &sender); 37 | 38 | void PromiscRx (Ptr packet, uint16_t channelFreq, WifiTxVector tx, MpduInfo mpdu, SignalNoiseDbm sn, uint16_t sta_id); 39 | 40 | void MonitorTx (const Ptr< const Packet > packet, uint16_t channelFreqMhz, WifiTxVector txVector, MpduInfo aMpdu, uint16_t sta_id); 41 | 42 | void SetBroadcastInterval (Time interval); 43 | 44 | void PhyTxDropTrace (Ptr packet); 45 | 46 | void PhyRxDropTrace (Ptr, WifiPhyRxfailureReason reason); 47 | 48 | /** \brief Update a neighbor's last contact time, or add a new neighbor 49 | */ 50 | void UpdateNeighbor (Mac48Address addr); 51 | /** \brief Print a list of neighbors 52 | */ 53 | void PrintNeighbors (); 54 | 55 | /** \brief Change the data rate used for broadcasts. 56 | */ 57 | void SetWifiMode (WifiMode mode); 58 | 59 | /** \brief Remove neighbors you haven't heard from after some time. 60 | */ 61 | void RemoveOldNeighbors (); 62 | 63 | //You can create more functions like getters, setters, and others 64 | 65 | private: 66 | /** \brief This is an inherited function. Code that executes once the application starts 67 | */ 68 | void StartApplication(); 69 | Time m_broadcast_time; /**< How often do you broadcast messages */ 70 | uint32_t m_packetSize; /**< Packet size in bytes */ 71 | Ptr m_waveDevice; /**< A WaveNetDevice that is attached to this device */ 72 | 73 | std::vector m_neighbors; /**< A table representing neighbors of this node */ 74 | 75 | Time m_time_limit; /**< Time limit to keep neighbors in a list */ 76 | 77 | WifiMode m_mode; /**< data rate used for broadcasts */ 78 | //You can define more stuff to record statistics, etc. 79 | }; 80 | } 81 | 82 | #endif 83 | -------------------------------------------------------------------------------- /examples/SUMOTraceExample/custom-data-tag.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * cacc-data-tag.cc 3 | * 4 | * Created on: Oct 29, 2019 5 | * Author: adil 6 | */ 7 | #include "../SUMOTraceExample/custom-data-tag.h" 8 | 9 | #include "ns3/log.h" 10 | #include "ns3/simulator.h" 11 | 12 | namespace ns3 { 13 | 14 | NS_LOG_COMPONENT_DEFINE("CustomDataTag"); 15 | NS_OBJECT_ENSURE_REGISTERED (CustomDataTag); 16 | 17 | CustomDataTag::CustomDataTag() { 18 | m_timestamp = Simulator::Now(); 19 | m_nodeId = -1; 20 | } 21 | CustomDataTag::CustomDataTag(uint32_t node_id) { 22 | m_timestamp = Simulator::Now(); 23 | m_nodeId = node_id; 24 | } 25 | 26 | CustomDataTag::~CustomDataTag() { 27 | } 28 | 29 | //Almost all custom tags will have similar implementation of GetTypeId and GetInstanceTypeId 30 | TypeId CustomDataTag::GetTypeId (void) 31 | { 32 | static TypeId tid = TypeId ("ns3::CustomDataTag") 33 | .SetParent () 34 | .AddConstructor (); 35 | return tid; 36 | } 37 | TypeId CustomDataTag::GetInstanceTypeId (void) const 38 | { 39 | return CustomDataTag::GetTypeId (); 40 | } 41 | 42 | /** The size required for the data contained within tag is: 43 | * size needed for a ns3::Vector for position + 44 | * size needed for a ns3::Time for timestamp + 45 | * size needed for a uint32_t for node id 46 | */ 47 | uint32_t CustomDataTag::GetSerializedSize (void) const 48 | { 49 | return sizeof(Vector) + sizeof (ns3::Time) + sizeof(uint32_t); 50 | } 51 | /** 52 | * The order of how you do Serialize() should match the order of Deserialize() 53 | */ 54 | void CustomDataTag::Serialize (TagBuffer i) const 55 | { 56 | //we store timestamp first 57 | i.WriteDouble(m_timestamp.GetDouble()); 58 | 59 | //then we store the position 60 | i.WriteDouble (m_currentPosition.x); 61 | i.WriteDouble (m_currentPosition.y); 62 | i.WriteDouble (m_currentPosition.z); 63 | 64 | //Then we store the node ID 65 | i.WriteU32(m_nodeId); 66 | } 67 | /** This function reads data from a buffer and store it in class's instance variables. 68 | */ 69 | void CustomDataTag::Deserialize (TagBuffer i) 70 | { 71 | //We extract what we stored first, so we extract the timestamp 72 | m_timestamp = Time::FromDouble (i.ReadDouble(), Time::NS);; 73 | 74 | //Then the position 75 | m_currentPosition.x = i.ReadDouble(); 76 | m_currentPosition.y = i.ReadDouble(); 77 | m_currentPosition.z = i.ReadDouble(); 78 | //Finally, we extract the node id 79 | m_nodeId = i.ReadU32(); 80 | 81 | } 82 | /** 83 | * This function can be used with ASCII traces if enabled. 84 | */ 85 | void CustomDataTag::Print (std::ostream &os) const 86 | { 87 | os << "Custom Data --- Node :" << m_nodeId << "\t(" << m_timestamp << ")" << " Pos (" << m_currentPosition << ")"; 88 | } 89 | 90 | //Your accessor and mutator functions 91 | uint32_t CustomDataTag::GetNodeId() { 92 | return m_nodeId; 93 | } 94 | 95 | void CustomDataTag::SetNodeId(uint32_t node_id) { 96 | m_nodeId = node_id; 97 | } 98 | Vector CustomDataTag::GetPosition(void) { 99 | return m_currentPosition; 100 | } 101 | 102 | Time CustomDataTag::GetTimestamp() { 103 | return m_timestamp; 104 | } 105 | 106 | void CustomDataTag::SetPosition(Vector pos) { 107 | m_currentPosition = pos; 108 | } 109 | 110 | void CustomDataTag::SetTimestamp(Time t) { 111 | m_timestamp = t; 112 | } 113 | 114 | } /* namespace ns3 */ 115 | 116 | 117 | -------------------------------------------------------------------------------- /examples/SUMOTraceExample/custom-data-tag.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This tag combines position, velocity, and acceleration in one tag. 3 | */ 4 | 5 | #ifndef CUSTOM_DATA_TAG_H 6 | #define CUSTOM_DATA_TAG_H 7 | 8 | #include "ns3/tag.h" 9 | #include "ns3/vector.h" 10 | #include "ns3/nstime.h" 11 | 12 | namespace ns3 13 | { 14 | /** We're creating a custom tag for simulation. A tag can be added to any packet, but you cannot add a tag of the same type twice. 15 | */ 16 | class CustomDataTag : public Tag { 17 | public: 18 | 19 | //Functions inherited from ns3::Tag that you have to implement. 20 | static TypeId GetTypeId(void); 21 | virtual TypeId GetInstanceTypeId(void) const; 22 | virtual uint32_t GetSerializedSize(void) const; 23 | virtual void Serialize (TagBuffer i) const; 24 | virtual void Deserialize (TagBuffer i); 25 | virtual void Print (std::ostream & os) const; 26 | 27 | //These are custom accessor & mutator functions 28 | Vector GetPosition(void); 29 | uint32_t GetNodeId(); 30 | Time GetTimestamp (); 31 | 32 | void SetPosition (Vector pos); 33 | void SetNodeId (uint32_t node_id); 34 | void SetTimestamp (Time t); 35 | 36 | 37 | 38 | CustomDataTag(); 39 | CustomDataTag(uint32_t node_id); 40 | virtual ~CustomDataTag(); 41 | private: 42 | 43 | uint32_t m_nodeId; 44 | /** Current position */ 45 | Vector m_currentPosition; 46 | /** Timestamp this tag was created */ 47 | Time m_timestamp; 48 | 49 | }; 50 | } 51 | 52 | #endif -------------------------------------------------------------------------------- /examples/SUMOTraceExample/main-program.cc: -------------------------------------------------------------------------------- 1 | #include "custom-application.h" 2 | #include "wave-setup.h" 3 | #include "ns3/network-module.h" 4 | #include "ns3/core-module.h" 5 | #include "ns3/mobility-module.h" 6 | #include "ns2-node-utility.h" 7 | 8 | using namespace ns3; 9 | 10 | int main (int argc, char *argv[]) 11 | { 12 | CommandLine cmd; 13 | cmd.Parse (argc, argv); 14 | 15 | std::string mobility_file = "scratch/SUMOTraceExample/ns2mobility.tcl"; 16 | 17 | //A tool I created so that we only start the applications within nodes when they actually enter the simulation. 18 | Ns2NodeUtility ns2_utility (mobility_file); 19 | 20 | uint32_t nnodes = ns2_utility.GetNNodes(); 21 | double sim_time = ns2_utility.GetSimulationTime(); 22 | 23 | NodeContainer nodes; 24 | nodes.Create (nnodes); 25 | 26 | //Using the bulit-in ns-2 mobility helper 27 | Ns2MobilityHelper sumo_trace (mobility_file); 28 | sumo_trace.Install(); //install ns-2 mobility in all nodes 29 | 30 | //To write shorter code, I put the code to setup WaveNetDevice in a separate file. 31 | WaveSetup wave; 32 | wave.ConfigureDevices(nodes); 33 | 34 | std::cout << "NS2 mobility & devices configured..." << std::endl; 35 | //Let's install my CustomApplication to all nodes and start them at the appropriate time using my utilitiy. 36 | ApplicationContainer apps; 37 | for (uint32_t i=0 ; i n = nodes.Get(i); 40 | Ptr app = CreateObject (); 41 | //app->SetStartTime (Seconds (0)); 42 | //app->SetStopTime (Seconds (sim_time)); 43 | app->SetStartTime(Seconds (ns2_utility.GetEntryTimeForNode(i))); 44 | app->SetStopTime (Seconds (ns2_utility.GetExitTimeForNode(i))); 45 | n->AddApplication(app); 46 | 47 | } 48 | std::cout << "Applications setup done!" << std::endl; 49 | Simulator::Stop(Seconds (sim_time)); //because this is the last timestamp in your ns-2 trace 50 | Simulator::Run (); 51 | 52 | std::cout << "End of Program" << std::endl; 53 | 54 | } 55 | -------------------------------------------------------------------------------- /examples/SUMOTraceExample/ns2-node-utility.cc: -------------------------------------------------------------------------------- 1 | #include "ns2-node-utility.h" 2 | 3 | #include 4 | 5 | namespace ns3 6 | { 7 | Ns2NodeUtility::Ns2NodeUtility (std::string name) 8 | { 9 | m_file_name = name; 10 | m_input_file.open(m_file_name); 11 | 12 | std::string line; 13 | 14 | std::vector node_ids; 15 | 16 | while (std::getline (m_input_file, line)) 17 | { 18 | std::smatch sm; 19 | std::regex r("\\$ns_ at (\\d*.\\d) \"\\$node_\\((\\d*)\\)"); 20 | if (std::regex_search(line, sm, r)) 21 | { 22 | //std::cout << "MATCH!" << std::endl; 23 | 24 | uint32_t id = std::stoi(sm[2]); 25 | double new_latest = std::stof(sm[1]); 26 | 27 | if ( std::find (node_ids.begin(), node_ids.end(), id) != node_ids.end()) 28 | { 29 | double entry_time = std::get<0> (m_node_times [id]); 30 | m_node_times [id] = std::make_pair(entry_time, new_latest); 31 | } 32 | else 33 | { 34 | m_node_times [id] = std::make_pair(new_latest, new_latest); 35 | } 36 | node_ids.push_back(id); 37 | } 38 | else 39 | { 40 | //std::cout << "No Match!" << std::endl; 41 | } 42 | } 43 | } 44 | uint32_t 45 | Ns2NodeUtility::GetNNodes () 46 | { 47 | return m_node_times.size(); 48 | } 49 | double 50 | Ns2NodeUtility::GetEntryTimeForNode (uint32_t nodeId) 51 | { 52 | return std::get<0>(m_node_times [nodeId]); 53 | } 54 | double 55 | Ns2NodeUtility::GetExitTimeForNode (uint32_t nodeId) 56 | { 57 | return std::get<1>(m_node_times [nodeId]); 58 | } 59 | double 60 | Ns2NodeUtility::GetSimulationTime() 61 | { 62 | double time = 0; 63 | 64 | for (uint32_t i=0 ; i(m_node_times[i]) ); 66 | 67 | return time; 68 | } 69 | 70 | 71 | void 72 | Ns2NodeUtility::PrintInformation() 73 | { 74 | uint32_t s = m_node_times.size(); 75 | for (uint32_t i=0 ; i(m_node_times[i]) << " and ended " << std::get<1>(m_node_times[i]) << std::endl; 78 | } 79 | } 80 | } 81 | 82 | -------------------------------------------------------------------------------- /examples/SUMOTraceExample/ns2-node-utility.h: -------------------------------------------------------------------------------- 1 | /* 2 | * ns2-node-utility.h 3 | * 4 | * Created on: Sep 14, 2020 5 | * Author: addola 6 | */ 7 | 8 | #ifndef SUMOTRACEEXAMPLE_NS2_NODE_UTILITY_H_ 9 | #define SUMOTRACEEXAMPLE_NS2_NODE_UTILITY_H_ 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | namespace ns3 18 | { 19 | class Ns2NodeUtility 20 | { 21 | public: 22 | Ns2NodeUtility (std::string file_name); 23 | /** Prints information. For debugging 24 | */ 25 | void PrintInformation (); 26 | /** 27 | * \return the number of nodes in the ns-2 trace 28 | */ 29 | uint32_t GetNNodes (); 30 | /** 31 | * \param nodeId of the node. 32 | * \return the time the node has entered into the ns-2 simulation trace in double. 33 | */ 34 | double GetEntryTimeForNode (uint32_t nodeId); 35 | /** Get the last time stamp of a node. At this point we can assume a node has left the simulation environment so we can turn its applications or communication devices off. 36 | * \param nodeId of the node 37 | * \return the last timestamp the node has done something during the ns-2 simulation trace in double. 38 | */ 39 | double GetExitTimeForNode (uint32_t nodeId); 40 | /** 41 | * \return The total simulation time of the ns-2 simulation in seconds as double 42 | */ 43 | double GetSimulationTime (); 44 | 45 | private: 46 | std::string m_file_name; /**< File name of the ns-2 mobility trace */ 47 | std::ifstream m_input_file; /**< input file stream object */ 48 | std::map > m_node_times; /**< a map to keep track of nodes entry & exit times. */ 49 | 50 | }; 51 | } 52 | 53 | #endif /* NS_3_30_1_SCRATCH_YOUTUBEQUESTIONS_NS2_NODE_UTILITY_H_ */ 54 | -------------------------------------------------------------------------------- /examples/SUMOTraceExample/wave-setup.cc: -------------------------------------------------------------------------------- 1 | #include "../SUMOTraceExample/wave-setup.h" 2 | 3 | namespace ns3 4 | { 5 | 6 | WaveSetup::WaveSetup(){} 7 | WaveSetup::~WaveSetup () {} 8 | 9 | NetDeviceContainer WaveSetup::ConfigureDevices (NodeContainer& nodes) 10 | { 11 | /* 12 | Setting up WAVE devices. With PHY & MAC using default settings. 13 | */ 14 | YansWifiChannelHelper waveChannel = YansWifiChannelHelper::Default (); 15 | YansWavePhyHelper wavePhy = YansWavePhyHelper::Default (); 16 | wavePhy.SetChannel (waveChannel.Create ()); 17 | wavePhy.SetPcapDataLinkType (WifiPhyHelper::DLT_IEEE802_11_RADIO); 18 | wavePhy.Set ("TxPowerStart", DoubleValue (5) ); 19 | wavePhy.Set ("TxPowerEnd", DoubleValue (33) ); 20 | wavePhy.Set ("TxPowerLevels", UintegerValue (8)); 21 | //Setup up MAC 22 | QosWaveMacHelper waveMac = QosWaveMacHelper::Default (); 23 | WaveHelper waveHelper = WaveHelper::Default (); 24 | 25 | waveHelper.SetRemoteStationManager ("ns3::ConstantRateWifiManager", 26 | "DataMode", StringValue ("OfdmRate6MbpsBW10MHz" ), 27 | "ControlMode",StringValue ("OfdmRate6MbpsBW10MHz"), 28 | "NonUnicastMode", StringValue ("OfdmRate6MbpsBW10MHz")); 29 | 30 | NetDeviceContainer devices = waveHelper.Install (wavePhy, waveMac, nodes); 31 | 32 | 33 | //if you want PCAP trace, uncomment this! 34 | //wavePhy.EnablePcap ("custom-application", devices); //This generates *.pcap files 35 | 36 | return devices; 37 | } 38 | 39 | } -------------------------------------------------------------------------------- /examples/SUMOTraceExample/wave-setup.h: -------------------------------------------------------------------------------- 1 | #ifndef WAVE_SETUP_H 2 | #define WAVE_SETUP_H 3 | #include "ns3/core-module.h" 4 | #include "ns3/wave-module.h" 5 | #include "ns3/network-module.h" 6 | 7 | namespace ns3 8 | { 9 | /** \brief This is a "utility class". It does not an extension to ns3. 10 | */ 11 | class WaveSetup 12 | { 13 | public: 14 | WaveSetup (); 15 | virtual ~WaveSetup (); 16 | 17 | NetDeviceContainer ConfigureDevices (NodeContainer &n); 18 | }; 19 | } 20 | 21 | #endif -------------------------------------------------------------------------------- /examples/SimpleUdpAppExample/simple-udp-application.cc: -------------------------------------------------------------------------------- 1 | #include "ns3/log.h" 2 | #include "simple-udp-application.h" 3 | #include "ns3/udp-socket.h" 4 | #include "ns3/simulator.h" 5 | #include "ns3/csma-net-device.h" 6 | #include "ns3/ethernet-header.h" 7 | #include "ns3/arp-header.h" 8 | #include "ns3/ipv4-header.h" 9 | #include "ns3/udp-header.h" 10 | 11 | #define PURPLE_CODE "\033[95m" 12 | #define CYAN_CODE "\033[96m" 13 | #define TEAL_CODE "\033[36m" 14 | #define BLUE_CODE "\033[94m" 15 | #define GREEN_CODE "\033[32m" 16 | #define YELLOW_CODE "\033[33m" 17 | #define LIGHT_YELLOW_CODE "\033[93m" 18 | #define RED_CODE "\033[91m" 19 | #define BOLD_CODE "\033[1m" 20 | #define END_CODE "\033[0m" 21 | 22 | namespace ns3 23 | { 24 | NS_LOG_COMPONENT_DEFINE("SimpleUdpApplication"); 25 | NS_OBJECT_ENSURE_REGISTERED(SimpleUdpApplication); 26 | 27 | TypeId 28 | SimpleUdpApplication::GetTypeId() 29 | { 30 | static TypeId tid = TypeId("ns3::SimpleUdpApplication") 31 | .AddConstructor() 32 | .SetParent(); 33 | return tid; 34 | } 35 | 36 | TypeId 37 | SimpleUdpApplication::GetInstanceTypeId() const 38 | { 39 | return SimpleUdpApplication::GetTypeId(); 40 | } 41 | 42 | SimpleUdpApplication::SimpleUdpApplication() 43 | { 44 | m_port1 = 7777; 45 | m_port2 = 9999; 46 | } 47 | SimpleUdpApplication::~SimpleUdpApplication() 48 | { 49 | } 50 | void SimpleUdpApplication::SetupReceiveSocket(Ptr socket, uint16_t port) 51 | { 52 | InetSocketAddress local = InetSocketAddress(Ipv4Address::GetAny(), port); 53 | if (socket->Bind(local) == -1) 54 | { 55 | NS_FATAL_ERROR("Failed to bind socket"); 56 | } 57 | } 58 | void SimpleUdpApplication::StartApplication() 59 | { 60 | //Receive sockets 61 | TypeId tid = TypeId::LookupByName("ns3::UdpSocketFactory"); 62 | m_recv_socket1 = Socket::CreateSocket(GetNode(), tid); 63 | m_recv_socket2 = Socket::CreateSocket(GetNode(), tid); 64 | 65 | SetupReceiveSocket(m_recv_socket1, m_port1); 66 | SetupReceiveSocket(m_recv_socket2, m_port2); 67 | 68 | m_recv_socket1->SetRecvCallback(MakeCallback(&SimpleUdpApplication::HandleReadOne, this)); 69 | m_recv_socket2->SetRecvCallback(MakeCallback(&SimpleUdpApplication::HandleReadTwo, this)); 70 | 71 | //Send Socket 72 | m_send_socket = Socket::CreateSocket(GetNode(), tid); 73 | } 74 | 75 | void SimpleUdpApplication::HandleReadOne(Ptr socket) 76 | { 77 | NS_LOG_FUNCTION(this << socket); 78 | Ptr packet; 79 | Address from; 80 | Address localAddress; 81 | while ((packet = socket->RecvFrom(from))) 82 | { 83 | NS_LOG_INFO(TEAL_CODE << "HandleReadOne : Received a Packet of size: " << packet->GetSize() << " at time " << Now().GetSeconds() << END_CODE); 84 | NS_LOG_INFO(packet->ToString()); 85 | } 86 | } 87 | 88 | void SimpleUdpApplication::HandleReadTwo(Ptr socket) 89 | { 90 | NS_LOG_FUNCTION(this << socket); 91 | Ptr packet; 92 | Address from; 93 | Address localAddress; 94 | while ((packet = socket->RecvFrom(from))) 95 | { 96 | NS_LOG_INFO(PURPLE_CODE << "HandleReadTwo : Received a Packet of size: " << packet->GetSize() << " at time " << Now().GetSeconds() << END_CODE); 97 | NS_LOG_INFO("Content: " << packet->ToString()); 98 | } 99 | } 100 | 101 | void SimpleUdpApplication::SendPacket(Ptr packet, Ipv4Address destination, uint16_t port) 102 | { 103 | NS_LOG_FUNCTION (this << packet << destination << port); 104 | m_send_socket->Connect(InetSocketAddress(Ipv4Address::ConvertFrom(destination), port)); 105 | m_send_socket->Send(packet); 106 | } 107 | 108 | } // namespace ns3 109 | -------------------------------------------------------------------------------- /examples/SimpleUdpAppExample/simple-udp-application.h: -------------------------------------------------------------------------------- 1 | #ifndef NS3_UDP_ARQ_APPLICATION_H 2 | #define NS3_UDP_ARQ_APPLICATION_H 3 | #include "ns3/socket.h" 4 | #include "ns3/application.h" 5 | 6 | using namespace ns3; 7 | 8 | namespace ns3 9 | { 10 | class SimpleUdpApplication : public Application 11 | { 12 | public: 13 | SimpleUdpApplication (); 14 | virtual ~SimpleUdpApplication (); 15 | 16 | static TypeId GetTypeId (); 17 | virtual TypeId GetInstanceTypeId () const; 18 | 19 | /** \brief handles incoming packets on port 7777 20 | */ 21 | void HandleReadOne (Ptr socket); 22 | 23 | /** \brief handles incoming packets on port 9999 24 | */ 25 | void HandleReadTwo (Ptr socket); 26 | 27 | /** \brief Send an outgoing packet. This creates a new socket every time (not the best solution) 28 | */ 29 | void SendPacket (Ptr packet, Ipv4Address destination, uint16_t port); 30 | 31 | private: 32 | 33 | 34 | void SetupReceiveSocket (Ptr socket, uint16_t port); 35 | virtual void StartApplication (); 36 | 37 | 38 | Ptr m_recv_socket1; /**< A socket to receive on a specific port */ 39 | Ptr m_recv_socket2; /**< A socket to receive on a specific port */ 40 | uint16_t m_port1; 41 | uint16_t m_port2; 42 | 43 | Ptr m_send_socket; /**< A socket to listen on a specific port */ 44 | }; 45 | } 46 | 47 | #endif -------------------------------------------------------------------------------- /examples/SimpleUdpAppExample/udp-socket-example.cc: -------------------------------------------------------------------------------- 1 | #include "ns3/core-module.h" 2 | #include "ns3/network-module.h" 3 | #include "ns3/applications-module.h" 4 | #include "ns3/internet-module.h" 5 | #include "ns3/csma-module.h" 6 | #include "simple-udp-application.h" 7 | 8 | using namespace ns3; 9 | 10 | /** 11 | This example illustrates the use of SimpleUdpApplication. It should work regardless of the device you have. 12 | */ 13 | 14 | int main (int argc, char *argv[]) 15 | { 16 | CommandLine cmd; 17 | cmd.Parse (argc, argv); 18 | 19 | NodeContainer nodes; 20 | nodes.Create (4); 21 | 22 | CsmaHelper csma; 23 | csma.SetChannelAttribute ("DataRate", StringValue ("1Gbps")); 24 | csma.SetChannelAttribute ("Delay", TimeValue (NanoSeconds(6560))); 25 | 26 | NetDeviceContainer csmaDevs; 27 | csmaDevs = csma.Install (nodes); 28 | csma.EnableAsciiAll("simple-udp"); 29 | 30 | InternetStackHelper stack; 31 | stack.Install (nodes); 32 | 33 | Ipv4AddressHelper address; 34 | address.SetBase ("10.1.1.0", "255.255.255.0"); 35 | Ipv4InterfaceContainer ifaces; 36 | ifaces = address.Assign (csmaDevs); 37 | 38 | Ipv4GlobalRoutingHelper::PopulateRoutingTables (); 39 | Packet::EnablePrinting (); 40 | 41 | //Create our Two UDP applications 42 | Ptr udp0 = CreateObject (); 43 | Ptr udp1 = CreateObject (); 44 | 45 | //Set the start & stop times 46 | udp0->SetStartTime (Seconds(0)); 47 | udp0->SetStopTime (Seconds (10)); 48 | udp1->SetStartTime (Seconds(0)); 49 | udp1->SetStopTime (Seconds (10)); 50 | 51 | //install one application at node 0, and the other at node 1 52 | nodes.Get(0)->AddApplication (udp0); 53 | nodes.Get(1)->AddApplication (udp1); 54 | 55 | //This is the IP address of node 1 56 | Ipv4Address dest_ip ("10.1.1.2"); 57 | 58 | //Schedule an event to send a packet of size 400 using udp0 targeting IP of node 0, and port 7777 59 | Ptr packet1 = Create (400); 60 | Simulator::Schedule (Seconds (1), &SimpleUdpApplication::SendPacket, udp0, packet1, dest_ip, 7777); 61 | //Another packet of size 800, targeting the same IP address, but a different port. 62 | Ptr packet2 = Create (800); 63 | Simulator::Schedule (Seconds (2), &SimpleUdpApplication::SendPacket, udp0, packet2, dest_ip, 9999); 64 | 65 | LogComponentEnable ("SimpleUdpApplication", LOG_LEVEL_INFO); 66 | 67 | Simulator::Stop (Seconds (10)); 68 | Simulator::Run (); 69 | Simulator::Destroy (); 70 | 71 | } -------------------------------------------------------------------------------- /examples/ThreeRouters/three-routers-example.cc: -------------------------------------------------------------------------------- 1 | #include "ns3/core-module.h" 2 | #include "ns3/network-module.h" 3 | #include "ns3/csma-module.h" 4 | #include "ns3/internet-module.h" 5 | #include "ns3/point-to-point-module.h" 6 | #include "ns3/applications-module.h" 7 | #include "ns3/ipv4-global-routing-helper.h" 8 | 9 | using namespace ns3; 10 | 11 | //For colorful console printing 12 | /* 13 | * Usage example : 14 | * std::cout << BOLD_CODE << "some bold text << END_CODE << std::endl; 15 | * 16 | * std::cout << YELLOW_CODE << BOLD_CODE << "some bold yellow text << END_CODE << std::endl; 17 | * 18 | */ 19 | #define YELLOW_CODE "\033[33m" 20 | #define TEAL_CODE "\033[36m" 21 | #define BOLD_CODE "\033[1m" 22 | #define RED_CODE "\033[91m" 23 | #define END_CODE "\033[0m" 24 | 25 | uint32_t total_client_tx = 0; 26 | uint32_t total_client_rx = 0; 27 | uint32_t total_server_tx = 0; 28 | uint32_t total_server_rx = 0; 29 | 30 | void 31 | CheckQueueSize (std::string context, uint32_t before, uint32_t after) 32 | { 33 | std::cout << YELLOW_CODE << context << END_CODE << std::endl; 34 | std::cout << "\tTxQueue Size = " << after << std::endl; 35 | } 36 | 37 | void 38 | BackoffTrace (std::string context, Ptr packet) 39 | { 40 | std::cout << YELLOW_CODE << context << END_CODE << std::endl; 41 | EthernetHeader hdr; 42 | if (packet->PeekHeader (hdr)) 43 | { 44 | std::cout << "\t" << Now() << " Packet from " << hdr.GetSource () << " to " << hdr.GetDestination () << " is experiencing backoff" << std::endl; 45 | } 46 | } 47 | 48 | void ClientTx (std::string context, Ptr packet) 49 | { 50 | total_client_tx++; 51 | } 52 | void ClientRx (std::string context, Ptr packet) 53 | { 54 | total_client_rx++; 55 | } 56 | void ServerTx (std::string context, Ptr packet) 57 | { 58 | total_server_tx++; 59 | } 60 | void ServerRx (std::string context, Ptr packet) 61 | { 62 | total_server_rx++; 63 | } 64 | 65 | int 66 | main (int argc, char *argv[]) 67 | { 68 | CommandLine cmd; 69 | 70 | uint32_t n1 = 4; 71 | uint32_t n2 = 4; 72 | 73 | cmd.AddValue ("n1", "Number of LAN 1 nodes", n1); 74 | cmd.AddValue ("n2", "Number of LAN 2 nodes", n2); 75 | 76 | cmd.Parse (argc, argv); 77 | 78 | //LogComponentEnable("UdpEchoClientApplication", LOG_LEVEL_INFO); 79 | //LogComponentEnable("UdpEchoServerApplication", LOG_LEVEL_INFO); 80 | 81 | //For the first network 82 | NodeContainer lan1_nodes; 83 | 84 | //For the second network 85 | NodeContainer lan2_nodes; 86 | 87 | //for the nodes in the middle. 88 | NodeContainer router_nodes; 89 | 90 | lan1_nodes.Create (n1); 91 | lan2_nodes.Create (n2); 92 | router_nodes.Create (3); 93 | 94 | //Let's create LAN 1 by attaching a CsmaNetDevice to all the nodes on the LAN 95 | CsmaHelper csma1; 96 | csma1.SetChannelAttribute ("DataRate", StringValue ("100Mbps")); 97 | csma1.SetChannelAttribute ("Delay", TimeValue (NanoSeconds (6560))); 98 | //Router 1 is accessible on LAN 1, so we add it to the list nodes. 99 | lan1_nodes.Add (router_nodes.Get (0)); 100 | //Actually attaching CsmaNetDevice to all LAN 1 nodes. 101 | NetDeviceContainer lan1Devices; 102 | lan1Devices = csma1.Install (lan1_nodes); 103 | 104 | //Doing the same for LAN 2 105 | CsmaHelper csma2; 106 | csma2.SetChannelAttribute ("DataRate", StringValue ("100Mbps")); 107 | csma2.SetChannelAttribute ("Delay", TimeValue (NanoSeconds (6560))); 108 | //Router 2 is on LAN 2, so we add it to the node container 109 | lan2_nodes.Add (router_nodes.Get (1)); 110 | 111 | NetDeviceContainer lan2Devices; 112 | lan2Devices = csma2.Install (lan2_nodes); 113 | 114 | /* So far our two LANs are disjoint, r1 and r2 need to be connected */ 115 | //A PointToPoint connection between the two routers 116 | PointToPointHelper pointToPoint; 117 | pointToPoint.SetDeviceAttribute ("DataRate", StringValue ("10Mbps")); 118 | pointToPoint.SetChannelAttribute ("Delay", StringValue ("2ms")); 119 | 120 | NetDeviceContainer firstHopLinkDevs; 121 | firstHopLinkDevs = pointToPoint.Install (router_nodes.Get(0), router_nodes.Get(2)); 122 | 123 | //routerDevices = 124 | NetDeviceContainer secondHopLinkDevs; 125 | secondHopLinkDevs = pointToPoint.Install (router_nodes.Get(2), router_nodes.Get(1)); 126 | 127 | 128 | //Setting IP addresses. Notice that router 1 & 2 are in LAN 1 & 2 respectively. 129 | InternetStackHelper stack; 130 | stack.Install (lan1_nodes); 131 | stack.Install (lan2_nodes); 132 | stack.Install (router_nodes.Get(2)); 133 | Ipv4AddressHelper address; 134 | //For LAN 1 135 | address.SetBase ("10.1.1.0", "255.255.255.0"); 136 | Ipv4InterfaceContainer lan1interfaces; 137 | lan1interfaces = address.Assign (lan1Devices); 138 | //For LAN 2 139 | address.SetBase ("10.1.2.0", "255.255.255.0"); 140 | Ipv4InterfaceContainer lan2interfaces; 141 | lan2interfaces = address.Assign (lan2Devices); 142 | //For PointToPoint 143 | address.SetBase ("10.1.100.0", "255.255.255.0"); 144 | Ipv4InterfaceContainer routerInterfaces; 145 | routerInterfaces = address.Assign (firstHopLinkDevs); 146 | 147 | address.SetBase ("10.1.200.0", "255.255.255.0"); 148 | Ipv4InterfaceContainer routerInterfaces2; 149 | routerInterfaces = address.Assign (secondHopLinkDevs); 150 | 151 | //Let's install a UdpEchoServer on all nodes of LAN2 152 | UdpEchoServerHelper echoServer (9); 153 | ApplicationContainer serverApps = echoServer.Install (lan2_nodes); 154 | serverApps.Start (Seconds (0)); 155 | serverApps.Stop (Seconds (10)); 156 | 157 | //Let's create UdpEchoClients in all LAN1 nodes. 158 | UdpEchoClientHelper echoClient (lan2interfaces.GetAddress (0), 9); 159 | echoClient.SetAttribute ("MaxPackets", UintegerValue (100)); 160 | echoClient.SetAttribute ("Interval", TimeValue (MilliSeconds (200))); 161 | echoClient.SetAttribute ("PacketSize", UintegerValue (1024)); 162 | 163 | //We'll install UdpEchoClient on two nodes in lan1 nodes 164 | NodeContainer clientNodes (lan1_nodes.Get(0), lan1_nodes.Get(1)); 165 | 166 | ApplicationContainer clientApps = echoClient.Install (clientNodes); 167 | clientApps.Start (Seconds (1)); 168 | clientApps.Stop (Seconds (10)); 169 | 170 | //For routers to be able to forward packets, they need to have routing rules. 171 | Ipv4GlobalRoutingHelper::PopulateRoutingTables (); 172 | 173 | csma1.EnablePcap("lan1", lan1Devices); 174 | csma2.EnablePcap("lan2", lan2Devices); 175 | pointToPoint.EnablePcapAll("routers"); 176 | pointToPoint.EnableAscii("ascii-p2p", router_nodes); 177 | 178 | //Config::Connect("/NodeList/*/DeviceList/*/$ns3::PointToPointNetDevice/TxQueue/PacketsInQueue", MakeCallback(&CheckQueueSize)); 179 | //Config::Connect("/NodeList/*/DeviceList/*/$ns3::CsmaNetDevice/TxQueue/PacketsInQueue", MakeCallback(&CheckQueueSize)); 180 | 181 | 182 | Config::Connect("/NodeList/*/DeviceList/*/$ns3::CsmaNetDevice/MacTxBackoff", MakeCallback(&BackoffTrace)); 183 | 184 | Config::Connect("/NodeList/*/ApplicationList/*/$ns3::UdpEchoClient/Tx", MakeCallback(&ClientTx)); 185 | Config::Connect("/NodeList/*/ApplicationList/*/$ns3::UdpEchoClient/Rx", MakeCallback(&ClientRx)); 186 | //Config::Connect("/NodeList/*/ApplicationList/*/$ns3::UdpEchoServer/Tx", MakeCallback(&ServerTx)); 187 | Config::Connect("/NodeList/*/ApplicationList/*/$ns3::UdpEchoServer/Rx", MakeCallback(&ServerRx)); 188 | 189 | 190 | 191 | Simulator::Stop (Seconds (20)); 192 | Simulator::Run (); 193 | 194 | std::cout << "Client Tx: " << total_client_tx << "\tClient Rx: " << total_client_rx << std::endl; 195 | std::cout << "Server Rx: " << total_server_rx << std::endl; 196 | 197 | Simulator::Destroy (); 198 | return 0; 199 | 200 | } -------------------------------------------------------------------------------- /examples/TutorialLesson/tutorial-lesson.cc: -------------------------------------------------------------------------------- 1 | #include "ns3/core-module.h" 2 | #include "ns3/network-module.h" 3 | #include "ns3/csma-module.h" 4 | #include "ns3/internet-module.h" 5 | #include "ns3/point-to-point-module.h" 6 | #include "ns3/applications-module.h" 7 | #include "ns3/ipv4-global-routing-helper.h" 8 | 9 | using namespace ns3; 10 | 11 | //For colorful console printing 12 | /* 13 | * Usage example : 14 | * std::cout << BOLD_CODE << "some bold text << END_CODE << std::endl; 15 | * 16 | * std::cout << YELLOW_CODE << BOLD_CODE << "some bold yellow text << END_CODE << std::endl; 17 | * 18 | */ 19 | #define YELLOW_CODE "\033[33m" 20 | #define TEAL_CODE "\033[36m" 21 | #define BOLD_CODE "\033[1m" 22 | #define RED_CODE "\033[91m" 23 | #define END_CODE "\033[0m" 24 | 25 | uint32_t total_client_tx = 0; 26 | uint32_t total_client_rx = 0; 27 | uint32_t total_server_tx = 0; 28 | uint32_t total_server_rx = 0; 29 | 30 | void 31 | CheckQueueSize (std::string context, uint32_t before, uint32_t after) 32 | { 33 | std::cout << YELLOW_CODE << context << END_CODE << std::endl; 34 | std::cout << "\tTxQueue Size = " << after << std::endl; 35 | } 36 | 37 | void 38 | BackoffTrace (std::string context, Ptr packet) 39 | { 40 | std::cout << YELLOW_CODE << context << END_CODE << std::endl; 41 | EthernetHeader hdr; 42 | if (packet->PeekHeader (hdr)) 43 | { 44 | std::cout << "\t" << Now() << " Packet from " << hdr.GetSource () << " to " << hdr.GetDestination () << " is experiencing backoff" << std::endl; 45 | } 46 | } 47 | 48 | void ClientTx (std::string context, Ptr packet) 49 | { 50 | total_client_tx++; 51 | } 52 | void ClientRx (std::string context, Ptr packet) 53 | { 54 | total_client_rx++; 55 | } 56 | void ServerTx (std::string context, Ptr packet) 57 | { 58 | total_server_tx++; 59 | } 60 | void ServerRx (std::string context, Ptr packet) 61 | { 62 | total_server_rx++; 63 | } 64 | 65 | int 66 | main (int argc, char *argv[]) 67 | { 68 | CommandLine cmd; 69 | 70 | uint32_t n1 = 4; 71 | uint32_t n2 = 4; 72 | 73 | cmd.AddValue ("n1", "Number of LAN 1 nodes", n1); 74 | cmd.AddValue ("n2", "Number of LAN 2 nodes", n2); 75 | 76 | cmd.Parse (argc, argv); 77 | 78 | //LogComponentEnable("UdpEchoClientApplication", LOG_LEVEL_INFO); 79 | //LogComponentEnable("UdpEchoServerApplication", LOG_LEVEL_INFO); 80 | 81 | //For the first network 82 | NodeContainer lan1_nodes; 83 | 84 | //For the second network 85 | NodeContainer lan2_nodes; 86 | 87 | //for the nodes in the middle. 88 | NodeContainer router_nodes; 89 | 90 | lan1_nodes.Create (n1); 91 | lan2_nodes.Create (n2); 92 | router_nodes.Create (2); 93 | 94 | //Let's create LAN 1 by attaching a CsmaNetDevice to all the nodes on the LAN 95 | CsmaHelper csma1; 96 | csma1.SetChannelAttribute ("DataRate", StringValue ("100Mbps")); 97 | csma1.SetChannelAttribute ("Delay", TimeValue (NanoSeconds (6560))); 98 | //Router 1 is accessible on LAN 1, so we add it to the list nodes. 99 | lan1_nodes.Add (router_nodes.Get (0)); 100 | //Actually attaching CsmaNetDevice to all LAN 1 nodes. 101 | NetDeviceContainer lan1Devices; 102 | lan1Devices = csma1.Install (lan1_nodes); 103 | 104 | //Doing the same for LAN 2 105 | CsmaHelper csma2; 106 | csma2.SetChannelAttribute ("DataRate", StringValue ("100Mbps")); 107 | csma2.SetChannelAttribute ("Delay", TimeValue (NanoSeconds (6560))); 108 | //Router 2 is on LAN 2, so we add it to the node container 109 | lan2_nodes.Add (router_nodes.Get (1)); 110 | 111 | NetDeviceContainer lan2Devices; 112 | lan2Devices = csma2.Install (lan2_nodes); 113 | 114 | /* So far our two LANs are disjoint, r1 and r2 need to be connected */ 115 | //A PointToPoint connection between the two routers 116 | PointToPointHelper pointToPoint; 117 | pointToPoint.SetDeviceAttribute ("DataRate", StringValue ("10Mbps")); 118 | pointToPoint.SetChannelAttribute ("Delay", StringValue ("2ms")); 119 | 120 | NetDeviceContainer routerDevices; 121 | routerDevices = pointToPoint.Install (router_nodes); 122 | 123 | //Setting IP addresses. Notice that router 1 & 2 are in LAN 1 & 2 respectively. 124 | InternetStackHelper stack; 125 | stack.Install (lan1_nodes); 126 | stack.Install (lan2_nodes); 127 | 128 | Ipv4AddressHelper address; 129 | //For LAN 1 130 | address.SetBase ("10.1.1.0", "255.255.255.0"); 131 | Ipv4InterfaceContainer lan1interfaces; 132 | lan1interfaces = address.Assign (lan1Devices); 133 | //For LAN 2 134 | address.SetBase ("10.1.2.0", "255.255.255.0"); 135 | Ipv4InterfaceContainer lan2interfaces; 136 | lan2interfaces = address.Assign (lan2Devices); 137 | //For PointToPoint 138 | address.SetBase ("10.1.100.0", "255.255.255.0"); 139 | Ipv4InterfaceContainer routerInterfaces; 140 | routerInterfaces = address.Assign (routerDevices); 141 | 142 | //Let's install a UdpEchoServer on all nodes of LAN2 143 | UdpEchoServerHelper echoServer (9); 144 | ApplicationContainer serverApps = echoServer.Install (lan2_nodes); 145 | serverApps.Start (Seconds (0)); 146 | serverApps.Stop (Seconds (10)); 147 | 148 | //Let's create UdpEchoClients in all LAN1 nodes. 149 | UdpEchoClientHelper echoClient (lan2interfaces.GetAddress (0), 9); 150 | echoClient.SetAttribute ("MaxPackets", UintegerValue (100)); 151 | echoClient.SetAttribute ("Interval", TimeValue (MilliSeconds (200))); 152 | echoClient.SetAttribute ("PacketSize", UintegerValue (1024)); 153 | 154 | //We'll install UdpEchoClient on two nodes in lan1 nodes 155 | NodeContainer clientNodes (lan1_nodes.Get(0), lan1_nodes.Get(1)); 156 | 157 | ApplicationContainer clientApps = echoClient.Install (clientNodes); 158 | clientApps.Start (Seconds (1)); 159 | clientApps.Stop (Seconds (10)); 160 | 161 | //For routers to be able to forward packets, they need to have routing rules. 162 | Ipv4GlobalRoutingHelper::PopulateRoutingTables (); 163 | 164 | csma1.EnablePcap("lan1", lan1Devices); 165 | csma2.EnablePcap("lan2", lan2Devices); 166 | pointToPoint.EnablePcapAll("routers"); 167 | pointToPoint.EnableAscii("ascii-p2p", router_nodes); 168 | 169 | //Config::Connect("/NodeList/*/DeviceList/*/$ns3::PointToPointNetDevice/TxQueue/PacketsInQueue", MakeCallback(&CheckQueueSize)); 170 | //Config::Connect("/NodeList/*/DeviceList/*/$ns3::CsmaNetDevice/TxQueue/PacketsInQueue", MakeCallback(&CheckQueueSize)); 171 | 172 | 173 | Config::Connect("/NodeList/*/DeviceList/*/$ns3::CsmaNetDevice/MacTxBackoff", MakeCallback(&BackoffTrace)); 174 | 175 | Config::Connect("/NodeList/*/ApplicationList/*/$ns3::UdpEchoClient/Tx", MakeCallback(&ClientTx)); 176 | Config::Connect("/NodeList/*/ApplicationList/*/$ns3::UdpEchoClient/Rx", MakeCallback(&ClientRx)); 177 | //Config::Connect("/NodeList/*/ApplicationList/*/$ns3::UdpEchoServer/Tx", MakeCallback(&ServerTx)); 178 | Config::Connect("/NodeList/*/ApplicationList/*/$ns3::UdpEchoServer/Rx", MakeCallback(&ServerRx)); 179 | 180 | 181 | 182 | Simulator::Stop (Seconds (20)); 183 | Simulator::Run (); 184 | 185 | std::cout << "Client Tx: " << total_client_tx << "\tClient Rx: " << total_client_rx << std::endl; 186 | std::cout << "Server Rx: " << total_server_rx << std::endl; 187 | 188 | Simulator::Destroy (); 189 | return 0; 190 | 191 | } 192 | -------------------------------------------------------------------------------- /examples/WaveTest/wave-test.cc: -------------------------------------------------------------------------------- 1 | #include "ns3/wave-module.h" 2 | #include "ns3/wifi-module.h" 3 | #include "ns3/mobility-module.h" 4 | #include "ns3/core-module.h" 5 | 6 | 7 | //For colorful console printing 8 | /* 9 | * Usage example : 10 | * std::cout << BOLD_CODE << "some bold text << END_CODE << std::endl; 11 | * 12 | * std::cout << YELLOW_CODE << BOLD_CODE << "some bold yellow text << END_CODE << std::endl; 13 | * 14 | */ 15 | #define YELLOW_CODE "\033[33m" 16 | #define TEAL_CODE "\033[36m" 17 | #define BOLD_CODE "\033[1m" 18 | #define END_CODE "\033[0m" 19 | 20 | 21 | using namespace ns3; 22 | 23 | NS_LOG_COMPONENT_DEFINE ("WaveExample1"); 24 | 25 | //Note: this is a promiscuous trace for all packet reception. This is also on physical layer, so packets still have WifiMacHeader 26 | void Rx (std::string context, Ptr packet, uint16_t channelFreqMhz, WifiTxVector txVector,MpduInfo aMpdu, SignalNoiseDbm signalNoise) 27 | { 28 | //context will include info about the source of this event. Use string manipulation if you want to extract info. 29 | std::cout << BOLD_CODE << context << END_CODE << std::endl; 30 | //Print the info. 31 | std::cout << "\tSize=" << packet->GetSize() 32 | << " Freq="< packet, ns3::WifiPhyRxfailureReason reason) 49 | { 50 | std::cout << BOLD_CODE << YELLOW_CODE << "Packet Rx Dropped!" << END_CODE << std::endl; 51 | //From ns-3.30, the reasons are defined in an enum type in ns3::WifiPhy class. 52 | std::cout << " Reason : " << reason << std::endl; 53 | std::cout << context << std::endl; 54 | 55 | WifiMacHeader hdr; 56 | if (packet->PeekHeader(hdr)) 57 | { 58 | 59 | std::cout << " Destination MAC : " << hdr.GetAddr1() << "\tSource MAC : " << hdr.GetAddr2() << "\tSeq No. " << hdr.GetSequenceNumber() << std::endl; 60 | } 61 | } 62 | 63 | //Fired when a packet is Enqueued in MAC 64 | void EnqueueTrace(std::string context, Ptr item) 65 | { 66 | std::cout << TEAL_CODE << "A Packet was enqueued : " << context << END_CODE << std::endl; 67 | 68 | Ptr p = item->GetPacket(); 69 | /* 70 | * Do something with the packet, like attach a tag. ns3 automatically attaches a timestamp for enqueued packets; 71 | */ 72 | 73 | } 74 | //Fired when a packet is Dequeued from MAC layer. A packet is dequeued before it is transmitted. 75 | void DequeueTrace(std::string context, Ptr item) 76 | { 77 | std::cout << TEAL_CODE << "A Packet was dequeued : " << context << END_CODE << std::endl; 78 | 79 | Ptr p = item->GetPacket(); 80 | Time queue_delay = Simulator::Now() - item->GetTimeStamp(); 81 | 82 | //Keep in mind that a packet might get dequeued (dropped_ if it exceeded MaxDelay (default is 500ms) 83 | std::cout << "\tQueuing delay=" << queue_delay << std::endl; 84 | 85 | 86 | } 87 | 88 | int main (int argc, char *argv[]) 89 | { 90 | CommandLine cmd; 91 | 92 | //Number of nodes 93 | uint32_t nNodes = 3; 94 | 95 | cmd.AddValue ("n","Number of nodes", nNodes); 96 | 97 | cmd.Parse (argc, argv); 98 | 99 | 100 | double simTime = 10; 101 | NodeContainer nodes; 102 | nodes.Create(nNodes); 103 | 104 | //Nodes MUST have some sort of mobility because that's needed to compute the received signal strength 105 | MobilityHelper mobility; 106 | Ptr positionAlloc = CreateObject (); 107 | positionAlloc->Add (Vector (0.0, 0.0, 0.0)); 108 | positionAlloc->Add (Vector (5.0, 0.0, 0.0)); 109 | positionAlloc->Add (Vector (5.0, 10.0, 0.0)); 110 | 111 | mobility.SetPositionAllocator (positionAlloc); 112 | mobility.SetMobilityModel ("ns3::ConstantPositionMobilityModel"); 113 | mobility.Install (nodes); 114 | 115 | //I prefer using WaveHelper to create WaveNetDevice 116 | YansWifiChannelHelper waveChannel = YansWifiChannelHelper::Default (); 117 | YansWavePhyHelper wavePhy = YansWavePhyHelper::Default (); 118 | wavePhy.SetChannel (waveChannel.Create ()); 119 | wavePhy.SetPcapDataLinkType (WifiPhyHelper::DLT_IEEE802_11_RADIO); 120 | 121 | /* 122 | * If you create applications that control TxPower, define the low & high end of TxPower. 123 | * This is done by using 'TxInfo' as shown below. 124 | * 33 dBm is the highest allowed for non-government use (as per 802.11-2016 standard, page 3271 125 | * 44.8 dBm is for government use. 126 | * 127 | * Setting them to the same value is the easy way to go. 128 | * I can instead set TxPowerStart to a value lower than 33, but then I need to set the number of levels for each PHY 129 | */ 130 | wavePhy.Set ("TxPowerStart", DoubleValue (8) ); 131 | wavePhy.Set ("TxPowerEnd", DoubleValue (33) ); 132 | 133 | 134 | 135 | QosWaveMacHelper waveMac = QosWaveMacHelper::Default (); 136 | WaveHelper waveHelper = WaveHelper::Default (); 137 | 138 | waveHelper.SetRemoteStationManager ("ns3::ConstantRateWifiManager", 139 | "DataMode", StringValue ("OfdmRate6MbpsBW10MHz" ), 140 | "ControlMode",StringValue ("OfdmRate6MbpsBW10MHz"), 141 | "NonUnicastMode", StringValue ("OfdmRate6MbpsBW10MHz")); 142 | 143 | 144 | NetDeviceContainer devices = waveHelper.Install (wavePhy, waveMac, nodes); 145 | wavePhy.EnablePcap ("WaveTest", devices); 146 | 147 | //prepare a packet with a payload of 500 Bytes. Basically it has zeros in the payload 148 | Ptr packet = Create (1000); 149 | 150 | //destination MAC 151 | Mac48Address dest = Mac48Address::GetBroadcast(); 152 | 153 | /* 154 | * 0x88dc is the ethertype corresponding to WSMP. IPv4's etherType is 0x0800, and IPv6 is 0x86DD 155 | * The standard doesn't allow sending IP packets over CCH channel 156 | */ 157 | uint16_t protocol = 0x88dc; 158 | 159 | //We can also set the transmission parameters at the higher layeres 160 | TxInfo tx; 161 | tx.preamble = WIFI_PREAMBLE_LONG; 162 | //We set the channel on which the packet is sent. The WaveNetDevice must have access to the channel 163 | //CCH is enabled by default. 164 | tx.channelNumber = CCH; 165 | 166 | //We can set per-packet data rate. This packet will have a rate of 12Mbps. 167 | tx.dataRate = WifiMode ("OfdmRate12MbpsBW10MHz"); 168 | 169 | /* 170 | * Set the Access Catogory (AC) of the packet. 171 | * The 802.11e EDCA standard defines 4 AC's named Voice, Video, Best Effort & Background in order of priority. 172 | * The value determines the EdcaQueue in which the packet will be enqueued. 173 | * 174 | * The 'tid' is a value from 0-7 that maps to ACs as follows 175 | * 1 or 2 : Background (Lowest priority) 176 | * 0 or 3 : Best effort 177 | * 4 or 5 : Video 178 | * 6 or 7 : Voice (Highest priority) 179 | */ 180 | tx.priority = 7; //We set the AC to highest priority. We can set this per packet. 181 | 182 | /* 183 | * We can also set TxPower. This maps to the user define TxPowerStart & TxPowerEnd. 184 | * 7 : corresponds to the highest user-defined power (TxPowerEnd). In this code, it's 33 dBm 185 | * 1 : lowest (TxPowerStart). In this code, it's 8.3 dBm 186 | * 187 | * We'll have N equally spaced power levels. 188 | * A value of 8 indicates application don't want to set power or data rate. Values >8 are invalid. 189 | */ 190 | tx.txPowerLevel = 3; //When we define TxPowerStart & TxPowerEnd for a WifiPhy, 7 is correspond to TxPowerEnd, and 1 TxPowerStart, and numbers in between are levels. 191 | 192 | /*************** Sending a packet ***************/ 193 | 194 | /* 195 | * In order to send a packet, we will call SendX function of WaveNetDevice. 196 | */ 197 | 198 | //Get the WaveNetDevice for the first devices, using node 0. 199 | Ptr d0 = devices.Get (0); 200 | Ptr wd0 = DynamicCast (d0); 201 | 202 | /* 203 | * We want to call 204 | * wd0->SendX (packet, destination, protocol, tx); 205 | * By scheduling a simulator event as follows: 206 | */ 207 | Simulator::Schedule ( Seconds (1) , &WaveNetDevice::SendX, wd0, packet, dest, protocol, tx); 208 | 209 | //Let us schedule try to have all three nodes schedule messages for broadcast 210 | for (uint32_t t=0 ; t di = devices.Get (i); 216 | Ptr wdi = DynamicCast (di); 217 | 218 | Ptr packet_i = Create (400); 219 | 220 | Ptr low_priority_packet = Create (250); // A low priority packet 221 | 222 | TxInfo txi; 223 | txi.preamble = WIFI_PREAMBLE_LONG; 224 | txi.channelNumber = CCH; 225 | //We always need to set TxPower to something. Otherwise, default data rate would be used. 226 | txi.txPowerLevel = 3; 227 | switch (i) 228 | { 229 | case 0: 230 | //I am going to make node 0 broadcast at 27Mbps, with priority 5. 231 | txi.dataRate = WifiMode ("OfdmRate27MbpsBW10MHz"); 232 | txi.priority = 5; //check the pcap file for the TID value in the Wifi MAC header 233 | Simulator::Schedule ( Seconds (t) , &WaveNetDevice::SendX, wdi, packet_i, dest, protocol, txi); 234 | //We also are going to schedule another packet with lowest priority 235 | txi.priority = 1; //1 is for BK (Background) priority. 236 | Simulator::Schedule ( Seconds (t) , &WaveNetDevice::SendX, wdi, low_priority_packet, dest, protocol, txi); 237 | 238 | break; 239 | 240 | case 1: 241 | //I am going to set only the data rate for packets sent by node1 242 | txi.dataRate = WifiMode ("OfdmRate9MbpsBW10MHz"); 243 | Simulator::Schedule ( Seconds (t) , &WaveNetDevice::SendX, wdi, packet_i, dest, protocol, txi); 244 | break; 245 | 246 | case 2: 247 | /* I am not going to set data rate for packets out of node 2. 248 | * The data rate will be whatever we used for NonUnicastMode when we set WifiRemoteStationManager 249 | */ 250 | Simulator::Schedule ( Seconds (t) , &WaveNetDevice::SendX, wdi, packet_i, dest, protocol, txi); 251 | break; 252 | } 253 | } 254 | } 255 | /****** Unicast Example *******/ 256 | //Let's send a Unicast packet from n0 to n2 257 | //Get the MAC address of the target node 258 | Ptr d2 = DynamicCast(devices.Get(2)); 259 | Mac48Address target_mac = Mac48Address::ConvertFrom (d2->GetAddress()); 260 | 261 | Ptr unicast_packet = Create (200); 262 | TxInfo tx_u; 263 | /* 264 | * Schedule sending from WaveNetDevice 0. 265 | * Since this is a unicast, the frame will be acknowledged with an acknowledgment frame 266 | */ 267 | Simulator::Schedule ( Seconds(simTime-1) , &WaveNetDevice::SendX, wd0, unicast_packet, target_mac, protocol, tx_u ); 268 | 269 | 270 | 271 | /* Using tracesources to trace some simulation events */ 272 | 273 | /* 274 | * Connecting to a promiscous Rx trace source. This will invoke the 'Rx' function everytime a packet is received. 275 | * 276 | * The MonitorSnifferRx trace is defined in WifiPhy. 277 | */ 278 | Config::Connect("/NodeList/*/DeviceList/*/$ns3::WaveNetDevice/PhyEntities/*/MonitorSnifferRx", MakeCallback (&Rx) ); 279 | 280 | //Set the number of power levels. 281 | Config::Set("/NodeList/*/DeviceList/*/$ns3::WaveNetDevice/PhyEntities/*/TxPowerLevels", ns3::UintegerValue(7)); 282 | 283 | 284 | /* 285 | * What if some packets were dropped due to collision, or whatever? We use this trace to fire RxDrop function 286 | */ 287 | Config::Connect("/NodeList/*/DeviceList/*/$ns3::WaveNetDevice/PhyEntities/*/PhyRxDrop", MakeCallback (&RxDrop) ); 288 | 289 | /* 290 | * We can also trace some MAC layer details 291 | */ 292 | Config::Connect ("/NodeList/*/DeviceList/*/$ns3::WaveNetDevice/MacEntities/*/$ns3::OcbWifiMac/*/Queue/Enqueue", MakeCallback (&EnqueueTrace)); 293 | 294 | Config::Connect ("/NodeList/*/DeviceList/*/$ns3::WaveNetDevice/MacEntities/*/$ns3::OcbWifiMac/*/Queue/Dequeue", MakeCallback (&DequeueTrace)); 295 | 296 | 297 | 298 | Simulator::Stop(Seconds(simTime)); 299 | Simulator::Run(); 300 | Simulator::Destroy(); 301 | 302 | } 303 | -------------------------------------------------------------------------------- /ns3helpers/MyColor.py: -------------------------------------------------------------------------------- 1 | class MyColor: 2 | PURPLE = '\033[95m' 3 | CYAN = '\033[96m' 4 | DARKCYAN = '\033[36m' 5 | BLUE = '\033[94m' 6 | GREEN = '\033[32m' 7 | YELLOW = '\033[33m' 8 | LIGHT_YELLOW = '\033[93m' 9 | RED = '\033[91m' 10 | BOLD = '\033[1m' 11 | ITALICS = '\033[3m' 12 | UNDERLINE = '\033[4m' 13 | END = '\033[0m' 14 | WHITE = '\033[97m' 15 | MAGENTA = '\033[95m' 16 | GREY = '\033[90m' 17 | LIGHT_GREEN = '\033[90m' 18 | BLACK = '\033[90m' 19 | DEFAULT = '\033[99m' 20 | -------------------------------------------------------------------------------- /ns3helpers/README.md: -------------------------------------------------------------------------------- 1 | # **NS3-HelperScripts** 2 | These scripts are written to make the processes of running `ns3` scripts and debugging them much easier. They properly format the `./waf` command-string for passing arguments, using a debugger and `PyViz`. 3 | 4 | I created this because I have multiple `ns3` programs under my `scratch` directory and I always have to remember how to write the name of the program correctly, or how do I run my `ns3` program in a debugger. 5 | 6 | The scripts work by finding the latest modified file under all directories under `scratch` to use the name of the directory, which is the name of the `ns3` program. 7 | 8 | So, if there's a directory under `scratch` named `MyWirelessUDPEchoExample`, it would be run like this: 9 | ``` bash 10 | ./waf --run MyWirelessUDPEchoExample 11 | ``` 12 | I written a script in `run_ns3.py`, in which I can run the latest modified project under `scratch` directory. First, I need to make sure I am in the `ns3` root directory (that's the one from which we run `./waf` commands), then use the full path name tothe `run_ns3.py` script. For example if `run_ns3.py` is stored in `~/UnixScripts/run_ns3.py`, then I run 13 | ``` bash 14 | ~/UnixScripts/run_ns3.py 15 | ``` 16 | Notice that I didn't need to specify the project name. My script looks for the latest modified project under `scratch` 17 | 18 | 19 | ## **Prerequisites** 20 | -------------------- 21 | * These Python scripts were tested with Python 2.7 & 3.6 on Ubuntu 14 to Ubuntu 18 & Mac OS from High Sierra and later. 22 | 23 | * When I first designed this, you needed to to create an environment variable called `$NS3_ROOT_DIR` so that the scripts would only run if your current working directory is `ns3`'s root directory from which you run the `waf` tool. *However*, I updated the scripts so that it checks if your current directory is an `ns3` root directory by checking for the presence of certain files and folders. 24 | 25 | To create environment variables, or add aliases edit the file`./bashrc` on Ubuntu, or `./bash_profile` on Mac OS. I defined an environment variable and aliases for my `ns3` directory as follows: navigate to my `ns3` directory. 26 | ```bash 27 | export $NS3_ROOT_DIR=/home/adil/NS3Work 28 | alias gons='cd $NS3_ROOT_DIR' 29 | ``` 30 | * Under the directory `$NS3_ROOT_DIR/scratch` you *must* only have directories for every project you're working on. The reason for this is the way I designed the code that checks for the latest modified project. It is a file called `sort_dir.py`, and it checks all files in the directory under `scratch` and returns the directory name containing the latest modified project. 31 | 32 | Let us say I have `Project1`, `Project2`, and `Project3`, then content of `scratch` would look like this: 33 | ```bash 34 | ./scratch/ 35 | Project1/ 36 | project1-main.cc 37 | SomeClass.cc 38 | SomeClass.h 39 | Project2/ 40 | project2-main.cc 41 | Project3/ 42 | project3-main.cc 43 | ``` 44 | 45 | * The helper scripts are written in Python in multiple `.py` files. Place all those `.py` files in one directory. On my computer, I created a directory called `~/UnixScripts` for all my helper scripts. 46 | 47 | * Additionally, you may create aliases for each of the scripts. I work mainly with three script files, so I created three aliases 48 | ```bash 49 | export UNIX_SCRIPTS_DIR='~/UnixScripts' 50 | alias r=$UNIX_SCRIPTS_DIR/run_ns3.py 51 | alias dr=$UNIX_SCRIPTS_DIR/debug_ns3.py 52 | alias rv=$UNIX_SCRIPTS_DIR/vis_ns3.py 53 | ``` 54 | * Scripts were tested to be compatible with `Python 2` & `Python 3`. Support for `Python 2` ends in 2020. 55 | 56 | 57 | ## **Helper Scripts Tutorial** 58 | ---- 59 | ### **`run_ns3.py`** 60 | * when you call this program, it will run the latest modified ns3 program under `$NS3_HOME_DIR/scratch` 61 | * To run this script, you need to be in the `ns3` root directory, and you must use the full-path name to the `run_ns3.py` file. 62 | * This program uses `sort_dir.py` to find the most recently modified program. 63 | - The command used to check the latest modified project on Ubuntu is different than the one used on Mac OS. The `sort_dir.py` scripts checks which operating system are you running, and use the proper command. 64 | * If you stored this file at a directory called `~/UnixScripts`, you will call it by running 65 | ```bash 66 | python ~/UnixScripts/run_ns3.py 67 | ``` 68 | * alternatively, you can change the file permission to execute it directly: 69 | ```bash 70 | > chmod 777 ~/scripts/run_ns3.py 71 | > ~/scripts/run_ns3.py 72 | ``` 73 | * I made my life easier by creating an alias to run this program. The alias can be anything you want. I called mine `r` 74 | ```bash 75 | alias r='~/scripts/run_ns3' 76 | ``` 77 | - This allows me to run the latest modified project under `scratch` simply by typing `r` to run the latest modified `ns3` program without parameters. You can choose any alias you want for this. 78 | ```bash 79 | r 80 | ``` 81 | * You can also pass command-line argument to your `ns3` program. You need to create command-line arguments in your `ns3` program using `ns3::CommandLine` interface method. 82 | 83 | Say you have two arguments to pass, `n=10` and `t=60` then you run it as follows: 84 | ```bash 85 | ~/UnixScripts/run_ns3.py --n=10 --t=60 86 | ``` 87 | Or you can simply use the alias you created. 88 | ```bash 89 | r --n=10 --t=60 90 | ``` 91 | If the latest modified project is named `Project2`, then using the scripts that way actually runs the command: 92 | ```bash 93 | ./waf --run "Project2 --n=10 --t=60" 94 | ``` 95 | As you can see, the script gives us a more compact way to write the `run` commands. 96 | ### **`debug_ns3.py`** 97 | * This will run the latest modified `ns3` program under `scratch` directory with a debugger. 98 | 99 | * It will use `gdb` if it was ran on Linux and `lldb` if it was ran on Mac OS. It automatically checks for the operating system. It is done this way because of `gdb` compatibility issues on Mac OS. 100 | 101 | * I suggest creating an alias for this as well, mine is called `dr`, and is created in `~/.bashrc` as follows: 102 | ```bash 103 | alias dr='~/scripts/debug_ns3.py' 104 | ``` 105 | * You can also pass command-line arguments to the `ns3` program just like in `run_ns3.py` example. 106 | 107 | * The command runs differently on Linux & Mac OS. 108 | 109 | - *On Mac OS* if we run the command with parameters `n1=4` and `n2=6` like this: 110 | ```bash 111 | dr --n1=4 --n2=6 112 | ``` 113 | The command translates into the proper way to pass `ns3` program arguments to `lldb` which should match this format: 114 | ```text 115 | ./waf --run Project2 --command-template="lldb %s -- --n1=4 --n2=6" 116 | ``` 117 | - *On Linux* the command translates into the proper format to pass arguments using `gdb` 118 | ```text 119 | ./waf --run TutorialLesson --command-template="gdb --args %s" 120 | ``` 121 | * I also have scripts named `gdb_ns3.py` & `llvm_ns3.py` to force the simulation to run using `gdb` & `lldb` debuggers respectively in case you wanted to do that. 122 | 123 | ### **`vis_ns3.py`** 124 | * If you have set up `ns3` with `PyViz` you may run the latest modified program using this command, which will use the `--vis` option with `ns3`. 125 | * I create an alias for this and call it `rv` as follows: 126 | ```bash 127 | alias rv='~/scripts/vis_ns3.py' 128 | ``` 129 | * You can also pass command-line arguments to the `ns3` program just like in `run_ns3.py` example. 130 | 131 | If I want to run the latest modified project with `PyViz` with command-line arguments --n1=4 --n2=6 132 | ```bash 133 | rv --n1=4 --n2=6 134 | ``` 135 | If the latest modified program is under `scratch/Project2` this translates to the command 136 | ```bash 137 | ./waf --run "TutorialLesson --n1=4 --n2=6" --vis 138 | ``` 139 | 140 | ## **Questions and Corrections?** 141 | ----- 142 | If you have questions, or corrections, or suggestion, contact me at `aalsuha@g.clemson.edu` or `adil.alsuhaim@gmail.com` if I am no longer with Clemson University. -------------------------------------------------------------------------------- /ns3helpers/__pycache__/MyColor.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/addola/NS3-HelperScripts/903809295f93987eb284dc9c762a82ecff012aba/ns3helpers/__pycache__/MyColor.cpython-37.pyc -------------------------------------------------------------------------------- /ns3helpers/__pycache__/sort_dir.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/addola/NS3-HelperScripts/903809295f93987eb284dc9c762a82ecff012aba/ns3helpers/__pycache__/sort_dir.cpython-37.pyc -------------------------------------------------------------------------------- /ns3helpers/debug_ns3.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | #pylint: disable=C0301 3 | 4 | ## @package ns3_debug 5 | # 6 | # The script debug_ns3.py runs the latest modified ns3 script under $NS3_ROOT_DIR/scratch in debug mode. It will automatically detect whether you're working on Ubuntu or Mac OSX and run either gdb or lldb. 7 | # 8 | # You have to be at $NS3_ROOT_DIR to run the script. 9 | # 10 | # You can also pass command line argument. Let's say this script is stored at $SCRIPT_DIR, then you first go to $NS3_ROOT_DIR and run: 11 | # 12 | # $NS3_ROOT_DIR> $SCRIPT_DIR/debug_ns3.py -t=30 -n=5 -i=1 13 | # 14 | # to run the latest modified program under 'scratch' directory. 15 | 16 | import sys 17 | import os 18 | from sys import platform 19 | import sort_dir as sort_dir_obj 20 | 21 | def main(argv): 22 | """ main function 23 | This function requires sort_dir.py to find the latest modified ns3 program under scratch 24 | """ 25 | default_program = sort_dir_obj.get_most_recent() 26 | print ("Debugging NS3 Program : " + default_program) 27 | 28 | # Determine which OS we're running. 29 | # This uses gdb for Ubuntu, and llvm (lldb) for Mac OSX 30 | gdb_args = "gdb --args %s" 31 | lldb_args = "lldb %s" 32 | if platform == "linux" or platform == "linux2": 33 | # linux 34 | debug_args = gdb_args 35 | print ("You are working on Linux") 36 | 37 | elif platform == "darwin": 38 | debug_args = lldb_args 39 | print ("You are working on OSX") 40 | else: 41 | print ("Can't tell what OS are you running. Using GDB") 42 | debug_args = gdb_args 43 | 44 | 45 | pwd = os.getcwd() 46 | mypath = os.getenv('NS3_ROOT_DIR', '~/workarea') 47 | 48 | if not sort_dir_obj.is_ns3_root_dir() : 49 | print ("Error : Make sure you are in the NS3 root directory") 50 | sys.exit(1) 51 | 52 | #./waf --run WaveSandbox --command-template="gdb --args %s --x=20 --y=99" 53 | #./waf --run WaveSandbox --command-template="lldb %s -- --x=20 --y=99" 54 | 55 | #Running debugger with no argument 56 | if len(argv) == 0: 57 | print (pwd + "/waf --run " + default_program + " --command-template=\"" + debug_args+ "\"") 58 | os.system(pwd + "/waf --run " + default_program + " --command-template=\"" + debug_args+ "\"") 59 | else: #Running with gdb and arguments (GDB only for now) 60 | command_string = pwd + "/waf --run " + default_program + " --command-template=\"" + debug_args 61 | 62 | if debug_args == gdb_args: 63 | for i in range(0, len(argv)): 64 | command_string = command_string + " " + argv[i] 65 | elif debug_args == lldb_args: 66 | command_string = command_string + " --" 67 | for i in range(0, len(argv)): 68 | command_string = command_string + " " + argv[i] 69 | command_string = command_string + "\"" 70 | 71 | 72 | #command_string = pwd + "/build/scratch/" + default_program + "/" + default_program + " " 73 | #for i in range(0, len(argv)): 74 | # command_string = command_string + " " + argv[i] 75 | #command_string = "gdb --args " + command_string 76 | 77 | print ("Processing Command: " + command_string) 78 | os.system(command_string) 79 | os.environ['NS3_PROGRAM'] = default_program 80 | 81 | 82 | 83 | if __name__ == "__main__": 84 | main(sys.argv[1:]) 85 | -------------------------------------------------------------------------------- /ns3helpers/gdb_ns3.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | #pylint: disable=C0301 3 | 4 | ## @package ns3_gdb 5 | # This scrpits runs ns3 program with gdb, allowing for command line arguments. 6 | # 7 | 8 | import sys 9 | import os 10 | from sys import platform 11 | import sort_dir as sort_dir_obj 12 | 13 | def main(argv): 14 | """ Main Function """ 15 | default_program = sort_dir_obj.get_most_recent() 16 | print ("Explicitly Debugging NS3 Program with GDB : " + default_program) 17 | 18 | # Determine which OS we're running. 19 | # This uses gdb for Ubuntu, and llvm (lldb) for Mac OSX 20 | debug_args = "gdb --args %s" 21 | 22 | pwd = os.getcwd() 23 | mypath = os.getenv('NS3_ROOT_DIR', '~/workarea') 24 | 25 | if not sort_dir_obj.is_ns3_root_dir(): 26 | print ("Error : Make sure you are in the NS3 root directory") 27 | sys.exit(1) 28 | 29 | #if ns3 program was run without arguments 30 | if len(argv) == 0: 31 | print (pwd + "/waf --run " + default_program + " --command-template=\"" + debug_args+ "\"") 32 | os.system(pwd + "/waf --run " + default_program + " --command-template=\"" + debug_args+ "\"") 33 | else: #Running with gdb and arguments (GDB only for now) 34 | command_string = pwd + "/waf --run " + default_program + " --command-template=\"" + debug_args 35 | 36 | for i in range(0, len(argv)): 37 | command_string = command_string + " " + argv[i] 38 | command_string = command_string + "\"" 39 | 40 | print ("Processing Command: " + command_string) 41 | os.system(command_string) 42 | 43 | if __name__ == "__main__": 44 | main(sys.argv[1:]) 45 | -------------------------------------------------------------------------------- /ns3helpers/llvm_ns3.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | #pylint: disable=C0301 3 | ''' 4 | @package ns3_lldb 5 | This scrpits runs ns3 program with lldb, allowing for command line arguments. This is designed to work on Mac OSX 6 | 7 | This is to use directly to force run the ns3 program using lldb specifically. 8 | ''' 9 | 10 | 11 | import sys 12 | import os 13 | from sys import platform 14 | import sort_dir as sort_dir_obj 15 | 16 | def main(argv): 17 | """ Main Function """ 18 | default_program = sort_dir_obj.get_most_recent() 19 | print ("Debugging NS3 Program with LLDB : " + default_program) 20 | 21 | # Determine which OS we're running. 22 | # This uses gdb for Ubuntu, and llvm for Mac OSX 23 | debug_args = "lldb %s" 24 | 25 | pwd = os.getcwd() 26 | mypath = os.getenv('NS3_ROOT_DIR', '~/workarea') 27 | 28 | if not sort_dir_obj.is_ns3_root_dir(): 29 | print ("Error : Make sure you are in the NS3 root directory") 30 | sys.exit(1) 31 | 32 | if len(argv) == 0: 33 | print (pwd + "/waf --run " + default_program + " --command-template=\"" + debug_args+ "\"") 34 | os.system(pwd + "/waf --run " + default_program + " --command-template=\"" + debug_args+ "\"") 35 | else: #Running with gdb and arguments (GDB only for now) 36 | command_string = pwd + "/waf --run " + default_program + " --command-template=\"" + debug_args + " --" 37 | 38 | for i in range(0, len(argv)): 39 | command_string = command_string + " " + argv[i] 40 | command_string = command_string + "\"" 41 | 42 | print ("Processing Command: " + command_string) 43 | os.system(command_string) 44 | 45 | if __name__ == "__main__": 46 | main(sys.argv[1:]) 47 | -------------------------------------------------------------------------------- /ns3helpers/ns3_most_recent.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ''' 3 | Simply prints the most recently modified NS3 project 4 | ''' 5 | import sort_dir as sort_dir_obj 6 | 7 | import sys 8 | import os 9 | import sort_dir as sort_dir_obj 10 | from MyColor import MyColor 11 | 12 | 13 | #Adds Color to the Terminal. 14 | try: 15 | from termcolor import colored 16 | no_color = False 17 | except ImportError: 18 | no_color = True 19 | pass # module doesn't exist, deal with it. 20 | 21 | 22 | def main(argv): 23 | """Main function""" 24 | default_program = sort_dir_obj.get_most_recent() 25 | print(default_program) 26 | 27 | if __name__ == "__main__": 28 | main(sys.argv[1:]) 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /ns3helpers/run_ns3.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ## @package ns3_run 3 | #

Pre-requisites:

4 | # 5 | #
    6 | #
  1. This was tested on Mac OSX (Sierra to Mojave) & Ubuntu 16 to 18 with Python 2 & Python3 installed.
  2. 7 | # 8 | #
  3. You need to defined $NS3_ROOT_DIR as an environment variable so that it points to the ns3 root directory from whhich you run ./waf
  4. 9 | # commands. For example:
    10 | #
    ~/Documents/NS3Download/ns-3.29

    11 | # ns-3.29 has the directories: src, build, etc.. 12 | # 13 | #
  5. Your NS3 program(s) should be in a directory under $NS3_ROOT_DIR/scratch. The name of the directory is the name of your program.
  6. 14 | # 15 | # Make sure that your program have at least one file that has the main function. 16 | # Clarification: 17 | # ns-3.29 > 18 | # scratch > 19 | # > NS3Program1 20 | # > Program.cc (this can have any name, but must have a main function) 21 | # > SomeUserDefinedFile.cc (Optional: if you want some separation of code when you design some C++ classes) 22 | # > SomeUserDefinedFile.h (All these will be compiled when you run ./waf ) 23 | # > NS3Program2 24 | # > main.cc 25 | # 26 | #
  7. All scripts use sort_dir.py to find the last modified project under scratch directory
  8. 27 | # 28 | #
  9. Make sure the python file permission allow "execution".
  10. You can do that by running 29 | # chmod 700 run_ns3.py 30 | # otherwise, you will have to run is by typing: "python run_ns3.py" instead of ./run_ns3.py 31 | #
32 | #

Usage:

33 | #
    34 | #
  • To run the last program you edited & saved under scratch directory simply run: 35 | # path_to_script/run_ns3.py
  • 36 | # 37 | # - You need to be in the NS3 root directory for this to run. 38 | # - You may place these python scripts in any directory. For example, under $NS3_ROOT_DIR/scripts.BaseException 39 | # + To run the last modified program, we type: 40 | # ./scripts/run_ns3.py 41 | # This execuates the following: 42 | # $NS3_ROOT_DIR/ns-3.29/waf --run LastModifiedProgram 43 | # 44 | #
  • You can run it with arguments like:
  • 45 | # ./scripts/run_ns3.py --nCsma=10 --nWifi=10 46 | # which runs 47 | # $NS3_ROOT_DIR/ns-3.29/waf --run LastModifiedProgram "--nCsma=10 --nWifi=10" 48 | # 49 | 50 | import sys 51 | import os 52 | import sort_dir as sort_dir_obj 53 | from MyColor import MyColor 54 | from subprocess import Popen, PIPE, STDOUT 55 | from sys import platform 56 | 57 | #Adds Color to the Terminal. 58 | try: 59 | from termcolor import colored 60 | no_color = False 61 | except ImportError: 62 | no_color = True 63 | pass # module doesn't exist, deal with it. 64 | 65 | print_details = 1 66 | 67 | def do_run_command (cmd_str): 68 | os.system (cmd_str) 69 | 70 | def make_compatible_str(line_input): 71 | ''' 72 | For compatibility with both Python2 and Python3 73 | ''' 74 | if type(line_input) is str: 75 | return line_input #for Python2 76 | elif type(line_input) is bytes: 77 | return line_input.decode() #Python3 78 | 79 | def main(argv): 80 | """Main function""" 81 | #Get the present working directory 82 | pwd = os.getcwd() 83 | #check if NS3_ROOT_DIR is set, otherwise choose ~/workarea as a default directory (will probably be wrong) 84 | mypath = os.getenv('NS3_ROOT_DIR', '~/eclipse-workspace/NS3Work') 85 | ''' 86 | #If you're not at the NS3 root directory, this program stops. 87 | if pwd != mypath: 88 | print (MyColor.RED + MyColor.BOLD + "Error : " +MyColor.END + MyColor.RED + "Make sure you are in the NS3 root directory" + MyColor.END) 89 | exit(1) 90 | 91 | if no_color: 92 | print "Error : Make sure you are in the NS3 root directory" 93 | else: 94 | err_str = 'Error : You need to be in the NS3 Root directory' 95 | sys.exit(colored(err_str, 'red')) 96 | ''' 97 | 98 | #Get the most recent modified program from $NS3_ROOT_DIR/scratch 99 | default_program = sort_dir_obj.get_most_recent() 100 | 101 | 102 | ''' 103 | if no_color: 104 | print "Script is running NS3 program : " + default_program 105 | else: 106 | print colored("Script is running NS3 program : " + default_program, 'green') 107 | ''' 108 | 109 | print (MyColor.GREEN + "Scripts is running ns3 program : " + default_program + MyColor.END) 110 | 111 | #If running without arguments... 112 | if len(argv) == 0: 113 | #Printing the command string so that users can see if they're not running the intended program. 114 | 115 | if print_details: 116 | #print "Program is not supplied with parameters" 117 | print ("Command : " + pwd + "/waf --run " + default_program) 118 | #Run the program! 119 | os.system(pwd + "/waf --run " + default_program) 120 | #Set NS3_PROGRAM to the last executed program (not needed. This should be removed later.) 121 | #os.environ['NS3_PROGRAM'] = default_program 122 | else: 123 | #Program have more than zero arguments, so we go through them in a loop, and use build a command string. 124 | #The default command string with a quotation mark added.. 125 | command_string = pwd + "/waf --run \"" + default_program 126 | 127 | #Looping through Command line arguments 128 | arguments = "" 129 | 130 | for i in range(0, len(argv)): 131 | #add commandline arguments one by one. 132 | arguments = arguments + argv[i] + "\n" 133 | command_string = command_string + " " + argv[i] 134 | 135 | #close the string literal 136 | command_string = command_string + "\"" 137 | 138 | 139 | #Showing command string before executaion. 140 | print ("Command: " + command_string) 141 | #Run it with parameters! 142 | 143 | do_run_command (command_string) 144 | 145 | #TODO : Delete this 146 | #Set NS3_PROGRAM to the last executed program (not needed. This should be removed later.) 147 | #os.environ['NS3_PROGRAM'] = default_program 148 | 149 | if __name__ == "__main__": 150 | main(sys.argv[1:]) 151 | 152 | 153 | -------------------------------------------------------------------------------- /ns3helpers/sort_dir.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | ## 4 | # Provides facilities to run_ns3.py, debug_ns3.py and vis_ns3.py, so it needs to be in the same directory as those scripts.abs 5 | # valgrind_ns3.py is a work-in-progress. 6 | # 7 | # The main purpose of this script is to get the project name of the latest modified project under $NS3_ROOT_DIR 8 | # Tested on OSX Sierra to Mojave , Ubuntu 16/18 9 | # Update: Now compatible with Python 2 & 3. Tested withPython 2.7 and 3.6 10 | # 11 | 12 | import sys 13 | import os 14 | from subprocess import Popen, PIPE, STDOUT 15 | from sys import platform 16 | from MyColor import MyColor 17 | 18 | #Adds Color to the Terminal. 19 | ''' 20 | try: 21 | from termcolor import colored 22 | no_color = False 23 | except ImportError, e: 24 | no_color = True 25 | pass # module doesn't exist, deal with it. 26 | ''' 27 | 28 | print_details = 0 29 | 30 | 31 | 32 | def print_arr(arr): 33 | for mystr in arr: 34 | print (mystr) 35 | if print_details: 36 | print ("-------- END OF PRINT ARR --------") 37 | 38 | 39 | 40 | #Removes directories with .git and and ending with ./scratch 41 | def remove_extras(dirs): 42 | array_size = len(dirs) 43 | 44 | if print_details: 45 | print("array size") 46 | print(array_size) 47 | 48 | ind = 1 49 | new_list = [] 50 | for filename in dirs: 51 | if print_details: 52 | print (str(ind) + " : Examinining : " + filename) 53 | if not (filename.__contains__('/scratch/.') or filename.endswith('./scratch')): 54 | new_list.append(filename) 55 | ind = ind + 1 56 | return new_list 57 | if print_details: 58 | print ("-------- END OF REMOVE EXTRAS --------") 59 | 60 | def is_ns3_root_dir (): 61 | ''' 62 | We will perform 'ls' to see if current working directory is for ns3 installation 63 | ''' 64 | pwd = os.getcwd() 65 | #Check for the presence of these 66 | check_list = ['src', 'waf', 'wscript', 'build', 'scratch', 'contrib', 'build'] 67 | 68 | cmd = 'ls' 69 | my_pipe = Popen(cmd, shell=True, stdin=PIPE, stdout=PIPE, stderr=STDOUT, close_fds=True) 70 | 71 | lines = my_pipe.stdout.readlines() 72 | ls_result = [] 73 | for line in lines: 74 | if type(line) is str: 75 | ls_result.append ( line.rstrip('\n') ) 76 | elif type (line) is bytes: 77 | ls_result.append (line.decode().rstrip('\n')) 78 | 79 | my_pipe.kill() 80 | #For success, the counter has to reach the len (check_list) 81 | success_counter = 0 82 | for f in check_list: # 83 | for rs in ls_result: 84 | if f==rs: 85 | success_counter = success_counter + 1 86 | break 87 | return success_counter == len(check_list) 88 | 89 | def listdir_shell(cmd): 90 | """lists the most recent changed directory under scratch""" 91 | 92 | if print_details: 93 | print ("***** PRINTING *****") 94 | print (cmd) 95 | 96 | my_pipe = Popen(cmd, shell=True, stdin=PIPE, stdout=PIPE, stderr=STDOUT, close_fds=True) 97 | path = os.getcwd() 98 | #return p.stdout.read() 99 | #print ("COMMAND : " + cmd) 100 | dirlist = [] 101 | lines_read = my_pipe.stdout.readlines() 102 | 103 | for path in lines_read: 104 | if type(path) is str: #if using Python2 105 | pass 106 | elif type(path) is bytes: #For Python3 107 | path = path.decode() 108 | 109 | stripped = str(path).rstrip('\n') 110 | dirlist.append(stripped) 111 | 112 | 113 | #dirlist = [path.rstrip('\n') for path in my_pipe.stdout.readlines()] 114 | if print_details: 115 | print ("Head of DIRLIST : ") 116 | print (dirlist[0]) 117 | 118 | if dirlist[-1].__contains__('.git'): 119 | print (MyColor.BOLD + MyColor.YELLOW + "WARNING : ./scratch directory was last modified by git. The last modified project might be incorrect" + MyColor.END +MyColor.END) 120 | 121 | 122 | dirlist = remove_extras(dirlist) 123 | 124 | if print_details: 125 | print ("AFTER REMOVAL") 126 | print_arr(dirlist) 127 | 128 | #print ("DIR LIST IS : ") 129 | #print (dirlist) 130 | 131 | #remove those with .git 132 | 133 | #if ".git" in dirlist[0].split('/'): 134 | #most_recent = os.environ['NS3_PROGRAM'] 135 | #return most_recent 136 | # print (".git was found.") 137 | # print ((dirlist)) 138 | #else: 139 | if len(dirlist) == 0: 140 | print (MyColor.RED + "SCRIPT ERROR : Can not determine which project was most recently modified. Has it been moved or deleted?" + MyColor.END) 141 | sys.exit() 142 | 143 | most_recent = dirlist[-1].split('/') 144 | 145 | if print_details: 146 | print ("MOST RECENTLY MODIFIED PROJECT IS : ") 147 | print(most_recent[2]) 148 | 149 | return most_recent[2] 150 | 151 | 152 | def get_most_recent(): 153 | """returns the most recent project name under scratch""" 154 | mypath = os.getenv('NS3_ROOT_DIR', '~/eclipse-workspace/NS3Work') 155 | 156 | ''' Old code 157 | if os.getcwd() != mypath: 158 | print ("Error : You need to be at the NS3 directory. Check if $NS3_ROOT_DIR is set") 159 | #sys.exit(1) 160 | #os.system("cd " + mypath) 161 | ''' 162 | if not is_ns3_root_dir(): #if this is NOT ns3 root dir, stop! 163 | print ("Error : You need to be at the NS3 directory. The directory '" + os.getcwd()+ "' doesn't seem to be an NS3 directory") 164 | sys.exit(1) 165 | #This command string works on Mac OSX 166 | mac_cmd = "find ./scratch -exec stat -f \"%m %N\" {} \\; | sort -n | tail " 167 | 168 | #this is the older one that automaticly picks the last element. 169 | #mac_cmd = "find ./scratch -exec stat -f \"%m %N\" {} \\; | sort -n | tail -1" 170 | 171 | #This command string works on Ubuntu. 172 | #Old Command: find ./scratch/ -type f -exec stat --format '%Y :%y %n' \"{}\" \; | sort -nr | head 173 | linux_cmd = "find ./scratch/ -type f -exec stat --format '%Y :%y %n' \"{}\" \; | sort -n" 174 | 175 | #Determine if we're running on Mac or Ubuntu 176 | cmd = '' 177 | if platform == "linux" or platform == "linux2": 178 | # linux 179 | cmd = linux_cmd 180 | elif platform == "darwin": 181 | cmd = mac_cmd 182 | else: 183 | print ("Can not tell which OS you are using. Going with Linux command") 184 | cmd = linux_cmd 185 | 186 | #Run the command, and get the more recently modified project. 187 | my_list = listdir_shell(cmd) 188 | 189 | return my_list 190 | 191 | 192 | 193 | def main(argv): 194 | """Main method to test things out""" 195 | print("Tester for scratch directory sorter") 196 | 197 | mac_cmd = "find ./scratch/ -exec stat -f \"%m %N\" {} \\; | sort -n | tail" 198 | linux_cmd = "find ./scratch/ -type f -exec stat --format '%Y :%y %n' \"{}\" \; | sort -n" 199 | 200 | cmd = '' 201 | if platform == "linux" or platform == "linux2": 202 | # linux 203 | cmd = linux_cmd 204 | elif platform == "darwin": 205 | cmd = mac_cmd 206 | else: 207 | print ("Can not tell which OS you are using. Going with Linux command") 208 | cmd = linux_cmd 209 | 210 | #args = "/home/addola/NS3workspace/NS3Work/ns-3.26/scratch -printf '%p\\n' | sort -r | head" 211 | my_list = listdir_shell(cmd) 212 | print("CMD : " + cmd) 213 | print ("List Content is ") 214 | print (my_list) 215 | 216 | is_ns3_root_dir() 217 | 218 | if __name__ == "__main__": 219 | main(sys.argv[1:]) 220 | 221 | -------------------------------------------------------------------------------- /ns3helpers/vis_ns3.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | ''' 4 | Run latest modified program with PyViz. This required PyBindGen support in ns3. 5 | I create an alias "rv" for "run visualized". 6 | ''' 7 | 8 | import sys 9 | import os 10 | import sort_dir as sort_dir_obj 11 | 12 | def main(argv): 13 | """Main function""" 14 | default_program = sort_dir_obj.get_most_recent() 15 | print ("Using PyViz With NS3 Program : " + default_program) 16 | 17 | 18 | pwd = os.getcwd() 19 | mypath = os.getenv('NS3_ROOT_DIR', '~/workarea') 20 | 21 | if not sort_dir_obj.is_ns3_root_dir(): 22 | print ("Error : Make sure you are in the NS3 root directory") 23 | #if pwd != mypath: 24 | # print ("Error : Make sure you are in the NS3 root directory") 25 | # sys.exit(1) 26 | 27 | if len(argv) == 0: 28 | command_string = pwd + "/waf --run " + default_program + " --vis" 29 | print ("Command String: " + command_string ) 30 | os.system(command_string) 31 | else: 32 | command_string = pwd + "/waf --run \"" + default_program 33 | 34 | for i in range(0, len(argv)): 35 | command_string = command_string + " " + argv[i] 36 | command_string = command_string + "\"" + " --vis" 37 | 38 | print ("Command String: " + command_string) 39 | os.system(command_string) 40 | #os.environ['NS3_PROGRAM'] = default_program 41 | 42 | if __name__ == "__main__": 43 | main(sys.argv[1:]) 44 | --------------------------------------------------------------------------------