src/lte/model/lte-ue-mac.cc
changeset 9413 20f1c6678ee2
parent 9406 7f0f9d8f8e20
child 9414 7b0db3dbf19b
--- a/src/lte/model/lte-ue-mac.cc	Wed Nov 14 16:05:54 2012 +0100
+++ b/src/lte/model/lte-ue-mac.cc	Tue Nov 20 18:18:01 2012 +0100
@@ -53,6 +53,7 @@
   UeMemberLteUeCmacSapProvider (LteUeMac* mac);
 
   // inherited from LteUeCmacSapProvider
+  virtual void ConfigureRach (RachConfig rc);
   virtual void StartContentionBasedRandomAccessProcedure ();
   virtual void StartNonContentionBasedRandomAccessProcedure (uint16_t rnti, uint8_t preambleId, uint8_t prachMask);
   virtual void AddLc (uint8_t lcId, LteUeCmacSapProvider::LogicalChannelConfig lcConfig, LteMacSapUser* msu);
@@ -69,6 +70,12 @@
 {
 }
 
+void 
+UeMemberLteUeCmacSapProvider::ConfigureRach (RachConfig rc)
+{
+  m_mac->DoConfigureRach (rc);
+}
+
   void 
 UeMemberLteUeCmacSapProvider::StartContentionBasedRandomAccessProcedure ()
 {
@@ -195,7 +202,9 @@
   :  m_bsrPeriodicity (MilliSeconds (1)), // ideal behavior
      m_bsrLast (MilliSeconds (0)),
      m_freshUlBsr (false),
-     m_rnti (0)
+     m_rnti (0),
+     m_rachConfigured (false),
+     m_waitingForRaResponse (false)
   
 {
   NS_LOG_FUNCTION (this);
@@ -336,15 +345,22 @@
 }
 
 void 
-LteUeMac::DoStartContentionBasedRandomAccessProcedure ()
+LteUeMac::RandomlySelectAndSendRaPreamble ()
 {
   NS_LOG_FUNCTION (this);
-  static uint32_t prachIdCounter = 256;
-  prachIdCounter += 2;
-  m_prachId = prachIdCounter;
-  NS_LOG_INFO ("sending RACH preamble " << m_prachId);
-
-
+  // 3GPP 36.321 5.1.1  
+  NS_ASSERT_MSG (m_rachConfigured, "RACH not configured");
+  UniformVariable uv;
+  // assume that there is no Random Access Preambles group B
+  m_raPreambleId = uv.GetInteger (0, m_rachConfig.numberOfRaPreambles - 1);
+  bool contention = true;
+  SendRaPreamble (contention);
+}
+   
+void
+LteUeMac::SendRaPreamble (bool contention)
+{
+  NS_LOG_FUNCTION (this << (uint32_t) m_raPreambleId << contention);
   // Since regular UL LteControlMessages need m_ulConfigured = true in
   // order to be sent by the UE, the rach preamble needs to be sent
   // with a dedicated primitive (not
@@ -352,23 +368,101 @@
   // bypass the m_ulConfigured flag. This is reasonable, since In fact
   // the RACH preamble is sent on 6RB bandwidth so the uplink
   // bandwidth does not need to be configured. 
+  m_uePhySapProvider->SendRachPreamble (m_raPreambleId);
+  NS_ASSERT (m_subframeNo > 0); // sanity check for subframe starting at 1
+  m_raRnti = m_subframeNo - 1;
+  NS_LOG_INFO (this << " sent preamble id " << (uint32_t) m_raPreambleId << ", RA-RNTI " << (uint32_t) m_raRnti);
+  // 3GPP 36.321 5.1.4 
+  Time raWindowBegin = MilliSeconds (3); 
+  Time raWindowEnd = MilliSeconds (3 + m_rachConfig.raResponseWindowSize);
+  Simulator::Schedule (raWindowBegin, &LteUeMac::StartWaitingForRaResponse, this);
+  m_noRaResponseReceivedEvent = Simulator::Schedule (raWindowEnd, &LteUeMac::RaResponseTimeout, this, contention);
+}
 
-  Ptr<RachPreambleLteControlMessage> msg = Create<RachPreambleLteControlMessage> ();
-  msg->SetPrachId (m_prachId);
-  m_uePhySapProvider->SendRachPreamble (m_prachId);
+void 
+LteUeMac::StartWaitingForRaResponse ()
+{
+   NS_LOG_FUNCTION (this);
+   m_waitingForRaResponse = true;
+}
+
+void 
+LteUeMac::RecvRaResponse (BuildRarListElement_s raResponse)
+{
+  NS_LOG_FUNCTION (this);
+  m_waitingForRaResponse = false;
+  m_noRaResponseReceivedEvent.Cancel ();
+  NS_LOG_INFO ("got RAR for RAPID " << (uint32_t) m_raPreambleId << ", setting T-C-RNTI = " << raResponse.m_rnti);
+  m_rnti = raResponse.m_rnti;
+  m_cmacSapUser->SetTemporaryCellRnti (m_rnti);
+  // in principle we should wait for contention resolution,
+  // but in the current LTE model when two or more identical
+  // preambles are sent no one is received, so there is no need
+  // for contention resolution
+  m_cmacSapUser->NotifyRandomAccessSuccessful ();
+}
+
+void 
+LteUeMac::RaResponseTimeout (bool contention)
+{
+  NS_LOG_FUNCTION (this << contention);
+  m_waitingForRaResponse = false;
+  // 3GPP 36.321 5.1.4
+  ++m_preambleTransmissionCounter;
+  if (m_preambleTransmissionCounter == m_rachConfig.preambleTransMax + 1)
+    {
+      NS_LOG_INFO ("RAR timeout, preambleTransMax reached => giving up");
+      m_cmacSapUser->NotifyRandomAccessFailed ();
+    }
+  else
+    {
+      NS_LOG_INFO ("RAR timeout, re-send preamble");
+      if (contention)
+        {
+          RandomlySelectAndSendRaPreamble ();
+        }
+      else
+        {
+          SendRaPreamble (contention);
+        }
+    }
+}
+
+void 
+LteUeMac::DoConfigureRach (LteUeCmacSapProvider::RachConfig rc)
+{
+  NS_LOG_FUNCTION (this);
+  m_rachConfig = rc;
+  m_rachConfigured = true;
+}
+
+void 
+LteUeMac::DoStartContentionBasedRandomAccessProcedure ()
+{
+  NS_LOG_FUNCTION (this);
+
+  // 3GPP 36.321 5.1.1
+  NS_ASSERT_MSG (m_rachConfigured, "RACH not configured");
+  m_preambleTransmissionCounter = 0;
+  m_backoffParameter = 0;
+  RandomlySelectAndSendRaPreamble ();
 }
 
 void 
 LteUeMac::DoStartNonContentionBasedRandomAccessProcedure (uint16_t rnti, uint8_t preambleId, uint8_t prachMask)
 {
   NS_LOG_FUNCTION (this << " rnti" << rnti);
+  NS_ASSERT_MSG (prachMask == 0, "requested PRACH MASK = " << (uint32_t) prachMask << ", but only PRACH MASK = 0 is supported");
   m_rnti = rnti;
+  m_raPreambleId = preambleId;
+  bool contention = false;
+  SendRaPreamble (contention);
 }
 
 void
 LteUeMac::DoAddLc (uint8_t lcId,  LteUeCmacSapProvider::LogicalChannelConfig lcConfig, LteMacSapUser* msu)
 {
-  NS_LOG_FUNCTION (this << " lcId" << (uint16_t) lcId);
+  NS_LOG_FUNCTION (this << " lcId" << (uint32_t) lcId);
   NS_ASSERT_MSG (m_lcInfoMap.find (lcId) == m_lcInfoMap.end (), "cannot add channel because LCID " << lcId << " is already present");
   
   LcInfo lcInfo;
@@ -403,6 +497,7 @@
           m_lcInfoMap.erase (it++);
         }
     }
