Simplification to p2p-net-device and p2p-channel (work in progress)

This commit is contained in:
George F. Riley
2007-06-14 10:41:47 +02:00
parent 4f0eae4a6d
commit 4042681e83
5 changed files with 104 additions and 147 deletions

View File

@@ -135,12 +135,14 @@ PointToPointChannel::TransmitEnd(Packet& p, Ptr<PointToPointNetDevice> src)
// 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.
//
Packet packet = p;
// Above is not correct (GFR). The event scheduler makes a copy
// of the packet
// Packet packet = p;
NS_DEBUG ("PointToPointChannel::TransmitEnd (): Schedule event in " <<
m_delay.GetSeconds () << "sec");
Simulator::Schedule (m_delay,
&PointToPointChannel::PropagationCompleteEvent,
this, packet, src);
this, p, src);
return true;
}

View File

@@ -16,7 +16,8 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
* Author: Craig Dowell <craigdo@ee.washington.edu>
* Revised: George Riley <riley@ece.gatech.edu>
*/
#include <iostream>
@@ -32,11 +33,17 @@ NS_DEBUG_COMPONENT_DEFINE ("PointToPointNetDevice");
namespace ns3 {
PointToPointNetDevice::PointToPointNetDevice (Ptr<Node> node)
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)
:
NetDevice(node, MacAddress ("00:00:00:00:00:00")),
NetDevice(node, MacAddress (6)),
m_txMachineState (READY),
m_bps (DataRate (0xffffffff)),
m_bps (rate),
m_tInterframeGap (Seconds(0)),
m_channel (0),
m_queue (0),
@@ -101,26 +108,25 @@ void PointToPointNetDevice::DoDispose()
//
// 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(DataRate bps)
PointToPointNetDevice::SetDataRate(const DataRate& bps)
{
m_bps = bps;
}
void
PointToPointNetDevice::SetInterframeGap(Time t)
PointToPointNetDevice::SetInterframeGap(const Time& t)
{
m_tInterframeGap = t;
}
@@ -133,68 +139,23 @@ PointToPointNetDevice::SendTo (Packet& p, const MacAddress& dest)
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.
//
// 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 there's a transmission in progress, we enque the packet for later
// trnsmission; otherwise we send it now.
if (m_txMachineState == READY)
{
return TransmitStart (p);
}
return true;
else
{
return m_queue->Enqueue(p);
}
}
bool
@@ -206,25 +167,25 @@ PointToPointNetDevice::TransmitStart (Packet &p)
//
// 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 it's time to tell the
// channel that we're done wiggling the wire.
// schedule an event that will be executed when the transmission is complete.
//
NS_ASSERT_MSG(m_txMachineState == READY, "Must be READY to transmit");
m_txMachineState = BUSY;
Time tEvent = Seconds (m_bps.CalculateTxTime(p.GetSize()));
Time txCompleteTime = Seconds (m_bps.CalculateTxTime(p.GetSize())) +
m_tInterframeGap;
NS_DEBUG ("PointToPointNetDevice::TransmitStart (): " <<
"Schedule TransmitCompleteEvent in " <<
tEvent.GetSeconds () << "sec");
Simulator::Schedule (tEvent,
&PointToPointNetDevice::TransmitCompleteEvent,
txCompleteTime.GetSeconds () << "sec");
// Schedule the tx complete event
Simulator::Schedule (txCompleteTime,
&PointToPointNetDevice::TransmitComplete,
this);
return m_channel->TransmitStart (p, this);
return m_channel->TransmitStart(p, this);
}
void
PointToPointNetDevice::TransmitCompleteEvent (void)
PointToPointNetDevice::TransmitComplete (void)
{
NS_DEBUG ("PointToPointNetDevice::TransmitCompleteEvent ()");
//
@@ -234,49 +195,10 @@ PointToPointNetDevice::TransmitCompleteEvent (void)
// the transmitter after the interframe gap.
//
NS_ASSERT_MSG(m_txMachineState == BUSY, "Must be BUSY if transmitting");
m_txMachineState = GAP;
Packet 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);
}
Packet p;
if (!m_queue->Dequeue(p)) return; // Nothing to do at this point
TransmitStart(p);
}
TraceResolver *

View File

@@ -30,6 +30,7 @@
#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 {
@@ -80,7 +81,8 @@ public:
* @see PointToPointTopology::AddPointToPointLink ()
* @param node the Node to which this device is connected.
*/
PointToPointNetDevice (Ptr<Node> node);
PointToPointNetDevice (Ptr<Node> node,
const DataRate& = g_defaultRate.GetValue());
/**
* Copy Construct a PointToPointNetDevice
*
@@ -105,7 +107,7 @@ public:
*
* @param nd the object to be copied
*/
PointToPointNetDevice& operator= (PointToPointNetDevice nd);
PointToPointNetDevice& operator= (const 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
@@ -114,7 +116,7 @@ public:
* @see Attach ()
* @param bps the data rate at which this object operates
*/
void SetDataRate(DataRate bps);
void SetDataRate(const DataRate& bps);
/**
* Set the inteframe gap used to separate packets. The interframe gap
* defines the minimum space required between packets sent by this device.
@@ -125,7 +127,7 @@ public:
* @see Attach ()
* @param t the interframe gap time
*/
void SetInterframeGap(Time t);
void SetInterframeGap(const Time& t);
/**
* Attach the device to a channel.
*
@@ -190,6 +192,19 @@ protected:
* @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.
@@ -223,33 +238,11 @@ private:
/**
* Stop Sending a Packet Down the Wire and Begin the Interframe Gap.
*
* 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.
* The TransmitComplete method is used internally to finish the process
* of sending a packet out on the channel.
*
* @see PointToPointChannel::TransmitEnd ()
* @see TransmitReadyEvent ()
* @returns true if success, false on failure
*/
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);
void TransmitComplete(void);
/**
* Create a Trace Resolver for events in the net device.
*
@@ -263,8 +256,7 @@ private:
enum TxMachineState
{
READY, /**< The transmitter is ready to begin transmission of a packet */
BUSY, /**< The transmitter is busy transmitting a packet */
GAP /**< The transmitter is in the interframe gap time */
BUSY /**< The transmitter is busy transmitting a packet */
};
/**
* The state of the Net Device transmit state machine.
@@ -305,6 +297,11 @@ private:
* @see class TraceResolver
*/
CallbackTraceSource<Packet &> m_rxTrace;
/**
* Default data rate. Used for all newly created p2p net devices
*/
static DataRateDefaultValue g_defaultRate;
};
}; // namespace ns3

View File

@@ -33,6 +33,9 @@
namespace ns3 {
// Static variables
uint8_t MacAddress::g_nextAddress[MacAddress::MAX_LEN];
static char
AsciiToLowCase (char c)
{
@@ -54,6 +57,13 @@ MacAddress::MacAddress () : m_len(0)
}
}
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);
@@ -148,6 +158,17 @@ MacAddress::Set (uint8_t const ad[MacAddress::MAX_LEN], uint8_t len)
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);

View File

@@ -46,6 +46,13 @@ public:
* This MacAddress has length of zero, and is internally all zeros
*/
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
*
@@ -97,6 +104,14 @@ public:
*/
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;