make MultiModelSpectrumChannel support SpectrumModel changes at run time
authorNicola Baldo <nbaldo@cttc.es>
Fri, 26 Oct 2012 14:10:40 +0200
changeset 9113 63eba52498e1
parent 9112 ede7a74e7411
child 9114 41bfd88f8055
make MultiModelSpectrumChannel support SpectrumModel changes at run time
CHANGES.html
src/spectrum/model/multi-model-spectrum-channel.cc
src/spectrum/model/multi-model-spectrum-channel.h
--- a/CHANGES.html	Sun Oct 21 15:48:47 2012 -0700
+++ b/CHANGES.html	Fri Oct 26 14:10:40 2012 +0200
@@ -64,6 +64,8 @@
 <h2>Changed behavior:</h2>
 <ul>
 <li>Sending a packet through Ipv4RawSocket now supports checksum in the Ipv4Header. It is still not possible to manually put in arbitrary checksum as the checksum is automatically calculated at Ipv4L3Protocol. The user has to enable checksum globally for this to work. Simply calling Ipv4Header::EnableChecksum() for a single Ipv4Header will not work.</li>
+<li>Now MultiModelSpectrumChannel allows a SpectrumPhy instance to change SpectrumModel at runtime by issuing a call to MultiModelSpectrumChannel::AddRx (). Previously, MultiModelSpectrumChannel required each SpectrumPhy instance to stick with the same SpectrumModel for the whole simulation. 
+</li>
 </ul>
 
 <hr>
--- a/src/spectrum/model/multi-model-spectrum-channel.cc	Sun Oct 21 15:48:47 2012 -0700
+++ b/src/spectrum/model/multi-model-spectrum-channel.cc	Fri Oct 26 14:10:40 2012 +0200
@@ -91,7 +91,6 @@
   m_spectrumPropagationLoss = 0;
   m_txSpectrumModelInfoMap.clear ();
   m_rxSpectrumModelInfoMap.clear ();
-  m_phyVector.clear ();
   SpectrumChannel::DoDispose ();
 }
 
@@ -142,12 +141,24 @@
 
   std::vector<Ptr<SpectrumPhy> >::const_iterator it;
 
-  // make sure this phy had not been already added
-  for ( it = m_phyVector.begin (); it != m_phyVector.end (); ++it)
+  // remove a previous entry of this phy if it exists
+  // we need to scan for all rxSpectrumModel values since we don't
+  // know which spectrum model the phy had when it was previously added
+  // (it's probably different than the current one)
+  for (RxSpectrumModelInfoMap_t::iterator rxInfoIterator = m_rxSpectrumModelInfoMap.begin ();
+       rxInfoIterator !=  m_rxSpectrumModelInfoMap.end ();
+       ++rxInfoIterator)
     {
-      NS_ASSERT (*it != phy);
+      std::set<Ptr<SpectrumPhy> >::iterator phyIt = rxInfoIterator->second.m_rxPhySet.find (phy);
+      if (phyIt !=  rxInfoIterator->second.m_rxPhySet.end ())
+        {
+          rxInfoIterator->second.m_rxPhySet.erase (phyIt);
+          --m_numDevices;
+          break; // there should be at most one entry
+        }       
     }
-  m_phyVector.push_back (phy);
+
+  ++m_numDevices;
 
   RxSpectrumModelInfoMap_t::iterator rxInfoIterator = m_rxSpectrumModelInfoMap.find (rxSpectrumModelUid);
 
@@ -157,8 +168,9 @@
       std::pair<RxSpectrumModelInfoMap_t::iterator, bool> ret;
       ret = m_rxSpectrumModelInfoMap.insert (std::make_pair (rxSpectrumModelUid, RxSpectrumModelInfo (rxSpectrumModel)));
       NS_ASSERT (ret.second);
-      // also add the phy to the newly created list of SpectrumPhy for this RxSpectrumModel
-      ret.first->second.m_rxPhyList.push_back (phy);
+      // also add the phy to the newly created set of SpectrumPhy for this RxSpectrumModel
+      std::pair<std::set<Ptr<SpectrumPhy> >::iterator, bool> ret2 = ret.first->second.m_rxPhySet.insert (phy);
+      NS_ASSERT (ret2.second);
 
       // and create the necessary converters for all the TX spectrum models that we know of
       for (TxSpectrumModelInfoMap_t::iterator txInfoIterator = m_txSpectrumModelInfoMap.begin ();
@@ -176,7 +188,8 @@
   else
     {
       // spectrum model is already known, just add the device to the corresponding list
-      rxInfoIterator->second.m_rxPhyList.push_back (phy);
+      std::pair<std::set<Ptr<SpectrumPhy> >::iterator, bool> ret2 = rxInfoIterator->second.m_rxPhySet.insert (phy);
+      NS_ASSERT (ret2.second);
     }
 
 }
@@ -224,6 +237,7 @@
   return txInfoIterator;
 }
 
+    
 
 void
 MultiModelSpectrumChannel::StartTx (Ptr<SpectrumSignalParameters> txParams)
@@ -268,14 +282,12 @@
         }
 
 
