src/wifi/model/parf-wifi-manager.cc
changeset 11153 324c767aefdd
child 11245 5c781d7e5a25
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/wifi/model/parf-wifi-manager.cc	Sun Jan 25 11:21:46 2015 -0800
@@ -0,0 +1,311 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2014 Universidad de la República - Uruguay
+ *
+ * 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: Matias Richart <mrichart@fing.edu.uy>
+ */
+
+#include "parf-wifi-manager.h"
+#include "wifi-phy.h"
+#include "ns3/assert.h"
+#include "ns3/log.h"
+#include "ns3/uinteger.h"
+#include "ns3/trace-source-accessor.h"
+
+#define Min(a,b) ((a < b) ? a : b)
+
+NS_LOG_COMPONENT_DEFINE ("ns3::ParfWifiManager");
+
+
+namespace ns3 {
+
+/**
+ * Hold per-remote-station state for PARF Wifi manager.
+ *
+ * This struct extends from WifiRemoteStation struct to hold additional
+ * information required by the PARF Wifi manager
+ */
+struct ParfWifiRemoteStation : public WifiRemoteStation
+{
+  uint32_t m_nAttempt; //!< Number of transmission attempts.
+  uint32_t m_nSuccess; //!< Number of successful transmission attempts.
+  uint32_t m_nFail; //!< Number of failed transmission attempts.
+  bool m_usingRecoveryRate; //!< If using recovery rate.
+  bool m_usingRecoveryPower; //!< If using recovery power.
+  uint32_t m_nRetry; //!< Number of transmission retries.
+
+  uint32_t m_currentRate; //!< Current rate used by the remote station.
+
+  uint8_t m_currentPower; //!< Current power used by the remote station.
+
+  uint32_t m_nSupported; //!< Number of supported rates by the remote station.
+  bool m_initialized; //!< For initializing variables.
+};
+
+NS_OBJECT_ENSURE_REGISTERED (ParfWifiManager);
+
+TypeId
+ParfWifiManager::GetTypeId (void)
+{
+  static TypeId tid = TypeId ("ns3::ParfWifiManager")
+    .SetParent<WifiRemoteStationManager> ()
+    .AddConstructor<ParfWifiManager> ()
+    .AddAttribute ("AttemptThreshold",
+                   "The minimum number of transmission attempts to try a new power or rate.",
+                   UintegerValue (15),
+                   MakeUintegerAccessor (&ParfWifiManager::m_attemptThreshold),
+                   MakeUintegerChecker<uint32_t> ())
+    .AddAttribute ("SuccessThreshold",
+                   "The minimum number of successful transmissions to try a new power or rate.",
+                   UintegerValue (10),
+                   MakeUintegerAccessor (&ParfWifiManager::m_successThreshold),
+                   MakeUintegerChecker<uint32_t> ())
+    .AddTraceSource ("PowerChange",
+                     "The transmission power has change",
+                     MakeTraceSourceAccessor (&ParfWifiManager::m_powerChange),
+                     "ns3::ParfWifiManager::PowerChangeTracedCallback")
+    .AddTraceSource ("RateChange",
+                     "The transmission rate has change",
+                     MakeTraceSourceAccessor (&ParfWifiManager::m_rateChange),
+                     "ns3::ParfWifiManager::RateChangeTracedCallback")
+  ;
+  return tid;
+}
+
+ParfWifiManager::ParfWifiManager ()
+{
+  NS_LOG_FUNCTION (this);
+}
+ParfWifiManager::~ParfWifiManager ()
+{
+  NS_LOG_FUNCTION (this);
+}
+
+void
+ParfWifiManager::SetupPhy (Ptr<WifiPhy> phy)
+{
+  m_nPower = phy->GetNTxPower ();
+  WifiRemoteStationManager::SetupPhy (phy);
+}
+
+WifiRemoteStation *
+ParfWifiManager::DoCreateStation (void) const
+{
+  NS_LOG_FUNCTION (this);
+  ParfWifiRemoteStation *station = new ParfWifiRemoteStation ();
+
+  station->m_nSuccess = 0;
+  station->m_nFail = 0;
+  station->m_usingRecoveryRate = false;
+  station->m_usingRecoveryPower = false;
+  station->m_initialized = false;
+  station->m_nRetry = 0;
+  station->m_nAttempt = 0;
+
+  NS_LOG_DEBUG ("create station=" << station << ", timer=" << station->m_nAttempt
+                                  << ", rate=" << station->m_currentRate << ", power=" << (int)station->m_currentPower);
+
+  return station;
+}
+
+void
+ParfWifiManager::CheckInit (ParfWifiRemoteStation *station)
+{
+  if (!station->m_initialized)
+    {
+      station->m_nSupported = GetNSupported (station);
+      station->m_currentRate = station->m_nSupported - 1;
+      station->m_currentPower = m_nPower - 1;
+      m_powerChange (station->m_currentPower, station->m_state->m_address);
+      m_rateChange (station->m_currentRate, station->m_state->m_address);
+      station->m_initialized = true;
+    }
+}
+
+void
+ParfWifiManager::DoReportRtsFailed (WifiRemoteStation *station)
+{
+  NS_LOG_FUNCTION (this << station);
+}
+/**
+ * \internal
+ * It is important to realize that "recovery" mode starts after failure of
+ * the first transmission after a rate increase and ends at the first successful
+ * transmission. Specifically, recovery mode spans retransmissions boundaries.
+ * Fundamentally, ARF handles each data transmission independently, whether it
+ * is the initial transmission of a packet or the retransmission of a packet.
+ * The fundamental reason for this is that there is a backoff between each data
+ * transmission, be it an initial transmission or a retransmission.
+ */
+void
+ParfWifiManager::DoReportDataFailed (WifiRemoteStation *st)
+{
+  NS_LOG_FUNCTION (this << st);
+  ParfWifiRemoteStation *station = (ParfWifiRemoteStation *)st;
+  CheckInit (station);
+  station->m_nAttempt++;
+  station->m_nFail++;
+  station->m_nRetry++;
+  station->m_nSuccess = 0;
+
+  NS_LOG_DEBUG ("station=" << station << " data fail retry=" << station->m_nRetry << ", timer=" << station->m_nAttempt
+                           << ", rate=" << station->m_currentRate << ", power=" << (int)station->m_currentPower);
+  if (station->m_usingRecoveryRate)
+    {
+      NS_ASSERT (station->m_nRetry >= 1);
+      if (station->m_nRetry == 1)
+        {
+          // need recovery fallback
+          if (station->m_currentRate != 0)
+            {
+              NS_LOG_DEBUG ("station=" << station << " dec rate");
+              station->m_currentRate--;
+              m_rateChange (station->m_currentRate, station->m_state->m_address);
+              station->m_usingRecoveryRate = false;
+            }
+        }
+      station->m_nAttempt = 0;
+    }
+  else if (station->m_usingRecoveryPower)
+    {
+      NS_ASSERT (station->m_nRetry >= 1);
+      if (station->m_nRetry == 1)
+        {
+          // need recovery fallback
+          if (station->m_currentPower < m_nPower - 1)
+            {
+              NS_LOG_DEBUG ("station=" << station << " inc power");
+              station->m_currentPower++;
+              m_powerChange (station->m_currentPower, station->m_state->m_address);
+              station->m_usingRecoveryPower = false;
+            }
+        }
+      station->m_nAttempt = 0;
+    }
+  else
+    {
+      NS_ASSERT (station->m_nRetry >= 1);
+      if (((station->m_nRetry - 1) % 2) == 1)
+        {
+          // need normal fallback
+          if (station->m_currentPower == m_nPower - 1)
+            {
+              if (station->m_currentRate != 0)
+                {
+                  NS_LOG_DEBUG ("station=" << station << " dec rate");
+                  station->m_currentRate--;
+                  m_rateChange (station->m_currentRate, station->m_state->m_address);
+                }
+            }
+          else
+            {
+              NS_LOG_DEBUG ("station=" << station << " inc power");
+              station->m_currentPower++;
+              m_powerChange (station->m_currentPower, station->m_state->m_address);
+            }
+        }
+      if (station->m_nRetry >= 2)
+        {
+          station->m_nAttempt = 0;
+        }
+    }
+}
+void
+ParfWifiManager::DoReportRxOk (WifiRemoteStation *station,
+                               double rxSnr, WifiMode txMode)
+{
+  NS_LOG_FUNCTION (this << station << rxSnr << txMode);
+}
+void ParfWifiManager::DoReportRtsOk (WifiRemoteStation *station,
+                                     double ctsSnr, WifiMode ctsMode, double rtsSnr)
+{
+  NS_LOG_FUNCTION (this << station << ctsSnr << ctsMode << rtsSnr);
+  NS_LOG_DEBUG ("station=" << station << " rts ok");
+}
+void ParfWifiManager::DoReportDataOk (WifiRemoteStation *st,
+                                      double ackSnr, WifiMode ackMode, double dataSnr)
+{
+  NS_LOG_FUNCTION (this << st << ackSnr << ackMode << dataSnr);
+  ParfWifiRemoteStation *station = (ParfWifiRemoteStation *) st;
+  CheckInit (station);
+  station->m_nAttempt++;
+  station->m_nSuccess++;
+  station->m_nFail = 0;
+  station->m_usingRecoveryRate = false;
+  station->m_usingRecoveryPower = false;
+  station->m_nRetry = 0;
+  NS_LOG_DEBUG ("station=" << station << " data ok success=" << station->m_nSuccess << ", timer=" << station->m_nAttempt << ", rate=" << station->m_currentRate << ", power=" << (int)station->m_currentPower);
+  if ((station->m_nSuccess == m_successThreshold
+       || station->m_nAttempt == m_attemptThreshold)
+      && (station->m_currentRate < (station->m_state->m_operationalRateSet.size () - 1)))
+    {
+      NS_LOG_DEBUG ("station=" << station << " inc rate");
+      station->m_currentRate++;
+      m_rateChange (station->m_currentRate, station->m_state->m_address);
+      station->m_nAttempt = 0;
+      station->m_nSuccess = 0;
+      station->m_usingRecoveryRate = true;
+    }
+  else if (station->m_nSuccess == m_successThreshold || station->m_nAttempt == m_attemptThreshold)
+    {
+      //we are at the maximum rate, we decrease power
+      if (station->m_currentPower != 0)
+        {
+          NS_LOG_DEBUG ("station=" << station << " dec power");
+          station->m_currentPower--;
+          m_powerChange (station->m_currentPower, station->m_state->m_address);
+        }
+      station->m_nAttempt = 0;
+      station->m_nSuccess = 0;
+      station->m_usingRecoveryPower = true;
+    }
+}
+void
+ParfWifiManager::DoReportFinalRtsFailed (WifiRemoteStation *station)
+{
+  NS_LOG_FUNCTION (this << station);
+}
+void
+ParfWifiManager::DoReportFinalDataFailed (WifiRemoteStation *station)
+{
+  NS_LOG_FUNCTION (this << station);
+}
+
+WifiTxVector
+ParfWifiManager::DoGetDataTxVector (WifiRemoteStation *st, uint32_t size)
+{
+  NS_LOG_FUNCTION (this << st << size);
+  ParfWifiRemoteStation *station = (ParfWifiRemoteStation *) st;
+  CheckInit (station);
+  return WifiTxVector (GetSupported (station, station->m_currentRate), station->m_currentPower, GetLongRetryCount (station), GetShortGuardInterval (station), Min (GetNumberOfReceiveAntennas (station),GetNumberOfTransmitAntennas ()), GetNumberOfTransmitAntennas (station), GetStbc (station));
+}
+WifiTxVector
+ParfWifiManager::DoGetRtsTxVector (WifiRemoteStation *st)
+{
+  NS_LOG_FUNCTION (this << st);
+  /// \todo we could/should implement the Arf algorithm for
+  /// RTS only by picking a single rate within the BasicRateSet.
+  ParfWifiRemoteStation *station = (ParfWifiRemoteStation *) st;
+  return WifiTxVector (GetSupported (station, 0), GetDefaultTxPowerLevel (), GetShortRetryCount (station), GetShortGuardInterval (station), Min (GetNumberOfReceiveAntennas (station),GetNumberOfTransmitAntennas ()), GetNumberOfTransmitAntennas (station), GetStbc (station));
+}
+
+bool
+ParfWifiManager::IsLowLatency (void) const
+{
+  NS_LOG_FUNCTION (this);
+  return true;
+}
+} // namespace ns3