# HG changeset patch # User George F. Riley # Date 1184316010 -7200 # Node ID 1fdec986d77442a732fd87149a8fd9530785e7bf # Parent 914adb9a1aab53d78ee863d248aeddb52ae461e4 Simplifications to the point to point devices and channel diff -r 914adb9a1aab -r 1fdec986d774 src/devices/p2p/p2p-channel.cc --- a/src/devices/p2p/p2p-channel.cc Tue Jul 10 13:45:20 2007 +0100 +++ b/src/devices/p2p/p2p-channel.cc Fri Jul 13 10:40:10 2007 +0200 @@ -76,8 +76,7 @@ NS_ASSERT(m_nDevices < N_DEVICES && "Only two devices permitted"); NS_ASSERT(device != 0); - m_link[m_nDevices].m_src = device; - ++m_nDevices; + m_link[m_nDevices++].m_src = device; // // If we have both devices connected to the channel, then finish introducing // the two halves and set the links to IDLE. @@ -91,8 +90,9 @@ } } -bool -PointToPointChannel::TransmitStart(Packet& p, Ptr src) +bool PointToPointChannel::TransmitStart(Packet& p, + Ptr src, + const Time& txTime) { NS_DEBUG ("PointToPointChannel::TransmitStart (" << &p << ", " << src << ")"); @@ -104,65 +104,15 @@ uint32_t wire = src == m_link[0].m_src ? 0 : 1; - if (m_link[wire].m_state == TRANSMITTING) - { - NS_DEBUG("PointToPointChannel::TransmitStart (): **** ERROR ****"); - NS_DEBUG("PointToPointChannel::TransmitStart (): state TRANSMITTING"); - return false; - } - - NS_DEBUG("PointToPointChannel::TransmitStart (): switch to TRANSMITTING"); - m_link[wire].m_state = TRANSMITTING; + // Here we schedule the packet receive event at the receiver, + // which simplifies this model quite a bit. The channel just + // adds the propagation delay time + Simulator::Schedule (txTime + m_delay, + &PointToPointNetDevice::Receive, + m_link[wire].m_dst, p); return true; } -bool -PointToPointChannel::TransmitEnd(Packet& p, Ptr src) -{ - NS_DEBUG("PointToPointChannel::TransmitEnd (" << &p << ", " << src << ")"); - NS_DEBUG ("PointToPointChannel::TransmitEnd (): UID is " << - p.GetUid () << ")"); - - NS_ASSERT(m_link[0].m_state != INITIALIZING); - NS_ASSERT(m_link[1].m_state != INITIALIZING); - - uint32_t wire = src == m_link[0].m_src ? 0 : 1; - - NS_ASSERT(m_link[wire].m_state == TRANSMITTING); - - m_link[wire].m_state = PROPAGATING; -// -// 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; - NS_DEBUG ("PointToPointChannel::TransmitEnd (): Schedule event in " << - m_delay.GetSeconds () << "sec"); - Simulator::Schedule (m_delay, - &PointToPointChannel::PropagationCompleteEvent, - this, packet, src); - return true; -} - -void -PointToPointChannel::PropagationCompleteEvent( - Packet p, - Ptr src) -{ - NS_DEBUG("PointToPointChannel::PropagationCompleteEvent (" << &p << ", " << - src << ")"); - NS_DEBUG ("PointToPointChannel::PropagationCompleteEvent (): UID is " << - p.GetUid () << ")"); - - uint32_t wire = src == m_link[0].m_src ? 0 : 1; - NS_ASSERT(m_link[wire].m_state == PROPAGATING); - m_link[wire].m_state = IDLE; - - NS_DEBUG ("PointToPointChannel::PropagationCompleteEvent (): Receive"); - m_link[wire].m_dst->Receive (p); -} - - uint32_t PointToPointChannel::GetNDevices (void) const { @@ -176,13 +126,13 @@ return m_link[i].m_src; } - DataRate +const DataRate& PointToPointChannel::GetDataRate (void) { return m_bps; } - Time +const Time& PointToPointChannel::GetDelay (void) { return m_delay; diff -r 914adb9a1aab -r 1fdec986d774 src/devices/p2p/p2p-channel.h --- a/src/devices/p2p/p2p-channel.h Tue Jul 10 13:45:20 2007 +0100 +++ b/src/devices/p2p/p2p-channel.h Fri Jul 13 10:40:10 2007 +0200 @@ -51,11 +51,7 @@ */ class PointToPointChannel : public Channel { public: -// -// This is really kidding myself, since just setting N_DEVICES to 3 isn't -// going to come close to magically creating a multi-drop link, but I can't -// bring myself to just type 2 in the code (even though I type 0 and 1 :-). -// +// Each point to point link has exactly two net devices static const int N_DEVICES = 2; /** * \brief Create a PointToPointChannel @@ -68,7 +64,7 @@ /** * \brief Create a PointToPointChannel * - * \param bps The bitrate of the channel + * \param bps The maximum bitrate of the channel * \param delay Transmission delay through the channel */ PointToPointChannel (const DataRate& bps, const Time& delay); @@ -77,7 +73,7 @@ * \brief Create a PointToPointChannel * * \param name the name of the channel for identification purposes - * \param bps The bitrate of the channel + * \param bps The maximum bitrate of the channel * \param delay Transmission delay through the channel */ PointToPointChannel (const std::string& name, @@ -88,21 +84,22 @@ * \param device pointer to the netdevice to attach to the channel */ void Attach (Ptr device); - bool TransmitStart (Packet& p, Ptr src); - bool TransmitEnd (Packet &p, Ptr src); - void PropagationCompleteEvent(Packet p, Ptr src); + bool TransmitStart (Packet& p, Ptr src, + const Time& txTime); + // Below two not needed + //bool TransmitEnd (Packet &p, Ptr src); + //void PropagationCompleteEvent(Packet p, Ptr src); virtual uint32_t GetNDevices (void) const; virtual Ptr GetDevice (uint32_t i) const; - virtual DataRate GetDataRate (void); - virtual Time GetDelay (void); + virtual const DataRate& GetDataRate (void); + virtual const Time& GetDelay (void); private: DataRate m_bps; Time m_delay; - int32_t m_nDevices; enum WireState diff -r 914adb9a1aab -r 1fdec986d774 src/devices/p2p/p2p-net-device.cc --- a/src/devices/p2p/p2p-net-device.cc Tue Jul 10 13:45:20 2007 +0100 +++ b/src/devices/p2p/p2p-net-device.cc Fri Jul 13 10:40:10 2007 +0200 @@ -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 + * Author: Craig Dowell + * Revised: George Riley */ #include @@ -32,11 +33,17 @@ namespace ns3 { -PointToPointNetDevice::PointToPointNetDevice (Ptr node) +DataRateDefaultValue PointToPointNetDevice::g_defaultRate( + "PointToPointLinkDataRate", + "The default data rate for point to point links", + DataRate ("10Mb/s")); + + PointToPointNetDevice::PointToPointNetDevice (Ptr 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), @@ -73,6 +80,9 @@ // We're assuming that the tracing will be set up after the topology creation // phase and this won't actually matter. // +// GFR Comments. Don't see where the "copy the pointer and add reference" +// stated above is done. Can original author please comment and/or fix. +// Shouldn't the queue pointer also bump the refcount? PointToPointNetDevice::PointToPointNetDevice (const PointToPointNetDevice& nd) : NetDevice(nd), @@ -92,6 +102,8 @@ } + // GFR COmments...shouldn't this decrement the refcount instead + // of just nil-ing out the pointer? Don't understand this. void PointToPointNetDevice::DoDispose() { m_channel = 0; @@ -101,100 +113,54 @@ // // 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). + // This resolves some of the questions above about copy constructors. + // Why should we ever copy or assign a net device? return *this; } - void -PointToPointNetDevice::SetDataRate(DataRate bps) +void PointToPointNetDevice::SetDataRate(const DataRate& bps) { m_bps = bps; } - void -PointToPointNetDevice::SetInterframeGap(Time t) +void PointToPointNetDevice::SetInterframeGap(const Time& t) { m_tInterframeGap = t; } - bool -PointToPointNetDevice::SendTo (Packet& p, const MacAddress& dest) +bool PointToPointNetDevice::SendTo (Packet& p, const MacAddress& dest) { NS_DEBUG ("PointToPointNetDevice::SendTo (" << &p << ", " << &dest << ")"); NS_DEBUG ("PointToPointNetDevice::SendTo (): UID is " << p.GetUid () << ")"); + // GFR Comment. Why is this an assertion? Can't a link legitimately + // "go down" during the simulation? Shouldn't we just wait for it + // to come back up? 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. +// link, this means that we're simulating something like a UART. // -// 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,81 +172,41 @@ // // 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 txTime = Seconds (m_bps.CalculateTxTime(p.GetSize())); + Time txCompleteTime = txTime + 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, txTime); } - void -PointToPointNetDevice::TransmitCompleteEvent (void) +void PointToPointNetDevice::TransmitComplete (void) { NS_DEBUG ("PointToPointNetDevice::TransmitCompleteEvent ()"); // // This function is called to finish the process of transmitting a packet. // We need to tell the channel that we've stopped wiggling the wire and -// schedule an event that will be executed when it's time to re-enable -// the transmitter after the interframe gap. +// get the next packet from the queue. If the queue is empty, we are +// done, otherwise transmit the next packet. // NS_ASSERT_MSG(m_txMachineState == BUSY, "Must be BUSY if transmitting"); - m_txMachineState = GAP; + m_txMachineState = READY; 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); + if (!m_queue->Dequeue(p)) return; // Nothing to do at this point + TransmitStart(p); } - 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 * -PointToPointNetDevice::DoCreateTraceResolver (TraceContext const &context) +TraceResolver* PointToPointNetDevice::DoCreateTraceResolver ( + TraceContext const &context) { CompositeTraceResolver *resolver = new CompositeTraceResolver (context); resolver->Add ("queue", @@ -292,8 +218,7 @@ return resolver; } -bool -PointToPointNetDevice::Attach (Ptr ch) +bool PointToPointNetDevice::Attach (Ptr ch) { NS_DEBUG ("PointToPointNetDevice::Attach (" << &ch << ")"); @@ -301,7 +226,9 @@ m_channel->Attach(this); m_bps = m_channel->GetDataRate (); - m_tInterframeGap = m_channel->GetDelay (); + // GFR Comment. Below is definitely wrong. Interframe gap + // is unrelated to channel delay. + //m_tInterframeGap = m_channel->GetDelay (); /* * For now, this device is up whenever a channel is attached to it. @@ -315,38 +242,32 @@ return true; } -void -PointToPointNetDevice::AddQueue (Ptr q) +void PointToPointNetDevice::AddQueue (Ptr q) { NS_DEBUG ("PointToPointNetDevice::AddQueue (" << q << ")"); m_queue = q; } -void -PointToPointNetDevice::Receive (Packet& p) +void PointToPointNetDevice::Receive (Packet& p) { - // ignore return value for now. NS_DEBUG ("PointToPointNetDevice::Receive (" << &p << ")"); m_rxTrace (p); ForwardUp (p); } -Ptr -PointToPointNetDevice::GetQueue(void) const +Ptr PointToPointNetDevice::GetQueue(void) const { return m_queue; } -Ptr -PointToPointNetDevice::DoGetChannel(void) const +Ptr PointToPointNetDevice::DoGetChannel(void) const { return m_channel; } -bool -PointToPointNetDevice::DoNeedsArp (void) const +bool PointToPointNetDevice::DoNeedsArp (void) const { return false; } diff -r 914adb9a1aab -r 1fdec986d774 src/devices/p2p/p2p-net-device.h --- a/src/devices/p2p/p2p-net-device.h Tue Jul 10 13:45:20 2007 +0100 +++ b/src/devices/p2p/p2p-net-device.h Fri Jul 13 10:40:10 2007 +0200 @@ -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 @@ * @see PointToPointTopology::AddPointToPointLink () * @param node the Node to which this device is connected. */ - PointToPointNetDevice (Ptr node); + PointToPointNetDevice (Ptr node, + const DataRate& = g_defaultRate.GetValue()); /** * Copy Construct a PointToPointNetDevice * @@ -105,7 +107,7 @@ * * @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 @@ * @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 @@ * @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 @@ * @returns a pointer to the channel */ virtual Ptr 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,39 +238,17 @@ /** * 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. * * @see class TraceResolver */ - virtual TraceResolver *DoCreateTraceResolver (TraceContext const &context); + virtual TraceResolver* DoCreateTraceResolver (TraceContext const &context); virtual bool DoNeedsArp (void) const; /** * Enumeration of the states of the transmit machine of the net device. @@ -263,8 +256,7 @@ 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 @@ * @see class TraceResolver */ CallbackTraceSource m_rxTrace; + /** + * Default data rate. Used for all newly created p2p net devices + */ + static DataRateDefaultValue g_defaultRate; + }; }; // namespace ns3 diff -r 914adb9a1aab -r 1fdec986d774 src/node/mac-address.cc --- a/src/node/mac-address.cc Tue Jul 10 13:45:20 2007 +0100 +++ b/src/node/mac-address.cc Fri Jul 13 10:40:10 2007 +0200 @@ -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(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 @@ 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); diff -r 914adb9a1aab -r 1fdec986d774 src/node/mac-address.h --- a/src/node/mac-address.h Tue Jul 10 13:45:20 2007 +0100 +++ b/src/node/mac-address.h Fri Jul 13 10:40:10 2007 +0200 @@ -47,6 +47,13 @@ */ 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. @@ -97,6 +104,14 @@ */ 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; diff -r 914adb9a1aab -r 1fdec986d774 src/simulator/simulator.h --- a/src/simulator/simulator.h Tue Jul 10 13:45:20 2007 +0100 +++ b/src/simulator/simulator.h Fri Jul 13 10:40:10 2007 +0200 @@ -173,6 +173,10 @@ */ template static EventId Schedule (Time const &time, void (T::*mem_ptr) (T1), OBJ obj, T1 a1); + template + static EventId Schedule (Time const &time, void (T::*mem_ptr) (const T1&), OBJ obj, T1 a1); // GFR + template + static EventId Schedule (Time const &time, void (T::*mem_ptr) (T1&), OBJ obj, T1 a1); // GFR /** * @param time the relative expiration time of the event. * @param mem_ptr member method pointer to invoke @@ -234,6 +238,10 @@ */ template static EventId Schedule (Time const &time, void (*f) (T1), T1 a1); + template + static EventId Schedule (Time const &time, void (*f) (const T1&), T1 a1); // GFR + template + static EventId Schedule (Time const &time, void (*f) (T1&), T1 a1); // GFR /** * @param time the relative expiration time of the event. * @param f the function to invoke @@ -533,6 +541,10 @@ static EventImpl *MakeEvent (void (T::*mem_ptr) (void), OBJ obj); template static EventImpl *MakeEvent (void (T::*mem_ptr) (T1), OBJ obj, T1 a1); + template + static EventImpl *MakeEvent (void (T::*mem_ptr) (const T1&), OBJ obj, T1 a1); // GFR + template + static EventImpl *MakeEvent (void (T::*mem_ptr) (T1&), OBJ obj, T1 a1); // GFR template static EventImpl *MakeEvent (void (T::*mem_ptr) (T1,T2), OBJ obj, T1 a1, T2 a2); template @@ -642,6 +654,56 @@ return ev; } +template +EventImpl *Simulator::MakeEvent (void (T::*mem_ptr) (const T1&), OBJ obj, T1 a1) +{ + // one argument version, with const reference + class EventMemberImpl1 : public EventImpl { + public: + typedef void (T::*F)(const T1&); + EventMemberImpl1 (OBJ obj, F function, T1 a1) + : m_obj (obj), + m_function (function), + m_a1 (a1) + {} + protected: + virtual ~EventMemberImpl1 () {} + private: + virtual void Notify (void) { + (EventMemberImplTraits::GetReference (m_obj).*m_function) (m_a1); + } + OBJ m_obj; + F m_function; + T1 m_a1; + } *ev = new EventMemberImpl1 (obj, mem_ptr, a1); + return ev; +} + +template +EventImpl *Simulator::MakeEvent (void (T::*mem_ptr) (T1&), OBJ obj, T1 a1) +{ + // one argument version with non-const reference + class EventMemberImpl1 : public EventImpl { + public: + typedef void (T::*F)(T1&); + EventMemberImpl1 (OBJ obj, F function, T1 a1) + : m_obj (obj), + m_function (function), + m_a1 (a1) + {} + protected: + virtual ~EventMemberImpl1 () {} + private: + virtual void Notify (void) { + (EventMemberImplTraits::GetReference (m_obj).*m_function) (m_a1); + } + OBJ m_obj; + F m_function; + T1 m_a1; + } *ev = new EventMemberImpl1 (obj, mem_ptr, a1); + return ev; +} + template EventImpl *Simulator::MakeEvent (void (T::*mem_ptr) (T1,T2), OBJ obj, T1 a1, T2 a2) { @@ -920,6 +982,18 @@ return Schedule (time, MakeEvent (mem_ptr, obj, a1)); } +template +EventId Simulator::Schedule (Time const &time, void (T::*mem_ptr) (const T1&), OBJ obj, T1 a1) +{ + return Schedule (time, MakeEvent (mem_ptr, obj, a1)); +} + +template +EventId Simulator::Schedule (Time const &time, void (T::*mem_ptr) (T1&), OBJ obj, T1 a1) +{ + return Schedule (time, MakeEvent (mem_ptr, obj, a1)); +} + template EventId Simulator::Schedule (Time const &time, void (T::*mem_ptr) (T1,T2), OBJ obj, T1 a1, T2 a2) {