--- a/src/devices/p2p/p2p-channel.cc Thu Jun 14 10:41:47 2007 +0200
+++ b/src/devices/p2p/p2p-channel.cc Fri Jun 15 13:19:57 2007 -0700
@@ -135,14 +135,12 @@
// The sender is going to free the packet as soon as it has been transmitted.
// We need to copy it to get a reference so it won't e deleted.
//
-// Above is not correct (GFR). The event scheduler makes a copy
-// of the packet
-// Packet packet = p;
+ Packet packet = p;
NS_DEBUG ("PointToPointChannel::TransmitEnd (): Schedule event in " <<
m_delay.GetSeconds () << "sec");
Simulator::Schedule (m_delay,
&PointToPointChannel::PropagationCompleteEvent,
- this, p, src);
+ this, packet, src);
return true;
}
--- a/src/devices/p2p/p2p-net-device.cc Thu Jun 14 10:41:47 2007 +0200
+++ b/src/devices/p2p/p2p-net-device.cc Fri Jun 15 13:19:57 2007 -0700
@@ -16,8 +16,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
- * Author: Craig Dowell <craigdo@ee.washington.edu>
- * Revised: George Riley <riley@ece.gatech.edu>
+ * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
*/
#include <iostream>
@@ -33,17 +32,11 @@
namespace ns3 {
-DataRateDefaultValue PointToPointNetDevice::g_defaultRate(
- "PointToPointLinkDataRate",
- "The default data rate for point to point links",
- DataRate ("10Mb/s"));
-
- PointToPointNetDevice::PointToPointNetDevice (Ptr<Node> node,
- const DataRate& rate)
+PointToPointNetDevice::PointToPointNetDevice (Ptr<Node> node)
:
- NetDevice(node, MacAddress (6)),
+ NetDevice(node, MacAddress ("00:00:00:00:00:00")),
m_txMachineState (READY),
- m_bps (rate),
+ m_bps (DataRate (0xffffffff)),
m_tInterframeGap (Seconds(0)),
m_channel (0),
m_queue (0),
@@ -108,25 +101,26 @@
//
// Assignment operator for PointToPointNetDevice.
//
+// This uses the non-obvious trick of taking the source net device passed by
+// value instead of by reference. This causes the copy constructor to be
+// invoked (where the real work is done -- see above). All we have to do
+// here is to return the newly constructed net device.
//
-PointToPointNetDevice&
-PointToPointNetDevice::operator= (const PointToPointNetDevice& nd)
+ PointToPointNetDevice&
+PointToPointNetDevice::operator= (const PointToPointNetDevice nd)
{
NS_DEBUG ("PointToPointNetDevice::operator= (" << &nd << ")");
- // FIXME. Not sure what to do here
- // GFR Note. I would suggest dis-allowing netdevice assignment,
- // as well as pass-by-value (ie. copy constructor).
return *this;
}
void
-PointToPointNetDevice::SetDataRate(const DataRate& bps)
+PointToPointNetDevice::SetDataRate(DataRate bps)
{
m_bps = bps;
}
void
-PointToPointNetDevice::SetInterframeGap(const Time& t)
+PointToPointNetDevice::SetInterframeGap(Time t)
{
m_tInterframeGap = t;
}
@@ -139,23 +133,68 @@
NS_ASSERT (IsLinkUp ());
+#ifdef NOTYET
+ struct NetDevicePacketDestAddress tag;
+ tag.address = address;
+ p.AddTag (tag);
+#endif
+
//
// This class simulates a point to point device. In the case of a serial
// link, this means that we're simulating something like a UART. This is
// not a requirement for a point-to-point link, but it's a typical model for
// the device.
//
+// Generally, a real device will have a list of pending packets to transmit.
+// An on-device CPU frees the main CPU(s) of the details of what is happening
+// in the device and feeds the USART. The main CPU basically just sees the
+// list of packets -- it puts packets into the list, and the device frees the
+// packets when they are transmitted.
//
-// If there's a transmission in progress, we enque the packet for later
-// trnsmission; otherwise we send it now.
+// In the case of our virtual device here, the queue pointed to by m_queue
+// corresponds to this list. The main CPU adds packets to the list by
+// calling this method and when the device completes a send, the packets are
+// freed in an "interrupt" service routine.
+//
+// We're going to do the same thing here. So first of all, the incoming packet
+// goes onto our queue if possible. If the queue can't handle it, there's
+// nothing to be done.
+//
+ if (m_queue->Enqueue(p) == false )
+ {
+ return false;
+ }
+//
+// If there's a transmission in progress, the "interrupt" will keep the
+// transmission process going. If the device is idle, we need to start a
+// transmission.
+//
+// In the real world, the USART runs until it finishes sending bits, and then
+// pulls on the device's transmit complete interrupt wire. At the same time,
+// the electrons from the last wiggle of the wire are busy propagating down
+// the wire. In the case of a long speed-of-light delay in the wire, we could
+// conceivably start transmitting the next packet before the end of the
+// previously sent data has even reached the end of the wire. This situation
+// is usually avoided (like the plague) and an "interframe gap" is introduced.
+// This is usually the round-trip delay on the channel plus some hard-to-
+// quantify receiver turn-around time (the time required for the receiver
+// to process the last frame and prepare for reception of the next).
+//
+// So, if the transmit machine is ready, we need to schedule a transmit
+// complete event (at which time we tell the channel we're no longer sending
+// bits). A separate transmit ready event (at which time the transmitter
+// becomes ready to start sending bits again is scheduled there). Finally,
+// we tell the channel (via TransmitStart ()) that we've started wiggling the
+// wire and bits are coming out.
+//
+// If the transmit machine is not ready, we just leave and the transmit ready
+// event we know is coming will kick-start the transmit process.
+//
if (m_txMachineState == READY)
{
return TransmitStart (p);
}
- else
- {
- return m_queue->Enqueue(p);
- }
+ return true;
}
bool
@@ -167,25 +206,25 @@
//
// This function is called to start the process of transmitting a packet.
// We need to tell the channel that we've started wiggling the wire and
-// schedule an event that will be executed when the transmission is complete.
+// schedule an event that will be executed when it's time to tell the
+// channel that we're done wiggling the wire.
//
NS_ASSERT_MSG(m_txMachineState == READY, "Must be READY to transmit");
m_txMachineState = BUSY;
- Time txCompleteTime = Seconds (m_bps.CalculateTxTime(p.GetSize())) +
- m_tInterframeGap;
+ Time tEvent = Seconds (m_bps.CalculateTxTime(p.GetSize()));
NS_DEBUG ("PointToPointNetDevice::TransmitStart (): " <<
"Schedule TransmitCompleteEvent in " <<
- txCompleteTime.GetSeconds () << "sec");
- // Schedule the tx complete event
- Simulator::Schedule (txCompleteTime,
- &PointToPointNetDevice::TransmitComplete,
+ tEvent.GetSeconds () << "sec");
+
+ Simulator::Schedule (tEvent,
+ &PointToPointNetDevice::TransmitCompleteEvent,
this);
- return m_channel->TransmitStart(p, this);
+ return m_channel->TransmitStart (p, this);
}
void
-PointToPointNetDevice::TransmitComplete (void)
+PointToPointNetDevice::TransmitCompleteEvent (void)
{
NS_DEBUG ("PointToPointNetDevice::TransmitCompleteEvent ()");
//
@@ -195,10 +234,49 @@
// the transmitter after the interframe gap.
//
NS_ASSERT_MSG(m_txMachineState == BUSY, "Must be BUSY if transmitting");
- m_txMachineState = READY;
+ m_txMachineState = GAP;
Packet p;
- if (!m_queue->Dequeue(p)) return; // Nothing to do at this point
- TransmitStart(p);
+ bool found;
+ found = m_queue->Dequeue (p);
+ NS_ASSERT_MSG(found, "Packet must be on queue if transmitted");
+ NS_DEBUG ("PointToPointNetDevice::TransmitCompleteEvent (): Pkt UID is " <<
+ p.GetUid () << ")");
+ m_channel->TransmitEnd (p, this);
+
+ NS_DEBUG (
+ "PointToPointNetDevice::TransmitCompleteEvent (): " <<
+ "Schedule TransmitReadyEvent in "
+ << m_tInterframeGap.GetSeconds () << "sec");
+
+ Simulator::Schedule (m_tInterframeGap,
+ &PointToPointNetDevice::TransmitReadyEvent,
+ this);
+}
+
+ void
+PointToPointNetDevice::TransmitReadyEvent (void)
+{
+ NS_DEBUG ("PointToPointNetDevice::TransmitReadyEvent ()");
+//
+// This function is called to enable the transmitter after the interframe
+// gap has passed. If there are pending transmissions, we use this opportunity
+// to start the next transmit.
+//
+ NS_ASSERT_MSG(m_txMachineState == GAP, "Must be in interframe gap");
+ m_txMachineState = READY;
+
+ if (m_queue->IsEmpty())
+ {
+ return;
+ }
+ else
+ {
+ Packet p;
+ bool found;
+ found = m_queue->Peek (p);
+ NS_ASSERT_MSG(found, "IsEmpty false but no Packet on queue?");
+ TransmitStart (p);
+ }
}
TraceResolver *
--- a/src/devices/p2p/p2p-net-device.h Thu Jun 14 10:41:47 2007 +0200
+++ b/src/devices/p2p/p2p-net-device.h Fri Jun 15 13:19:57 2007 -0700
@@ -30,7 +30,6 @@
#include "ns3/callback-trace-source.h"
#include "ns3/nstime.h"
#include "ns3/data-rate.h"
-#include "ns3/default-value.h"
#include "ns3/ptr.h"
namespace ns3 {
@@ -81,8 +80,7 @@
* @see PointToPointTopology::AddPointToPointLink ()
* @param node the Node to which this device is connected.
*/
- PointToPointNetDevice (Ptr<Node> node,
- const DataRate& = g_defaultRate.GetValue());
+ PointToPointNetDevice (Ptr<Node> node);
/**
* Copy Construct a PointToPointNetDevice
*
@@ -107,7 +105,7 @@
*
* @param nd the object to be copied
*/
- PointToPointNetDevice& operator= (const PointToPointNetDevice& nd);
+ PointToPointNetDevice& operator= (PointToPointNetDevice nd);
/**
* Set the Data Rate used for transmission of packets. The data rate is
* set in the Attach () method from the corresponding field in the channel
@@ -116,7 +114,7 @@
* @see Attach ()
* @param bps the data rate at which this object operates
*/
- void SetDataRate(const DataRate& bps);
+ void SetDataRate(DataRate bps);
/**
* Set the inteframe gap used to separate packets. The interframe gap
* defines the minimum space required between packets sent by this device.
@@ -127,7 +125,7 @@
* @see Attach ()
* @param t the interframe gap time
*/
- void SetInterframeGap(const Time& t);
+ void SetInterframeGap(Time t);
/**
* Attach the device to a channel.
*
@@ -192,19 +190,6 @@
* @returns a pointer to the channel
*/
virtual Ptr<Channel> DoGetChannel(void) const;
- /**
- * Set a new default data rate
- * @param Data rate to set for new default
- */
- static void SetDefaultRate(const DataRate&);
-
- /**
- * Get the current default rate.
- * @returns a const reference to current default
- */
-
- static const DataRate& GetDefaultRate();
-
private:
/**
* Send a Packet Down the Wire.
@@ -238,11 +223,33 @@
/**
* Stop Sending a Packet Down the Wire and Begin the Interframe Gap.
*
- * The TransmitComplete method is used internally to finish the process
- * of sending a packet out on the channel.
+ * The TransmitCompleteEvent method is used internally to finish the process
+ * of sending a packet out on the channel. During execution of this method
+ * the TransmitEnd method is called on the channel to let it know that the
+ * physical device this class represents has virually finished sending
+ * signals. The channel uses this event to begin its speed of light delay
+ * timer after which it notifies the Net Device at the other end of the
+ * link that the bits have arrived. During this method, the net device
+ * also schedules the TransmitReadyEvent at which time the transmitter
+ * becomes ready to send the next packet.
*
+ * @see PointToPointChannel::TransmitEnd ()
+ * @see TransmitReadyEvent ()
+ * @returns true if success, false on failure
*/
- void TransmitComplete(void);
+ void TransmitCompleteEvent (void);
+ /**
+ * Cause the Transmitter to Become Ready to Send Another Packet.
+ *
+ * The TransmitReadyEvent method is used internally to re-enable the
+ * transmit machine of the net device. It is scheduled after a suitable
+ * interframe gap after the completion of the previous transmission.
+ * The queue is checked at this time, and if there is a packet waiting on
+ * the queue, the transmission process is begun.
+ *
+ * @see TransmitStart ()
+ */
+ void TransmitReadyEvent (void);
/**
* Create a Trace Resolver for events in the net device.
*
@@ -256,7 +263,8 @@
enum TxMachineState
{
READY, /**< The transmitter is ready to begin transmission of a packet */
- BUSY /**< The transmitter is busy transmitting a packet */
+ BUSY, /**< The transmitter is busy transmitting a packet */
+ GAP /**< The transmitter is in the interframe gap time */
};
/**
* The state of the Net Device transmit state machine.
@@ -297,11 +305,6 @@
* @see class TraceResolver
*/
CallbackTraceSource<Packet &> m_rxTrace;
- /**
- * Default data rate. Used for all newly created p2p net devices
- */
- static DataRateDefaultValue g_defaultRate;
-
};
}; // namespace ns3
--- a/src/node/mac-address.cc Thu Jun 14 10:41:47 2007 +0200
+++ b/src/node/mac-address.cc Fri Jun 15 13:19:57 2007 -0700
@@ -33,9 +33,6 @@
namespace ns3 {
-// Static variables
-uint8_t MacAddress::g_nextAddress[MacAddress::MAX_LEN];
-
static char
AsciiToLowCase (char c)
{
@@ -57,13 +54,6 @@
}
}
-MacAddress::MacAddress(uint8_t len) : m_len(len)
-{
- NS_ASSERT (len <= MacAddress::MAX_LEN);
- AdvanceAddress();
- memcpy(m_address, g_nextAddress, len);
-}
-
MacAddress::MacAddress (uint8_t const *address, uint8_t len)
{
NS_ASSERT (len <= MacAddress::MAX_LEN);
@@ -158,17 +148,6 @@
m_len = len;
}
-// Static methods
-void MacAddress::AdvanceAddress()
- {
- // Advance to next address, little end first
- for(size_t i = 0; i < MAX_LEN; ++i)
- {
- if (++g_nextAddress[i] != 0) break;
- }
- }
-
-// Non-member operators
bool operator == (MacAddress const&a, MacAddress const&b)
{
return a.IsEqual (b);
--- a/src/node/mac-address.h Thu Jun 14 10:41:47 2007 +0200
+++ b/src/node/mac-address.h Fri Jun 15 13:19:57 2007 -0700
@@ -47,13 +47,6 @@
*/
MacAddress (void);
/**
- * \brief Construct a MacAddress using the next available
- * address.
- * \see MacAddres::Next
- * \param len length, in bytes, of the desired address
- */
- MacAddress(uint8_t len);
- /**
* \brief Construct a MacAddress from a byte-array
*
* low byte should be first.
@@ -104,14 +97,6 @@
*/
void Set (uint8_t const ad[MAX_LEN], uint8_t len);
- // Static methods/members
- /**
- *
- * Advance the global to the next available mac address.
- */
- static void AdvanceAddress();
- static uint8_t g_nextAddress[MAX_LEN];
-
private:
uint8_t m_address[MAX_LEN];
uint8_t m_len;