+  m_rachConfigured = false;
 }
 
 void
@@ -450,7 +545,7 @@
           itBsr = m_ulBsrReceived.find ((*it).first);
           if (((itBsr!=m_ulBsrReceived.end ()) && ((*itBsr).second > 0)))
             {
-              NS_LOG_LOGIC (this << "\t" << bytesPerActiveLc << " bytes to LC " << (uint16_t)(*it).first << " queue " << (*itBsr).second);
+              NS_LOG_LOGIC (this << "\t" << bytesPerActiveLc << " bytes to LC " << (uint32_t)(*it).first << " queue " << (*itBsr).second);
               (*it).second.macSapUser->NotifyTxOpportunity (bytesPerActiveLc, 0);
               if ((*itBsr).second >=  static_cast<uint64_t> (bytesPerActiveLc))
                 {
@@ -466,20 +561,24 @@
     }
   else if (msg->GetMessageType () == LteControlMessage::RAR)
     {
-      Ptr<RarLteControlMessage> msg2 = DynamicCast<RarLteControlMessage> (msg);
-      
-      if (msg2->GetPrachId () == m_prachId)
+      if (m_waitingForRaResponse)
         {
-          m_rnti = msg2->GetRar ().m_rnti;
-          NS_LOG_INFO ("got RAR for PRACH ID " << m_prachId << ", setting T-C-RNTI = " << m_rnti);
-          m_cmacSapUser->SetTemporaryCellRnti (m_rnti);
-            
-          // in principle we should wait for contention resolution,
-          // but, since we don't model RACH PREAMBLE collisions, we
-          // just stop here
-          m_cmacSapUser->NotifyRandomAccessSuccessful ();
+          Ptr<RarLteControlMessage> rarMsg = DynamicCast<RarLteControlMessage> (msg);
+          uint16_t raRnti = rarMsg->GetRaRnti ();
+          NS_LOG_LOGIC (this << "got RAR with RA-RNTI " << (uint32_t) raRnti << ", expecting " << (uint32_t) m_raRnti);
+          if (raRnti == m_raRnti) // RAR corresponds to TX subframe of preamble
+            {
+              for (std::list<RarLteControlMessage::Rar>::const_iterator it = rarMsg->RarListBegin ();
+                   it != rarMsg->RarListEnd ();
+                   ++it)
+                {
+                  if (it->rapId == m_raPreambleId) // RAR is for me
+                    {
+                      RecvRaResponse (it->rarPayload);
+                    }
+                }
+            }
         }
-      // else the RAR is not for me
     }
   else
     {
@@ -492,6 +591,8 @@
 LteUeMac::DoSubframeIndication (uint32_t frameNo, uint32_t subframeNo)
 {
   NS_LOG_FUNCTION (this);
+  m_frameNo = frameNo;
+  m_subframeNo = subframeNo;
   if ((Simulator::Now () >= m_bsrLast + m_bsrPeriodicity) && (m_freshUlBsr==true))
     {
       SendReportBufferStatus ();