OLD | NEW |
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ | 1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ |
2 /* | 2 /* |
3 * This program is free software; you can redistribute it and/or modify | 3 * This program is free software; you can redistribute it and/or modify |
4 * it under the terms of the GNU General Public License version 2 as | 4 * it under the terms of the GNU General Public License version 2 as |
5 * published by the Free Software Foundation; | 5 * published by the Free Software Foundation; |
6 * | 6 * |
7 * This program is distributed in the hope that it will be useful, | 7 * This program is distributed in the hope that it will be useful, |
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of | 8 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
10 * GNU General Public License for more details. | 10 * GNU General Public License for more details. |
11 * | 11 * |
12 * You should have received a copy of the GNU General Public License | 12 * You should have received a copy of the GNU General Public License |
13 * along with this program; if not, write to the Free Software | 13 * along with this program; if not, write to the Free Software |
14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
15 * | 15 * |
16 * Author: George F. Riley<riley@ece.gatech.edu> | 16 * Author: George F. Riley<riley@ece.gatech.edu> |
17 */ | 17 */ |
18 | 18 |
19 // Interface between ns3 and the network animator | 19 // Interface between ns3 and the network animator |
20 | 20 |
| 21 #include <iomanip> |
21 #include <stdio.h> | 22 #include <stdio.h> |
22 #include <sstream> | 23 #include <sstream> |
| 24 #include <string> |
| 25 #include <map> |
23 | 26 |
24 #include "ns3/net-anim-config.h" | 27 #include "ns3/net-anim-config.h" |
25 | 28 |
26 // Socket related includes | 29 // Socket related includes |
27 #if defined(HAVE_SYS_SOCKET_H) && defined(HAVE_NETINET_IN_H) | 30 #if defined(HAVE_SYS_SOCKET_H) && defined(HAVE_NETINET_IN_H) |
28 #include <sys/socket.h> | 31 #include <sys/socket.h> |
29 #include <netinet/in.h> | 32 #include <netinet/in.h> |
30 #else | 33 #else |
31 #include <fcntl.h> | 34 #include <fcntl.h> |
32 #endif | 35 #endif |
33 | 36 |
34 // ns3 includes | 37 // ns3 includes |
35 #include "ns3/animation-interface.h" | 38 #include "ns3/animation-interface.h" |
36 #include "ns3/channel.h" | 39 #include "ns3/channel.h" |
37 #include "ns3/config.h" | 40 #include "ns3/config.h" |
38 #include "ns3/node.h" | 41 #include "ns3/node.h" |
39 #include "ns3/canvas-location.h" | 42 #include "ns3/canvas-location.h" |
40 #include "ns3/packet.h" | 43 #include "ns3/packet.h" |
41 #include "ns3/simulator.h" | 44 #include "ns3/simulator.h" |
| 45 #include "ns3/mobility-model.h" |
42 | 46 |
43 using namespace std; | 47 using namespace std; |
44 | 48 |
45 NS_LOG_COMPONENT_DEFINE ("AnimationInterface"); | 49 NS_LOG_COMPONENT_DEFINE ("AnimationInterface"); |
46 | 50 |
47 namespace ns3 { | 51 namespace ns3 { |
48 | 52 |
49 AnimationInterface::AnimationInterface () | 53 AnimationInterface::AnimationInterface () |
50 : m_fHandle (STDOUT_FILENO), m_model (0) | 54 : m_fHandle (STDOUT_FILENO), m_xml(false), m_model (0) |
51 { | 55 { |
52 } | 56 } |
53 | 57 |
54 AnimationInterface::~AnimationInterface () | 58 AnimationInterface::~AnimationInterface () |
55 { | 59 { |
| 60 StopAnimation(); |
56 } | 61 } |
57 | 62 |
58 bool AnimationInterface::SetOutputFile (const std::string& fn) | 63 bool AnimationInterface::SetOutputFile (const std::string& fn) |
59 { | 64 { |
60 FILE* f = fopen (fn.c_str (), "w"); | 65 FILE* f = fopen (fn.c_str (), "w"); |
61 if (!f) | 66 if (!f) |
62 { | 67 { |
63 return false; // Can't open | 68 return false; // Can't open |
64 } | 69 } |
65 m_fHandle = fileno (f); // Set the file handle | 70 m_fHandle = fileno (f); // Set the file handle |
66 return true; | 71 return true; |
67 } | 72 } |
68 | 73 |
| 74 void AnimationInterface::SetXMLOutput() |
| 75 { |
| 76 m_xml = true; |
| 77 } |
| 78 ·· |
69 bool AnimationInterface::SetServerPort (uint16_t port) | 79 bool AnimationInterface::SetServerPort (uint16_t port) |
70 { | 80 { |
71 #if defined(HAVE_SYS_SOCKET_H) && defined(HAVE_NETINET_IN_H) | 81 #if defined(HAVE_SYS_SOCKET_H) && defined(HAVE_NETINET_IN_H) |
72 int s = socket (AF_INET, SOCK_STREAM, 0); | 82 int s = socket (AF_INET, SOCK_STREAM, 0); |
73 struct sockaddr_in addr; | 83 struct sockaddr_in addr; |
74 addr.sin_family = AF_INET; | 84 addr.sin_family = AF_INET; |
75 addr.sin_port = htons (port); | 85 addr.sin_port = htons (port); |
76 addr.sin_addr.s_addr = htonl (INADDR_ANY); | 86 addr.sin_addr.s_addr = htonl (INADDR_ANY); |
77 if (bind (s, (struct sockaddr*)&addr, sizeof (addr)) < 0) | 87 if (bind (s, (struct sockaddr*)&addr, sizeof (addr)) < 0) |
78 { | 88 { |
79 NS_LOG_WARN ("Can't bind to port " << port << ", exiting."); | 89 NS_LOG_WARN ("Can't bind to port " << port << ", exiting."); |
80 return false; | 90 return false; |
81 } | 91 } |
82 listen (s, 1); | 92 listen (s, 1); |
83 NS_LOG_INFO ("Waiting for animator connection"); | 93 NS_LOG_INFO ("Waiting for animator connection"); |
84 // Now wait for the animator to connect in | 94 // Now wait for the animator to connect in |
85 m_fHandle = accept (s, 0, 0); | 95 m_fHandle = accept (s, 0, 0); |
86 NS_LOG_INFO ("Got animator connection from remote"); | 96 NS_LOG_INFO ("Got animator connection from remote"); |
87 // set the linger socket option | 97 // set the linger socket option |
88 int t = 1; | 98 int t = 1; |
89 setsockopt (s, SOL_SOCKET, SO_LINGER, &t, sizeof(t)); | 99 setsockopt (s, SOL_SOCKET, SO_LINGER, &t, sizeof(t)); |
90 return true; | 100 return true; |
91 #endif | 101 #endif |
92 return false; // never reached unless the above is disabled | 102 return false; // never reached unless the above is disabled |
93 // which is done to support a platform like MinGW | 103 // which is done to support a platform like MinGW |
94 } | 104 } |
95 | 105 |
96 void AnimationInterface::StartAnimation () | 106 void AnimationInterface::StartAnimation () |
97 { | 107 { |
| 108 // Find the min/max x/y for the xml topology element |
| 109 double minX = 0; |
| 110 double minY = 0; |
| 111 double maxX = 0; |
| 112 double maxY = 0; |
| 113 bool first = true; |
| 114 for (NodeList::Iterator i = NodeList::Begin (); i != NodeList::End (); ++i) |
| 115 { |
| 116 Ptr<Node> n = *i; |
| 117 Ptr<CanvasLocation> loc = n->GetObject<CanvasLocation> (); |
| 118 Ptr<MobilityModel> mobility = 0; |
| 119 Vector v; |
| 120 if (loc) |
| 121 { |
| 122 v = loc->GetLocation(); |
| 123 } |
| 124 else |
| 125 { // No canvas location, try position from mobility model |
| 126 mobility = n->GetObject<MobilityModel>(); |
| 127 if (mobility) v = mobility->GetPosition(); |
| 128 } |
| 129 if (!loc && !mobility) continue; |
| 130 if (first) |
| 131 { |
| 132 minX = v.x; |
| 133 minY = v.y; |
| 134 maxX = v.x; |
| 135 maxY = v.y; |
| 136 first = false; |
| 137 } |
| 138 else |
| 139 { |
| 140 minX = min(minX, v.x); |
| 141 minY = min(minY, v.y); |
| 142 maxX = max(maxX, v.x); |
| 143 maxY = max(maxY, v.y); |
| 144 } |
| 145 } |
| 146 |
| 147 if (m_xml) |
| 148 { // output the xml headers |
| 149 // Compute width/height, and add a small margin |
| 150 double w = maxX - minX; |
| 151 double h = maxY - minY; |
| 152 minX -= w * 0.05; |
| 153 minY -= h * 0.05; |
| 154 maxX = minX + w * 1.10; |
| 155 maxY = minY + h * 1.10; |
| 156 ostringstream oss; |
| 157 oss << "<anim lp = \"0\">" << endl << "<topology"; |
| 158 oss << " minX = \"" << minX << "\" minY = \"" << minY |
| 159 << "\" maxX = \"" << maxX << "\" maxY = \"" << maxY |
| 160 << "\">" << endl; |
| 161 WriteN (m_fHandle, oss.str ()); |
| 162 } |
| 163 ······ |
98 // Dump the topology | 164 // Dump the topology |
99 for (NodeList::Iterator i = NodeList::Begin (); i != NodeList::End (); ++i) | 165 for (NodeList::Iterator i = NodeList::Begin (); i != NodeList::End (); ++i) |
100 { | 166 { |
101 Ptr<Node> n = *i; | 167 Ptr<Node> n = *i; |
102 Ptr<CanvasLocation> loc = n->GetObject<CanvasLocation> (); | 168 Ptr<CanvasLocation> loc = n->GetObject<CanvasLocation> (); |
| 169 Ptr<MobilityModel> mobility = 0; |
| 170 ······ |
| 171 Vector v; |
103 if (loc) | 172 if (loc) |
104 { | 173 { |
105 // Location exists, dump it | 174 v = loc->GetLocation(); |
106 Vector v = loc->GetLocation (); | 175 } |
107 ostringstream oss; | 176 else |
| 177 { // No canvas location, try position from mobility model |
| 178 mobility = n->GetObject<MobilityModel>(); |
| 179 if (mobility) v = mobility->GetPosition(); |
| 180 } |
| 181 if (!loc && !mobility) continue; // Can't find a position |
| 182 // Location exists, dump it |
| 183 ostringstream oss; |
| 184 if (m_xml) |
| 185 { |
| 186 oss << "<node lp = \"0\" id = \"" << n->GetId () |
| 187 << "\" locX = \"" << v.x |
| 188 << "\" locY = \"" << v.y << "\"/>" << endl; |
| 189 } |
| 190 else |
| 191 { |
108 oss << "0.0 N " << n->GetId ()· | 192 oss << "0.0 N " << n->GetId ()· |
109 << " " << v.x << " " << v.y << endl; | 193 << " " << v.x << " " << v.y << endl; |
110 WriteN (m_fHandle, oss.str ().c_str (), oss.str ().length ()); | |
111 } | 194 } |
| 195 WriteN (m_fHandle, oss.str ()); |
112 } | 196 } |
113 // Now dump the p2p links | 197 // Now dump the p2p links |
114 for (NodeList::Iterator i = NodeList::Begin (); i != NodeList::End (); ++i) | 198 for (NodeList::Iterator i = NodeList::Begin (); i != NodeList::End (); ++i) |
115 { | 199 { |
116 Ptr<Node> n = *i; | 200 Ptr<Node> n = *i; |
117 uint32_t n1Id = n->GetId (); | 201 uint32_t n1Id = n->GetId (); |
118 uint32_t nDev = n->GetNDevices (); // Number of devices | 202 uint32_t nDev = n->GetNDevices (); // Number of devices |
119 for (uint32_t i = 0; i < nDev; ++i) | 203 for (uint32_t i = 0; i < nDev; ++i) |
120 { | 204 { |
121 Ptr<NetDevice> dev = n->GetDevice (i); | 205 Ptr<NetDevice> dev = n->GetDevice (i); |
122 Ptr<Channel> ch = dev->GetChannel (); | 206 Ptr<Channel> ch = dev->GetChannel (); |
123 if (!ch)· | 207 if (!ch)· |
124 { | 208 { |
125 continue; // No channel, can't be p2p device | 209 continue; // No channel, can't be p2p device |
126 } | 210 } |
127 string channelType = ch->GetInstanceTypeId ().GetName (); | 211 string channelType = ch->GetInstanceTypeId ().GetName (); |
128 if (channelType == string ("ns3::PointToPointChannel")) | 212 if (channelType == string ("ns3::PointToPointChannel")) |
129 { // Since these are duplex links, we only need to dump | 213 { // Since these are duplex links, we only need to dump |
130 // if srcid < dstid | 214 // if srcid < dstid |
131 uint32_t nChDev = ch->GetNDevices (); | 215 uint32_t nChDev = ch->GetNDevices (); |
132 for (uint32_t j = 0; j < nChDev; ++j) | 216 for (uint32_t j = 0; j < nChDev; ++j) |
133 { | 217 { |
134 Ptr<NetDevice> chDev = ch->GetDevice (j); | 218 Ptr<NetDevice> chDev = ch->GetDevice (j); |
135 uint32_t n2Id = chDev->GetNode ()->GetId (); | 219 uint32_t n2Id = chDev->GetNode ()->GetId (); |
136 if (n1Id < n2Id) | 220 if (n1Id < n2Id) |
137 { // ouptut the p2p link | 221 { // ouptut the p2p link |
138 ostringstream oss; | 222 ostringstream oss; |
139 oss << "0.0 L " << n1Id << " " << n2Id << endl; | 223 if (m_xml) |
140 WriteN (m_fHandle, oss.str ().c_str (), | 224 { |
141 oss.str ().length ()); | 225 oss << "<link fromLP = \"0\" fromId = \"" << n1Id |
| 226 << "\" toLp = \"0\" toId = \"" << n2Id· |
| 227 << "\"/>" << endl; |
| 228 } |
| 229 else |
| 230 { |
| 231 oss << "0.0 L " << n1Id << " " << n2Id << endl; |
| 232 } |
| 233 WriteN (m_fHandle, oss.str ()); |
142 } | 234 } |
143 } | 235 } |
144 } | 236 } |
145 else | |
146 { | |
147 NS_FATAL_ERROR ("Net animation currently only supports point-to-po
int links."); | |
148 } | |
149 } | 237 } |
150 } | 238 } |
151 ·· | 239 if (m_xml) |
| 240 { |
| 241 string endTopo("</topology>\n"); |
| 242 WriteN(m_fHandle, endTopo); |
| 243 } |
152 // Connect the callback for packet tx events | 244 // Connect the callback for packet tx events |
153 Config::Connect ("/ChannelList/*/TxRxPointToPoint", | 245 Config::Connect ("/ChannelList/*/TxRxPointToPoint", |
154 MakeCallback (&AnimationInterface::DevTxTrace, this)); | 246 MakeCallback (&AnimationInterface::DevTxTrace, this)); |
| 247 Config::Connect ("NodeList/*/DeviceList/*/$ns3::WifiNetDevice/Phy/PhyTxBegin", |
| 248 MakeCallback (&AnimationInterface::PhyTxBeginTrace, this)); |
| 249 Config::Connect ("NodeList/*/DeviceList/*/$ns3::WifiNetDevice/Phy/PhyRxBegin", |
| 250 MakeCallback (&AnimationInterface::PhyRxBeginTrace, this)); |
| 251 Config::Connect ("NodeList/*/DeviceList/*/$ns3::WifiNetDevice/Phy/PhyRxEnd", |
| 252 MakeCallback (&AnimationInterface::PhyRxEndTrace, this)); |
| 253 Config::Connect ("NodeList/*/DeviceList/*/$ns3::WifiNetDevice/Phy/PhyRxDrop", |
| 254 MakeCallback (&AnimationInterface::PhyRxDropTrace, this)); |
155 } | 255 } |
156 | 256 |
157 void AnimationInterface::StopAnimation () | 257 void AnimationInterface::StopAnimation () |
158 { | 258 { |
159 if (m_fHandle > 0)· | 259 if (m_fHandle > 0)· |
160 { | 260 { |
| 261 if (m_xml) |
| 262 { // Terminate the anim element |
| 263 string endAnim("</anim>\n"); |
| 264 WriteN (m_fHandle, endAnim); |
| 265 } |
161 close (m_fHandle); | 266 close (m_fHandle); |
| 267 m_fHandle = 0; |
162 } | 268 } |
163 } | 269 } |
164 | 270 |
165 | 271 |
166 // Private methods | 272 // Private methods |
167 int AnimationInterface::WriteN (int h, const char* data, uint32_t count) | 273 int AnimationInterface::WriteN (int h, const char* data, uint32_t count) |
168 { // Write count bytes to h from data | 274 { // Write count bytes to h from data |
169 uint32_t nLeft = count; | 275 uint32_t nLeft = count; |
170 const char* p = data; | 276 const char* p = data; |
171 uint32_t written = 0; | 277 uint32_t written = 0; |
172 | 278 |
173 while (nLeft) | 279 while (nLeft) |
174 { | 280 { |
175 int n = write (h, p, nLeft); | 281 int n = write (h, p, nLeft); |
176 if (n <= 0)· | 282 if (n <= 0)· |
177 { | 283 { |
178 return written; | 284 return written; |
179 } | 285 } |
180 written += n; | 286 written += n; |
181 nLeft -= n; | 287 nLeft -= n; |
182 p += n; | 288 p += n; |
183 } | 289 } |
184 return written; | 290 return written; |
185 } | 291 } |
186 ·· | 292 |
| 293 int AnimationInterface::WriteN(int h, const string& st) |
| 294 { |
| 295 return WriteN(h, st.c_str(), st.length()); |
| 296 } |
| 297 |
| 298 |
| 299 //Trace callbacks |
187 void AnimationInterface::DevTxTrace (std::string context, Ptr<const Packet> p, | 300 void AnimationInterface::DevTxTrace (std::string context, Ptr<const Packet> p, |
188 Ptr<NetDevice> tx, Ptr<NetDevice> rx, | 301 Ptr<NetDevice> tx, Ptr<NetDevice> rx, |
189 Time txTime, Time rxTime) | 302 Time txTime, Time rxTime) |
190 { | 303 { |
191 Time now = Simulator::Now (); | 304 Time now = Simulator::Now (); |
192 ostringstream oss; | 305 ostringstream oss; |
193 oss << now.GetSeconds() << " P " | 306 double fbTx = now.GetSeconds(); |
194 << tx->GetNode ()->GetId () << " " | 307 double lbTx = (now + txTime).GetSeconds(); |
195 << rx->GetNode ()->GetId () << " " | 308 double fbRx = (now + rxTime - txTime).GetSeconds(); |
196 << (now + txTime).GetSeconds () << " " // last bit tx time | 309 double lbRx = (now + rxTime).GetSeconds(); |
197 << (now + rxTime - txTime).GetSeconds() << " " // first bit rx time | 310 ·· |
198 << (now + rxTime).GetSeconds () << endl; // last bit rx time | 311 if (m_xml) |
199 WriteN (m_fHandle, oss.str ().c_str (), oss.str ().length ()); | 312 { |
| 313 oss << setprecision(10); |
| 314 oss << "<packet fromLp = \"0\" fromId = \"" << tx->GetNode()->GetId() |
| 315 << "\" fbTx = \"" << fbTx |
| 316 << "\" lbTx = \"" << lbTx |
| 317 << "\">" << endl; |
| 318 oss << "<rx toLp = \"0\" toId = \"" << rx->GetNode()->GetId() |
| 319 << "\" fbRx = \"" << fbRx |
| 320 << "\" lbRx = \"" << lbRx |
| 321 << "\"/>" << endl; |
| 322 oss << "</packet>" << endl; |
| 323 } |
| 324 else |
| 325 { |
| 326 oss << setprecision(10); |
| 327 oss << now.GetSeconds() << " P " |
| 328 << tx->GetNode ()->GetId () << " " |
| 329 << rx->GetNode ()->GetId () << " " |
| 330 << (now + txTime).GetSeconds () << " " // last bit tx time |
| 331 << (now + rxTime - txTime).GetSeconds() << " " // first bit rx time |
| 332 << (now + rxTime).GetSeconds () << endl; // last bit rx time |
| 333 } |
| 334 WriteN (m_fHandle, oss.str ()); |
| 335 } |
| 336 |
| 337 // We use a PacketInfo structure for wireless traces to keep up |
| 338 // when each receiver has received packets. Also a PacketRxInfo |
| 339 // to keep up with each receiver and the time it received the packet |
| 340 class RxInfo· |
| 341 { |
| 342 public: |
| 343 RxInfo(Ptr<const NetDevice> nd, const Time& fbRx) |
| 344 : m_nd(nd), m_fbRx(fbRx.GetSeconds()), m_lbRx(0) {} |
| 345 ·· |
| 346 public: |
| 347 Ptr<const NetDevice> m_nd; // The receiving net device |
| 348 double m_fbRx; // First bit rx time |
| 349 double m_lbRx; // Last bit rx time |
| 350 }; |
| 351 ···· |
| 352 class PacketInfo |
| 353 { |
| 354 public: |
| 355 PacketInfo(); |
| 356 PacketInfo(Ptr<const NetDevice> nd, uint32_t nRx,· |
| 357 const Time& fbTx, const Time& lbTx); |
| 358 //void AddTxEnd(const Time& lbTx); // Not needed |
| 359 void AddRxBegin(Ptr<const NetDevice> nd, const Time& fbRx); |
| 360 bool AddRxEnd(Ptr<const NetDevice> nd, const Time& fbRx); |
| 361 void AddRxDrop(); |
| 362 public: |
| 363 Ptr<const NetDevice> m_nd; |
| 364 uint32_t m_nRx; // Number of receivers expected |
| 365 uint32_t m_nDrop; // Number of drops |
| 366 uint32_t m_nRxEnd; // Number of rxEnd callbacks |
| 367 double m_fbTx; // Time of first bit tx |
| 368 double m_lbTx; // Time of first bit tx |
| 369 vector<RxInfo> m_rx; |
| 370 }; |
| 371 |
| 372 PacketInfo::PacketInfo() |
| 373 : m_nd(0), m_nRx(0), m_nDrop(0), m_nRxEnd(0), m_fbTx(0), m_lbTx(0) |
| 374 { |
| 375 } |
| 376 |
| 377 PacketInfo::PacketInfo(Ptr<const NetDevice> nd, uint32_t nRx,· |
| 378 const Time& fbTx, const Time& lbTx) |
| 379 : m_nd(nd), m_nRx(nRx), m_nDrop(0), m_nRxEnd(0),· |
| 380 m_fbTx(fbTx.GetSeconds()), m_lbTx(lbTx.GetSeconds()) |
| 381 { |
| 382 } |
| 383 |
| 384 void PacketInfo::AddRxBegin(Ptr<const NetDevice> nd, const Time& fbRx) |
| 385 { |
| 386 m_rx.push_back(RxInfo(nd, fbRx)); |
| 387 } |
| 388 |
| 389 bool PacketInfo::AddRxEnd(Ptr<const NetDevice> nd, const Time& lbRx) |
| 390 { |
| 391 // Find the RxInfo |
| 392 for (uint32_t i = 0; i < m_rx.size(); ++i) |
| 393 { |
| 394 if (m_rx[i].m_nd == nd) |
| 395 { // Found it |
| 396 m_rx[i].m_lbRx = lbRx.GetSeconds(); |
| 397 m_nRxEnd++; |
| 398 if ((m_nRxEnd + m_nDrop) == m_nRx) return true; // Got them all |
| 399 return false; // Still more rxEnd expected |
| 400 } |
| 401 } |
| 402 // This should not happen, but if so we just bump the drop count |
| 403 m_nDrop++; |
| 404 if ((m_nRxEnd + m_nDrop) == m_nRx) return true; // Got them all |
| 405 return false; // Still more rxEnd expected |
| 406 } |
| 407 |
| 408 void PacketInfo::AddRxDrop() |
| 409 { |
| 410 m_nDrop++; |
| 411 } |
| 412 static map<uint32_t, PacketInfo> pendingWirelessPackets; |
| 413 ·· |
| 414 void AnimationInterface::PhyTxBeginTrace (std::string context, |
| 415 Ptr<const Packet> p, |
| 416 Ptr<const NetDevice> nd,· |
| 417 const Time& txTime,· |
| 418 uint32_t nReceivers) |
| 419 { |
| 420 // Add a new pending wireless |
| 421 pendingWirelessPackets[p->GetUid()] =· |
| 422 PacketInfo(nd, nReceivers,· |
| 423 Simulator::Now(), |
| 424 Simulator::Now() + txTime); |
| 425 } |
| 426 |
| 427 void AnimationInterface::PhyRxBeginTrace (std::string context, |
| 428 Ptr<const Packet> p, |
| 429 Ptr<const NetDevice> nd) |
| 430 { |
| 431 pendingWirelessPackets[p->GetUid()].AddRxBegin(nd, Simulator::Now()); |
| 432 } |
| 433 ·· |
| 434 void AnimationInterface::PhyRxEndTrace (std::string context, |
| 435 Ptr<const Packet> p, |
| 436 Ptr<const NetDevice> nd) |
| 437 { |
| 438 uint32_t uid = p->GetUid(); |
| 439 PacketInfo& pkt = pendingWirelessPackets[uid]; |
| 440 if (pkt.AddRxEnd(nd, Simulator::Now())) |
| 441 { |
| 442 OutputWirelessPacket(uid, pkt); |
| 443 pendingWirelessPackets.erase(pendingWirelessPackets.find(uid));; |
| 444 } |
| 445 } |
| 446 ·· |
| 447 void AnimationInterface::PhyRxDropTrace (std::string context, |
| 448 Ptr<const Packet> p, |
| 449 Ptr<const NetDevice> nd) |
| 450 { |
| 451 pendingWirelessPackets[p->GetUid()].AddRxDrop(); |
| 452 } |
| 453 |
| 454 // Helper to output a wireless packet. |
| 455 // For now, only the XML interface is supported |
| 456 void AnimationInterface::OutputWirelessPacket(uint32_t uid, PacketInfo& pktInfo) |
| 457 { |
| 458 if (!m_xml) return; |
| 459 ostringstream oss; |
| 460 uint32_t nodeId = pktInfo.m_nd->GetNode ()->GetId (); |
| 461 double lbTx = pktInfo.m_lbTx; |
| 462 #ifdef REMOVE_LATER |
| 463 // This is a hack until the notify tx end is working |
| 464 if (lbTx == 0) |
| 465 { |
| 466 if (pktInfo.m_rx.empty()) |
| 467 { |
| 468 lbTx = pktInfo.m_fbTx + 100E-6; // 100 microsec |
| 469 } |
| 470 else |
| 471 { |
| 472 lbTx = pktInfo.m_fbTx + |
| 473 pktInfo.m_rx[0].m_lbRx - pktInfo.m_rx[0].m_fbRx; |
| 474 } |
| 475 } |
| 476 #endif |
| 477 // Need to figure out about range |
| 478 oss << setprecision(10); |
| 479 oss << "<wpacket fromLp = \"0\" fromId = \"" << nodeId· |
| 480 << "\" fbTx = \"" << pktInfo.m_fbTx· |
| 481 << "\" lbTx = \"" << lbTx |
| 482 << "\" range = \"500\">" << endl; |
| 483 // Now add each rx |
| 484 for (uint32_t i = 0; i < pktInfo.m_rx.size(); ++i) |
| 485 { |
| 486 RxInfo& rx = pktInfo.m_rx[i]; |
| 487 uint32_t rxId = rx.m_nd->GetNode ()->GetId (); |
| 488 oss << "<rx toLp = \"0\" toId = \"" << rxId |
| 489 << "\" fbRx = \"" << rx.m_fbRx |
| 490 << "\" lbRx = \"" << rx.m_lbRx |
| 491 << "\"/>" << endl; |
| 492 } |
| 493 oss << "</wpacket>" << endl; |
| 494 WriteN (m_fHandle, oss.str ()); |
200 } | 495 } |
201 | 496 |
202 } // namespace ns3 | 497 } // namespace ns3 |
OLD | NEW |