1 /* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2011,2012 Centre Tecnologic de Telecomunicacions de Catalunya (CTTC)
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation;
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17  *
18  * Author: Manuel Requena <manuel.requena@cttc.es>
19  *         Nicola Baldo <nbaldo@cttc.es>
20  */
21 
22 #include "ns3/simulator.h"
23 #include "ns3/log.h"
24 
25 #include "ns3/lte-rlc-tm.h"
26 
27 namespace ns3 {
28 
29 NS_LOG_COMPONENT_DEFINE ("LteRlcTm");
30 
31 NS_OBJECT_ENSURE_REGISTERED (LteRlcTm);
32 
LteRlcTm()33 LteRlcTm::LteRlcTm ()
34   : m_maxTxBufferSize (0),
35     m_txBufferSize (0)
36 {
37   NS_LOG_FUNCTION (this);
38 }
39 
~LteRlcTm()40 LteRlcTm::~LteRlcTm ()
41 {
42   NS_LOG_FUNCTION (this);
43 }
44 
45 TypeId
GetTypeId(void)46 LteRlcTm::GetTypeId (void)
47 {
48   static TypeId tid = TypeId ("ns3::LteRlcTm")
49     .SetParent<LteRlc> ()
50     .SetGroupName("Lte")
51     .AddConstructor<LteRlcTm> ()
52     .AddAttribute ("MaxTxBufferSize",
53                    "Maximum Size of the Transmission Buffer (in Bytes)",
54                    UintegerValue (2 * 1024 * 1024),
55                    MakeUintegerAccessor (&LteRlcTm::m_maxTxBufferSize),
56                    MakeUintegerChecker<uint32_t> ())
57     ;
58   return tid;
59 }
60 
61 void
DoDispose()62 LteRlcTm::DoDispose ()
63 {
64   NS_LOG_FUNCTION (this);
65   m_rbsTimer.Cancel ();
66   m_txBuffer.clear ();
67 
68   LteRlc::DoDispose ();
69 }
70 
71 
72 /**
73  * RLC SAP
74  */
75 
76 void
DoTransmitPdcpPdu(Ptr<Packet> p)77 LteRlcTm::DoTransmitPdcpPdu (Ptr<Packet> p)
78 {
79   NS_LOG_FUNCTION (this << m_rnti << (uint32_t) m_lcid << p->GetSize ());
80 
81   if (m_txBufferSize + p->GetSize () <= m_maxTxBufferSize)
82     {
83       NS_LOG_LOGIC ("Tx Buffer: New packet added");
84       m_txBuffer.push_back (TxPdu (p, Simulator::Now ()));
85       m_txBufferSize += p->GetSize ();
86       NS_LOG_LOGIC ("NumOfBuffers = " << m_txBuffer.size() );
87       NS_LOG_LOGIC ("txBufferSize = " << m_txBufferSize);
88     }
89   else
90     {
91       // Discard full RLC SDU
92       NS_LOG_LOGIC ("TxBuffer is full. RLC SDU discarded");
93       NS_LOG_LOGIC ("MaxTxBufferSize = " << m_maxTxBufferSize);
94       NS_LOG_LOGIC ("txBufferSize    = " << m_txBufferSize);
95       NS_LOG_LOGIC ("packet size     = " << p->GetSize ());
96     }
97 
98   /** Report Buffer Status */
99   DoReportBufferStatus ();
100   m_rbsTimer.Cancel ();
101 }
102 
103 
104 /**
105  * MAC SAP
106  */
107 
108 void
DoNotifyTxOpportunity(LteMacSapUser::TxOpportunityParameters txOpParams)109 LteRlcTm::DoNotifyTxOpportunity (LteMacSapUser::TxOpportunityParameters txOpParams)
110 {
111   NS_LOG_FUNCTION (this << m_rnti << (uint32_t) m_lcid << txOpParams.bytes  << (uint32_t) txOpParams.layer << (uint32_t) txOpParams.harqId);
112 
113   // 5.1.1.1 Transmit operations
114   // 5.1.1.1.1 General
115   // When submitting a new TMD PDU to lower layer, the transmitting TM RLC entity shall:
116   // - submit a RLC SDU without any modification to lower layer.
117 
118 
119   if ( m_txBuffer.size () == 0 )
120     {
121       NS_LOG_LOGIC ("No data pending");
122       return;
123     }
124 
125   Ptr<Packet> packet = m_txBuffer.begin ()->m_pdu->Copy ();
126 
127   if (txOpParams.bytes < packet->GetSize ())
128     {
129       NS_LOG_WARN ("TX opportunity too small = " << txOpParams.bytes <<
130                    " (PDU size: " << packet->GetSize () << ")");
131       return;
132     }
133 
134   m_txBufferSize -= packet->GetSize ();
135   m_txBuffer.erase (m_txBuffer.begin ());
136 
137   m_txPdu (m_rnti, m_lcid, packet->GetSize ());
138 
139   // Send RLC PDU to MAC layer
140   LteMacSapProvider::TransmitPduParameters params;
141   params.pdu = packet;
142   params.rnti = m_rnti;
143   params.lcid = m_lcid;
144   params.layer = txOpParams.layer;
145   params.harqProcessId = txOpParams.harqId;
146   params.componentCarrierId = txOpParams.componentCarrierId;
147 
148   m_macSapProvider->TransmitPdu (params);
149 
150   if (! m_txBuffer.empty ())
151     {
152       m_rbsTimer.Cancel ();
153       m_rbsTimer = Simulator::Schedule (MilliSeconds (10), &LteRlcTm::ExpireRbsTimer, this);
154     }
155 }
156 
157 void
DoNotifyHarqDeliveryFailure()158 LteRlcTm::DoNotifyHarqDeliveryFailure ()
159 {
160   NS_LOG_FUNCTION (this);
161 }
162 
163 void
DoReceivePdu(LteMacSapUser::ReceivePduParameters rxPduParams)164 LteRlcTm::DoReceivePdu (LteMacSapUser::ReceivePduParameters rxPduParams)
165 {
166   NS_LOG_FUNCTION (this << m_rnti << (uint32_t) m_lcid << rxPduParams.p->GetSize ());
167 
168   m_rxPdu (m_rnti, m_lcid, rxPduParams.p->GetSize (), 0);
169 
170   // 5.1.1.2 Receive operations
171   // 5.1.1.2.1  General
172   // When receiving a new TMD PDU from lower layer, the receiving TM RLC entity shall:
173   // - deliver the TMD PDU without any modification to upper layer.
174 
175    m_rlcSapUser->ReceivePdcpPdu (rxPduParams.p);
176 }
177 
178 
179 void
DoReportBufferStatus(void)180 LteRlcTm::DoReportBufferStatus (void)
181 {
182   Time holDelay (0);
183   uint32_t queueSize = 0;
184 
185   if (! m_txBuffer.empty ())
186     {
187       holDelay = Simulator::Now () - m_txBuffer.front ().m_waitingSince;
188 
189       queueSize = m_txBufferSize; // just data in tx queue (no header overhead for RLC TM)
190     }
191 
192   LteMacSapProvider::ReportBufferStatusParameters r;
193   r.rnti = m_rnti;
194   r.lcid = m_lcid;
195   r.txQueueSize = queueSize;
196   r.txQueueHolDelay = holDelay.GetMilliSeconds () ;
197   r.retxQueueSize = 0;
198   r.retxQueueHolDelay = 0;
199   r.statusPduSize = 0;
200 
201   NS_LOG_LOGIC ("Send ReportBufferStatus = " << r.txQueueSize << ", " << r.txQueueHolDelay );
202   m_macSapProvider->ReportBufferStatus (r);
203 }
204 
205 void
ExpireRbsTimer(void)206 LteRlcTm::ExpireRbsTimer (void)
207 {
208   NS_LOG_LOGIC ("RBS Timer expires");
209 
210   if (! m_txBuffer.empty ())
211     {
212       DoReportBufferStatus ();
213       m_rbsTimer = Simulator::Schedule (MilliSeconds (10), &LteRlcTm::ExpireRbsTimer, this);
214     }
215 }
216 
217 } // namespace ns3
218