Frequency channel switch on channel, PHY and MAC levels
authorPavel Boyko <boyko@iitp.ru>
Thu, 02 Apr 2009 14:33:38 +0400
changeset 4934 345b49df838b
parent 4933 72f0481cfb2d
child 4935 8091159b7dc9
child 4937 7211ebc93e69
Frequency channel switch on channel, PHY and MAC levels
src/devices/mesh/mesh-wifi-interface-mac.cc
src/devices/mesh/mesh-wifi-interface-mac.h
src/devices/wifi/yans-wifi-channel.cc
src/devices/wifi/yans-wifi-phy.cc
src/devices/wifi/yans-wifi-phy.h
--- a/src/devices/mesh/mesh-wifi-interface-mac.cc	Thu Apr 02 13:38:38 2009 +0400
+++ b/src/devices/mesh/mesh-wifi-interface-mac.cc	Thu Apr 02 14:33:38 2009 +0400
@@ -1,7 +1,7 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/* 
+/*
  * Copyright (c) 2009 IITP RAS
- * 
+ *
  * 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;
@@ -14,7 +14,7 @@
  * 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
- * 
+ *
  * Authors: Kirill Andreev <andreev@iitp.ru>
  *          Pavel Boyko <boyko@iitp.ru>
  */
@@ -30,6 +30,7 @@
 #include "ns3/mesh-wifi-mac-header.h"
 #include "ns3/random-variable.h"
 #include "ns3/simulator.h"
+#include "ns3/yans-wifi-phy.h"
 
 NS_LOG_COMPONENT_DEFINE ("MeshWifiInterfaceMac");
 
@@ -67,7 +68,7 @@
 MeshWifiInterfaceMac::MeshWifiInterfaceMac ()
 {
   NS_LOG_FUNCTION (this);
-  
+
   m_rxMiddle = new MacRxMiddle ();
   m_rxMiddle->SetForwardCallback (MakeCallback (&MeshWifiInterfaceMac::Receive, this));
 
@@ -187,6 +188,8 @@
   m_phy = phy;
   m_dcfManager->SetupPhyListener (phy);
   m_low->SetPhy (phy);
+
+  NS_LOG_DEBUG("SetWifiPhy: Can switch channel now: " << CanSwitchChannel() ); // TMP
 }
 
 void
@@ -290,21 +293,75 @@
   m_VO = 0;
   m_beaconSendEvent.Cancel ();
   m_beaconDca = 0;
-  
+
   WifiMac::DoDispose ();
 }
 
 //-----------------------------------------------------------------------------
 // Plugins
 //-----------------------------------------------------------------------------
-void 
+void
 MeshWifiInterfaceMac::InstallPlugin ( Ptr<MeshWifiInterfaceMacPlugin> plugin)
 {
+  NS_LOG_FUNCTION (this);
+
   plugin->SetParent (this);
   m_plugins.push_back (plugin);
 }
 
 //-----------------------------------------------------------------------------
+// Switch channels
+//-----------------------------------------------------------------------------
+bool MeshWifiInterfaceMac::CanSwitchChannel () const
+{
+  NS_LOG_FUNCTION (this);
+
+  // now only YansWifiPhy can switch channels runtime
+  if (m_phy != 0)
+    {
+      Ptr<YansWifiPhy> phy = m_phy->GetObject<YansWifiPhy> ();
+      return (phy != 0);
+    }
+  else
+    return false;
+}
+
+uint16_t MeshWifiInterfaceMac::GetFrequencyChannel () const
+{
+  NS_LOG_FUNCTION (this);
+  NS_ASSERT (m_phy != 0); // need PHY to set/get channel
+
+  Ptr<YansWifiPhy> phy = m_phy->GetObject<YansWifiPhy> ();
+  if (phy != 0)
+    return phy->GetFrequencyChannel ();
+  else
+    return 0;
+}
+
+void MeshWifiInterfaceMac::SwitchFrequencyChannel (uint16_t new_id)
+{
+  NS_LOG_FUNCTION (this);
+  NS_ASSERT (m_phy != 0); // need PHY to set/get channel
+  /* TODO
+   *
+   * Correct channel switching is:
+   *
+   * 1. Interface down, e.g. to stop packets from layer 3
+   * 2. Wait before all output queues will be empty
+   * 3. Switch PHY channel
+   * 4. Interface up
+   *
+   * Now we use dirty channel switch -- just change frequency
+   */
+  NS_ASSERT(CanSwitchChannel());
+
+  Ptr<YansWifiPhy> phy = m_phy->GetObject<YansWifiPhy> ();
+  phy->SetFrequencyChannel (new_id);
+  // Don't know NAV on new channel
+  m_dcfManager->NotifyNavResetNow (Seconds (0));
+}
+
+//-----------------------------------------------------------------------------
 // Forward frame up/down
 //-----------------------------------------------------------------------------
 void
