diff -r 8359b3ac1ab0 src/netanim/helper/animation-interface-helper.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/netanim/helper/animation-interface-helper.cc Thu Jun 09 12:53:37 2011 -0700 @@ -0,0 +1,67 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: John Abraham + */ + +// Animation Interface helpers + +#include "ns3/animation-interface-helper.h" +namespace ns3 { +AnimPacketInfo::AnimPacketInfo() + : m_nd (0), m_nRx (0), m_nDrop (0), m_nRxEnd (0), m_fbTx (0), m_lbTx (0) +{ +} + +AnimPacketInfo::AnimPacketInfo(Ptr nd, uint32_t nRx, + const Time& fbTx, const Time& lbTx) + : m_nd (nd), m_nRx (nRx), m_nDrop (0), m_nRxEnd (0), + m_fbTx (fbTx.GetSeconds ()), m_lbTx (lbTx.GetSeconds ()) +{ +} + +void AnimPacketInfo::AddRxBegin (Ptr nd, const Time& fbRx) +{ + m_rx.push_back (AnimRxInfo (nd, fbRx)); +} + +bool AnimPacketInfo::AddRxEnd (Ptr nd, const Time& lbRx) + +{ + // Find the RxInfo + for (uint32_t i = 0; i < m_rx.size (); ++i) + { + if (m_rx[i].m_nd == nd) + { // Found it + m_rx[i].m_lbRx = lbRx.GetSeconds (); + m_nRxEnd++; + if ((m_nRxEnd + m_nDrop) == m_nRx) return true; // Got them all + return false; // Still more rxEnd expected + } + } + // This should not happen, but if so we just bump the drop count + m_nDrop++; + if ((m_nRxEnd + m_nDrop) == m_nRx) return true; // Got them all + return false; // Still more rxEnd expected + +} + +void AnimPacketInfo::AddRxDrop () +{ + m_nDrop++; +} + + +} // namespace ns3 diff -r 8359b3ac1ab0 src/netanim/helper/animation-interface-helper.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/netanim/helper/animation-interface-helper.h Thu Jun 09 12:53:37 2011 -0700 @@ -0,0 +1,64 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: John Abraham + */ + +// Animation Interface helpers + +#ifndef _ANIMATION_INTERFACE_HELPER_H_ +#define _ANIMATION_INTERFACE_HELPER_H_ + +#include "ns3/node.h" +#include "ns3/mobility-model.h" +#include "ns3/packet.h" +#include "ns3/simulator.h" +#include + + +namespace ns3 { +// We use a PacketInfo structure for wireless traces to keep up +// when each receiver has received packets. Also a PacketRxInfo +// to keep up with each receiver and the time it received the packet +struct AnimRxInfo + +{ + AnimRxInfo(Ptr nd, const Time& fbRx) + : m_nd (nd), m_fbRx (fbRx.GetSeconds ()), m_lbRx (0) {} + Ptr m_nd; // The receiving net device + double m_fbRx; // First bit rx time + double m_lbRx; // Last bit rx time +}; + +struct AnimPacketInfo + +{ + AnimPacketInfo (); + AnimPacketInfo(Ptr nd, uint32_t nRx, + const Time& fbTx, const Time& lbTx); + void AddRxBegin (Ptr nd, const Time& fbRx); + bool AddRxEnd (Ptr nd, const Time& fbRx); + void AddRxDrop (); + Ptr m_nd; + uint32_t m_nRx; // Number of receivers expected + uint32_t m_nDrop; // Number of drops + uint32_t m_nRxEnd; // Number of rxEnd callbacks + double m_fbTx; // Time of first bit tx + double m_lbTx; // Time of first bit tx + std::vector m_rx; +}; +} // namespace ns3 + +#endif diff -r 8359b3ac1ab0 src/netanim/model/animation-interface.cc --- a/src/netanim/model/animation-interface.cc Fri Jun 03 10:54:07 2011 -0700 +++ b/src/netanim/model/animation-interface.cc Thu Jun 09 12:53:37 2011 -0700 @@ -20,6 +20,9 @@ #include #include +#include +#include +#include // Socket related includes #if defined(HAVE_SYS_SOCKET_H) && defined(HAVE_NETINET_IN_H) @@ -37,6 +40,7 @@ #include "ns3/mobility-model.h" #include "ns3/packet.h" #include "ns3/simulator.h" +#include "ns3/animation-interface-helper.h" using namespace std; @@ -45,12 +49,18 @@ namespace ns3 { AnimationInterface::AnimationInterface () - : m_fHandle (STDOUT_FILENO), m_model (0) + : m_fHandle (STDOUT_FILENO), m_xml (false),m_model (0) { } AnimationInterface::~AnimationInterface () { + StopAnimation (); +} + +void AnimationInterface::SetXMLOutput () +{ + m_xml = true; } bool AnimationInterface::SetOutputFile (const std::string& fn) @@ -93,20 +103,74 @@ void AnimationInterface::StartAnimation () { + // Find the min/max x/y for the xml topology element + double minX = 0; + double minY = 0; + double maxX = 0; + double maxY = 0; + bool first = true; + for (NodeList::Iterator i = NodeList::Begin (); i != NodeList::End (); ++i) + { + Ptr n = *i; + Ptr loc = n->GetObject (); + Vector v; + if (!loc) continue; + if (loc) + { + v = loc->GetPosition (); + } + if (first) + { + minX = v.x; + minY = v.y; + maxX = v.x; + maxY = v.y; + first = false; + } + else + { + minX = min (minX, v.x); + minY = min (minY, v.y); + maxX = max (maxX, v.x); + maxY = max (maxY, v.y); + } + } + + if (m_xml) + { // output the xml headers + // Compute width/height, and add a small margin + double w = maxX - minX; + double h = maxY - minY; + minX -= w * 0.05; + minY -= h * 0.05; + maxX = minX + w * 1.10; + maxY = minY + h * 1.10; + ostringstream oss; + oss << GetXMLOpen_anim (0); + oss << GetXMLOpen_topology (minX,minY,maxX,maxY); + WriteN (m_fHandle, oss.str ()); + } // Dump the topology for (NodeList::Iterator i = NodeList::Begin (); i != NodeList::End (); ++i) { Ptr n = *i; Ptr loc = n->GetObject (); - if (loc) + if (!loc) continue; // Can't find a position + ostringstream oss; + if (m_xml) + { + Vector v = loc->GetPosition (); + oss << GetXMLOpenClose_node (0,n->GetId (),v.x,v.y); + } + else { // Location exists, dump it Vector v = loc->GetPosition (); - ostringstream oss; oss << "0.0 N " << n->GetId () << " " << v.x << " " << v.y << endl; - WriteN (m_fHandle, oss.str ().c_str (), oss.str ().length ()); } + + WriteN (m_fHandle, oss.str ().c_str (), oss.str ().length ()); } // Now dump the p2p links for (NodeList::Iterator i = NodeList::Begin (); i != NodeList::End (); ++i) @@ -134,9 +198,16 @@ if (n1Id < n2Id) { // ouptut the p2p link ostringstream oss; - oss << "0.0 L " << n1Id << " " << n2Id << endl; - WriteN (m_fHandle, oss.str ().c_str (), - oss.str ().length ()); + if (m_xml) + { + oss << GetXMLOpenClose_link (0,n1Id,0,n2Id); + } + else + { + oss << "0.0 L " << n1Id << " " << n2Id << endl; + } + WriteN (m_fHandle, oss.str ()); + } } } @@ -146,20 +217,47 @@ } } } + if (m_xml) + { + WriteN (m_fHandle, GetXMLClose ("topology")); + } // Connect the callback for packet tx events Config::Connect ("/ChannelList/*/TxRxPointToPoint", MakeCallback (&AnimationInterface::DevTxTrace, this)); +#if 0 // To be implemented after trace sources are installed + Config::Connect ("NodeList/*/DeviceList/*/$ns3::WifiNetDevice/Phy/PhyTxBegin", + MakeCallback (&AnimationInterface::PhyTxBeginTrace, this)); + Config::Connect ("NodeList/*/DeviceList/*/$ns3::WifiNetDevice/Phy/PhyTxEnd", + MakeCallback (&AnimationInterface::PhyTxEndTrace, this)); + Config::Connect ("NodeList/*/DeviceList/*/$ns3::WifiNetDevice/Phy/PhyRxBegin", + MakeCallback (&AnimationInterface::PhyRxBeginTrace, this)); + Config::Connect ("NodeList/*/DeviceList/*/$ns3::WifiNetDevice/Phy/PhyRxEnd", + MakeCallback (&AnimationInterface::PhyRxEndTrace, this)); + Config::Connect ("NodeList/*/DeviceList/*/$ns3::WifiNetDevice/Phy/PhyRxDrop", + MakeCallback (&AnimationInterface::PhyRxDropTrace, this)); +#endif + } void AnimationInterface::StopAnimation () { if (m_fHandle > 0) { + if (m_xml) + { // Terminate the anim element + WriteN (m_fHandle, GetXMLClose ("anim")); + } close (m_fHandle); + m_fHandle = 0; } } +int AnimationInterface::WriteN (int h, const string& st) +{ + return WriteN (h, st.c_str (), st.length ()); +} + // Private methods int AnimationInterface::WriteN (int h, const char* data, uint32_t count) @@ -167,7 +265,6 @@ uint32_t nLeft = count; const char* p = data; uint32_t written = 0; - while (nLeft) { int n = write (h, p, nLeft); @@ -188,13 +285,192 @@ { Time now = Simulator::Now (); ostringstream oss; - oss << now.GetSeconds () << " P " - << tx->GetNode ()->GetId () << " " - << rx->GetNode ()->GetId () << " " - << (now + txTime).GetSeconds () << " " // last bit tx time - << (now + rxTime - txTime).GetSeconds () << " " // first bit rx time - << (now + rxTime).GetSeconds () << endl; // last bit rx time - WriteN (m_fHandle, oss.str ().c_str (), oss.str ().length ()); + double fbTx = now.GetSeconds (); + double lbTx = (now + txTime).GetSeconds (); + double fbRx = (now + rxTime - txTime).GetSeconds (); + double lbRx = (now + rxTime).GetSeconds (); + if (m_xml) + { + oss << GetXMLOpen_packet (0,tx->GetNode ()->GetId (),fbTx,lbTx); + oss << GetXMLOpenClose_rx (0,rx->GetNode ()->GetId (),fbRx,lbRx); + oss << GetXMLClose ("packet"); + } + else + { + oss << setprecision (10); + oss << now.GetSeconds () << " P " + << tx->GetNode ()->GetId () << " " + << rx->GetNode ()->GetId () << " " + << (now + txTime).GetSeconds () << " " // last bit tx time + << (now + rxTime - txTime).GetSeconds () << " " // first bit rx time + << (now + rxTime).GetSeconds () << endl; // last bit rx time + } + WriteN (m_fHandle, oss.str ()); } + +void AnimationInterface::PhyTxBeginTrace (std::string context, + Ptr p, + Ptr nd, + const Time& txTime, + uint32_t nReceivers) +{ + // Add a new pending wireless + pendingWirelessPackets[p->GetUid ()] = + AnimPacketInfo (nd, nReceivers, Simulator::Now (), Simulator::Now () + txTime); +} + + +void AnimationInterface::PhyTxEndTrace (std::string context, + Ptr p, + Ptr nd) +{ +} + + +void AnimationInterface::PhyRxBeginTrace (std::string context, + Ptr p, + Ptr nd) +{ + pendingWirelessPackets[p->GetUid ()].AddRxBegin (nd, Simulator::Now ()); +} + + +void AnimationInterface::PhyRxEndTrace (std::string context, + Ptr p, + Ptr nd) +{ + + uint32_t uid = p->GetUid (); + AnimPacketInfo& pkt = pendingWirelessPackets[uid]; + if (pkt.AddRxEnd (nd, Simulator::Now ())) + { + //cout << "Packet " << uid << " complete" << endl; + OutputWirelessPacket (uid, pkt); + pendingWirelessPackets.erase (pendingWirelessPackets.find (uid));; + } +} + + +void AnimationInterface::PhyRxDropTrace (std::string context, + Ptr p, + Ptr nd) +{ + pendingWirelessPackets[p->GetUid ()].AddRxDrop (); + +} + +// Helper to output a wireless packet. +// For now, only the XML interface is supported + +void AnimationInterface::OutputWirelessPacket (uint32_t uid, AnimPacketInfo& pktInfo) + +{ + if (!m_xml) return; + ostringstream oss; + uint32_t nodeId = pktInfo.m_nd->GetNode ()->GetId (); + double lbTx = pktInfo.m_lbTx; + +#if 0 // To be tested + + // This is a hack until the notify tx end is working + if (lbTx == 0) + { + if (pktInfo.m_rx.empty ()) + { + lbTx = pktInfo.m_fbTx + 100E-6; // 100 microsec + } + else + { + lbTx = pktInfo.m_fbTx + + pktInfo.m_rx[0].m_lbRx - pktInfo.m_rx[0].m_fbRx; + } + } + +#endif + + // Oops, need to figure out about range + oss << GetXMLOpen_wpacket (0,nodeId,pktInfo.m_fbTx,lbTx,500); + // Now add each rx + for (uint32_t i = 0; i < pktInfo.m_rx.size (); ++i) + { + AnimRxInfo& rx = pktInfo.m_rx[i]; + uint32_t rxId = rx.m_nd->GetNode ()->GetId (); + oss << GetXMLOpenClose_rx (0,rxId,rx.m_fbRx,rx.m_lbRx); + } + oss << GetXMLClose ("wpacket"); + WriteN (m_fHandle, oss.str ()); +} + + +// XML Private Helpers + +std::string AnimationInterface::GetXMLOpen_anim (uint32_t lp) +{ + ostringstream oss; + oss <<"\n"; + return oss.str (); +} +std::string AnimationInterface::GetXMLOpen_topology (double minX,double minY,double maxX,double maxY) +{ + ostringstream oss; + oss <<"" << endl; + return oss.str (); + +} + +std::string AnimationInterface::GetXMLOpenClose_node (uint32_t lp,uint32_t id,double locX,double locY) +{ + ostringstream oss; + oss <<""; + return oss.str (); +} +std::string AnimationInterface::GetXMLOpenClose_link (uint32_t fromLp,uint32_t fromId, uint32_t toLp, uint32_t toId) +{ + ostringstream oss; + oss << "" << endl; + return oss.str (); +} + + +std::string AnimationInterface::GetXMLOpen_packet (uint32_t fromLp,uint32_t fromId, double fbTx, double lbTx) +{ + ostringstream oss; + oss << setprecision (10); + oss << "" << endl; + return oss.str (); +} + +std::string AnimationInterface::GetXMLOpen_wpacket (uint32_t fromLp,uint32_t fromId, double fbTx, double lbTx, double range) +{ + ostringstream oss; + oss << setprecision (10); + oss << "" << endl; + return oss.str (); + +} + +std::string AnimationInterface::GetXMLOpenClose_rx (uint32_t toLp, uint32_t toId, double fbRx, double lbRx) +{ + ostringstream oss; + oss << setprecision (10); + oss << "" << endl; + return oss.str (); +} + + } // namespace ns3 diff -r 8359b3ac1ab0 src/netanim/model/animation-interface.h --- a/src/netanim/model/animation-interface.h Fri Jun 03 10:54:07 2011 -0700 +++ b/src/netanim/model/animation-interface.h Thu Jun 09 12:53:37 2011 -0700 @@ -22,18 +22,21 @@ #define ANIMATION_INTERFACE__H #include - +#include +#include #include "ns3/ptr.h" #include "ns3/net-device.h" #include "ns3/nstime.h" #include "ns3/log.h" #include "ns3/node-list.h" - +#include "ns3/simulator.h" +#include "ns3/config.h" +#include "ns3/animation-interface-helper.h" namespace ns3 { class NetModel; - +//class AnimPacketInfo; /** * \defgroup netanim Netanim * @@ -72,6 +75,15 @@ bool SetOutputFile (const std::string& fn); /** + * @brief Specify that animation commands are to be written + * in XML format. + * + * @returns none + */ + + void SetXMLOutput (); + +/** * @brief Specify that animation commands are to be written to * a socket. * @@ -103,18 +115,55 @@ */ void StopAnimation (); - private: // Packet tx animation callback - void DevTxTrace (std::string context, Ptr p, - Ptr tx, Ptr rx, - Time txTime, Time rxTime); + void DevTxTrace (std::string context, + Ptr p, + Ptr tx, + Ptr rx, + Time txTime, + Time rxTime); + void PhyTxBeginTrace (std::string context, + Ptr p, + Ptr nd, + const Time& txTime, + uint32_t nReceivers); + void PhyTxEndTrace (std::string context, + Ptr p, + Ptr nd); + void PhyRxBeginTrace (std::string context, + Ptr p, + Ptr nd); + void PhyRxEndTrace (std::string context, + Ptr p, + Ptr nd); + void PhyRxDropTrace (std::string context, + Ptr p, + Ptr nd); // Write specified amount of data to the specified handle int WriteN (int, const char*, uint32_t); + // Write a string to the specified handle; + int WriteN (int, const std::string&); + //Helper to output xml wireless packet + void OutputWirelessPacket (uint32_t, AnimPacketInfo&); private: int m_fHandle; // File handle for output (-1 if none) + bool m_xml; // True if xml format desired NetModel* m_model; // If non nil, points to the internal network model // for the interlan animator + std::map pendingWirelessPackets; + +// XML helpers + + std::string GetXMLOpen_anim (uint32_t lp); + std::string GetXMLOpen_topology (double minX,double minY,double maxX,double maxY); + std::string GetXMLOpenClose_node (uint32_t lp,uint32_t id,double locX,double locY); + std::string GetXMLOpenClose_link (uint32_t fromLp,uint32_t fromId, uint32_t toLp, uint32_t toId); + std::string GetXMLOpen_packet (uint32_t fromLp,uint32_t fromId, double fbTx, double lbTx); + std::string GetXMLOpenClose_rx (uint32_t toLp, uint32_t toId, double fbRx, double lbRx); + std::string GetXMLOpen_wpacket (uint32_t fromLp,uint32_t fromId, double fbTx, double lbTx, double range); + std::string GetXMLClose (std::string name) {return "\n"; } + }; } #endif diff -r 8359b3ac1ab0 src/netanim/wscript --- a/src/netanim/wscript Fri Jun 03 10:54:07 2011 -0700 +++ b/src/netanim/wscript Thu Jun 09 12:53:37 2011 -0700 @@ -1,25 +1,27 @@ -## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*- +## -*-Mode : python; py-indent-offset : 4; indent-tabs-mode : nil; coding : utf-8; -*- -def build(bld): - module = bld.create_ns3_module('netanim', ['internet', 'mobility']) +def build (bld) : + module = bld.create_ns3_module ('netanim', ['internet', 'mobility']) module.includes = '.' - module.source = [ - 'model/animation-interface.cc', - ] + module.source = [ + 'model/animation-interface.cc', + 'helper/animation-interface-helper.cc', + ] - headers = bld.new_task_gen('ns3header') + headers = bld.new_task_gen ('ns3header') headers.module = 'netanim' - headers.source = [ - 'model/animation-interface.h', - ] + headers.source = [ + 'model/animation-interface.h', + 'helper/animation-interface-helper.h', + ] - if (bld.env['ENABLE_EXAMPLES']): - bld.add_subdirs('examples') + if (bld.env['ENABLE_EXAMPLES']) : + bld.add_subdirs ('examples') - bld.ns3_python_bindings() + bld.ns3_python_bindings () -def configure(conf): - conf.check(header_name='sys/socket.h', define_name='HAVE_SYS_SOCKET_H') - conf.check(header_name='netinet/in.h', define_name='HAVE_NETINET_IN_H') + def configure (conf) : + conf.check (header_name='sys/socket.h', define_name='HAVE_SYS_SOCKET_H') + conf.check (header_name='netinet/in.h', define_name='HAVE_NETINET_IN_H')