-      for (std::list<Ptr<SpectrumPhy> >::const_iterator rxPhyIterator = rxInfoIterator->second.m_rxPhyList.begin ();
-           rxPhyIterator != rxInfoIterator->second.m_rxPhyList.end ();
+      for (std::set<Ptr<SpectrumPhy> >::const_iterator rxPhyIterator = rxInfoIterator->second.m_rxPhySet.begin ();
+           rxPhyIterator != rxInfoIterator->second.m_rxPhySet.end ();
            ++rxPhyIterator)
         {
           NS_ASSERT_MSG ((*rxPhyIterator)->GetRxSpectrumModel ()->GetUid () == rxSpectrumModelUid,
-                         "MultiModelSpectrumChannel only supports devices that use a single RxSpectrumModel that does not change for the whole simulation");
-
-
+                         "SpectrumModel change was not notified to MultiModelSpectrumChannel (i.e., AddRx should be called again after model is changed)");
 
           if ((*rxPhyIterator) != txParams->txPhy)
             {
@@ -364,7 +376,7 @@
 uint32_t
 MultiModelSpectrumChannel::GetNDevices (void) const
 {
-  return m_phyVector.size ();
+  return m_numDevices;
 
 }
 
@@ -372,7 +384,32 @@
 Ptr<NetDevice>
 MultiModelSpectrumChannel::GetDevice (uint32_t i) const
 {
-  return m_phyVector.at (i)->GetDevice ();
+  NS_ASSERT (i < m_numDevices);
+  // this method implementation is computationally intensive. This
+  // method would be faster if we actually used a std::vector for
+  // storing devices, which we don't due to the need to have fast 
+  // SpectrumModel conversions and to allow PHY devices to changea
+  // SpectrumModel at run time. Note that having this method slow is
+  // acceptable as it is not used much at run time (often not at all).
+  // On the other hand, having slow SpectrumModel conversion would be
+  // less acceptable. 
+  uint32_t j = 0;
+  for (RxSpectrumModelInfoMap_t::const_iterator rxInfoIterator = m_rxSpectrumModelInfoMap.begin ();
+       rxInfoIterator !=  m_rxSpectrumModelInfoMap.end ();
+       ++rxInfoIterator)
+    {
+      for (std::set<Ptr<SpectrumPhy> >::const_iterator phyIt = rxInfoIterator->second.m_rxPhySet.begin ();
+           phyIt != rxInfoIterator->second.m_rxPhySet.end ();
+           ++phyIt)        
+        {
+          if (j == i)
+            {
+              return (*phyIt)->GetDevice ();
+            }
+        }
+    }
+  NS_FATAL_ERROR ("m_numDevice > actual number of devices");
+  return 0;
 }
 
 
--- a/src/spectrum/model/multi-model-spectrum-channel.h	Sun Oct 21 15:48:47 2012 -0700
+++ b/src/spectrum/model/multi-model-spectrum-channel.h	Fri Oct 26 14:10:40 2012 +0200
@@ -28,7 +28,7 @@
 #include <ns3/spectrum-propagation-loss-model.h>
 #include <ns3/propagation-delay-model.h>
 #include <map>
-#include <list>
+#include <set>
 
 namespace ns3 {
 
@@ -62,7 +62,7 @@
   RxSpectrumModelInfo (Ptr<const SpectrumModel> rxSpectrumModel);
 
   Ptr<const SpectrumModel> m_rxSpectrumModel;
-  std::list<Ptr<SpectrumPhy> > m_rxPhyList;
+  std::set<Ptr<SpectrumPhy> > m_rxPhySet;
 };
 
 typedef std::map<SpectrumModelUid_t, RxSpectrumModelInfo> RxSpectrumModelInfoMap_t;
@@ -75,9 +75,13 @@
  *
  * This SpectrumChannel implementation can handle the presence of
  * SpectrumPhy instances which can use
- * different spectrum models, i.e.,  different SpectrumModel. The only
- * requirement is that every SpectrumPhy instance uses the same
- * SpectrumModel for the whole simulation.
+ * different spectrum models, i.e.,  different SpectrumModel. 
+ *
+ * \note It is allowed for a receiving SpectrumPhy to switch to a
+ * different SpectrumModel during the simulation. The requirement
+ * for this to work is that, after the SpectrumPhy switched its
+ * SpectrumModel,  MultiModelSpectrumChannel::AddRx () is
+ * called again passing the pointer to that SpectrumPhy.
  */
 class MultiModelSpectrumChannel : public SpectrumChannel
 {
@@ -120,18 +124,6 @@
    */
   TxSpectrumModelInfoMap_t::const_iterator FindAndEventuallyAddTxSpectrumModel (Ptr<const SpectrumModel> txSpectrumModel);
 
-
-  /**
-   * make sure that there are SpectrumConverters from any
-   * SpectrumPhy being used for TX to the given SpectrumModel being used for RX
-   *
-   * @param rxPhy the RXing SpectrumPhy
-   * @param rxSpectrumModel the SpectrumModel used for RX by rxPhy
-   */
-  void CheckAddRxSpectrumModel (Ptr<SpectrumPhy> rxPhy, Ptr<const SpectrumModel> rxSpectrumModel);
-
-
-
   /**
    * used internally to reschedule transmission after the propagation delay
    *
@@ -177,13 +169,7 @@
    */
   RxSpectrumModelInfoMap_t m_rxSpectrumModelInfoMap;
 
-  /**
-   * this is only used to provide a straighforward implementation of
-   * GetNDevices() and GetDevice()
-   *
-   */
-  std::vector<Ptr<SpectrumPhy> > m_phyVector;
-
+  uint32_t m_numDevices;
 
   double m_maxLossDb;