@@ -319,7 +376,7 @@
 {
   // copy packet to allow modifications
   Ptr<Packet> packet = const_packet->Copy ();
-  
+
   WifiMacHeader hdr;
   hdr.SetTypeData ();
   hdr.SetAddr2 (GetAddress ());
@@ -327,19 +384,20 @@
   hdr.SetAddr4 (from);
   hdr.SetDsFrom ();
   hdr.SetDsTo ();
+
   // Address 1 is unknwon here. Routing plugin is responsible to correctly set it.
   hdr.SetAddr1 (Mac48Address ());
-  
+
   // Filter packet through all installed plugins
   for (PluginList::const_iterator i = m_plugins.begin(); i != m_plugins.end(); ++i)
     {
       bool drop = ! ((*i)->UpdateOutcomingFrame(packet, hdr, from, to));
       if (drop) return; // plugin drops frame
     }
-  
+
   // Assert that address1 is set. Assert will fail e.g. if there is no installed routing plugin.
   NS_ASSERT (hdr.GetAddr1() != Mac48Address() );
-  
+
   // Queue frame
   WifiRemoteStation *destination = m_stationManager->Lookup (to);
 
@@ -415,7 +473,7 @@
   m_beaconInterval = interval;
 }
 
-Time 
+Time
 MeshWifiInterfaceMac::GetBeaconInterval () const
 {
   return m_beaconInterval;
@@ -430,7 +488,7 @@
       // Now start sending beacons after some random delay (to avoid collisions)
       UniformVariable coefficient (0.0, m_randomStart.GetSeconds());
       Time randomStart = Seconds (coefficient.GetValue());
-      
+
       m_beaconSendEvent = Simulator::Schedule (randomStart, &MeshWifiInterfaceMac::SendBeacon, this);
       m_tbtt = Simulator::Now() + randomStart;
     }
@@ -455,14 +513,14 @@
 {
   // User of ShiftTbtt () must take care don't shift it to the past
   NS_ASSERT (GetTbtt() + shift > Simulator::Now());
-  
+
   m_tbtt += shift;
   // Shift scheduled event
   Simulator::Cancel (m_beaconSendEvent);
   m_beaconSendEvent = Simulator::Schedule (GetTbtt () - Simulator::Now(), &MeshWifiInterfaceMac::SendBeacon, this);
 }
 
