a new (wholy untested) Dcf implementation
authormlacage@thira.inria.fr
Tue, 13 Nov 2007 16:32:39 +0100
changeset 2095 f6ec39e97e4b
parent 2094 ba3caa8ee26d
child 2096 4e282663666c
a new (wholy untested) Dcf implementation
src/devices/wifi/dcf-manager.cc
src/devices/wifi/dcf-manager.h
src/devices/wifi/wscript
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/wifi/dcf-manager.cc	Tue Nov 13 16:32:39 2007 +0100
@@ -0,0 +1,386 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+
+#include "ns3/assert.h"
+#include "ns3/log.h"
+#include "ns3/simulator.h"
+#include <math.h>
+
+#include "dcf-manager.h"
+#include "mac-parameters.h"
+
+NS_LOG_COMPONENT_DEFINE ("DcfManager");
+
+namespace ns3 {
+
+/****************************************************************
+ *      Implement the DCF state holder
+ ****************************************************************/
+
+void 
+DcfState::SetAifsn (uint32_t aifsn)
+{
+  m_aifsn = aifsn;
+}
+
+void 
+DcfState::SetCwBounds (uint32_t minCw, uint32_t maxCw)
+{
+  m_cwMin = minCw;
+  m_cwMax = maxCw;
+}
+
+void 
+DcfState::ResetCw (void)
+{
+  m_cw = m_cwMin;
+}
+void 
+DcfState::UpdateFailedCw (void)
+{
+  uint32_t cw = m_cw;
+  cw *= 2;
+  cw = std::min (m_cwMax, cw);
+  m_cw = cw;
+}
+void 
+DcfState::UpdateBackoffSlotsNow (uint32_t nSlots)
+{
+  uint32_t n = std::min (nSlots, m_backoffSlots);
+  m_backoffSlots -= n;
+}
+
+void 
+DcfState::StartBackoffNow (uint32_t nSlots)
+{
+  NS_ASSERT (m_backoffSlots == 0);
+  m_backoffSlots = nSlots;
+  m_backoffStart = Simulator::Now ();
+}
+
+uint32_t 
+DcfState::GetAifsn (void) const
+{
+  return m_aifsn;
+}
+uint32_t
+DcfState::GetCw (void) const
+{
+  return m_cw;
+}
+uint32_t 
+DcfState::GetBackoffSlots (void) const
+{
+  return m_backoffSlots;
+}
+Time 
+DcfState::GetBackoffStart (void) const
+{
+  return m_backoffStart;
+}
+
+
+/****************************************************************
+ *      Implement the DCF manager of all DCF state holders
+ ****************************************************************/
+
+void 
+DcfManager::Add (DcfState *dcf)
+{
+  m_states.push_back (dcf);
+}
+
+Time
+DcfManager::MostRecent (Time a, Time b) const
+{
+  return Max (a, b);
+}
+Time
+DcfManager::MostRecent (Time a, Time b, Time c) const
+{
+  Time retval;
+  retval = Max (a, b);
+  retval = Max (retval, c);
+  return retval;
+}
+Time
+DcfManager::MostRecent (Time a, Time b, Time c, Time d) const
+{
+  Time e = Max (a, b);
+  Time f = Max (c, d);
+  Time retval = Max (e, f);
+  return retval;
+}
+
+bool 
+DcfManager::IsBusy (void) const
+{
+  // PHY busy
+  if (m_rxing) 
+    {
+      return true;
+    }
+  Time lastTxEnd = m_lastTxStart + m_lastTxDuration;
+  if (lastTxEnd > Simulator::Now ()) 
+    {
+      return true;
+    }
+  // NAV busy
+  Time lastNavEnd = m_lastNavStart + m_lastNavDuration;
+  if (lastNavEnd > Simulator::Now ())
+    {
+      return true;
+    }
+  return false;
+}
+
+
+void 
+DcfManager::RequestAccess (DcfState *state)
+{
+  UpdateBackoff ();
+  if (m_accessTimeout.IsRunning ())
+    {
+      /* we don't need to do anything because we have an access
+       * timer which will expire soon.
+       */
+      NS_LOG_DEBUG ("access timer running. will be notified");
+      return;
+    }
+  /**
+   * Since no access timeout is running, and if we have no
+   * backoff running for this DcfState, start a new backoff
+   * if needed.
+   */ 
+  if (state->GetBackoffSlots () == 0 && 
+      IsBusy ())
+    {
+      /* someone else has accessed the medium.
+       * generate a backoff.
+       */
+      state->NotifyCollision ();
+    }
+
+  DoGrantAccess ();
+  DoRestartAccessTimeoutIfNeeded ();  
+}
+
+void
+DcfManager::DoGrantAccess (void)
+{
+  for (States::const_iterator i = m_states.begin (); i != m_states.end (); )
+    {
+      DcfState *state = *i;
+      if (state->GetBackoffSlots () == 0 && state->NeedsAccess ())
+        {
+          /**
+           * This is the first dcf we find with an expired backoff and which
+           * needs access to the medium. i.e., it has data to send.
+           */
+          state->NotifyAccessGranted ();
+          i++; // go to the next item in the list.
+          for (States::const_iterator j = i; j != m_states.end (); j++)
+            {
+              DcfState *state = *j;
+              if (state->GetBackoffSlots () == 0 && state->NeedsAccess ())
+                {
+                  /**
+                   * all other dcfs with a lower priority whose backoff
+                   * has expired and which needed access to the medium
+                   * must be notified that we did get an internal collision.
+                   */
+                  state->NotifyInternalCollision ();
+                }
+            }
+          break;
+        }
+      i++;
+    }
+}
+
+void
+DcfManager::AccessTimeout (void)
+{
+  UpdateBackoff ();
+  DoGrantAccess ();
+  DoRestartAccessTimeoutIfNeeded ();
+}
+
+Time
+DcfManager::GetAccessGrantStart (void) const
+{
+  Time rxAccessStart;
+  if (m_lastRxEnd >= m_lastRxStart) 
+    {
+      rxAccessStart = m_lastRxEnd + m_parameters->GetSifs ();
+      if (!m_lastRxReceivedOk) 
+        {
+          rxAccessStart += m_ackTxTime;
+        } 
+    } 
+  else 
+    {
+      rxAccessStart = m_lastRxStart + m_lastRxDuration + m_parameters->GetSifs ();
+    }
+  Time busyAccessStart = m_lastBusyStart + m_lastBusyDuration + m_parameters->GetSifs ();
+  Time txAccessStart = m_lastTxStart + m_lastTxDuration + m_parameters->GetSifs ();
+  Time navAccessStart = m_lastNavStart + m_lastNavDuration + m_parameters->GetSifs ();
+  Time accessGrantedStart = MostRecent (rxAccessStart, 
+                                        busyAccessStart,
+                                        txAccessStart, 
+                                        navAccessStart);
+  NS_LOG_DEBUG ("access grant start=" << accessGrantedStart);
+  return accessGrantedStart;
+}
+
+void
+DcfManager::UpdateBackoff (void)
+{
+  for (States::const_iterator i = m_states.begin (); i != m_states.end (); i++)
+    {
+      DcfState *state = *i;
+
+      Time mostRecentEvent = MostRecent (state->GetBackoffStart (),
+                                         GetAccessGrantStart ());
+      if (mostRecentEvent < Simulator::Now ())
+        {
+          Scalar nSlots = (Simulator::Now () - mostRecentEvent) / m_parameters->GetSlotTime ();
+          uint32_t nIntSlots = lrint (nSlots.GetDouble ());
+          /**
+           * For each DcfState, calculate how many backoff slots elapsed since
+           * the last time its backoff counter was updated. If the number of 
+           * slots is smaller than its AIFSN, the backoff did not start, so,
+           * we do not update it.
+           */
+          if (nIntSlots > state->GetAifsn ())
+            {
+              state->UpdateBackoffSlotsNow (nIntSlots - state->GetAifsn ());
+            }
+        }
+    }
+}
+
+void
+DcfManager::DoRestartAccessTimeoutIfNeeded (void)
+{
+  /**
+   * Is there a DcfState which needs to access the medium, and, 
+   * if there is one, how many slots for AIFS+backoff does it require ?
+   */
+  bool accessTimeoutNeeded = false;
+  uint32_t minNSlots = 0xffffffff;
+  Time backoffStart;
+  for (States::const_iterator i = m_states.begin (); i != m_states.end (); i++)
+    {
+      DcfState *state = *i;
+      if (state->NeedsAccess ())
+        {
+          accessTimeoutNeeded = true;
+          minNSlots = std::min (state->GetAifsn () + state->GetBackoffSlots (), minNSlots);
+        }
+    }
+  if (accessTimeoutNeeded)
+    {
+      /**
+       * If one of the DcfState needs access to the medium, calculate when its
+       * backoff is expected to end.
+       */
+      Time expectedBackoffEnd = GetAccessGrantStart () + Scalar (minNSlots) * m_parameters->GetSlotTime ();
+      /**
+       * It is not possible that the backoff was expected to end before now
+       * because if it were possible, this would mean that we have missed
+       * a backoff expiration ! And that would be a bug.
+       */
+      NS_ASSERT (expectedBackoffEnd >= Simulator::Now ());
+      if (expectedBackoffEnd > Simulator::Now ())
+        {
+          Time expectedBackoffDelay = expectedBackoffEnd - Simulator::Now ();
+          if (m_accessTimeout.IsRunning () &&
+              Simulator::GetDelayLeft (m_accessTimeout) > expectedBackoffDelay)
+            {
+              m_accessTimeout.Cancel ();
+            }
+          if (m_accessTimeout.IsExpired ())
+            {
+              m_accessTimeout = Simulator::Schedule (expectedBackoffDelay,
+                                                     &DcfManager::AccessTimeout, this);
+            }
+        }
+    }
+}
+
+void 
+DcfManager::NotifyRxStartNow (Time duration)
+{
+  Time now = Simulator::Now ();
+  NS_LOG_DEBUG ("rx start at="<<now<<", for="<<duration);
+  UpdateBackoff ();
+  m_lastRxStart = now;
+  m_lastRxDuration = duration;
+  m_rxing = true;
+}
+void 
+DcfManager::NotifyRxEndOkNow (void)
+{
+  Time now = Simulator::Now ();
+  NS_LOG_DEBUG ("rx end ok at="<<now);
+  m_lastRxEnd = now;
+  m_lastRxReceivedOk = true;
+  m_rxing = false;
+}
+void 
+DcfManager::NotifyRxEndErrorNow (void)
+{
+  Time now = Simulator::Now ();
+  NS_LOG_DEBUG ("rx end error at=");
+  m_lastRxEnd = now;
+  m_lastRxReceivedOk = false;
+  m_rxing = false;
+}
+void 
+DcfManager::NotifyTxStartNow (Time duration)
+{
+  Time now = Simulator::Now ();
+  NS_LOG_DEBUG ("tx start at="<<now<<" for "<<duration);
+  UpdateBackoff ();
+  m_lastTxStart = now;
+  m_lastTxDuration = duration;
+}
+void 
+DcfManager::NotifyCcaBusyStartNow (Time duration)
+{
+  Time now = Simulator::Now ();
+  NS_LOG_DEBUG ("busy start at="<<now<<" for "<<duration);
+  UpdateBackoff ();
+  m_lastBusyStart = now;
+  m_lastBusyDuration = duration;
+}
+void 
+DcfManager::NotifyNavResetNow (Time duration)
+{
+  Time now = Simulator::Now ();
+  NS_LOG_DEBUG ("nav reset at="<<now<<", for="<<duration);
+  UpdateBackoff ();
+  m_lastNavStart = now;
+  m_lastNavDuration = duration;
+  UpdateBackoff ();
+  /**
+   * If the nav reset indicates an end-of-nav which is earlier
+   * than the previous end-of-nav, the expected end of backoff
+   * might be later than previously thought so, we might need
+   * to restart a new access timeout.
+   */
+  DoRestartAccessTimeoutIfNeeded ();
+}
+void 
+DcfManager::NotifyNavStartNow (Time duration)
+{
+  Time now = Simulator::Now ();
+  NS_ASSERT (m_lastNavStart < now);
+  NS_LOG_DEBUG ("nav start at="<<now<<", for="<<duration);
+  UpdateBackoff ();
+  // XXX handle 
+  m_lastNavStart = now;
+  m_lastNavDuration = duration;
+}
+
+} // namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/wifi/dcf-manager.h	Tue Nov 13 16:32:39 2007 +0100
@@ -0,0 +1,139 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+
+#include "ns3/nstime.h"
+#include "ns3/event-id.h"
+#include <vector>
+
+namespace ns3 {
+
+class MacParameters;
+
+class DcfState
+{
+public:
+  virtual ~DcfState ();
+
+  void SetAifsn (uint32_t aifsn);
+  void SetCwBounds (uint32_t minCw, uint32_t maxCw);
+  void ResetCw (void);
+  void UpdateFailedCw (void);
+  void StartBackoffNow (uint32_t nSlots);
+
+private:
+  friend class DcfManager;
+
+  uint32_t GetAifsn (void) const;
+  uint32_t GetCw (void) const;
+  uint32_t GetBackoffSlots (void) const;
+  Time GetBackoffStart (void) const;
+
+  void UpdateBackoffSlotsNow (uint32_t nSlots);
+
+  virtual bool NeedsAccess (void) const = 0;
+  virtual void NotifyAccessGranted (void) = 0;
+  virtual void NotifyInternalCollision (void) = 0;
+  virtual void NotifyCollision (void) = 0;
+
+  uint32_t m_aifsn;
+  uint32_t m_backoffSlots;
+  Time m_backoffStart;
+  uint32_t m_cwMin;
+  uint32_t m_cwMax;
+  uint32_t m_cw;
+};
+
+class DcfManager
+{
+  void SetParameters (const MacParameters *parameters);
+
+  // at the lowest mandatory rate.
+  // used for EIFS calculation.
+  void SetAckTxDuration (Time ackTxDuration);
+
+  void Add (DcfState *dcf);
+
+  void RequestAccess (DcfState *state);
+
+  /**
+   * \param duration expected duration of reception
+   *
+   * Notify the DCF that a packet reception started 
+   * for the expected duration.
+   */
+  void NotifyRxStartNow (Time duration);
+  /**
+   * Notify the DCF that a packet reception was just
+   * completed successfully.
+   */
+  void NotifyRxEndOkNow (void);
+  /**
+   * Notify the DCF that a packet reception was just
+   * completed unsuccessfully.
+   */
+  void NotifyRxEndErrorNow (void);
+  /**
+   * \param duration expected duration of transmission
+   *
+   * Notify the DCF that a packet transmission was
+   * just started and is expected to last for the specified
+   * duration.
+   */
+  void NotifyTxStartNow (Time duration);
+  /**
+   * \param duration expected duration of cca busy period
+   *
+   * Notify the DCF that a CCA busy period has just started.
+   */
+  void NotifyCcaBusyStartNow (Time duration);
+  /**
+   * \param duration the value of the received NAV.
+   *
+   * Called at end of rx
+   */
+  void NotifyNavResetNow (Time duration);
+  /**
+   * \param duration the value of the received NAV.
+   *
+   * Called at end of rx
+   */
+  void NotifyNavStartNow (Time duration);
+
+private:
+  void UpdateBackoff (void);
+  Time MostRecent (Time a, Time b) const;
+  Time MostRecent (Time a, Time b, Time c) const;
+  Time MostRecent (Time a, Time b, Time c, Time d) const;
+  /**
+   * Access will never be granted to the medium _before_
+   * the time returned by this method.
+   * 
+   * \returns the absolute time at which access could start to 
+   * be granted
+   */
+  Time GetAccessGrantStart (void) const;
+  void DoRestartAccessTimeoutIfNeeded (void);
+  void AccessTimeout (void);
+  void DoGrantAccess (void);
+  bool IsBusy (void) const;
+
+  typedef std::vector<DcfState *> States;
+
+  States m_states;
+  Time m_lastNavStart;
+  Time m_lastNavDuration;
+  Time m_lastRxStart;
+  Time m_lastRxDuration;
+  bool m_lastRxReceivedOk;
+  Time m_lastRxEnd;
+  Time m_lastTxStart;
+  Time m_lastTxDuration;
+  Time m_lastBusyStart;
+  Time m_lastBusyDuration;
+  bool m_rxing;
+  bool m_sleeping;
+  Time m_ackTxTime;
+  EventId m_accessTimeout;
+  MacParameters *m_parameters;
+};
+
+} // namespace ns3
--- a/src/devices/wifi/wscript	Fri Nov 09 13:25:01 2007 +0100
+++ b/src/devices/wifi/wscript	Tue Nov 13 16:32:39 2007 +0100
@@ -32,7 +32,8 @@
         'mac-high-nqsta.cc',
         'wifi-net-device.cc',
         'wifi-default-parameters.cc',
-        'random-stream.cc'
+        'random-stream.cc',
+        'dcf-manager.cc',
         ]
     headers = bld.create_obj('ns3header')
     headers.source = [