/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2011 Centre Tecnologic de Telecomunicacions de Catalunya (CTTC)
*
* 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: Nicola Baldo <nbaldo@cttc.es>
* Author: Marco Miozzo <mmiozzo@cttc.es>
*/
#include <ns3/log.h>
#include <ns3/pointer.h>
#include <ns3/packet.h>
#include <ns3/packet-burst.h>
#include <ns3/random-variable.h>
#include "lte-ue-mac.h"
#include "lte-ue-net-device.h"
#include "lte-radio-bearer-tag.h"
#include <ns3/ff-mac-common.h>
#include <ns3/lte-control-messages.h>
#include <ns3/simulator.h>
#include <ns3/lte-common.h>
NS_LOG_COMPONENT_DEFINE ("LteUeMac");
namespace ns3 {
NS_OBJECT_ENSURE_REGISTERED (LteUeMac);
///////////////////////////////////////////////////////////
// SAP forwarders
///////////////////////////////////////////////////////////
class UeMemberLteUeCmacSapProvider : public LteUeCmacSapProvider
{
public:
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);
virtual void RemoveLc (uint8_t lcId);
virtual void Reset ();
private:
LteUeMac* m_mac;
};
UeMemberLteUeCmacSapProvider::UeMemberLteUeCmacSapProvider (LteUeMac* mac)
: m_mac (mac)
{
}
void
UeMemberLteUeCmacSapProvider::ConfigureRach (RachConfig rc)
{
m_mac->DoConfigureRach (rc);
}
void
UeMemberLteUeCmacSapProvider::StartContentionBasedRandomAccessProcedure ()
{
m_mac->DoStartContentionBasedRandomAccessProcedure ();
}
void
UeMemberLteUeCmacSapProvider::StartNonContentionBasedRandomAccessProcedure (uint16_t rnti, uint8_t preambleId, uint8_t prachMask)
{
m_mac->DoStartNonContentionBasedRandomAccessProcedure (rnti, preambleId, prachMask);
}
void
UeMemberLteUeCmacSapProvider::AddLc (uint8_t lcId, LogicalChannelConfig lcConfig, LteMacSapUser* msu)
{
m_mac->DoAddLc (lcId, lcConfig, msu);
}
void
UeMemberLteUeCmacSapProvider::RemoveLc (uint8_t lcid)
{
m_mac->DoRemoveLc (lcid);
}
void
UeMemberLteUeCmacSapProvider::Reset ()
{
m_mac->DoReset ();
}
class UeMemberLteMacSapProvider : public LteMacSapProvider
{
public:
UeMemberLteMacSapProvider (LteUeMac* mac);
// inherited from LteMacSapProvider
virtual void TransmitPdu (TransmitPduParameters params);
virtual void ReportBufferStatus (ReportBufferStatusParameters params);
private:
LteUeMac* m_mac;
};
UeMemberLteMacSapProvider::UeMemberLteMacSapProvider (LteUeMac* mac)
: m_mac (mac)
{
}
void
UeMemberLteMacSapProvider::TransmitPdu (TransmitPduParameters params)
{
m_mac->DoTransmitPdu (params);
}
void
UeMemberLteMacSapProvider::ReportBufferStatus (ReportBufferStatusParameters params)
{
m_mac->DoReportBufferStatus (params);
}
class UeMemberLteUePhySapUser : public LteUePhySapUser
{
public:
UeMemberLteUePhySapUser (LteUeMac* mac);
// inherited from LtePhySapUser
virtual void ReceivePhyPdu (Ptr<Packet> p);
virtual void SubframeIndication (uint32_t frameNo, uint32_t subframeNo);
virtual void ReceiveLteControlMessage (Ptr<LteControlMessage> msg);
private:
LteUeMac* m_mac;
};
UeMemberLteUePhySapUser::UeMemberLteUePhySapUser (LteUeMac* mac) : m_mac (mac)
{
}
void
UeMemberLteUePhySapUser::ReceivePhyPdu (Ptr<Packet> p)
{
m_mac->DoReceivePhyPdu (p);
}
void
UeMemberLteUePhySapUser::SubframeIndication (uint32_t frameNo, uint32_t subframeNo)
{
m_mac->DoSubframeIndication (frameNo, subframeNo);
}
void
UeMemberLteUePhySapUser::ReceiveLteControlMessage (Ptr<LteControlMessage> msg)
{
m_mac->DoReceiveLteControlMessage (msg);
}
//////////////////////////////////////////////////////////
// LteUeMac methods
///////////////////////////////////////////////////////////
TypeId
LteUeMac::GetTypeId (void)
{
static TypeId tid = TypeId ("ns3::LteUeMac")
.SetParent<Object> ()
.AddConstructor<LteUeMac> ();
return tid;
}
LteUeMac::LteUeMac ()
: m_bsrPeriodicity (MilliSeconds (1)), // ideal behavior
m_bsrLast (MilliSeconds (0)),
m_freshUlBsr (false),
m_harqProcessId (0),
m_rnti (0),
m_rachConfigured (false),
m_waitingForRaResponse (false)
{
NS_LOG_FUNCTION (this);
m_miUlHarqProcessesPacket.resize (HARQ_PERIOD);
for (uint8_t i = 0; i < m_miUlHarqProcessesPacket.size (); i++)
{
Ptr<PacketBurst> pb = CreateObject <PacketBurst> ();
m_miUlHarqProcessesPacket.at (i) = pb;
}
m_miUlHarqProcessesPacketTimer.resize (HARQ_PERIOD, 0);
m_macSapProvider = new UeMemberLteMacSapProvider (this);
m_cmacSapProvider = new UeMemberLteUeCmacSapProvider (this);
m_uePhySapUser = new UeMemberLteUePhySapUser (this);
m_raPreambleUniformVariable = CreateObject<UniformRandomVariable> ();
}
LteUeMac::~LteUeMac ()
{
NS_LOG_FUNCTION (this);
}
void
LteUeMac::DoDispose ()
{
NS_LOG_FUNCTION (this);
m_miUlHarqProcessesPacket.clear ();
delete m_macSapProvider;
delete m_cmacSapProvider;
delete m_uePhySapUser;
Object::DoDispose ();
}
LteUePhySapUser*
LteUeMac::GetLteUePhySapUser (void)
{
return m_uePhySapUser;
}
void
LteUeMac::SetLteUePhySapProvider (LteUePhySapProvider* s)
{
m_uePhySapProvider = s;
}
LteMacSapProvider*
LteUeMac::GetLteMacSapProvider (void)
{
return m_macSapProvider;
}
void
LteUeMac::SetLteUeCmacSapUser (LteUeCmacSapUser* s)
{
m_cmacSapUser = s;
}
LteUeCmacSapProvider*
LteUeMac::GetLteUeCmacSapProvider (void)
{
return m_cmacSapProvider;
}
void
LteUeMac::DoTransmitPdu (LteMacSapProvider::TransmitPduParameters params)
{
NS_LOG_FUNCTION (this);
NS_ASSERT_MSG (m_rnti == params.rnti, "RNTI mismatch between RLC and MAC");
LteRadioBearerTag tag (params.rnti, params.lcid, 0 /* UE works in SISO mode*/);
params.pdu->AddPacketTag (tag);
// store pdu in HARQ buffer
m_miUlHarqProcessesPacket.at (m_harqProcessId)->AddPacket (params.pdu);
m_miUlHarqProcessesPacketTimer.at (m_harqProcessId) = HARQ_PERIOD;
m_uePhySapProvider->SendMacPdu (params.pdu);
}
void
LteUeMac::DoReportBufferStatus (LteMacSapProvider::ReportBufferStatusParameters params)
{
NS_LOG_FUNCTION (this << (uint32_t) params.lcid);
std::map <uint8_t, LteMacSapProvider::ReportBufferStatusParameters>::iterator it;
it = m_ulBsrReceived.find (params.lcid);
if (it!=m_ulBsrReceived.end ())
{
// update entry
(*it).second = params;
}
else
{
m_ulBsrReceived.insert (std::pair<uint8_t, LteMacSapProvider::ReportBufferStatusParameters> (params.lcid, params));
}
m_freshUlBsr = true;
}
void
LteUeMac::SendReportBufferStatus (void)
{
NS_LOG_FUNCTION (this);
if (m_rnti == 0)
{
NS_LOG_INFO ("MAC not initialized, BSR deferred");
return;
}
if (m_ulBsrReceived.size () == 0)
{
NS_LOG_INFO ("No BSR report to transmit");
return;
}
MacCeListElement_s bsr;
bsr.m_rnti = m_rnti;
bsr.m_macCeType = MacCeListElement_s::BSR;
// BSR is reported for each LCG
std::map <uint8_t, LteMacSapProvider::ReportBufferStatusParameters>::iterator it;
std::vector<uint32_t> queue (4, 0); // one value per each of the 4 LCGs, initialized to 0
for (it = m_ulBsrReceived.begin (); it != m_ulBsrReceived.end (); it++)
{
uint8_t lcid = it->first;
std::map <uint8_t, LcInfo>::iterator lcInfoMapIt;
lcInfoMapIt = m_lcInfoMap.find (lcid);
NS_ASSERT (lcInfoMapIt != m_lcInfoMap.end ());
uint8_t lcg = lcInfoMapIt->second.lcConfig.logicalChannelGroup;
queue.at (lcg) += ((*it).second.txQueueSize + (*it).second.retxQueueSize + (*it).second.statusPduSize);
}
// FF API says that all 4 LCGs are always present
bsr.m_macCeValue.m_bufferStatus.push_back (BufferSizeLevelBsr::BufferSize2BsrId (queue.at (0)));
bsr.m_macCeValue.m_bufferStatus.push_back (BufferSizeLevelBsr::BufferSize2BsrId (queue.at (1)));
bsr.m_macCeValue.m_bufferStatus.push_back (BufferSizeLevelBsr::BufferSize2BsrId (queue.at (2)));
bsr.m_macCeValue.m_bufferStatus.push_back (BufferSizeLevelBsr::BufferSize2BsrId (queue.at (3)));
// create the feedback to eNB
Ptr<BsrLteControlMessage> msg = Create<BsrLteControlMessage> ();
msg->SetBsr (bsr);
m_uePhySapProvider->SendLteControlMessage (msg);
}
void
LteUeMac::RandomlySelectAndSendRaPreamble ()
{
NS_LOG_FUNCTION (this);
// 3GPP 36.321 5.1.1
NS_ASSERT_MSG (m_rachConfigured, "RACH not configured");
// assume that there is no Random Access Preambles group B
m_raPreambleId = m_raPreambleUniformVariable->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
// m_uePhySapProvider->SendLteControlMessage (msg)) so that it can
// 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.
NS_ASSERT (m_subframeNo > 0); // sanity check for subframe starting at 1
m_raRnti = m_subframeNo - 1;
m_uePhySapProvider->SendRachPreamble (m_raPreambleId, m_raRnti);
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);
}
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" << (uint32_t) lcId);
NS_ASSERT_MSG (m_lcInfoMap.find (lcId) == m_lcInfoMap.end (), "cannot add channel because LCID " << lcId << " is already present");
LcInfo lcInfo;
lcInfo.lcConfig = lcConfig;
lcInfo.macSapUser = msu;
m_lcInfoMap[lcId] = lcInfo;
}
void
LteUeMac::DoRemoveLc (uint8_t lcId)
{
NS_LOG_FUNCTION (this << " lcId" << lcId);
NS_ASSERT_MSG (m_lcInfoMap.find (lcId) == m_lcInfoMap.end (), "could not find LCID " << lcId);
m_lcInfoMap.erase (lcId);
}
void
LteUeMac::DoReset ()
{
NS_LOG_FUNCTION (this);
std::map <uint8_t, LcInfo>::iterator it = m_lcInfoMap.begin ();
while (it != m_lcInfoMap.end ())
{
// don't delete CCCH)
if (it->first == 0)
{
++it;
}
else
{
// note: use of postfix operator preserves validity of iterator
m_lcInfoMap.erase (it++);
}
}
m_rachConfigured = false;
m_freshUlBsr = false;
m_ulBsrReceived.clear ();
}
void
LteUeMac::DoReceivePhyPdu (Ptr<Packet> p)
{
LteRadioBearerTag tag;
p->RemovePacketTag (tag);
if (tag.GetRnti () == m_rnti)
{
// packet is for the current user
std::map <uint8_t, LcInfo>::const_iterator it = m_lcInfoMap.find (tag.GetLcid ());
NS_ASSERT_MSG (it != m_lcInfoMap.end (), "received packet with unknown lcid");
it->second.macSapUser->ReceivePdu (p);
}
}
void
LteUeMac::DoReceiveLteControlMessage (Ptr<LteControlMessage> msg)
{
NS_LOG_FUNCTION (this);
if (msg->GetMessageType () == LteControlMessage::UL_DCI)
{
Ptr<UlDciLteControlMessage> msg2 = DynamicCast<UlDciLteControlMessage> (msg);
UlDciListElement_s dci = msg2->GetDci ();
if (dci.m_ndi==1)
{
// New transmission -> emtpy pkt buffer queue (for deleting eventual pkts not acked )
Ptr<PacketBurst> pb = CreateObject <PacketBurst> ();
m_miUlHarqProcessesPacket.at (m_harqProcessId) = pb;
// Retrieve data from RLC
std::map <uint8_t, LteMacSapProvider::ReportBufferStatusParameters>::iterator itBsr;
uint16_t activeLcs = 0;
uint32_t statusPduMinSize = 0;
for (itBsr = m_ulBsrReceived.begin (); itBsr != m_ulBsrReceived.end (); itBsr++)
{
if (((*itBsr).second.statusPduSize > 0) || ((*itBsr).second.retxQueueSize > 0) || ((*itBsr).second.txQueueSize > 0))
{
activeLcs++;
if (((*itBsr).second.statusPduSize!=0)&&((*itBsr).second.statusPduSize < statusPduMinSize))
{
statusPduMinSize = (*itBsr).second.statusPduSize;
}
if (((*itBsr).second.statusPduSize!=0)&&(statusPduMinSize == 0))
{
statusPduMinSize = (*itBsr).second.statusPduSize;
}
}
}
if (activeLcs == 0)
{
NS_LOG_ERROR (this << " No active flows for this UL-DCI");
return;
}
std::map <uint8_t, LcInfo>::iterator it;
uint32_t bytesPerActiveLc = dci.m_tbSize / activeLcs;
bool statusPduPriority = false;
if ((statusPduMinSize != 0)&&(bytesPerActiveLc < statusPduMinSize))
{
// send only the status PDU which has highest priority
statusPduPriority = true;
NS_LOG_DEBUG (this << " Reduced resource -> send only Status, b ytes " << statusPduMinSize);
if (dci.m_tbSize < statusPduMinSize)
{
NS_FATAL_ERROR ("Insufficient Tx Opportunity for sending a status message");
}
}
NS_LOG_LOGIC (this << " UE " << m_rnti << ": UL-CQI notified TxOpportunity of " << dci.m_tbSize << " => " << bytesPerActiveLc << " bytes per active LC" << " statusPduMinSize " << statusPduMinSize);
for (it = m_lcInfoMap.begin (); it!=m_lcInfoMap.end (); it++)
{
itBsr = m_ulBsrReceived.find ((*it).first);
NS_LOG_DEBUG (this << " Processing LC " << (uint32_t)(*it).first << " bytesPerActiveLc " << bytesPerActiveLc);
if ( (itBsr!=m_ulBsrReceived.end ()) &&
( ((*itBsr).second.statusPduSize > 0) ||
((*itBsr).second.retxQueueSize > 0) ||
((*itBsr).second.txQueueSize > 0)) )
{
if ((statusPduPriority) && ((*itBsr).second.statusPduSize == statusPduMinSize))
{
(*it).second.macSapUser->NotifyTxOpportunity ((*itBsr).second.statusPduSize, 0, 0);
NS_LOG_LOGIC (this << "\t" << bytesPerActiveLc << " send " << (*itBsr).second.statusPduSize << " status bytes to LC " << (uint32_t)(*it).first << " statusQueue " << (*itBsr).second.statusPduSize << " retxQueue" << (*itBsr).second.retxQueueSize << " txQueue" << (*itBsr).second.txQueueSize);
(*itBsr).second.statusPduSize = 0;
break;
}
else
{
uint32_t bytesForThisLc = bytesPerActiveLc;
NS_LOG_LOGIC (this << "\t" << bytesPerActiveLc << " bytes to LC " << (uint32_t)(*it).first << " statusQueue " << (*itBsr).second.statusPduSize << " retxQueue" << (*itBsr).second.retxQueueSize << " txQueue" << (*itBsr).second.txQueueSize);
if (((*itBsr).second.statusPduSize > 0) && (bytesForThisLc > (*itBsr).second.statusPduSize))
{
(*it).second.macSapUser->NotifyTxOpportunity ((*itBsr).second.statusPduSize, 0, 0);
bytesForThisLc -= (*itBsr).second.statusPduSize;
NS_LOG_DEBUG (this << " serve STATUS " << (*itBsr).second.statusPduSize);
(*itBsr).second.statusPduSize = 0;
}
else
{
if ((*itBsr).second.statusPduSize>bytesForThisLc)
{
NS_FATAL_ERROR ("Insufficient Tx Opportunity for sending a status message");
}
}
if ((bytesForThisLc > 7) && // 7 is the min TxOpportunity useful for Rlc
(((*itBsr).second.retxQueueSize > 0) ||
((*itBsr).second.txQueueSize > 0)))
{
if ((*itBsr).second.retxQueueSize > 0)
{
NS_LOG_DEBUG (this << " serve retx DATA, bytes " << bytesForThisLc);
(*it).second.macSapUser->NotifyTxOpportunity (bytesForThisLc, 0, 0);
if ((*itBsr).second.retxQueueSize >= bytesForThisLc)
{
(*itBsr).second.retxQueueSize -= bytesForThisLc;
}
else
{
(*itBsr).second.retxQueueSize = 0;
}
}
else if ((*itBsr).second.txQueueSize > 0)
{
NS_LOG_DEBUG (this << " serve tx DATA, bytes " << bytesForThisLc);
(*it).second.macSapUser->NotifyTxOpportunity (bytesForThisLc, 0, 0);
if ((*itBsr).second.txQueueSize >= bytesForThisLc - 2)
{
(*itBsr).second.txQueueSize -= bytesForThisLc - 2;
}
else
{
(*itBsr).second.txQueueSize = 0;
}
}
}
else
{
if ( ((*itBsr).second.retxQueueSize > 0) || ((*itBsr).second.txQueueSize > 0))
{
// resend BSR info for updating eNB peer MAC
m_freshUlBsr = true;
}
}
NS_LOG_LOGIC (this << "\t" << bytesPerActiveLc << "\t new queues " << (uint32_t)(*it).first << " statusQueue " << (*itBsr).second.statusPduSize << " retxQueue" << (*itBsr).second.retxQueueSize << " txQueue" << (*itBsr).second.txQueueSize);
}
}
}
}
else
{
// HARQ retransmission -> retrieve data from HARQ buffer
NS_LOG_DEBUG (this << " UE MAC RETX HARQ " << (uint16_t)m_harqProcessId);
Ptr<PacketBurst> pb = m_miUlHarqProcessesPacket.at (m_harqProcessId);
for (std::list<Ptr<Packet> >::const_iterator j = pb->Begin (); j != pb->End (); ++j)
{
Ptr<Packet> pkt = (*j)->Copy ();
m_uePhySapProvider->SendMacPdu (pkt);
}
m_miUlHarqProcessesPacketTimer.at (m_harqProcessId) = HARQ_PERIOD;
}
}
else if (msg->GetMessageType () == LteControlMessage::RAR)
{
if (m_waitingForRaResponse)
{
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);
// TODO:: RRC generates the RecvRaResponse messaged
// for avoiding holes in transmission at PHY layer
// (which produce erroneous UL CQI evaluation)
}
}
}
}
}
else
{
NS_LOG_WARN (this << " LteControlMessage not recognized");
}
}
void
LteUeMac::RefreshHarqProcessesPacketBuffer (void)
{
NS_LOG_FUNCTION (this);
for (uint16_t i = 0; i < m_miUlHarqProcessesPacketTimer.size (); i++)
{
if (m_miUlHarqProcessesPacketTimer.at (i) == 0)
{
if (m_miUlHarqProcessesPacket.at (i)->GetSize () > 0)
{
// timer expired: drop packets in buffer for this process
NS_LOG_INFO (this << " HARQ Proc Id " << i << " packets buffer expired");
Ptr<PacketBurst> emptyPb = CreateObject <PacketBurst> ();
m_miUlHarqProcessesPacket.at (i) = emptyPb;
}
}
else
{
m_miUlHarqProcessesPacketTimer.at (i)--;
}
}
}
void
LteUeMac::DoSubframeIndication (uint32_t frameNo, uint32_t subframeNo)
{
NS_LOG_FUNCTION (this);
m_frameNo = frameNo;
m_subframeNo = subframeNo;
RefreshHarqProcessesPacketBuffer ();
if ((Simulator::Now () >= m_bsrLast + m_bsrPeriodicity) && (m_freshUlBsr==true))
{
SendReportBufferStatus ();
m_bsrLast = Simulator::Now ();
m_freshUlBsr = false;
m_harqProcessId = (m_harqProcessId + 1) % HARQ_PERIOD;
}
}
int64_t
LteUeMac::AssignStreams (int64_t stream)
{
NS_LOG_FUNCTION (this << stream);
m_raPreambleUniformVariable->SetStream (stream);
return 1;
}
} // namespace ns3