-void 
+void
 MeshWifiInterfaceMac::ScheduleNextBeacon ()
 {
   m_tbtt += GetBeaconInterval ();
@@ -474,19 +532,19 @@
 {
   NS_LOG_FUNCTION (this);
   NS_LOG_DEBUG (GetAddress() <<" is sending beacon");
-  
+
   NS_ASSERT (! m_beaconSendEvent.IsRunning());
   NS_ASSERT (Simulator::Now().GetMicroSeconds() == GetTbtt().GetMicroSeconds());     // assert that beacon is just on time
-   
+
   // Form & send beacon
   MeshWifiBeacon beacon (GetSsid (), GetSupportedRates (), m_beaconInterval.GetMicroSeconds ());
-  
+
   // Ask all plugins to add their specific information elements to beacon
   for (PluginList::const_iterator i = m_plugins.begin(); i != m_plugins.end(); ++i)
     (*i)->UpdateBeacon (beacon);
-  
+
   m_beaconDca->Queue (beacon.CreatePacket(), beacon.CreateHeader(GetAddress()));
-  
+
   ScheduleNextBeacon ();
 }
 
@@ -500,20 +558,20 @@
     {
       MgtBeaconHeader beacon_hdr;
       Mac48Address from = hdr->GetAddr2 ();
-      
+
       packet->PeekHeader (beacon_hdr);
-      
+
       NS_LOG_DEBUG ("Beacon received from "<<hdr->GetAddr2()<<
                    " I am "<<GetAddress ()<<
                    " at "<<Simulator::Now ().GetMicroSeconds ()<<
                    " microseconds");
-      
+
       // update supported rates
       if (beacon_hdr.GetSsid ().IsEqual(GetSsid()))
         {
           SupportedRates rates = beacon_hdr.GetSupportedRates ();
           WifiRemoteStation * peerSta = m_stationManager->Lookup (hdr->GetAddr2 ());
-      
+
           for (uint32_t i = 0; i < m_phy->GetNModes (); i++)
           {
             WifiMode mode = m_phy->GetMode (i);
@@ -526,14 +584,14 @@
           }
         }
     }
-  
+
   // Filter frame through all installed plugins
   for (PluginList::iterator i = m_plugins.begin (); i != m_plugins.end(); ++i)
     {
       bool drop = ! ((*i)->Receive(packet, *hdr));
       if (drop) return; // plugin drops frame
     }
-    
+
   // Forward data up
   if (hdr->IsData ())
       ForwardUp (packet, hdr->GetAddr4(), hdr->GetAddr3());
--- a/src/devices/mesh/mesh-wifi-interface-mac.h	Thu Apr 02 13:38:38 2009 +0400
+++ b/src/devices/mesh/mesh-wifi-interface-mac.h	Thu Apr 02 14:33:38 2009 +0400
@@ -121,13 +121,32 @@
   /// Install plugin. TODO return unique ID to allow unregister plugins
   void InstallPlugin (Ptr<MeshWifiInterfaceMacPlugin> plugin);
   //\}
-  ///\name Management frame sender:
+  
+  /** \name Channel switching
+   * 
+   * Channel center frequency = Channel starting frequency + 5 × nch (MHz), 
+   * where Starting channel frequency is standard-dependent as defined in IEEE 802.11-2007 17.3.8.3.2.
+   * 
+   * Number of channels to use must be limited elsewhere. 
+   */
   //\{
-  void SendManagementFrame(Ptr<Packet> frame, const WifiMacHeader& hdr);
+  /// Return true if PHY layer can switch channels
+  bool CanSwitchChannel () const;
+  /// Current channel Id
+  uint16_t GetFrequencyChannel () const;
+  /// Switch channel
+  void SwitchFrequencyChannel (uint16_t new_id);
   //\}
+  
+  /// To be used by plugins sending management frames.
+  void SendManagementFrame(Ptr<Packet> frame, const WifiMacHeader& hdr);
+  /// \return true if meshId is correct Ssid
   bool CheckMeshId(Ssid meshId) const;
+  /// \return true if rates are supported
   bool CheckSupportedRates(SupportedRates rates) const;
+  /// \return list of supported bitrates
   SupportedRates GetSupportedRates () const;
+  
 private:
   /// Frame receive handler
   void  Receive (Ptr<Packet> packet, WifiMacHeader const *hdr);
--- a/src/devices/wifi/yans-wifi-channel.cc	Thu Apr 02 13:38:38 2009 +0400
+++ b/src/devices/wifi/yans-wifi-channel.cc	Thu Apr 02 14:33:38 2009 +0400
@@ -81,6 +81,10 @@
     {
       if (sender != (*i))
         {
+          // For now don't account for interchannel interference
+          if ((*i)->GetFrequencyChannel() != sender->GetFrequencyChannel())
+            continue;
+          
           Ptr<MobilityModel> receiverMobility = (*i)->GetMobility ()->GetObject<MobilityModel> ();
           Time delay = m_delay->GetDelay (senderMobility, receiverMobility);
           double rxPowerDbm = m_loss->CalcRxPower (txPowerDbm, senderMobility, receiverMobility);
--- a/src/devices/wifi/yans-wifi-phy.cc	Thu Apr 02 13:38:38 2009 +0400
+++ b/src/devices/wifi/yans-wifi-phy.cc	Thu Apr 02 14:33:38 2009 +0400
@@ -109,13 +109,21 @@
                    PointerValue (),
                    MakePointerAccessor (&YansWifiPhy::m_state),
                    MakePointerChecker<WifiPhyStateHelper> ())
+    .AddAttribute ("ChannelSwitchDelay",
+                   "Delay between two short frames transmitted on different frequencies",
+                   TimeValue (MicroSeconds (250)),
+                   MakeTimeAccessor (&YansWifiPhy::m_channelSwitchDelay), 
+                   MakeTimeChecker ())
+    
     ;
   return tid;
 }
 
 YansWifiPhy::YansWifiPhy ()
- : m_endSyncEvent (),
-   m_random (0.0, 1.0)
+ : m_channelId(0),
+   m_endSyncEvent (),
+   m_random (0.0, 1.0),
+   m_channelStartingFrequency(0.0)
 {
   NS_LOG_FUNCTION (this);
   m_state = CreateObject<WifiPhyStateHelper> ();
@@ -288,6 +296,32 @@
 {
   m_channel = channel;
   m_channel->Add (this);
+  m_channelId = 0;      // always start on channel starting frequency
+}
+
+void 
+YansWifiPhy::SetFrequencyChannel (uint16_t nch)
+{
+  Simulator::Schedule (m_channelSwitchDelay, &YansWifiPhy::DoSetChannelId, this, nch);
+}
+
+void
+YansWifiPhy::DoSetChannelId (uint16_t nch)
+{
+  NS_LOG_DEBUG("switching channel " << m_channelId << " -> " << nch);
+  m_channelId = nch;
+}
+
+uint16_t 
+YansWifiPhy::GetFrequencyChannel() const
+{
+  return m_channelId;
+}
+
+double
+YansWifiPhy::GetChannelCenterFrequency() const
+{
+  return m_channelStartingFrequency + 5e6 * GetFrequencyChannel();
 }
 
 void 
@@ -424,6 +458,7 @@
 {
   NS_LOG_FUNCTION (this);
   m_interference.Configure80211aParameters ();
+  m_channelStartingFrequency = 5e9; // 5 GHz 
   m_modes.push_back (WifiPhy::Get6mba ());
   m_modes.push_back (WifiPhy::Get9mba ());
   m_modes.push_back (WifiPhy::Get12mba ());
--- a/src/devices/wifi/yans-wifi-phy.h	Thu Apr 02 13:38:38 2009 +0400
+++ b/src/devices/wifi/yans-wifi-phy.h	Thu Apr 02 14:33:38 2009 +0400
@@ -69,6 +69,21 @@
   virtual ~YansWifiPhy ();
 
   void SetChannel (Ptr<YansWifiChannel> channel);
+  
+  /** 
+   * \brief Set channel number. 
+   * 
+   * Channel center frequency = Channel starting frequency + 5 × nch (MHz)
+   *
+   * where Starting channel frequency is standard-dependent, see SetStandard()
+   * as defined in IEEE 802.11-2007 17.3.8.3.2.
+   */ 
+  void SetFrequencyChannel (uint16_t id);
+  /// Return current channel ID, see SetChannelId()
+  uint16_t GetFrequencyChannel () const;
+  /// Return current center channel frequency in Hz, see SetChannelId()
+  double GetChannelCenterFrequency() const;
+  
   void StartReceivePacket (Ptr<Packet> packet,
                            double rxPowerDbm,
                            WifiMode mode,
@@ -94,6 +109,8 @@
   Ptr<ErrorRateModel> GetErrorRateModel (void) const;
   Ptr<Object> GetDevice (void) const;
   Ptr<Object> GetMobility (void);
+  
+  
 
 
   virtual double GetTxPowerStart (void) const;
@@ -132,6 +149,7 @@
   double RatioToDb (double ratio) const;
   double GetPowerDbm (uint8_t power) const;
   void EndSync (Ptr<Packet> packet, Ptr<InterferenceHelper::Event> event);
+  void DoSetChannelId(uint16_t id);
 
 private:
   double   m_edThresholdW;
@@ -143,14 +161,18 @@
   uint32_t m_nTxPower;
 
   Ptr<YansWifiChannel> m_channel;
+  uint16_t m_channelId;
   Ptr<Object> m_device;
   Ptr<Object> m_mobility;
   Modes m_modes;
   EventId m_endSyncEvent;
   UniformVariable m_random;
   WifiPhyStandard m_standard;
+  /// Standard-dependent center frequency of 0-th channel 
+  double m_channelStartingFrequency;
   Ptr<WifiPhyStateHelper> m_state;
   InterferenceHelper m_interference;
+  Time m_channelSwitchDelay;
 
 };