HARQ first draft version: RR works, PF todo, LteMiErrorModel on-going
authormmiozzo
Mon, 08 Oct 2012 17:18:22 +0200
changeset 9351 6e074e67a1ad
parent 9350 fae7cfe4cfb0
child 9352 0b43d0a862dc
HARQ first draft version: RR works, PF todo, LteMiErrorModel on-going
src/lte/doc/source/lte-design.rst
src/lte/helper/lte-helper.cc
src/lte/model/lte-common.h
src/lte/model/lte-control-messages.cc
src/lte/model/lte-control-messages.h
src/lte/model/lte-enb-mac.cc
src/lte/model/lte-enb-mac.h
src/lte/model/lte-enb-phy-sap.h
src/lte/model/lte-enb-phy.cc
src/lte/model/lte-enb-phy.h
src/lte/model/lte-enb-rrc.cc
src/lte/model/lte-harq-phy.cc
src/lte/model/lte-harq-phy.h
src/lte/model/lte-mac-sap.h
src/lte/model/lte-mi-error-model.cc
src/lte/model/lte-mi-error-model.h
src/lte/model/lte-radio-bearer-tag.cc
src/lte/model/lte-rlc-am.cc
src/lte/model/lte-rlc-am.h
src/lte/model/lte-rlc-um.cc
src/lte/model/lte-rlc-um.h
src/lte/model/lte-rlc.cc
src/lte/model/lte-rlc.h
src/lte/model/lte-spectrum-phy.cc
src/lte/model/lte-spectrum-phy.h
src/lte/model/lte-ue-mac.cc
src/lte/model/lte-ue-mac.h
src/lte/model/lte-ue-phy.cc
src/lte/model/lte-ue-phy.h
src/lte/model/pf-ff-mac-scheduler.cc
src/lte/model/pf-ff-mac-scheduler.h
src/lte/model/rr-ff-mac-scheduler.cc
src/lte/model/rr-ff-mac-scheduler.h
src/lte/test/lte-test-entities.cc
src/lte/test/lte-test-mimo.cc
src/lte/test/lte-test-mimo.h
src/lte/test/lte-test-pf-ff-mac-scheduler.cc
src/lte/test/lte-test-phy-error-model.cc
src/lte/wscript
--- a/src/lte/doc/source/lte-design.rst	Fri Aug 31 16:49:46 2012 +0200
+++ b/src/lte/doc/source/lte-design.rst	Mon Oct 08 17:18:22 2012 +0200
@@ -568,12 +568,26 @@
 The alternative model is based on the physical error model developed for this simulator and explained in the following subsections. This scheme is able to adapt the MCS selection to the actual PHY layer performance according to the specific CQI report. According to their definition, a CQI index is assigned when a single PDSCH TB with the modulation coding scheme and code rate correspondent to that CQI index in table 7.2.3-1 of [TS36213]_ can be received with an error probability less than 0.1. In case of wideband CQIs, the reference TB includes all the RBGs available in order to have a reference based on the whole available resources; while, for subband CQIs, the reference TB is sized as the RBGs.
 
 
+.. only:: latex
+
+    .. raw:: latex
+
+        \clearpage
+
 Round Robin (RR) Scheduler
 --------------------------
 
 The Round Robin (RR) scheduler is probably the simplest scheduler found in the literature. It works by dividing the
-available resources among the active flows, i.e., those logical channels which have a non-empty RLC queue. If the number of RBGs is greater than the number of active flows, all the flows can be allocated in the same subframe. Otherwise, if the number of active flows is greater than the number of RBGs, not all the flows can be scheduled in a given subframe; then, in the next subframe the allocation will start from the last flow that was not allocated.  The MCS to be adopted for each user is done according to the received wideband CQIs. 
-
+available resources among the active flows, i.e., those logical channels which have a non-empty RLC queue. If the number of RBGs is greater than the number of active flows, all the flows can be allocated in the same subframe. Otherwise, if the number of active flows is greater than the number of RBGs, not all the flows can be scheduled in a given subframe; then, in the next subframe the allocation will start from the last flow that was not allocated.  The MCS to be adopted for each user is done according to the received wideband CQIs.
+
+For what concern the HARQ, RR implements the non adaptive version, which implies that in allocating the retransmission RR uses a similar allocation configuration of the original block, which means maintaining the same RBGs and MCS. UEs that are allocated for HARQ retransmissions are not considered for the transmission of new data in case they have a transmission opportunity in the same TTI.
+
+
+.. only:: latex
+
+    .. raw:: latex
+
+        \clearpage
 
 Proportional Fair (PF) Scheduler
 --------------------------------
@@ -643,6 +657,7 @@
    \right)}{\tau}
    
 
+*HARQ PF specifications: to be defined*.
 
 Transport Blocks
 ----------------
@@ -1550,9 +1565,6 @@
 
 
 
-
-
-
 .. only:: latex
 
     .. raw:: latex
@@ -1563,9 +1575,23 @@
 HARQ Model
 ----------
 
-The HARQ scheme implemented is based on a incremental redundancy (IR) solutions combined with multiple stop-and-wait processes for enabling a continuous data flow. The core of the HARQ algorithm has been implemented within the respective schedulers class (i.e., ``RrFfMacScheduler`` and ``PfFfMacScheduler``), while the decodification part of the HARQ has been implemented in the ``LteSpectrumPhy`` class.
-
-At the MAC layer, the HARQ entity residing in the scheduler is in charge of controlling the 8 HARQ processes for generating new packets and managing the retransmissions both for the DL and the UL. The scheduler collects the HARQ feedbacks from eNB and UE PHY layers (respectively UL and DL connection) by means of the FF API ``SchedUlTriggerReq`` and ``SchedUlTriggerReq`` in a FIFO buffer for maintaining the order of arrival. According to the HARQ feedbacks and the RLC buffers status, the scheduler generates a set of DCIs including both retransmissions of HARQ blocks received erroneous and new transmissions giving priority to the former. In allocating the retransmission we adopt this assumption, the scheduler uses a similar allocation configuration of the original block, which means maintaining the same number of RBGs and the same MCS. In case of the RGBs used for the original transmission are available they will be reused, otherwise the closest in frequency are selected in order to maintain similar channel conditions. It is to be noted that, the choice of maintaining in the retransmissions the same MCS of the original block is mandatory, otherwise the PHY would not be able of estimating the error probability of aggregated retransmissions. According to the standard, the UL retransmissions are synchronous and therefore are allocated 7 ms after the original transmission. While for the DL, they are asynchronous ans therefore can be allocated in a more flexible way starting from 7 ms. In detail, they receive highest priority for being transmitted after 7 ms; however, due to resource constraints they might be delayed a bit more. The HARQ processes behavior is depicted in Figure:ref:`fig-harq-processes-scheme`.
+The HARQ scheme implemented is based on a incremental redundancy (IR) solutions combined with multiple stop-and-wait processes for enabling a continuous data flow. In detail, the solution adopted is the *soft combining hybrid IR Full incremental redundancy* (also called IR Type II), which implies that the retransmissions include only new information. The resource allocation algorithm of the HARQ has been implemented within the respective schedulers class (i.e., ``RrFfMacScheduler`` and ``PfFfMacScheduler``, refer to their respective sections for more info), while the decodification part of the HARQ has been implemented in the ``LteSpectrumPhy`` class which will be detailed in this section.
+
+According to the standard, the UL retransmissions are synchronous and therefore are allocated 7 ms after the original transmission. On the other hand, for the DL, they are asynchronous ans therefore can be allocated in a more flexible way starting from 7 ms and it is a matter of the specific scheduler implementation. The HARQ processes behavior is depicted in Figure:ref:`fig-harq-processes-scheme`.
+
+At the MAC layer, the HARQ entity residing in the scheduler is in charge of controlling the 8 HARQ processes for generating new packets and managing the retransmissions both for the DL and the UL. The scheduler collects the HARQ feedback from eNB and UE PHY layers (respectively UL and DL connection) by means of the FF API primitives ``SchedUlTriggerReq`` and ``SchedUlTriggerReq``, and stores them in a FIFO buffer for maintaining the order of arrival. According to the HARQ feedback and the RLC buffers status, the scheduler generates a set of DCIs including both retransmissions of HARQ blocks received erroneous and new transmissions, in general, giving priority to the former. On this matter, the scheduler has to take into consideration one constraint when allocating the resource for HARQ retransmissions, it must use the same modulation order of the first transmission attempt (i.e., QPSK for MCS :math:`\in [0..9]`, 16QAM for MCS :math:`\in [10..16]` and 64QAM for MCS :math:`\in [17..28]`). This restriction comes from the specification of the rate matcher in the 3GPP standard [TS36212]_, where for generating the different TBs of the redundancy version the algorithm fixes the modulation order.
+
+
+The PHY Error Model model has been extended for considering IR HARQ according to [wimaxEmd]_, where the parameters for the AWGN curves mapping for MIESM mapping in case of retransmissions are given by:
+
+.. math::
+
+    R_{eff} = \frac{X}{\sum\limits_{i=1}^q C_i}
+
+    M_{I eff} = \frac{\sum\limits_{i=1}^q C_i M_i}{\sum\limits_{i=1}^q C_i}
+
+where :math:`X` is the number of original information bits, :math:`C_i` are number of coded bits, :math:`M_i` are the mutual informations per HARQ block received on the total number of :math:`q` retransmissions. Therefore, in order to be able to return the error probability with the error model implemented in the simulator evaluates the :math:`R_{eff}` and the :math:`MI_{I eff}` and return the value of error probability of the ECR of the same modulation with closest rate respect to the :math:`R_{eff}`. In order to consider the effect of HARQ retransmissions a new sets of curves have been integrated respect to the standard one used for the original MCS, especially for covering the cases when the most conservative MCS of a modulation is used. On this matter the curves for 1, 2 and 3 retransmissions have been evaluated for MCS 0, 10 and 17.
+It is to be noted that, the first tranmission has been assumed as containing all the information bits to be coded; therefore :math:`X` is equal to the size of the first TB sent of a an HARQ process.
 
 
 .. _fig-harq-processes-scheme:
@@ -1577,7 +1603,8 @@
 
 
 
-At the PHY layer the HARQ is involved in the evaluation of the error distribution process by controlling the information received per process bases and combining it with previous blocks, when necessary in retransmitted ones, by means of the MIESM mutual information scheme presented before. This part of HARQ devoted to manage the decodification of the HARQ blocks has been implemented in the ``LteSpectrumPhy`` class, where it has been also included the messaging algorithm in charge of communicating to the HARQ in the scheduler the result of the decodifications. These messages are encapsulated in the ``dlInfoListElement`` for DL and ``ulInfoListElement`` for UL and sent through the PUCCH and the PHICH respectively in an ideal error free way according to the assumptions in their implementation. A scketch of the iteration bewteen HARQ and LTE protocol stack in represented in Figure:ref:`fig-harq-architecture`.
+This part of HARQ devoted to manage the decodification of the HARQ blocks has been implemented in the ``LteSpectrumPhy`` class, where it has been also included the messaging algorithm in charge of communicating to the HARQ in the scheduler the result of the decodifications. These messages are encapsulated in the ``dlInfoListElement`` for DL and ``ulInfoListElement`` for UL and sent through the PUCCH and the PHICH respectively in an ideal error free way according to the assumptions in their implementation. A sketch of the iteration between HARQ and LTE protocol stack in represented in Figure:ref:`fig-harq-architecture`.
+
 
 
 .. _fig-harq-architecture:
@@ -1597,7 +1624,6 @@
 
 
 
-
 -----------------------
 Channel and Propagation
 -----------------------
--- a/src/lte/helper/lte-helper.cc	Fri Aug 31 16:49:46 2012 +0200
+++ b/src/lte/helper/lte-helper.cc	Mon Oct 08 17:18:22 2012 +0200
@@ -308,6 +308,11 @@
 
   Ptr<LteEnbPhy> phy = CreateObject<LteEnbPhy> (dlPhy, ulPhy);
 
+  Ptr<LteHarqPhy> harq = Create<LteHarqPhy> ();
+  dlPhy->SetHarqPhyModule (harq);
+  ulPhy->SetHarqPhyModule (harq);
+  phy->SetHarqPhyModule (harq);
+
   Ptr<LteCtrlSinrChunkProcessor> pCtrl = Create<LteCtrlSinrChunkProcessor> (phy->GetObject<LtePhy> ());
   ulPhy->AddCtrlSinrChunkProcessor (pCtrl); // for evaluating SRS UL-CQI
 
@@ -374,6 +379,7 @@
   n->AddDevice (dev);
   ulPhy->SetLtePhyRxDataEndOkCallback (MakeCallback (&LteEnbPhy::PhyPduReceived, phy));
   ulPhy->SetLtePhyRxCtrlEndOkCallback (MakeCallback (&LteEnbPhy::ReceiveLteControlMessageList, phy));
+  ulPhy->SetLtePhyUlHarqFeedbackCallback (MakeCallback (&LteEnbPhy::ReceiveLteUlHarqFeedback, phy));
   rrc->SetForwardUpCallback (MakeCallback (&LteEnbNetDevice::Receive, dev));
 
   NS_LOG_LOGIC ("set the propagation model frequencies");
@@ -426,6 +432,11 @@
 
   Ptr<LteUePhy> phy = CreateObject<LteUePhy> (dlPhy, ulPhy);
 
+  Ptr<LteHarqPhy> harq = Create<LteHarqPhy> ();
+  dlPhy->SetHarqPhyModule (harq);
+  ulPhy->SetHarqPhyModule (harq);
+  phy->SetHarqPhyModule (harq);
+
   Ptr<LteCtrlSinrChunkProcessor> pCtrl = Create<LteCtrlSinrChunkProcessor> (phy->GetObject<LtePhy> (), dlPhy);
   dlPhy->AddCtrlSinrChunkProcessor (pCtrl);
 
@@ -474,6 +485,7 @@
   n->AddDevice (dev);
   dlPhy->SetLtePhyRxDataEndOkCallback (MakeCallback (&LteUePhy::PhyPduReceived, phy));
   dlPhy->SetLtePhyRxCtrlEndOkCallback (MakeCallback (&LteUePhy::ReceiveLteControlMessageList, phy));
+  dlPhy->SetLtePhyDlHarqFeedbackCallback (MakeCallback (&LteUePhy::ReceiveLteDlHarqFeedback, phy));
   nas->SetForwardUpCallback (MakeCallback (&LteUeNetDevice::Receive, dev));
 
 
--- a/src/lte/model/lte-common.h	Fri Aug 31 16:49:46 2012 +0200
+++ b/src/lte/model/lte-common.h	Mon Oct 08 17:18:22 2012 +0200
@@ -27,6 +27,8 @@
 // see 36.213 section 8
 #define UL_PUSCH_TTIS_DELAY 4
 
+#define HARQ_PERIOD 7
+
 namespace ns3 {
 
 
--- a/src/lte/model/lte-control-messages.cc	Fri Aug 31 16:49:46 2012 +0200
+++ b/src/lte/model/lte-control-messages.cc	Mon Oct 08 17:18:22 2012 +0200
@@ -176,5 +176,34 @@
 }
 
 
+
+// ---------------------------------------------------------------------------
+
+
+DlHarqFeedbackLteControlMessage::DlHarqFeedbackLteControlMessage (void)
+{
+  SetMessageType (LteControlMessage::DL_HARQ);
+}
+
+
+DlHarqFeedbackLteControlMessage::~DlHarqFeedbackLteControlMessage (void)
+{
+
+}
+
+void
+DlHarqFeedbackLteControlMessage::SetDlHarqFeedback (DlInfoListElement_s m)
+{
+  m_dlInfoListElement = m;
+}
+
+
+DlInfoListElement_s
+DlHarqFeedbackLteControlMessage::GetDlHarqFeedback (void)
+{
+  return m_dlInfoListElement;
+}
+
+
 } // namespace ns3
 
--- a/src/lte/model/lte-control-messages.h	Fri Aug 31 16:49:46 2012 +0200
+++ b/src/lte/model/lte-control-messages.h	Mon Oct 08 17:18:22 2012 +0200
@@ -48,7 +48,8 @@
   {
     DL_DCI, UL_DCI, // Downlink/Uplink Data Control Indicator
     DL_CQI, UL_CQI, // Downlink/Uplink Channel Quality Indicator
-    BSR // Buffer Status Report
+    BSR, // Buffer Status Report
+    DL_HARQ // UL HARQ feedback
   };
 
   LteControlMessage (void);
@@ -77,7 +78,7 @@
 
 
 
-// ----------------------------------------------------------------------------------------------------------
+// -----------------------------------------------------------------------
 
 
 #ifndef DL_DCI_LTE_CONTROL_MESSAGES_H
@@ -120,7 +121,7 @@
 #endif /* DL_DCI_LTE_CONTROL_MESSAGES_H */
 
 
-// ----------------------------------------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
 
 
 #ifndef UL_DCI_LTE_CONTROL_MESSAGES_H
@@ -164,7 +165,7 @@
 
 
 
-// ----------------------------------------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
 
 
 
@@ -210,7 +211,7 @@
 #endif /* DLCQI_LTE_CONTROL_MESSAGES_H */
 
 
-// ----------------------------------------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
 
 #ifndef BSR_LTE_CONTROL_MESSAGES_H
 #define BSR_LTE_CONTROL_MESSAGES_H
@@ -253,5 +254,49 @@
 };
 } // namespace ns3
 
-#endif /* LTE_CONTROL_MESSAGES_H */
+#endif /* BSR_LTE_CONTROL_MESSAGES_H */
+
+
+// ---------------------------------------------------------------------------
+
+#ifndef DL_HARQ_LTE_CONTROL_MESSAGES_H
+#define DL_HARQ_LTE_CONTROL_MESSAGES_H
+
+#include <ns3/object.h>
+#include <ns3/ff-mac-common.h>
+
+namespace ns3 {
 
+/**
+ * \ingroup lte
+ * The downlink DlHarqFeedbackLteControlMessage defines the specific
+ * messages for transmitting the DL HARQ feedback through PUCCH
+ */
+class DlHarqFeedbackLteControlMessage : public LteControlMessage
+{
+public:
+  DlHarqFeedbackLteControlMessage (void);
+  virtual ~DlHarqFeedbackLteControlMessage (void);
+
+  /**
+  * \brief add a DL HARQ feedback record into the message.
+  * \param DlInfoListElement_s the dl HARQ feedback
+  */
+  void SetDlHarqFeedback (DlInfoListElement_s m);
+
+  /**
+  * \brief Get DL HARQ informations
+  * \return DL HARQ message
+  */
+  DlInfoListElement_s GetDlHarqFeedback (void);
+
+
+private:
+  DlInfoListElement_s m_dlInfoListElement;
+
+
+};
+} // namespace ns3
+
+#endif /* DL_HARQ_LTE_CONTROL_MESSAGES_H */
+
--- a/src/lte/model/lte-enb-mac.cc	Fri Aug 31 16:49:46 2012 +0200
+++ b/src/lte/model/lte-enb-mac.cc	Mon Oct 08 17:18:22 2012 +0200
@@ -234,6 +234,8 @@
   virtual void SubframeIndication (uint32_t frameNo, uint32_t subframeNo);
   virtual void ReceiveLteControlMessage (Ptr<LteControlMessage> msg);
   virtual void UlCqiReport (FfMacSchedSapProvider::SchedUlCqiInfoReqParameters ulcqi);
+  virtual void UlInfoListElementHarqFeeback (UlInfoListElement_s params);
+  virtual void DlInfoListElementHarqFeeback (DlInfoListElement_s params);
 
 private:
   LteEnbMac* m_mac;
@@ -268,6 +270,18 @@
   m_mac->DoUlCqiReport (ulcqi);
 }
 
+void
+EnbMacMemberLteEnbPhySapUser::UlInfoListElementHarqFeeback (UlInfoListElement_s params)
+{
+  m_mac->DoUlInfoListElementHarqFeeback (params);
+}
+
+void
+EnbMacMemberLteEnbPhySapUser::DlInfoListElementHarqFeeback (DlInfoListElement_s params)
+{
+  m_mac->DoDlInfoListElementHarqFeeback (params);
+}
+
 
 // //////////////////////////////////////
 // generic LteEnbMac methods
@@ -312,6 +326,12 @@
 LteEnbMac::DoDispose ()
 {
   NS_LOG_FUNCTION (this);
+  m_dlCqiReceived.clear ();
+  m_ulCqiReceived.clear ();
+  m_ulCeReceived.clear ();
+  m_dlInfoListReceived.clear ();
+  m_ulInfoListReceived.clear ();
+m_miDlHarqProcessesPackets.clear ();
   delete m_macSapProvider;
   delete m_cmacSapProvider;
   delete m_schedSapUser;
@@ -412,7 +432,6 @@
       m_schedSapProvider->SchedDlCqiInfoReq (dlcqiInfoReq);
     }
 
-
   // Get downlink transmission opportunities
   uint32_t dlSchedFrameNo = m_frameNo;
   uint32_t dlSchedSubframeNo = m_subframeNo;
@@ -426,9 +445,18 @@
     {
       dlSchedSubframeNo = dlSchedSubframeNo + m_macChTtiDelay;
     }
-  FfMacSchedSapProvider::SchedDlTriggerReqParameters params;  // to be filled
-  params.m_sfnSf = ((0x3FF & dlSchedFrameNo) << 4) | (0xF & dlSchedSubframeNo);
-  m_schedSapProvider->SchedDlTriggerReq (params);
+  FfMacSchedSapProvider::SchedDlTriggerReqParameters dlparams;
+  dlparams.m_sfnSf = ((0x3FF & dlSchedFrameNo) << 4) | (0xF & dlSchedSubframeNo);
+
+  // Forward DL HARQ feebacks collected during last TTI
+  if (m_dlInfoListReceived.size () > 0)
+    {
+      dlparams.m_dlInfoList = m_dlInfoListReceived;
+      // empty local buffer
+      m_dlInfoListReceived.clear ();
+    }
+
+  m_schedSapProvider->SchedDlTriggerReq (dlparams);
 
 
   // --- UPLINK ---
@@ -475,26 +503,34 @@
   FfMacSchedSapProvider::SchedUlTriggerReqParameters ulparams;
   ulparams.m_sfnSf = ((0x3FF & ulSchedFrameNo) << 4) | (0xF & ulSchedSubframeNo);
 
-  std::map <uint16_t,UlInfoListElement_s>::iterator it;
-  for (it = m_ulInfoListElements.begin (); it != m_ulInfoListElements.end (); it++)
+  // Forward DL HARQ feebacks collected during last TTI
+  if (m_ulInfoListReceived.size () > 0)
     {
-      ulparams.m_ulInfoList.push_back ((*it).second);
+     ulparams.m_ulInfoList = m_ulInfoListReceived;
+      // empty local buffer
+      m_ulInfoListReceived.clear ();
     }
+
+//   std::map <uint16_t,UlInfoListElement_s>::iterator it;
+//   for (it = m_ulInfoListElements.begin (); it != m_ulInfoListElements.end (); it++)
+//     {
+//       ulparams.m_ulInfoList.push_back ((*it).second);
+//     }
   m_schedSapProvider->SchedUlTriggerReq (ulparams);
 
 
 
 
   // reset UL info
-  for (it = m_ulInfoListElements.begin (); it != m_ulInfoListElements.end (); it++)
-    {
-      for (uint16_t i = 0; i < (*it).second.m_ulReception.size (); i++)
-        {
-          (*it).second.m_ulReception.at (i) = 0;
-        }
-      (*it).second.m_receptionStatus = UlInfoListElement_s::Ok;
-      (*it).second.m_tpc = 0;
-    }
+//   for (it = m_ulInfoListElements.begin (); it != m_ulInfoListElements.end (); it++)
+//     {
+//       for (uint16_t i = 0; i < (*it).second.m_ulReception.size (); i++)
+//         {
+//           (*it).second.m_ulReception.at (i) = 0;
+//         }
+//       (*it).second.m_receptionStatus = UlInfoListElement_s::Ok;
+//       (*it).second.m_tpc = 0;
+//     }
 }
 
 void
@@ -511,6 +547,11 @@
       Ptr<BsrLteControlMessage> bsr = DynamicCast<BsrLteControlMessage> (msg);
       ReceiveBsrMessage (bsr->GetBsr ());
     }
+  else if (msg->GetMessageType () == LteControlMessage::DL_HARQ)
+    {
+      Ptr<DlHarqFeedbackLteControlMessage> dlharq = DynamicCast<DlHarqFeedbackLteControlMessage> (msg);
+      DoDlInfoListElementHarqFeeback (dlharq->GetDlHarqFeedback ());
+    }
   else
     {
       NS_LOG_LOGIC (this << " LteControlMessage not recognized");
@@ -525,7 +566,6 @@
     {
       NS_LOG_DEBUG (this << " eNB rxed an PUSCH UL-CQI");
     }
-  // TODO store UL-CQI to send them to scheduler
   m_ulCqiReceived.push_back (ulcqi);
 }
 
@@ -561,33 +601,33 @@
 
   // store info of the packet received
 
-  std::map <uint16_t,UlInfoListElement_s>::iterator it;
+//   std::map <uint16_t,UlInfoListElement_s>::iterator it;
 //   u_int rnti = tag.GetRnti ();
 //  u_int lcid = tag.GetLcid ();
-  it = m_ulInfoListElements.find (tag.GetRnti ());
-  if (it == m_ulInfoListElements.end ())
-    {
-      // new RNTI
-      UlInfoListElement_s ulinfonew;
-      ulinfonew.m_rnti = tag.GetRnti ();
-      // always allocate full size of ulReception vector, initializing all elements to 0
-      ulinfonew.m_ulReception.assign (MAX_LC_LIST+1, 0);
-      // set the element for the current LCID
-      ulinfonew.m_ulReception.at (tag.GetLcid ()) = p->GetSize ();
-      ulinfonew.m_receptionStatus = UlInfoListElement_s::Ok;
-      ulinfonew.m_tpc = 0; // Tx power control not implemented at this stage
-      m_ulInfoListElements.insert (std::pair<uint16_t, UlInfoListElement_s > (tag.GetRnti (), ulinfonew));
-
-    }
-  else
-    {
-      // existing RNTI: we just set the value for the current
-      // LCID. Note that the corresponding element had already been
-      // allocated previously.
-      NS_ASSERT_MSG ((*it).second.m_ulReception.at (tag.GetLcid ()) == 0, "would overwrite previously written ulReception element");
-      (*it).second.m_ulReception.at (tag.GetLcid ()) = p->GetSize ();
-      (*it).second.m_receptionStatus = UlInfoListElement_s::Ok;
-    }
+//   it = m_ulInfoListElements.find (tag.GetRnti ());
+//   if (it == m_ulInfoListElements.end ())
+//     {
+//       // new RNTI
+//       UlInfoListElement_s ulinfonew;
+//       ulinfonew.m_rnti = tag.GetRnti ();
+//       // always allocate full size of ulReception vector, initializing all elements to 0
+//       ulinfonew.m_ulReception.assign (MAX_LC_LIST+1, 0);
+//       // set the element for the current LCID
+//       ulinfonew.m_ulReception.at (tag.GetLcid ()) = p->GetSize ();
+//       ulinfonew.m_receptionStatus = UlInfoListElement_s::Ok;
+//       ulinfonew.m_tpc = 0; // Tx power control not implemented at this stage
+//       m_ulInfoListElements.insert (std::pair<uint16_t, UlInfoListElement_s > (tag.GetRnti (), ulinfonew));
+// 
+//     }
+//   else
+//     {
+//       // existing RNTI: we just set the value for the current
+//       // LCID. Note that the corresponding element had already been
+//       // allocated previously.
+//       NS_ASSERT_MSG ((*it).second.m_ulReception.at (tag.GetLcid ()) == 0, "would overwrite previously written ulReception element");
+//       (*it).second.m_ulReception.at (tag.GetLcid ()) = p->GetSize ();
+//       (*it).second.m_receptionStatus = UlInfoListElement_s::Ok;
+//     }
 
 
 
@@ -629,6 +669,16 @@
   params.m_rnti = rnti;
   params.m_transmissionMode = 0; // set to default value (SISO) for avoiding random initialization (valgrind error)
   m_cschedSapProvider->CschedUeConfigReq (params);
+
+  // Create DL trasmission HARQ buffers
+  std::vector < Ptr<Packet> > dlHarqLayer0pkt;
+  dlHarqLayer0pkt.resize (8);
+  std::vector < Ptr<Packet> > dlHarqLayer1pkt;
+  dlHarqLayer1pkt.resize (8);
+  DlHarqProcessesBuffer_t buf;
+  buf.push_back (dlHarqLayer0pkt);
+  buf.push_back (dlHarqLayer1pkt);
+  m_miDlHarqProcessesPackets.insert (std::pair <uint16_t, DlHarqProcessesBuffer_t> (rnti, buf));
 }
 
 void
@@ -703,9 +753,12 @@
   NS_LOG_FUNCTION (this);
   LteRadioBearerTag tag (params.rnti, params.lcid, params.layer);
   params.pdu->AddPacketTag (tag);
-//   Ptr<PacketBurst> pb = CreateObject<PacketBurst> ();
-//   pb->AddPacket (params.pdu);
-
+  // Store pkt in HARQ buffer
+  std::map <uint16_t, DlHarqProcessesBuffer_t>::iterator it =  m_miDlHarqProcessesPackets.find (params.rnti);
+  NS_ASSERT (it!=m_miDlHarqProcessesPackets.end ());
+  NS_LOG_DEBUG (this << " LAYER " <<(uint16_t)tag.GetLayer () << " HARQ ID " << (uint16_t)params.harqProcessId);
+//   NS_ASSERT ((*it).second.at (params.layer).at (params.harqProcessId) == 0);
+  (*it).second.at (params.layer).at (params.harqProcessId) = params.pdu;//->Copy ();
   m_enbPhySapProvider->SendMacPdu (params.pdu);
 }
 
@@ -746,12 +799,30 @@
         {
           for (uint16_t k = 0; k < ind.m_buildDataList.at (i).m_rlcPduList.at (j).size (); k++)
             {
-              LteFlowId_t flow (ind.m_buildDataList.at (i).m_rnti,
-                                ind.m_buildDataList.at (i).m_rlcPduList.at (j).at (k).m_logicalChannelIdentity);
-              it = m_rlcAttached.find (flow);
-              NS_ASSERT_MSG (it != m_rlcAttached.end (), "rnti=" << flow.m_rnti << " lcid=" << (uint32_t) flow.m_lcId);
-              NS_LOG_DEBUG (this << " rnti= " << flow.m_rnti << " lcid= " << (uint32_t) flow.m_lcId << " layer= " << k);
-              (*it).second->NotifyTxOpportunity (ind.m_buildDataList.at (i).m_rlcPduList.at (j).at (k).m_size, k);
+//               NS_ASSERT_MSG (ind.m_buildDataList.at (i).m_dci.m_ndi.size ()<=1, " NOT MIMO, layer " << k);
+//               NS_ASSERT_MSG (ind.m_buildDataList.size ()>i, " I " << i);
+//               NS_ASSERT_MSG (ind.m_buildDataList.at (i).m_dci.m_ndi.size ()>k, " k " << ind.m_buildDataList.at (i).m_rlcPduList.at (j).size ());
+              if (ind.m_buildDataList.at (i).m_dci.m_ndi.at (k) == 1)
+                {
+                  // New Data -> retrieve it from RLC
+                  LteFlowId_t flow (ind.m_buildDataList.at (i).m_rnti,
+                                    ind.m_buildDataList.at (i).m_rlcPduList.at (j).at (k).m_logicalChannelIdentity);
+                  it = m_rlcAttached.find (flow);
+                  NS_ASSERT_MSG (it != m_rlcAttached.end (), "rnti=" << flow.m_rnti << " lcid=" << (uint32_t) flow.m_lcId);
+                  NS_LOG_DEBUG (this << " rnti= " << flow.m_rnti << " lcid= " << (uint32_t) flow.m_lcId << " layer= " << k);
+                  (*it).second->NotifyTxOpportunity (ind.m_buildDataList.at (i).m_rlcPduList.at (j).at (k).m_size, k, ind.m_buildDataList.at (i).m_dci.m_harqProcess);
+                }
+              else
+                {
+                  if (ind.m_buildDataList.at (i).m_dci.m_tbsSize.at (k)>0)
+                    {
+                      // HARQ retransmission -> retrieve TB from HARQ buffer
+                      std::map <uint16_t, DlHarqProcessesBuffer_t>::iterator it = m_miDlHarqProcessesPackets.find (ind.m_buildDataList.at (i).m_rnti);
+                      NS_ASSERT(it!=m_miDlHarqProcessesPackets.end());
+                      Ptr<Packet> pkt = (*it).second.at (k).at ( ind.m_buildDataList.at (i).m_dci.m_harqProcess)->Copy ();
+                      m_enbPhySapProvider->SendMacPdu (pkt);
+                    }
+                }
             }
         }
       // send the relative DCI
@@ -884,5 +955,39 @@
   NS_LOG_FUNCTION (this);
 }
 
+void
+LteEnbMac::DoUlInfoListElementHarqFeeback (UlInfoListElement_s params)
+{
+  NS_LOG_FUNCTION (this);
+  m_ulInfoListReceived.push_back (params);
+}
+
+void
+LteEnbMac::DoDlInfoListElementHarqFeeback (DlInfoListElement_s params)
+{
+  NS_LOG_FUNCTION (this);
+  // Update HARQ buffer
+  std::map <uint16_t, DlHarqProcessesBuffer_t>::iterator it =  m_miDlHarqProcessesPackets.find (params.m_rnti);
+  NS_ASSERT (it!=m_miDlHarqProcessesPackets.end ());
+  for (uint8_t layer = 0; layer < params.m_harqStatus.size (); layer++)
+    {
+      if (params.m_harqStatus.at (layer)==DlInfoListElement_s::ACK)
+        {
+          // discard buffer
+          (*it).second.at (layer).at (params.m_harqProcessId) = 0;
+          NS_LOG_DEBUG (this << " HARQ-ACK UE " << params.m_rnti << " harqId " << (uint16_t)params.m_harqProcessId << " layer " << (uint16_t)layer);
+        }
+      else if (params.m_harqStatus.at (layer)==DlInfoListElement_s::NACK)
+        {
+          NS_LOG_DEBUG (this << " HARQ-NACK UE " << params.m_rnti << " harqId " << (uint16_t)params.m_harqProcessId << " layer " << (uint16_t)layer);
+        }
+      else
+        {
+          NS_FATAL_ERROR (" HARQ functionality not implemented");
+        }
+    }
+  m_dlInfoListReceived.push_back (params);
+}
+
 
 } // namespace ns3
--- a/src/lte/model/lte-enb-mac.h	Fri Aug 31 16:49:46 2012 +0200
+++ b/src/lte/model/lte-enb-mac.h	Mon Oct 08 17:18:22 2012 +0200
@@ -33,6 +33,7 @@
 #include <ns3/lte-enb-phy-sap.h>
 #include "ns3/traced-value.h"
 #include "ns3/trace-source-accessor.h"
+#include <ns3/packet.h>
 
 namespace ns3 {
 
@@ -40,7 +41,7 @@
 class UlCqiLteControlMessage;
 class PdcchMapLteControlMessage;
 
-
+typedef std::vector <std::vector < Ptr<Packet> > > DlHarqProcessesBuffer_t;
 
 /**
  * This class implements the MAC layer of the eNodeB device
@@ -184,18 +185,23 @@
   void DoReceivePhyPdu (Ptr<Packet> p);
 
 private:
-private:
+  void DoUlInfoListElementHarqFeeback (UlInfoListElement_s params);
+  void DoDlInfoListElementHarqFeeback (DlInfoListElement_s params);
   std::map <LteFlowId_t, LteMacSapUser*> m_rlcAttached;
 
   std::vector <CqiListElement_s> m_dlCqiReceived; // DL-CQI received
   std::vector <FfMacSchedSapProvider::SchedUlCqiInfoReqParameters> m_ulCqiReceived; // UL-CQI received
   std::vector <MacCeListElement_s> m_ulCeReceived; // CE received (BSR up to now)
 
+  std::vector <DlInfoListElement_s> m_dlInfoListReceived; // DL HARQ feedback received
+
+  std::vector <UlInfoListElement_s> m_ulInfoListReceived; // UL HARQ feedback received
+
 
   /*
   * Map of UE's info element (see 4.3.12 of FF MAC Scheduler API)
   */
-  std::map <uint16_t,UlInfoListElement_s> m_ulInfoListElements; 
+//   std::map <uint16_t,UlInfoListElement_s> m_ulInfoListElements; 
 
 
 
@@ -229,6 +235,9 @@
   TracedCallback<uint32_t, uint32_t, uint16_t, uint8_t, uint16_t> m_ulScheduling;
   
   uint8_t m_macChTtiDelay; // delay of MAC, PHY and channel in terms of TTIs
+
+
+  std::map <uint16_t, DlHarqProcessesBuffer_t> m_miDlHarqProcessesPackets; // Packet under trasmission of the DL HARQ process
   
 
 };
--- a/src/lte/model/lte-enb-phy-sap.h	Fri Aug 31 16:49:46 2012 +0200
+++ b/src/lte/model/lte-enb-phy-sap.h	Mon Oct 08 17:18:22 2012 +0200
@@ -103,6 +103,21 @@
    */
   virtual void UlCqiReport (FfMacSchedSapProvider::SchedUlCqiInfoReqParameters ulcqi) = 0;
 
+  /**
+   * Notify the HARQ on the UL tranmission status
+   *
+   * \param params
+   */
+  virtual void UlInfoListElementHarqFeeback (UlInfoListElement_s params) = 0;
+
+
+  /**
+   * Notify the HARQ on the DL tranmission status
+   *
+   * \param params
+   */
+  virtual void DlInfoListElementHarqFeeback (DlInfoListElement_s params) = 0;
+
 };
 
 
--- a/src/lte/model/lte-enb-phy.cc	Fri Aug 31 16:49:46 2012 +0200
+++ b/src/lte/model/lte-enb-phy.cc	Mon Oct 08 17:18:22 2012 +0200
@@ -155,6 +155,9 @@
 {
   m_enbPhySapProvider = new EnbMemberLteEnbPhySapProvider (this);
   m_enbCphySapProvider = new MemberLteEnbCphySapProvider<LteEnbPhy> (this);
+  m_harqPhyModule = Create <LteHarqPhy> ();
+  m_downlinkSpectrumPhy->SetHarqPhyModule (m_harqPhyModule);
+  m_uplinkSpectrumPhy->SetHarqPhyModule (m_harqPhyModule);
   Simulator::ScheduleNow (&LteEnbPhy::StartFrame, this);
 }
 
@@ -450,7 +453,7 @@
       m_currentSrsOffset = (m_currentSrsOffset + 1) % m_srsPeriodicity;
     }
   NS_LOG_INFO ("-----sub frame " << m_nrSubFrames << "-----");
-  
+  m_harqPhyModule->SubframeIndication (m_nrFrames, m_nrSubFrames);
   
   // update info on TB to be received
   std::list<UlDciLteControlMessage> uldcilist = DequeueUlDci ();
@@ -475,7 +478,15 @@
             {
               rbMap.push_back (i);
             }
-          m_uplinkSpectrumPhy->AddExpectedTb ((*dciIt).GetDci ().m_rnti, (*dciIt).GetDci ().m_tbSize, (*dciIt).GetDci ().m_mcs, rbMap, 0 /* always SISO*/);
+          m_uplinkSpectrumPhy->AddExpectedTb ((*dciIt).GetDci ().m_rnti, (*dciIt).GetDci ().m_tbSize, (*dciIt).GetDci ().m_mcs, rbMap, 0 /* always SISO*/, 0 /* no HARQ proc id in UL*/, 0.0 /* MI TBD */, false /* UL*/);
+          if ((*dciIt).GetDci ().m_ndi==1)
+            {
+              NS_LOG_DEBUG (this << " RNTI " << (*dciIt).GetDci ().m_rnti << " NEW TB");
+            }
+          else
+            {
+              NS_LOG_DEBUG (this << " RNTI " << (*dciIt).GetDci ().m_rnti << " HARQ RETX");
+            }
           m_ulRntiRxed.push_back ((*dciIt).GetDci ().m_rnti);
         }
     }
@@ -772,4 +783,18 @@
 }
 
 
+void
+LteEnbPhy::SetHarqPhyModule (Ptr<LteHarqPhy> harq)
+{
+  m_harqPhyModule = harq;
+}
+
+
+void
+LteEnbPhy::ReceiveLteUlHarqFeedback (UlInfoListElement_s mes)
+{
+  NS_LOG_FUNCTION (this);
+  m_enbPhySapUser->UlInfoListElementHarqFeeback (mes);
+}
+
 };
--- a/src/lte/model/lte-enb-phy.h	Fri Aug 31 16:49:46 2012 +0200
+++ b/src/lte/model/lte-enb-phy.h	Mon Oct 08 17:18:22 2012 +0200
@@ -27,6 +27,7 @@
 #include <ns3/lte-enb-phy-sap.h>
 #include <ns3/lte-enb-cphy-sap.h>
 #include <ns3/lte-phy.h>
+#include <ns3/lte-harq-phy.h>
 
 #include <map>
 #include <set>
@@ -230,6 +231,13 @@
   virtual void GenerateCtrlCqiReport (const SpectrumValue& sinr);
   virtual void GenerateDataCqiReport (const SpectrumValue& sinr);
 
+  /**
+  * \brief PhySpectrum generated a new UL HARQ feedback
+  */
+  virtual void ReceiveLteUlHarqFeedback (UlInfoListElement_s mes);
+
+  void SetHarqPhyModule (Ptr<LteHarqPhy> harq);
+
 
 private:
 
@@ -274,6 +282,8 @@
   std::map <uint16_t,uint16_t> m_srsCounter;
   std::vector <uint16_t> m_srsUeOffset;
   uint16_t m_currentSrsOffset;
+
+  Ptr<LteHarqPhy> m_harqPhyModule;
   
 };
 
--- a/src/lte/model/lte-enb-rrc.cc	Fri Aug 31 16:49:46 2012 +0200
+++ b/src/lte/model/lte-enb-rrc.cc	Mon Oct 08 17:18:22 2012 +0200
@@ -414,9 +414,11 @@
   ueRrc->DoRecvConnectionSetup (ueConfig);
   
   // configure MAC (and scheduler)
-  FfMacCschedSapProvider::CschedUeConfigReqParameters req;
-  req.m_rnti = rnti;
-  req.m_transmissionMode = (*it).second->GetTransmissionMode ();
+  LteEnbCmacSapProvider::UeConfig params;
+  params.m_rnti = rnti;
+  params.m_transmissionMode = (*it).second->GetTransmissionMode ();
+  m_cmacSapProvider->UeUpdateConfigurationReq (params);
+  
 
   // configure PHY
   m_cphySapProvider->SetTransmissionMode (rnti, (*it).second->GetTransmissionMode ());
@@ -745,6 +747,7 @@
               m_lastAllocatedRnti = rnti;
               Ptr<UeInfo> ueInfo = CreateObject<UeInfo> ();
               ueInfo->SetSrsConfigurationIndex (GetNewSrsConfigurationIndex ());
+              ueInfo->SetTransmissionMode (m_defaultTransmissionMode);
               m_ueMap.insert (std::pair<uint16_t, Ptr<UeInfo> > (rnti, ueInfo));
               NS_LOG_DEBUG (this << " New UE RNTI " << rnti << " cellId " << m_cellId << " srs CI " << ueInfo->GetSrsConfigurationIndex ());
               return rnti;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lte/model/lte-harq-phy.cc	Mon Oct 08 17:18:22 2012 +0200
@@ -0,0 +1,203 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2012 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: Marco Miozzo  <marco.miozzo@cttc.es>
+ */
+
+
+#include <ns3/lte-harq-phy.h>
+#include <ns3/log.h>
+#include <ns3/assert.h>
+
+NS_LOG_COMPONENT_DEFINE ("LteHarqPhy");
+
+namespace ns3 {
+
+//NS_OBJECT_ENSURE_REGISTERED (LteHarqPhy);
+
+
+LteHarqPhy::LteHarqPhy ()
+{
+  // Create DL Decodification HARQ buffers
+  std::vector <HarqProcessInfoList_t> dlHarqLayer0;
+  dlHarqLayer0.resize (8);
+  std::vector <HarqProcessInfoList_t> dlHarqLayer1;
+  dlHarqLayer1.resize (8);
+  m_miDlHarqProcessesInfoMap.push_back (dlHarqLayer0);
+  m_miDlHarqProcessesInfoMap.push_back (dlHarqLayer1);
+}
+
+
+LteHarqPhy::~LteHarqPhy ()
+{
+  m_miDlHarqProcessesInfoMap.clear ();
+  m_miUlHarqProcessesInfoMap.clear ();
+}
+
+
+void
+LteHarqPhy::SubframeIndication (uint32_t frameNo, uint32_t subframeNo)
+{
+  NS_LOG_FUNCTION (this);
+
+  // left shift UL HARQ buffers
+  std::map <uint16_t, std::vector <HarqProcessInfoList_t> >:: iterator it;
+  for (it = m_miUlHarqProcessesInfoMap.begin (); it != m_miUlHarqProcessesInfoMap.end (); it++)
+    {
+      (*it).second.erase ((*it).second.begin ());
+      HarqProcessInfoList_t h;
+      (*it).second.push_back (h);      
+    }
+
+}
+
+
+double
+LteHarqPhy::GetAccumulatedMiDl (uint8_t harqProcId, uint8_t layer)
+{
+  NS_LOG_FUNCTION (this << (uint32_t)harqProcId << (uint16_t)layer);
+  HarqProcessInfoList_t list = m_miDlHarqProcessesInfoMap.at (layer).at (harqProcId);
+  double mi = 0.0;
+  for (uint8_t i = 0; i < list.size (); i++)
+    {
+      mi += list.at (i).m_mi;
+    }
+  return (mi);
+}
+
+HarqProcessInfoList_t
+LteHarqPhy::GetHarqProcessInfoDl (uint8_t harqProcId, uint8_t layer)
+{
+  NS_LOG_FUNCTION (this << (uint32_t)harqProcId << (uint16_t)layer);
+  return (m_miDlHarqProcessesInfoMap.at (layer).at (harqProcId));   
+}
+
+
+double
+LteHarqPhy::GetAccumulatedMiUl (uint16_t rnti)
+{
+  NS_LOG_FUNCTION (this << rnti);
+
+  std::map <uint16_t, std::vector <HarqProcessInfoList_t> >::iterator it;
+  it = m_miUlHarqProcessesInfoMap.find (rnti);
+  NS_ASSERT_MSG (it!=m_miUlHarqProcessesInfoMap.end (), " Does not find MI for RNTI");
+  HarqProcessInfoList_t list = (*it).second.at (0);
+  double mi = 0.0;
+  for (uint8_t i = 0; i < list.size (); i++)
+    {
+      mi += list.at (i).m_mi;
+    }
+  return (mi);
+}
+
+HarqProcessInfoList_t
+LteHarqPhy::GetHarqProcessInfoUl (uint16_t rnti, uint8_t harqProcId)
+{
+  NS_LOG_FUNCTION (this << rnti << (uint16_t)harqProcId);
+  std::map <uint16_t, std::vector <HarqProcessInfoList_t> >::iterator it;
+  it = m_miUlHarqProcessesInfoMap.find (rnti);
+  if (it==m_miUlHarqProcessesInfoMap.end ())
+    {
+      // new entry
+      std::vector <HarqProcessInfoList_t> harqList;
+      harqList.resize (8);
+      m_miUlHarqProcessesInfoMap.insert (std::pair <uint16_t, std::vector <HarqProcessInfoList_t> > (rnti, harqList));
+      return (harqList.at (harqProcId));
+    }
+  else
+    {
+      return ((*it).second.at (harqProcId));
+    }
+}
+
+
+
+void
+LteHarqPhy::UpdateDlHarqProcessStatus (uint8_t id, uint8_t layer, double mi, uint16_t infoBits, uint16_t codeBits)
+{
+  NS_LOG_FUNCTION (this << (uint16_t) id << mi);
+  HarqProcessInfoElement_t el;
+  el.m_mi = mi;
+  el.m_infoBits = infoBits;
+  el.m_codeBits = codeBits;
+  m_miDlHarqProcessesInfoMap.at (layer).at (id).push_back (el);
+}
+
+
+void
+LteHarqPhy::ResetDlHarqProcessStatus (uint8_t id)
+{
+  NS_LOG_FUNCTION (this << (uint16_t) id);
+  for (uint8_t i = 0; i < m_miDlHarqProcessesInfoMap.size (); i++)
+    {
+      m_miDlHarqProcessesInfoMap.at (i).at (id).clear ();
+    }
+  
+}
+
+
+void
+LteHarqPhy::UpdateUlHarqProcessStatus (uint16_t rnti, double mi, uint16_t infoBits, uint16_t codeBits)
+{
+  NS_LOG_FUNCTION (this << rnti << mi);
+  std::map <uint16_t, std::vector <HarqProcessInfoList_t> >::iterator it;
+  it = m_miUlHarqProcessesInfoMap.find (rnti);
+  if (it==m_miUlHarqProcessesInfoMap.end ())
+    {
+      // new entry
+      std::vector <HarqProcessInfoList_t> harqList;
+      harqList.resize (8);
+      HarqProcessInfoElement_t el;
+      el.m_mi = mi;
+      el.m_infoBits = infoBits;
+      el.m_codeBits = codeBits;
+      harqList.at (7).push_back (el);
+      m_miUlHarqProcessesInfoMap.insert (std::pair <uint16_t, std::vector <HarqProcessInfoList_t> > (rnti, harqList));
+    }
+  else
+    {
+      HarqProcessInfoElement_t el;
+      el.m_mi = mi;
+      el.m_infoBits = infoBits;
+      el.m_codeBits = codeBits;
+      (*it).second.at (7).push_back (el);
+    }
+}
+
+void
+LteHarqPhy::ResetUlHarqProcessStatus (uint16_t rnti, uint8_t id)
+{
+  NS_LOG_FUNCTION (this << rnti << (uint16_t)id);
+  std::map <uint16_t, std::vector <HarqProcessInfoList_t> >::iterator it;
+  it = m_miUlHarqProcessesInfoMap.find (rnti);
+  if (it==m_miUlHarqProcessesInfoMap.end ())
+    {
+      // new entry
+      std::vector <HarqProcessInfoList_t> harqList;
+      harqList.resize (8);
+      m_miUlHarqProcessesInfoMap.insert (std::pair <uint16_t, std::vector <HarqProcessInfoList_t> > (rnti, harqList));
+    }
+  else
+    {
+      (*it).second.at (id).clear ();
+    }
+}
+
+
+
+
+} // end namespace
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lte/model/lte-harq-phy.h	Mon Oct 08 17:18:22 2012 +0200
@@ -0,0 +1,143 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2012 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: Marco Miozzo  <marco.miozzo@cttc.es>
+ */
+
+
+#ifndef LTE_HARQ_PHY_MODULE_H
+#define LTE_HARQ_PHY_MODULE_H
+
+
+
+#include <ns3/log.h>
+#include <ns3/assert.h>
+#include <math.h>
+#include <vector>
+#include <map>
+#include <ns3/simple-ref-count.h>
+
+
+namespace ns3 {
+
+
+
+struct HarqProcessInfoElement_t
+{
+   double m_mi;
+   uint8_t m_rv;
+   uint16_t m_infoBits;
+   uint16_t m_codeBits;
+};
+
+typedef std::vector <HarqProcessInfoElement_t> HarqProcessInfoList_t;
+
+/**
+ * \ingroup lte
+ * \brief The LteHarqPhy class implements the HARQ functionalities related to PHY layer
+ *(i.e., decodification buffers for incremental redundancy managment)
+ *
+*/
+class LteHarqPhy : public SimpleRefCount<LteHarqPhy>
+{
+public:
+  LteHarqPhy ();
+  ~LteHarqPhy ();
+
+  void SubframeIndication (uint32_t frameNo, uint32_t subframeNo);
+
+  /**
+  * \brief Return the cumulated MI of the HARQ procId in case of retranmissions
+  * for DL (asynchronous)
+  * \param harqProcId the HARQ proc id
+  * \param layer layer no. (for MIMO spatial multiplexing)
+  * \return the MI accumulated
+  */
+  double GetAccumulatedMiDl (uint8_t harqProcId, uint8_t layer);
+
+  /**
+  * \brief Return the info of the HARQ procId in case of retranmissions
+  * for DL (asynchronous)
+  * \param harqProcId the HARQ proc id
+  * \param layer layer no. (for MIMO spatail multiplexing)
+  * \return the vector of the info related to HARQ proc Id
+  */
+  HarqProcessInfoList_t GetHarqProcessInfoDl (uint8_t harqProcId, uint8_t layer);
+
+  /**
+  * \brief Return the cumulated MI of the HARQ procId in case of retranmissions
+  * for UL (synchronous)
+  * \return the MI accumulated
+  */
+  double GetAccumulatedMiUl (uint16_t rnti);
+
+  /**
+  * \brief Return the info of the HARQ procId in case of retranmissions
+  * for UL (asynchronous)
+  * \param harqProcId the HARQ proc id
+  * \param layer layer no. (for MIMO spatail multiplexing)
+  * \return the vector of the info related to HARQ proc Id
+  */
+  HarqProcessInfoList_t GetHarqProcessInfoUl (uint16_t rnti, uint8_t harqProcId);
+
+  /**
+  * \brief Update the Info associated to the decodification of an HARQ process
+  * for DL (asynchronous)
+  * \param id the HARQ proc id
+  * \param layer layer no. (for MIMO spatail multiplexing)
+  * \param mi the new MI
+  */
+  void UpdateDlHarqProcessStatus (uint8_t id, uint8_t layer, double mi, uint16_t infoBits, uint16_t codeBits);
+
+  /**
+  * \brief Reset  the info associated to the decodification of an HARQ process
+  * for DL (asynchronous)
+  * \param id the HARQ proc id
+  */
+  void ResetDlHarqProcessStatus(uint8_t id);
+
+  /**
+  * \brief Update the MI value associated to the decodification of an HARQ process
+  * for DL (asynchronous)
+  * \param rnti the RNTI of the transmitter
+  * \param mi the new MI
+  */
+  void UpdateUlHarqProcessStatus (uint16_t rnti, double mi, uint16_t infoBits, uint16_t codeBits);
+
+  /**
+  * \brief Reset  the info associated to the decodification of an HARQ process
+  * for DL (asynchronous)
+  * \param id the HARQ proc id
+  */
+  void ResetUlHarqProcessStatus(uint16_t rnti, uint8_t id);
+  
+  
+  
+
+
+private:
+
+  std::vector <std::vector <HarqProcessInfoList_t> > m_miDlHarqProcessesInfoMap;
+  std::map <uint16_t, std::vector <HarqProcessInfoList_t> > m_miUlHarqProcessesInfoMap;
+  
+
+};
+
+
+}
+
+#endif /* LTE_HARQ_PHY_MODULE_H */
--- a/src/lte/model/lte-mac-sap.h	Fri Aug 31 16:49:46 2012 +0200
+++ b/src/lte/model/lte-mac-sap.h	Mon Oct 08 17:18:22 2012 +0200
@@ -48,6 +48,7 @@
     uint16_t    rnti; /**< the C-RNTI identifying the UE */
     uint8_t     lcid; /**< the logical channel id corresponding to the sending RLC instance */
     uint8_t     layer; /**< the layer value that was passed by the MAC in the call to NotifyTxOpportunity that generated this PDU */
+    uint8_t     harqProcessId; /**< the HARQ process id that was passed by the MAC in the call to NotifyTxOpportunity that generated this PDU */
   };
 
   /**
@@ -101,7 +102,7 @@
    * \param bytes the number of bytes to transmit
    * \param layer the layer of transmission (MIMO)
    */
-  virtual void NotifyTxOpportunity (uint32_t bytes, uint8_t layer) = 0;
+  virtual void NotifyTxOpportunity (uint32_t bytes, uint8_t layer, uint8_t harqId) = 0;
 
   /**
    * Called by the MAC to notify the RLC that an HARQ process related
--- a/src/lte/model/lte-mi-error-model.cc	Fri Aug 31 16:49:46 2012 +0200
+++ b/src/lte/model/lte-mi-error-model.cc	Mon Oct 08 17:18:22 2012 +0200
@@ -492,6 +492,126 @@
   return errorRate;
 }
 
+
+TbStats_t
+LteMiErrorModel::GetTbDecodificationStats (const SpectrumValue& sinr, const std::vector<int>& map, uint16_t size, uint8_t mcs, double mi)
+{
+  NS_LOG_FUNCTION (sinr << &map << (uint32_t) size << (uint32_t) mcs);
+
+  double MI = Mib(sinr, map, mcs) + mi;
+  // estimate CB size (according to sec 5.1.2 of TS 36.212)
+  uint16_t Z = 6144; // max size of a codeblock (including CRC)
+  uint32_t B = size * 8;
+//   B = 1234;
+  uint32_t L = 0;
+  uint32_t C = 0; // no. of codeblocks
+  uint32_t Cplus = 0; // no. of codeblocks with size K+
+  uint32_t Kplus = 0; // no. of codeblocks with size K+
+  uint32_t Cminus = 0; // no. of codeblocks with size K+
+  uint32_t Kminus = 0; // no. of codeblocks with size K+
+  uint32_t B1 = 0;
+  uint32_t deltaK = 0;
+  if (B <= Z)
+    {
+      // only one codeblock
+      L = 0;
+      C = 1;
+      B1 = B;
+    }
+  else
+    {
+      L = 24;
+      C = ceil ((double)B / ((double)(Z-L)));
+      B1 = B + C * L;
+    }
+  // first segmentation: K+ = minimum K in table such that C * K >= B1
+//   uint i = 0;
+//   while (B1 > cbSizeTable[i] * C)
+//     {
+// //       NS_LOG_INFO (" K+ " << cbSizeTable[i] << " means " << cbSizeTable[i] * C);
+//       i++;
+//     }
+//   uint16_t KplusId = i;
+//   Kplus = cbSizeTable[i];
+
+  // implement a modified binary search
+  int min = 0;
+  int max = 187;
+  int mid = 0;
+  do
+    {
+      mid = (min+max) / 2;
+      if (B1 > cbSizeTable[mid]*C)
+        {
+          if (B1 < cbSizeTable[mid+1]*C)
+            {
+              break;
+            }
+          else
+            {
+              min = mid + 1;
+            }
+        }
+      else
+        {
+          if (B1 > cbSizeTable[mid-1]*C)
+            {
+              break;
+            }
+          else
+            {
+              max = mid - 1;
+            }
+        }
+  } while ((cbSizeTable[mid]*C != B1) && (min < max));
+  // adjust binary search to the largest integer value of K containing B1
+  if (B1 > cbSizeTable[mid]*C)
+    {
+      mid ++;
+    }
+
+  uint16_t KplusId = mid;
+  Kplus = cbSizeTable[mid];
+
+
+  if (C==1)
+    {
+      Cplus = 1;
+      Cminus = 0;
+      Kminus = 0;
+    }
+  else
+    {
+      // second segmentation size: K- = maximum K in table such that K < K+
+      Kminus = cbSizeTable[KplusId-1 > 0 ? KplusId-1 : 0];
+      deltaK = Kplus - Kminus;
+      Cminus = floor ((((double) C * Kplus) - (double)B1) / (double)deltaK);
+      Cplus = C - Cminus;
+    }
+  NS_LOG_INFO ("--------------------LteMiErrorModel: TB size of " << B << " needs of " << B1 << " bits reparted in " << C << " CBs as "<< Cplus << " block(s) of " << Kplus << " and " << Cminus << " of " << Kminus);
+
+  double errorRate = 1.0;
+  if (C!=1)
+    {
+      double cbler = MappingMiBler (MI, mcs, Kplus);
+      errorRate *= pow (1.0 - cbler, Cplus);
+      cbler = MappingMiBler (MI, mcs, Kminus);
+      errorRate *= pow (1.0 - cbler, Cminus);
+      errorRate = 1.0 - errorRate;
+    }
+  else
+    {
+      errorRate = MappingMiBler (MI, mcs, Kplus);
+    }
+
+  NS_LOG_LOGIC (" Error rate " << errorRate);
+  TbStats_t ret;
+  ret.error = errorRate;
+  ret.mi = MI;
+  return ret;
+}
+
+
 double
 LteMiErrorModel::GetPcfichPdcchError (const SpectrumValue& sinr)
 {
@@ -578,6 +698,148 @@
   return (errorRate);
 }
 
+
+
+
+TbStats_t
+LteMiErrorModel::GetTbDecodificationStats (const SpectrumValue& sinr, const std::vector<int>& map, uint16_t size, uint8_t mcs, HarqProcessInfoList_t miHistory)
+{
+  NS_LOG_FUNCTION (sinr << &map << (uint32_t) size << (uint32_t) mcs);
+
+  double tbMi = Mib(sinr, map, mcs);
+  double MI = 0.0;
+  double Reff = 0.0;
+  if (miHistory.size ()>0)
+    {
+      // evaluate R_eff and MI_eff
+      uint16_t codeBitsSum = 0;
+      double miSum = 0.0;
+      for (uint16_t i = 0; i < miHistory.size (); i++)
+        {
+          codeBitsSum += miHistory.at (i).m_codeBits;
+          miSum += (miHistory.at (i).m_mi*miHistory.at (i).m_codeBits);
+        }
+      Reff = miHistory.at (0).m_infoBits / codeBitsSum; // information bits are the size of the first TB
+      MI = miSum / (double)codeBitsSum;      
+    }
+  else
+    {
+      MI = tbMi;
+    }
+  NS_LOG_DEBUG (" MI " << MI << " Reff " << Reff);
+  // estimate CB size (according to sec 5.1.2 of TS 36.212)
+  uint16_t Z = 6144; // max size of a codeblock (including CRC)
+  uint32_t B = size * 8;
+//   B = 1234;
+  uint32_t L = 0;
+  uint32_t C = 0; // no. of codeblocks
+  uint32_t Cplus = 0; // no. of codeblocks with size K+
+  uint32_t Kplus = 0; // no. of codeblocks with size K+
+  uint32_t Cminus = 0; // no. of codeblocks with size K+
+  uint32_t Kminus = 0; // no. of codeblocks with size K+
+  uint32_t B1 = 0;
+  uint32_t deltaK = 0;
+  if (B <= Z)
+    {
+      // only one codeblock
+      L = 0;
+      C = 1;
+      B1 = B;
+    }
+  else
+    {
+      L = 24;
+      C = ceil ((double)B / ((double)(Z-L)));
+      B1 = B + C * L;
+    }
+  // first segmentation: K+ = minimum K in table such that C * K >= B1
+//   uint i = 0;
+//   while (B1 > cbSizeTable[i] * C)
+//     {
+// //       NS_LOG_INFO (" K+ " << cbSizeTable[i] << " means " << cbSizeTable[i] * C);
+//       i++;
+//     }
+//   uint16_t KplusId = i;
+//   Kplus = cbSizeTable[i];
+
+  // implement a modified binary search
+  int min = 0;
+  int max = 187;
+  int mid = 0;
+  do
+    {
+      mid = (min+max) / 2;
+      if (B1 > cbSizeTable[mid]*C)
+        {
+          if (B1 < cbSizeTable[mid+1]*C)
+            {
+              break;
+            }
+          else
+            {
+              min = mid + 1;
+            }
+        }
+      else
+        {
+          if (B1 > cbSizeTable[mid-1]*C)
+            {
+              break;
+            }
+          else
+            {
+              max = mid - 1;
+            }
+        }
+  } while ((cbSizeTable[mid]*C != B1) && (min < max));
+  // adjust binary search to the largest integer value of K containing B1
+  if (B1 > cbSizeTable[mid]*C)
+    {
+      mid ++;
+    }
+
+  uint16_t KplusId = mid;
+  Kplus = cbSizeTable[mid];
+
+
+  if (C==1)
+    {
+      Cplus = 1;
+      Cminus = 0;
+      Kminus = 0;
+    }
+  else
+    {
+      // second segmentation size: K- = maximum K in table such that K < K+
+      Kminus = cbSizeTable[KplusId-1 > 0 ? KplusId-1 : 0];
+      deltaK = Kplus - Kminus;
+      Cminus = floor ((((double) C * Kplus) - (double)B1) / (double)deltaK);
+      Cplus = C - Cminus;
+    }
+  NS_LOG_INFO ("--------------------LteMiErrorModel: TB size of " << B << " needs of " << B1 << " bits reparted in " << C << " CBs as "<< Cplus << " block(s) of " << Kplus << " and " << Cminus << " of " << Kminus);
+
+  double errorRate = 1.0;
+  if (C!=1)
+    {
+      double cbler = MappingMiBler (MI, mcs, Kplus);
+      errorRate *= pow (1.0 - cbler, Cplus);
+      cbler = MappingMiBler (MI, mcs, Kminus);
+      errorRate *= pow (1.0 - cbler, Cminus);
+      errorRate = 1.0 - errorRate;
+    }
+  else
+    {
+      errorRate = MappingMiBler (MI, mcs, Kplus);
+    }
+
+  NS_LOG_LOGIC (" Error rate " << errorRate);
+  TbStats_t ret;
+  ret.error = errorRate;
+  ret.mi = tbMi;
+  return ret;
+}
+
+
   
 
 } // namespace ns3
--- a/src/lte/model/lte-mi-error-model.h	Fri Aug 31 16:49:46 2012 +0200
+++ b/src/lte/model/lte-mi-error-model.h	Mon Oct 08 17:18:22 2012 +0200
@@ -38,6 +38,7 @@
 #include <ns3/ptr.h>
 #include <stdint.h>
 #include <ns3/spectrum-value.h>
+#include <ns3/lte-harq-phy.h>
 
 
 
@@ -48,6 +49,12 @@
   const uint16_t MI_MAP_QPSK_SIZE = 766;
   const uint16_t MI_MAP_16QAM_SIZE = 843;
   const uint16_t MI_MAP_64QAM_SIZE = 725;
+
+struct TbStats_t
+{
+  double error;
+  double mi;
+};
   
 
 
@@ -85,6 +92,19 @@
    * \return the TB error rate
    */  
   static double GetTbError (const SpectrumValue& sinr, const std::vector<int>& map, uint16_t size, uint8_t mcs);
+
+  /**
+   * \brief run the error-model algorithm for the specified TB
+   * \param sinr the perceived sinrs in the whole bandwidth
+   * \param map the actives RBs for the TB
+   * \param size the size in bytes of the TB
+   * \param mcs the MCS of the TB
+   * \param cumulatedMi  MI of past transmissions (in case of retx)
+   * \return the TB error rate
+   */
+  static TbStats_t GetTbDecodificationStats (const SpectrumValue& sinr, const std::vector<int>& map, uint16_t size, uint8_t mcs, double cumulatedMi);
+
+  static TbStats_t GetTbDecodificationStats (const SpectrumValue& sinr, const std::vector<int>& map, uint16_t size, uint8_t mcs, HarqProcessInfoList_t miHistory);
   
   /** 
   * \brief run the error-model algorithm for the specified PCFICH+PDCCH channels
--- a/src/lte/model/lte-radio-bearer-tag.cc	Fri Aug 31 16:49:46 2012 +0200
+++ b/src/lte/model/lte-radio-bearer-tag.cc	Mon Oct 08 17:18:22 2012 +0200
@@ -91,7 +91,7 @@
 uint32_t
 LteRadioBearerTag::GetSerializedSize (void) const
 {
-  return 3;
+  return 4;
 }
 
 void
@@ -99,6 +99,7 @@
 {
   i.WriteU16 (m_rnti);
   i.WriteU8 (m_lcid);
+  i.WriteU8 (m_layer);
 }
 
 void
@@ -106,6 +107,7 @@
 {
   m_rnti = (uint16_t) i.ReadU16 ();
   m_lcid = (uint8_t) i.ReadU8 ();
+  m_layer = (uint8_t) i.ReadU8 ();
 }
 
 uint16_t
@@ -129,7 +131,7 @@
 void
 LteRadioBearerTag::Print (std::ostream &os) const
 {
-  os << "rnti=" << m_rnti << ", lcid=" << (uint16_t) m_lcid;
+  os << "rnti=" << m_rnti << ", lcid=" << (uint16_t) m_lcid << ", layer=" << (uint16_t)m_layer;
 }
 
 } // namespace ns3
--- a/src/lte/model/lte-rlc-am.cc	Fri Aug 31 16:49:46 2012 +0200
+++ b/src/lte/model/lte-rlc-am.cc	Mon Oct 08 17:18:22 2012 +0200
@@ -162,7 +162,7 @@
  */
 
 void
-LteRlcAm::DoNotifyTxOpportunity (uint32_t bytes, uint8_t layer)
+LteRlcAm::DoNotifyTxOpportunity (uint32_t bytes, uint8_t layer, uint8_t harqId)
 {
   NS_LOG_FUNCTION (this << m_rnti << (uint32_t) m_lcid << bytes);
   
@@ -190,6 +190,8 @@
       params.pdu = packet;
       params.rnti = m_rnti;
       params.lcid = m_lcid;
+      params.layer = layer;
+      params.harqProcessId = harqId;
 
       m_macSapProvider->TransmitPdu (params);
       return;
@@ -211,6 +213,8 @@
           params.pdu = packet;
           params.rnti = m_rnti;
           params.lcid = m_lcid;
+          params.layer = layer;
+          params.harqProcessId = harqId;
 
           m_macSapProvider->TransmitPdu (params);
           return;
@@ -539,6 +543,7 @@
   params.rnti = m_rnti;
   params.lcid = m_lcid;
   params.layer = layer;
+  params.harqProcessId = harqId;
 
   m_macSapProvider->TransmitPdu (params);
 }
--- a/src/lte/model/lte-rlc-am.h	Fri Aug 31 16:49:46 2012 +0200
+++ b/src/lte/model/lte-rlc-am.h	Mon Oct 08 17:18:22 2012 +0200
@@ -48,7 +48,7 @@
   /**
    * MAC SAP
    */
-  virtual void DoNotifyTxOpportunity (uint32_t bytes, uint8_t layer);
+  virtual void DoNotifyTxOpportunity (uint32_t bytes, uint8_t layer, uint8_t harqId);
   virtual void DoNotifyHarqDeliveryFailure ();
   virtual void DoReceivePdu (Ptr<Packet> p);
 
--- a/src/lte/model/lte-rlc-um.cc	Fri Aug 31 16:49:46 2012 +0200
+++ b/src/lte/model/lte-rlc-um.cc	Mon Oct 08 17:18:22 2012 +0200
@@ -115,7 +115,7 @@
  */
 
 void
-LteRlcUm::DoNotifyTxOpportunity (uint32_t bytes, uint8_t layer)
+LteRlcUm::DoNotifyTxOpportunity (uint32_t bytes, uint8_t layer, uint8_t harqId)
 {
   NS_LOG_FUNCTION (this << m_rnti << (uint32_t) m_lcid << bytes);
 
@@ -372,6 +372,7 @@
   params.rnti = m_rnti;
   params.lcid = m_lcid;
   params.layer = layer;
+  params.harqProcessId = harqId;
 
   m_macSapProvider->TransmitPdu (params);
 
--- a/src/lte/model/lte-rlc-um.h	Fri Aug 31 16:49:46 2012 +0200
+++ b/src/lte/model/lte-rlc-um.h	Mon Oct 08 17:18:22 2012 +0200
@@ -47,7 +47,7 @@
   /**
    * MAC SAP
    */
-  virtual void DoNotifyTxOpportunity (uint32_t bytes, uint8_t layer);
+  virtual void DoNotifyTxOpportunity (uint32_t bytes, uint8_t layer, uint8_t harqId);
   virtual void DoNotifyHarqDeliveryFailure ();
   virtual void DoReceivePdu (Ptr<Packet> p);
 
--- a/src/lte/model/lte-rlc.cc	Fri Aug 31 16:49:46 2012 +0200
+++ b/src/lte/model/lte-rlc.cc	Mon Oct 08 17:18:22 2012 +0200
@@ -42,7 +42,7 @@
   LteRlcSpecificLteMacSapUser (LteRlc* rlc);
 
   // Interface implemented from LteMacSapUser
-  virtual void NotifyTxOpportunity (uint32_t bytes, uint8_t layer);
+  virtual void NotifyTxOpportunity (uint32_t bytes, uint8_t layer, uint8_t harqId);
   virtual void NotifyHarqDeliveryFailure ();
   virtual void ReceivePdu (Ptr<Packet> p);
 
@@ -61,9 +61,9 @@
 }
 
 void
-LteRlcSpecificLteMacSapUser::NotifyTxOpportunity (uint32_t bytes, uint8_t layer)
+LteRlcSpecificLteMacSapUser::NotifyTxOpportunity (uint32_t bytes, uint8_t layer, uint8_t harqId)
 {
-  m_rlc->DoNotifyTxOpportunity (bytes, layer);
+  m_rlc->DoNotifyTxOpportunity (bytes, layer, harqId);
 }
 
 void
@@ -210,7 +210,7 @@
 }
 
 void
-LteRlcSm::DoNotifyTxOpportunity (uint32_t bytes, uint8_t layer)
+LteRlcSm::DoNotifyTxOpportunity (uint32_t bytes, uint8_t layer, uint8_t harqId)
 {
   NS_LOG_FUNCTION (this << bytes);
   LteMacSapProvider::TransmitPduParameters params;
@@ -218,6 +218,7 @@
   params.rnti = m_rnti;
   params.lcid = m_lcid;
   params.layer = layer;
+  params.harqProcessId = harqId;
 
   // RLC Performance evaluation
   RlcTag tag (Simulator::Now());
--- a/src/lte/model/lte-rlc.h	Fri Aug 31 16:49:46 2012 +0200
+++ b/src/lte/model/lte-rlc.h	Mon Oct 08 17:18:22 2012 +0200
@@ -111,7 +111,7 @@
   LteRlcSapProvider* m_rlcSapProvider;
 
   // Interface forwarded by LteMacSapUser
-  virtual void DoNotifyTxOpportunity (uint32_t bytes, uint8_t layer) = 0;
+  virtual void DoNotifyTxOpportunity (uint32_t bytes, uint8_t layer, uint8_t harqId) = 0;
   virtual void DoNotifyHarqDeliveryFailure () = 0;
   virtual void DoReceivePdu (Ptr<Packet> p) = 0;
 
@@ -150,7 +150,7 @@
   static TypeId GetTypeId (void);
 
   virtual void DoTransmitPdcpPdu (Ptr<Packet> p);
-  virtual void DoNotifyTxOpportunity (uint32_t bytes, uint8_t layer);
+  virtual void DoNotifyTxOpportunity (uint32_t bytes, uint8_t layer, uint8_t harqId);
   virtual void DoNotifyHarqDeliveryFailure ();
   virtual void DoReceivePdu (Ptr<Packet> p);
 
--- a/src/lte/model/lte-spectrum-phy.cc	Fri Aug 31 16:49:46 2012 +0200
+++ b/src/lte/model/lte-spectrum-phy.cc	Mon Oct 08 17:18:22 2012 +0200
@@ -52,6 +52,38 @@
 // = 0.001 / 14 * 3 (ctrl fixed to 3 symbols) -1ns as margin to avoid overlapping simulator events
 static const Time DL_CTRL_DURATION = NanoSeconds (214286 -1);
 
+double EffectiveCodingRate[29] = {
+  0.08,
+  0.1,
+  0.11,
+  0.15,
+  0.19,
+  0.24,
+  0.3,
+  0.37,
+  0.44,
+  0.51,
+  0.3,
+  0.33,
+  0.37,
+  0.42,
+  0.48,
+  0.54,
+  0.6,
+  0.43,
+  0.45,
+  0.5,
+  0.55,
+  0.6,
+  0.65,
+  0.7,
+  0.75,
+  0.8,
+  0.85,
+  0.89,
+  0.92
+};
+
 
 
   
@@ -81,7 +113,9 @@
 
 LteSpectrumPhy::LteSpectrumPhy ()
   : m_state (IDLE),
-  m_transmissionMode (0)
+  m_transmissionMode (0),
+  m_layersNum (1),
+  errors (0)
 {
   NS_LOG_FUNCTION (this);
   m_random = CreateObject<UniformRandomVariable> ();
@@ -119,6 +153,8 @@
   m_ltePhyRxDataEndOkCallback    = MakeNullCallback< void, Ptr<Packet> >  ();
   m_ltePhyRxCtrlEndOkCallback = MakeNullCallback< void, std::list<Ptr<LteControlMessage> > > ();
   m_ltePhyRxCtrlEndErrorCallback = MakeNullCallback< void > ();
+  m_ltePhyDlHarqFeedbackCallback = MakeNullCallback< void, DlInfoListElement_s > ();
+  m_ltePhyUlHarqFeedbackCallback = MakeNullCallback< void, UlInfoListElement_s > ();
   SpectrumPhy::DoDispose ();
 } 
 
@@ -285,6 +321,20 @@
   m_ltePhyRxCtrlEndErrorCallback = c;
 }
 
+void
+LteSpectrumPhy::SetLtePhyDlHarqFeedbackCallback (LtePhyDlHarqFeedbackCallback c)
+{
+  NS_LOG_FUNCTION (this);
+  m_ltePhyDlHarqFeedbackCallback = c;
+}
+
+void
+LteSpectrumPhy::SetLtePhyUlHarqFeedbackCallback (LtePhyUlHarqFeedbackCallback c)
+{
+  NS_LOG_FUNCTION (this);
+  m_ltePhyUlHarqFeedbackCallback = c;
+}
+
 
 Ptr<AntennaModel>
 LteSpectrumPhy::GetRxAntenna ()
@@ -314,6 +364,14 @@
 }
 
 
+void
+LteSpectrumPhy::SetHarqPhyModule (Ptr<LteHarqPhy> harq)
+{
+  m_harqPhyModule = harq;
+}
+
+
+
 
 bool
 LteSpectrumPhy::StartTxDataFrame (Ptr<PacketBurst> pb, std::list<Ptr<LteControlMessage> > ctrlMsgList, Time duration)
@@ -717,22 +775,23 @@
 
 
 void
-LteSpectrumPhy::AddExpectedTb (uint16_t  rnti, uint16_t size, uint8_t mcs, std::vector<int> map, uint8_t layer)
+LteSpectrumPhy::AddExpectedTb (uint16_t  rnti, uint16_t size, uint8_t mcs, std::vector<int> map, uint8_t layer, uint8_t harqId, double miCumulated, bool downlink)
 {
-  NS_LOG_LOGIC (this << " rnti: " << rnti << " size " << size << " mcs " << (uint16_t)mcs << " layer " << (uint8_t)layer);
+  NS_LOG_FUNCTION (this << " rnti: " << rnti << " size " << size << " mcs " << (uint16_t)mcs << " layer " << (uint16_t)layer << " MI " << miCumulated);
   TbId_t tbId;
   tbId.m_rnti = rnti;
   tbId.m_layer = layer;
   expectedTbs_t::iterator it;
   it = m_expectedTbs.find (tbId);
   if (it != m_expectedTbs.end ())
-  {
-    // migth be a TB of an unreceived packet (due to high progpalosses)
-    m_expectedTbs.erase (it);
-  }
+    {
+      // migth be a TB of an unreceived packet (due to high progpalosses)
+      m_expectedTbs.erase (it);
+    }
   // insert new entry
-  tbInfo_t tbInfo = {size, mcs, map, false};
-  m_expectedTbs.insert (std::pair<TbId_t, tbInfo_t> (tbId,tbInfo ));
+  std::vector<uint8_t> rv;
+  tbInfo_t tbInfo = {size, mcs, map, harqId, miCumulated, downlink, false};
+  m_expectedTbs.insert (std::pair<TbId_t, tbInfo_t> (tbId,tbInfo));
 }
 
 
@@ -760,9 +819,33 @@
     {
       if (m_dataErrorModelEnabled)
         {
-          double errorRate = LteMiErrorModel::GetTbError (m_sinrPerceived, (*itTb).second.rbBitmap, (*itTb).second.size, (*itTb).second.mcs);
-          (*itTb).second.corrupt = m_random->GetValue () > errorRate ? false : true;
-          NS_LOG_DEBUG (this << "RNTI " << (*itTb).first.m_rnti << " size " << (*itTb).second.size << " mcs " << (uint32_t)(*itTb).second.mcs << " bitmap " << (*itTb).second.rbBitmap.size () << " layer " << (uint16_t)(*itTb).first.m_layer << " ErrorRate " << errorRate << " corrupted " << (*itTb).second.corrupt);
+//           double errorRate = LteMiErrorModel::GetTbError (m_sinrPerceived, (*itTb).second.rbBitmap, (*itTb).second.size, (*itTb).second.mcs);
+          // retrieve HARQ info
+          HarqProcessInfoList_t harqInfoList;
+          uint16_t ulHarqId = 0;  // TODO 0 means current HARQ porc under evaluation
+          if ((*itTb).second.downlink)
+            {
+              harqInfoList = m_harqPhyModule->GetHarqProcessInfoDl ((*itTb).second.harqProcessId, (*itTb).first.m_layer);
+            }
+          else
+            {
+              harqInfoList = m_harqPhyModule->GetHarqProcessInfoUl ((*itTb).first.m_rnti, ulHarqId);
+            }
+//           TbStats_t tbStats = LteMiErrorModel::GetTbDecodificationStats (m_sinrPerceived, (*itTb).second.rbBitmap, (*itTb).second.size, (*itTb).second.mcs, (*itTb).second.mi);
+          TbStats_t tbStats = LteMiErrorModel::GetTbDecodificationStats (m_sinrPerceived, (*itTb).second.rbBitmap, (*itTb).second.size, (*itTb).second.mcs, harqInfoList);
+          (*itTb).second.mi = tbStats.mi;
+          (*itTb).second.corrupt = m_random->GetValue () > tbStats.error ? false : true;
+          // DEBUG: force error for testing HARQ
+          if ((*itTb).second.downlink)
+          {
+//             if (((*itTb).second.harqProcessId == 0)&&(Simulator::Now ().GetNanoSeconds ()<=20000000))
+            if ((errors<1) && ( ((*itTb).first.m_rnti==1)||((*itTb).first.m_rnti==3)) )
+              {
+                (*itTb).second.corrupt = true;
+                errors++;
+              }
+          }
+          NS_LOG_DEBUG (this << "RNTI " << (*itTb).first.m_rnti << " size " << (*itTb).second.size << " mcs " << (uint32_t)(*itTb).second.mcs << " bitmap " << (*itTb).second.rbBitmap.size () << " layer " << (uint16_t)(*itTb).first.m_layer << " ErrorRate " << tbStats.error << " corrupted " << (*itTb).second.corrupt);
        }
       
 //       for (uint16_t i = 0; i < (*itTb).second.rbBitmap.size (); i++)
@@ -771,6 +854,7 @@
 //         }
       itTb++;
     }
+    std::map <uint16_t, DlInfoListElement_s> harqDlInfoMap;
     for (std::list<Ptr<PacketBurst> >::const_iterator i = m_rxPacketBurstList.begin (); 
     i != m_rxPacketBurstList.end (); ++i)
       {
@@ -783,7 +867,7 @@
             tbId.m_rnti = tag.GetRnti ();
             tbId.m_layer = tag.GetLayer ();
             itTb = m_expectedTbs.find (tbId);
-            NS_LOG_INFO (this << " Packet of " << tbId.m_rnti << " layer " <<  (uint8_t) tbId.m_layer);
+            NS_LOG_INFO (this << " Packet of " << tbId.m_rnti << " layer " <<  (uint16_t) tag.GetLayer ());
             if (itTb!=m_expectedTbs.end ())
               {
                 if (!(*itTb).second.corrupt)
@@ -800,10 +884,84 @@
                     // TB received with errors
                     m_phyRxEndErrorTrace (*j);
                   }
+
+                // send HARQ feedback
+                if (!(*itTb).second.downlink)
+                  {
+                    UlInfoListElement_s harqUlInfo;
+                    harqUlInfo.m_rnti = tbId.m_rnti;
+                    if ((*itTb).second.corrupt)
+                      {
+                        harqUlInfo.m_receptionStatus = UlInfoListElement_s::NotOk;
+                        NS_LOG_DEBUG (this << " RNTI " << tbId.m_rnti << " send UL-HARQ-NACK");
+                        m_harqPhyModule->UpdateUlHarqProcessStatus (tbId.m_rnti, (*itTb).second.mi, (*itTb).second.size, EffectiveCodingRate [(*itTb).second.mcs] * (*itTb).second.size);
+                      }
+                    else
+                      {
+                        harqUlInfo.m_receptionStatus = UlInfoListElement_s::Ok;
+                        NS_LOG_DEBUG (this << " RNTI " << tbId.m_rnti << " send UL-HARQ-ACK");
+                        m_harqPhyModule->ResetUlHarqProcessStatus (tbId.m_rnti, (*itTb).second.harqProcessId);
+                      }
+                      if (!m_ltePhyUlHarqFeedbackCallback.IsNull ())
+                        {
+                          m_ltePhyUlHarqFeedbackCallback (harqUlInfo);
+                        }
+                  }
+                else
+                  {
+                    std::map <uint16_t, DlInfoListElement_s>::iterator itHarq = harqDlInfoMap.find (tbId.m_rnti);
+                    if (itHarq==harqDlInfoMap.end ())
+                      {
+                        DlInfoListElement_s harqDlInfo;
+                        harqDlInfo.m_harqStatus.resize (m_layersNum, DlInfoListElement_s::NACK);
+                        harqDlInfo.m_rnti = tbId.m_rnti;
+                        harqDlInfo.m_harqProcessId = (*itTb).second.harqProcessId;
+                        if ((*itTb).second.corrupt)
+                          {
+                            harqDlInfo.m_harqStatus.at (tbId.m_layer) = DlInfoListElement_s::NACK;
+                            NS_LOG_DEBUG (this << " RNTI " << tbId.m_rnti << " harqId " << (uint16_t)(*itTb).second.harqProcessId << " layer " <<(uint16_t)tbId.m_layer << " send DL-HARQ-NACK");
+                            m_harqPhyModule->UpdateDlHarqProcessStatus ((*itTb).second.harqProcessId, tbId.m_layer, (*itTb).second.mi, (*itTb).second.size, EffectiveCodingRate [(*itTb).second.mcs] * (*itTb).second.size);
+                          }
+                        else
+                          {
+                            
+                            harqDlInfo.m_harqStatus.at (tbId.m_layer) = DlInfoListElement_s::ACK;
+                            NS_LOG_DEBUG (this << " RNTI " << tbId.m_rnti << " harqId " << (uint16_t)(*itTb).second.harqProcessId << " layer " <<(uint16_t)tbId.m_layer << " size " << (*itTb).second.size << " send DL-HARQ-ACK");
+                            m_harqPhyModule->ResetDlHarqProcessStatus ((*itTb).second.harqProcessId);
+                          }
+                        harqDlInfoMap.insert (std::pair <uint16_t, DlInfoListElement_s> (tbId.m_rnti, harqDlInfo));
+                      }
+                    else
+                    {
+                      if ((*itTb).second.corrupt)
+                        {
+                          (*itHarq).second.m_harqStatus.at (tbId.m_layer) = DlInfoListElement_s::NACK;
+                          NS_LOG_DEBUG (this << " RNTI " << tbId.m_rnti << " harqId " << (uint16_t)(*itTb).second.harqProcessId << " layer " <<(uint16_t)tbId.m_layer << " size " << (*itHarq).second.m_harqStatus.size () << " send DL-HARQ-NACK");
+                          m_harqPhyModule->UpdateDlHarqProcessStatus ((*itTb).second.harqProcessId, tbId.m_layer, (*itTb).second.mi, (*itTb).second.size, EffectiveCodingRate [(*itTb).second.mcs] * (*itTb).second.size);
+                        }
+                      else
+                        {
+                          NS_ASSERT_MSG (tbId.m_layer < (*itHarq).second.m_harqStatus.size (), " layer " << (uint16_t)tbId.m_layer);
+                          (*itHarq).second.m_harqStatus.at (tbId.m_layer) = DlInfoListElement_s::ACK;
+                          NS_LOG_DEBUG (this << " RNTI " << tbId.m_rnti << " harqId " << (uint16_t)(*itTb).second.harqProcessId << " layer " << (uint16_t)tbId.m_layer << " size " << (*itHarq).second.m_harqStatus.size () << " send DL-HARQ-ACK");
+                          m_harqPhyModule->ResetDlHarqProcessStatus ((*itTb).second.harqProcessId);
+                        }
+                    }
+                  } // end if ((*itTb).second.downlink) HARQ
               }
           }
       }
-      
+
+  // send DL HARQ feedback to LtePhy
+  std::map <uint16_t, DlInfoListElement_s>::iterator itHarq;
+  for (itHarq = harqDlInfoMap.begin (); itHarq != harqDlInfoMap.end (); itHarq++)
+    {
+      if (!m_ltePhyDlHarqFeedbackCallback.IsNull ())
+        {
+          m_ltePhyDlHarqFeedbackCallback ((*itHarq).second);
+        }
+    }
+  // forward control messages of this frame to LtePhy
   if (!m_rxControlMessageList.empty ())
     {
       if (!m_ltePhyRxCtrlEndOkCallback.IsNull ())
@@ -851,6 +1009,7 @@
     {
       if (!m_ltePhyRxCtrlEndOkCallback.IsNull ())
         {
+          NS_LOG_DEBUG (this << " PCFICH-PDCCH Rxed OK");
           m_ltePhyRxCtrlEndOkCallback (m_rxControlMessageList);
         }
     }
@@ -858,6 +1017,7 @@
     {
       if (!m_ltePhyRxCtrlEndErrorCallback.IsNull ())
         {
+          NS_LOG_DEBUG (this << " PCFICH-PDCCH Error");
           m_ltePhyRxCtrlEndErrorCallback ();
         }
     }
@@ -899,6 +1059,7 @@
   NS_LOG_FUNCTION (this << (uint16_t) txMode);
   NS_ASSERT_MSG (txMode < m_txModeGain.size (), "TransmissionMode not available: 1.." << m_txModeGain.size ());
   m_transmissionMode = txMode;
+  m_layersNum = TransmissionModesLayers::TxMode2LayerNum (txMode);
 }
 
 
--- a/src/lte/model/lte-spectrum-phy.h	Fri Aug 31 16:49:46 2012 +0200
+++ b/src/lte/model/lte-spectrum-phy.h	Mon Oct 08 17:18:22 2012 +0200
@@ -39,6 +39,8 @@
 #include "ns3/random-variable-stream.h"
 #include <map>
 #include <ns3/ff-mac-common.h>
+#include <ns3/lte-harq-phy.h>
+#include <ns3/lte-common.h>
 
 namespace ns3 {
 
@@ -61,6 +63,9 @@
   uint16_t size;
   uint8_t mcs;
   std::vector<int> rbBitmap;
+  uint8_t harqProcessId;
+  double mi;
+  bool downlink;
   bool corrupt;
 };
 
@@ -113,6 +118,18 @@
 */
 typedef Callback< void > LtePhyRxCtrlEndErrorCallback;
 
+/**
+* This method is used by the LteSpectrumPhy to notify the PHY about
+* the status of a certain DL HARQ process
+*/
+typedef Callback< void, DlInfoListElement_s > LtePhyDlHarqFeedbackCallback;
+
+/**
+* This method is used by the LteSpectrumPhy to notify the PHY about
+* the status of a certain UL HARQ process
+*/
+typedef Callback< void, UlInfoListElement_s > LtePhyUlHarqFeedbackCallback;
+
 
 
 /**
@@ -154,6 +171,8 @@
   void StartRxData (Ptr<LteSpectrumSignalParametersDataFrame> params);
   void StartRxCtrl (Ptr<SpectrumSignalParameters> params);
 
+  void SetHarqPhyModule (Ptr<LteHarqPhy> harq);
+
   /**
    * set the Power Spectral Density of outgoing signals in W/Hz.
    *
@@ -254,6 +273,22 @@
   void SetLtePhyRxCtrlEndErrorCallback (LtePhyRxCtrlEndErrorCallback c);
 
   /**
+  * set the callback for the DL HARQ feedback as part of the 
+  * interconnections betweenthe LteSpectrumPhy and the PHY
+  *
+  * @param c the callback
+  */
+  void SetLtePhyDlHarqFeedbackCallback (LtePhyDlHarqFeedbackCallback c);
+
+  /**
+  * set the callback for the UL HARQ feedback as part of the
+  * interconnections betweenthe LteSpectrumPhy and the PHY
+  *
+  * @param c the callback
+  */
+  void SetLtePhyUlHarqFeedbackCallback (LtePhyUlHarqFeedbackCallback c);
+
+  /**
    * \brief Set the state of the phy layer
    * \param newState the state
    */
@@ -290,9 +325,13 @@
   * \param mcs the MCS of the TB
   * \param map the map of RB(s) used
   * \param layer the layer (in case of MIMO tx)
+  * \param harqId the id of the HARQ process (valid only for DL)
+  * \param miCumulated the MI cumulated (in case of HARQ retx)
+  * \param downlink true when the TB is for DL
   */
-  void AddExpectedTb (uint16_t  rnti, uint16_t size, uint8_t mcs, std::vector<int> map, uint8_t layer);
-  
+  void AddExpectedTb (uint16_t  rnti, uint16_t size, uint8_t mcs, std::vector<int> map, uint8_t layer, uint8_t harqId, double miCumulated, bool downlink);
+
+
   /** 
   * 
   * 
@@ -375,8 +414,15 @@
   bool m_ctrlErrorModelEnabled; // when true (default) the phy error model is enabled for DL ctrl frame
   
   uint8_t m_transmissionMode; // for UEs: store the transmission mode
+  uint8_t m_layersNum;
   std::vector <double> m_txModeGain; // duplicate value of LteUePhy
-  
+
+  Ptr<LteHarqPhy> m_harqPhyModule;
+  LtePhyDlHarqFeedbackCallback m_ltePhyDlHarqFeedbackCallback;
+  LtePhyUlHarqFeedbackCallback m_ltePhyUlHarqFeedbackCallback;
+
+  uint16_t errors; // DEBUG
+
 };
 
 
--- a/src/lte/model/lte-ue-mac.cc	Fri Aug 31 16:49:46 2012 +0200
+++ b/src/lte/model/lte-ue-mac.cc	Mon Oct 08 17:18:22 2012 +0200
@@ -179,10 +179,12 @@
 LteUeMac::LteUeMac ()
   :  m_bsrPeriodicity (MilliSeconds (1)), // ideal behavior
   m_bsrLast (MilliSeconds (0)),
-  m_freshUlBsr (false)
+  m_freshUlBsr (false),
+  m_harqProcessId (0)
   
 {
   NS_LOG_FUNCTION (this);
+  m_miUlHarqProcessesPacket.resize (HARQ_PERIOD);
   m_macSapProvider = new UeMemberLteMacSapProvider (this);
   m_cmacSapProvider = new UeMemberLteUeCmacSapProvider (this);
   m_uePhySapUser = new UeMemberLteUePhySapUser (this);
@@ -198,6 +200,7 @@
 LteUeMac::DoDispose ()
 {
   NS_LOG_FUNCTION (this);
+  m_miUlHarqProcessesPacket.clear ();
   delete m_macSapProvider;
   delete m_cmacSapProvider;
   delete m_uePhySapUser;
@@ -244,11 +247,9 @@
   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);
-//   Ptr<PacketBurst> pb = CreateObject<PacketBurst> ();
-//   pb->AddPacket (params.pdu);
+  // store pdu in HARQ buffer
+  m_miUlHarqProcessesPacket.at (m_harqProcessId) = params.pdu;//->Copy ();
   m_uePhySapProvider->SendMacPdu (params.pdu);
-  // Uplink not implemented yet, so we wait can wait for the PHY SAP
-  // to be defined before we implement the transmission method.
 }
 
 void
@@ -354,39 +355,51 @@
     {
       Ptr<UlDciLteControlMessage> msg2 = DynamicCast<UlDciLteControlMessage> (msg);
       UlDciListElement_s dci = msg2->GetDci ();
-      std::map <uint8_t, uint64_t>::iterator itBsr;
-      NS_ASSERT_MSG (m_ulBsrReceived.size () <=4, " Too many LCs (max is 4)");
-      uint16_t activeLcs = 0;
-      for (itBsr = m_ulBsrReceived.begin (); itBsr != m_ulBsrReceived.end (); itBsr++)
+      if (dci.m_ndi==1)
         {
-          if ((*itBsr).second > 0)
+          // New transmission -> retrieve data from RLC
+          std::map <uint8_t, uint64_t>::iterator itBsr;
+          NS_ASSERT_MSG (m_ulBsrReceived.size () <=4, " Too many LCs (max is 4)");
+          uint16_t activeLcs = 0;
+          for (itBsr = m_ulBsrReceived.begin (); itBsr != m_ulBsrReceived.end (); itBsr++)
+            {
+              if ((*itBsr).second > 0)
+                {
+                  activeLcs++;
+                }
+            }
+          if (activeLcs == 0)
             {
-              activeLcs++;
+              NS_LOG_ERROR (this << " No active flows for this UL-DCI");
+              return;
+            }
+          std::map <uint8_t, LteMacSapUser*>::iterator it;
+          NS_LOG_FUNCTION (this << " UE: UL-CQI notified TxOpportunity of " << dci.m_tbSize);
+          for (it = m_macSapUserMap.begin (); it!=m_macSapUserMap.end (); it++)
+            {
+              itBsr = m_ulBsrReceived.find ((*it).first);
+              if (itBsr!=m_ulBsrReceived.end ())
+                {
+                  NS_LOG_FUNCTION (this << "\t" << dci.m_tbSize / m_macSapUserMap.size () << " bytes to LC " << (uint16_t)(*it).first << " queue " << (*itBsr).second);
+                  (*it).second->NotifyTxOpportunity (dci.m_tbSize / activeLcs, 0, 0); // layer and HARQ ID are not used in UL
+                  if ((*itBsr).second >=  static_cast<uint64_t> (dci.m_tbSize / activeLcs))
+                    {
+                      (*itBsr).second -= dci.m_tbSize / activeLcs;
+                    }
+                  else
+                    {
+                      (*itBsr).second = 0;
+                    }
+                }
             }
         }
-      if (activeLcs == 0)
-        {
-          NS_LOG_ERROR (this << " No active flows for this UL-DCI");
-          return;
-        }
-      std::map <uint8_t, LteMacSapUser*>::iterator it;
-      NS_LOG_FUNCTION (this << " UE: UL-CQI notified TxOpportunity of " << dci.m_tbSize);
-      for (it = m_macSapUserMap.begin (); it!=m_macSapUserMap.end (); it++)
+      else
         {
-          itBsr = m_ulBsrReceived.find ((*it).first);
-          if (itBsr!=m_ulBsrReceived.end ())
-            {
-              NS_LOG_FUNCTION (this << "\t" << dci.m_tbSize / m_macSapUserMap.size () << " bytes to LC " << (uint16_t)(*it).first << " queue " << (*itBsr).second);
-              (*it).second->NotifyTxOpportunity (dci.m_tbSize / activeLcs, 0);
-              if ((*itBsr).second >=  static_cast<uint64_t> (dci.m_tbSize / activeLcs))
-                {
-                  (*itBsr).second -= dci.m_tbSize / activeLcs;
-                }
-              else
-                {
-                  (*itBsr).second = 0;
-                }
-            }
+          // HARQ retransmission -> retrieve data from HARQ buffer
+          NS_LOG_DEBUG (this << " UE MAC RETX HARQ " << (uint16_t)m_harqProcessId);
+          Ptr<Packet> pkt = m_miUlHarqProcessesPacket.at (m_harqProcessId);
+          m_uePhySapProvider->SendMacPdu (pkt);
+          
         }
 
     }
@@ -406,6 +419,7 @@
       SendReportBufferStatus ();
       m_bsrLast = Simulator::Now ();
       m_freshUlBsr = false;
+      m_harqProcessId = (m_harqProcessId + 1) % HARQ_PERIOD;
     }
 }
 
--- a/src/lte/model/lte-ue-mac.h	Fri Aug 31 16:49:46 2012 +0200
+++ b/src/lte/model/lte-ue-mac.h	Mon Oct 08 17:18:22 2012 +0200
@@ -30,7 +30,8 @@
 #include <ns3/lte-ue-cmac-sap.h>
 #include <ns3/lte-ue-phy-sap.h>
 #include <ns3/nstime.h>
-
+#include <vector>
+#include <ns3/packet.h>
 
 namespace ns3 {
 
@@ -107,6 +108,9 @@
   
   bool m_freshUlBsr; // true when a BSR has been received in the last TTI
 
+  uint8_t m_harqProcessId;
+  std::vector < Ptr<Packet> > m_miUlHarqProcessesPacket; // Packets under trasmission of the UL HARQ processes
+
 
   uint16_t m_rnti;
 
--- a/src/lte/model/lte-ue-phy.cc	Fri Aug 31 16:49:46 2012 +0200
+++ b/src/lte/model/lte-ue-phy.cc	Mon Oct 08 17:18:22 2012 +0200
@@ -539,7 +539,7 @@
           for (int k = 0; k < GetRbgSize (); k++)
           {
             dlRb.push_back ((i * GetRbgSize ()) + k);
-            //NS_LOG_DEBUG(this << "DL-DCI allocated PRB " << (i*GetRbgSize()) + k);
+//             NS_LOG_DEBUG(this << " RNTI " << m_rnti << " RBG " << i << " DL-DCI allocated PRB " << (i*GetRbgSize()) + k);
           }
         }
         mask = (mask << 1);
@@ -549,7 +549,13 @@
       NS_LOG_DEBUG (this << " UE " << m_rnti << " DL-DCI " << dci.m_rnti << " bitmap "  << dci.m_rbBitmap);
       for (uint8_t i = 0; i < dci.m_tbsSize.size (); i++)
       {
-        m_downlinkSpectrumPhy->AddExpectedTb (dci.m_rnti, dci.m_tbsSize.at (i), dci.m_mcs.at (i), dlRb, i);
+        double miCumulated = 0.0;
+        if (dci.m_ndi.at (i)!=0)
+          {
+            // TODO : retrieve MI info on retransmissions
+            miCumulated = 0.0;
+          }
+        m_downlinkSpectrumPhy->AddExpectedTb (dci.m_rnti, dci.m_tbsSize.at (i), dci.m_mcs.at (i), dlRb, i, dci.m_harqProcess, miCumulated, true /* DL */);
       }
       
       SetSubChannelsForReception (dlRb);
@@ -633,11 +639,11 @@
 
   std::list<Ptr<LteControlMessage> > ctrlMsg = GetControlMessages ();
   // send packets in queue
+  NS_LOG_LOGIC (this << " UE - start TX PUSCH + PUCCH");
   // send the current burts of packets
   Ptr<PacketBurst> pb = GetPacketBurst ();
   if (pb)
     {
-      NS_LOG_LOGIC (this << " UE - start TX PUSCH + PUCCH");
       m_uplinkSpectrumPhy->StartTxDataFrame (pb, ctrlMsg, UL_DATA_DURATION);
     }
   else
@@ -835,4 +841,22 @@
 }
 
 
+void
+LteUePhy::ReceiveLteDlHarqFeedback (DlInfoListElement_s m)
+{
+  NS_LOG_FUNCTION (this);
+  // generate feedback to eNB and send it through ideal PUCCH
+  Ptr<DlHarqFeedbackLteControlMessage> msg = Create<DlHarqFeedbackLteControlMessage> ();
+  msg->SetDlHarqFeedback (m);
+  SetControlMessages (msg);
+}
+
+void
+LteUePhy::SetHarqPhyModule (Ptr<LteHarqPhy> harq)
+{
+  m_harqPhyModule = harq;
+}
+
+
+
 } // namespace ns3
--- a/src/lte/model/lte-ue-phy.h	Fri Aug 31 16:49:46 2012 +0200
+++ b/src/lte/model/lte-ue-phy.h	Mon Oct 08 17:18:22 2012 +0200
@@ -39,6 +39,7 @@
 class PacketBurst;
 class LteNetDevice;
 class LteEnbPhy;
+class LteHarqPhy;
 
 /**
  * \ingroup lte
@@ -196,7 +197,17 @@
   */
   void SendSrs ();
   
-  
+    /**
+  * \brief PhySpectrum generated a new DL HARQ feedback
+  */
+  virtual void ReceiveLteDlHarqFeedback (DlInfoListElement_s mes);
+
+  /**
+  * \brief Set the HARQ PHY module
+  */
+  void SetHarqPhyModule (Ptr<LteHarqPhy> harq);
+
+
 
 
 private:
@@ -254,6 +265,8 @@
   uint16_t m_srsPeriodicity;
   uint16_t m_srsCounter;
 
+  Ptr<LteHarqPhy> m_harqPhyModule;
+
 };
 
 
--- a/src/lte/model/pf-ff-mac-scheduler.cc	Fri Aug 31 16:49:46 2012 +0200
+++ b/src/lte/model/pf-ff-mac-scheduler.cc	Mon Oct 08 17:18:22 2012 +0200
@@ -29,6 +29,7 @@
 #include <ns3/lte-amc.h>
 #include <ns3/pf-ff-mac-scheduler.h>
 #include <ns3/lte-vendor-specific-parameters.h>
+#include <ns3/boolean.h>
 
 NS_LOG_COMPONENT_DEFINE ("PfFfMacScheduler");
 
@@ -247,6 +248,11 @@
                    UintegerValue (1000),
                    MakeUintegerAccessor (&PfFfMacScheduler::m_cqiTimersThreshold),
                    MakeUintegerChecker<uint32_t> ())
+    .AddAttribute ("HarqEnabled",
+                  "Activate/Deactivate the HARQ [by default is active].",
+                  BooleanValue (true),
+                  MakeBooleanAccessor (&PfFfMacScheduler::m_harqOn),
+                  MakeBooleanChecker ())
     ;
   return tid;
 }
@@ -564,7 +570,6 @@
       newEl.m_rnti = (*itMap).first;
       // create the DlDciListElement_s
       DlDciListElement_s newDci;
-      std::vector <struct RlcPduListElement_s> newRlcPduLe;
       newDci.m_rnti = (*itMap).first;
 
       uint16_t lcActives = LcActivePerFlow ((*itMap).first);
@@ -649,6 +654,7 @@
               || ((*itBufReq).second.m_rlcRetransmissionQueueSize > 0)
               || ((*itBufReq).second.m_rlcStatusPduSize > 0) ))
             {
+              std::vector <struct RlcPduListElement_s> newRlcPduLe;
               for (uint8_t j = 0; j < nLayer; j++)
                 {
                   RlcPduListElement_s newRlcEl;
@@ -658,21 +664,24 @@
                   newRlcPduLe.push_back (newRlcEl);
                   UpdateDlRlcBufferInfo (newDci.m_rnti, newRlcEl.m_logicalChannelIdentity, newRlcEl.m_size);
                 }
+              newEl.m_rlcPduList.push_back (newRlcPduLe);
             }
           if ((*itBufReq).first.m_rnti > (*itMap).first)
             {
               break;
             }
         }
-      newDci.m_ndi.push_back (1); // TBD (new data indicator)
-      newDci.m_rv.push_back (0); // TBD (redundancy version)
+      for (uint8_t j = 0; j < nLayer; j++)
+        {
+          newDci.m_ndi.push_back (1); // TBD (new data indicator)
+          newDci.m_rv.push_back (0); // TBD (redundancy version)
+        }
+      newDci.m_harqProcess = 0; // NO HARQ
 
       newEl.m_dci = newDci;
       // ...more parameters -> ingored in this version
 
-      newEl.m_rlcPduList.push_back (newRlcPduLe);
       ret.m_buildDataList.push_back (newEl);
-
       // update UE stats
       std::map <uint16_t, pfsFlowPerf_t>::iterator it;
       it = m_flowStatsDl.find ((*itMap).first);
--- a/src/lte/model/pf-ff-mac-scheduler.h	Fri Aug 31 16:49:46 2012 +0200
+++ b/src/lte/model/pf-ff-mac-scheduler.h	Mon Oct 08 17:18:22 2012 +0200
@@ -218,6 +218,13 @@
   uint32_t m_cqiTimersThreshold; // # of TTIs for which a CQI canbe considered valid
 
   std::map <uint16_t,uint8_t> m_uesTxMode; // txMode of the UEs
+  
+  // HARQ attributes
+  /**
+  * m_harqOn when false inhibit te HARQ mechanisms (by default active)
+  */
+  bool m_harqOn;
+  
 };
 
 } // namespace ns3
--- a/src/lte/model/rr-ff-mac-scheduler.cc	Fri Aug 31 16:49:46 2012 +0200
+++ b/src/lte/model/rr-ff-mac-scheduler.cc	Mon Oct 08 17:18:22 2012 +0200
@@ -24,12 +24,14 @@
 
 #include <ns3/log.h>
 #include <ns3/pointer.h>
+#include <set>
 
 #include <ns3/lte-amc.h>
 #include <ns3/rr-ff-mac-scheduler.h>
 #include <ns3/simulator.h>
 #include <ns3/lte-common.h>
 #include <ns3/lte-vendor-specific-parameters.h>
+#include <ns3/boolean.h>
 
 NS_LOG_COMPONENT_DEFINE ("RrFfMacScheduler");
 
@@ -234,6 +236,12 @@
 RrFfMacScheduler::DoDispose ()
 {
   NS_LOG_FUNCTION (this);
+  m_dlHarqProcessesDciBuffer.clear ();
+  m_dlHarqProcessesRlcPduListBuffer.clear ();
+  m_dlInfoListBuffered.clear ();
+  m_ulHarqCurrentProcessId.clear ();
+  m_ulHarqProcessesStatus.clear ();
+  m_ulHarqProcessesDciBuffer.clear ();
   delete m_cschedSapProvider;
   delete m_schedSapProvider;
 }
@@ -249,6 +257,11 @@
                    UintegerValue (1000),
                    MakeUintegerAccessor (&RrFfMacScheduler::m_cqiTimersThreshold),
                    MakeUintegerChecker<uint32_t> ())
+    .AddAttribute ("HarqEnabled",
+                   "Activate/Deactivate the HARQ [by default is active].",
+                   BooleanValue (true),
+                   MakeBooleanAccessor (&RrFfMacScheduler::m_harqOn),
+                   MakeBooleanChecker ())
     ;
   return tid;
 }
@@ -299,6 +312,26 @@
   if (it==m_uesTxMode.end ())
     {
       m_uesTxMode.insert (std::pair <uint16_t, double> (params.m_rnti, params.m_transmissionMode));
+      // generate HARQ buffers
+      m_dlHarqCurrentProcessId.insert (std::pair <uint16_t,uint8_t > (params.m_rnti, 0));
+      DlHarqProcessesStatus_t dlHarqPrcStatus;
+      dlHarqPrcStatus.resize (8,0);
+      m_dlHarqProcessesStatus.insert (std::pair <uint16_t, DlHarqProcessesStatus_t> (params.m_rnti, dlHarqPrcStatus));
+      DlHarqProcessesDciBuffer_t dlHarqdci;
+      dlHarqdci.resize (8);
+      m_dlHarqProcessesDciBuffer.insert (std::pair <uint16_t, DlHarqProcessesDciBuffer_t> (params.m_rnti, dlHarqdci));
+      DlHarqRlcPduListBuffer_t dlHarqRlcPdu;
+      dlHarqRlcPdu.resize (2);
+      dlHarqRlcPdu.at (0).resize (8);
+      dlHarqRlcPdu.at (1).resize (8);
+      m_dlHarqProcessesRlcPduListBuffer.insert (std::pair <uint16_t, DlHarqRlcPduListBuffer_t> (params.m_rnti, dlHarqRlcPdu));
+      m_ulHarqCurrentProcessId.insert (std::pair <uint16_t,uint8_t > (params.m_rnti, 0));
+      UlHarqProcessesStatus_t ulHarqPrcStatus;
+      ulHarqPrcStatus.resize (8,0);
+      m_ulHarqProcessesStatus.insert (std::pair <uint16_t, UlHarqProcessesStatus_t> (params.m_rnti, ulHarqPrcStatus));
+      UlHarqProcessesDciBuffer_t ulHarqdci;
+      ulHarqdci.resize (8);
+      m_ulHarqProcessesDciBuffer.insert (std::pair <uint16_t, UlHarqProcessesDciBuffer_t> (params.m_rnti, ulHarqdci));
     }
   else
     {
@@ -402,6 +435,41 @@
 }
 
 
+uint8_t
+RrFfMacScheduler::UpdateHarqProcessId (uint16_t rnti)
+{
+  NS_LOG_FUNCTION (this << rnti);
+
+  std::map <uint16_t, uint8_t>::iterator it = m_dlHarqCurrentProcessId.find (rnti);
+  if (it==m_dlHarqCurrentProcessId.end ())
+    {
+      NS_FATAL_ERROR ("No Process Id found for this RNTI " << rnti);
+    }
+  std::map <uint16_t, DlHarqProcessesStatus_t>::iterator itStat = m_dlHarqProcessesStatus.find (rnti);
+  if (itStat==m_dlHarqProcessesStatus.end ())
+    {
+      NS_FATAL_ERROR ("No Process Id Statusfound for this RNTI " << rnti);
+    }
+  uint8_t i = (*it).second;
+  do
+  {
+    i = (i + 1) % HARQ_PROC_NUM;
+//     NS_LOG_DEBUG (this << " check i " << (uint16_t)i << " stat " << (uint16_t)(*itStat).second.at (i));
+  } while ( ((*itStat).second.at (i)!=0)&&(i!=(*it).second));
+  if ((*itStat).second.at (i)==0)
+    {
+      (*it).second = i;
+      (*itStat).second.at (i) = 1;
+    }
+  else
+    {
+      return (9); // return a not valid harq proc id
+    }
+  
+  return ((*it).second);
+}
+
+
 void
 RrFfMacScheduler::DoSchedDlTriggerReq (const struct FfMacSchedSapProvider::SchedDlTriggerReqParameters& params)
 {
@@ -409,6 +477,255 @@
   // API generated by RLC for triggering the scheduling of a DL subframe
   
   RefreshDlCqiMaps ();
+  int rbgSize = GetRbgSize (m_cschedCellConfig.m_dlBandwidth);
+  int rbgNum = m_cschedCellConfig.m_dlBandwidth / rbgSize;
+  FfMacSchedSapUser::SchedDlConfigIndParameters ret;
+
+  // Generate RBGs map
+  std::vector <bool> rbgMap;
+  uint16_t rbgAllocatedNum = 0;
+  std::set <uint16_t> rntiAllocated;
+  rbgMap.resize (m_cschedCellConfig.m_dlBandwidth/rbgSize, false);
+
+  // Process DL HARQ feedback
+  // retrieve past HARQ retx buffered
+  if (m_dlInfoListBuffered.size ()>0)
+    {
+      if (params.m_dlInfoList.size ()>0)
+        {
+          NS_LOG_DEBUG (this << " RECEIVED DL-HARQ");
+          m_dlInfoListBuffered.insert (m_dlInfoListBuffered.end (), params.m_dlInfoList.begin (), params.m_dlInfoList.end ());
+        }
+    }
+  else
+    {
+      if (params.m_dlInfoList.size ()>0)
+        {
+          m_dlInfoListBuffered = params.m_dlInfoList;
+        }
+    }
+  if (m_harqOn == false)
+    {
+      // Ignore HARQ feedbacks
+      m_dlInfoListBuffered.clear ();
+      NS_LOG_DEBUG (this << " HARQ OFF");
+    }
+  std::vector <struct DlInfoListElement_s> dlInfoListUntxed;
+  for (uint8_t i = 0; i < m_dlInfoListBuffered.size (); i++)
+    {
+      uint8_t nLayers = m_dlInfoListBuffered.at (i).m_harqStatus.size ();
+      std::vector <bool> retx;
+      NS_LOG_DEBUG (this << " Processing DLHARQ-FEEDBACK");
+      if (nLayers == 1)
+        {
+          retx.push_back (m_dlInfoListBuffered.at (i).m_harqStatus.at (0) == DlInfoListElement_s::NACK);
+          retx.push_back (false);
+        }
+      else
+        {
+          retx.push_back (m_dlInfoListBuffered.at (i).m_harqStatus.at (0) == DlInfoListElement_s::NACK);
+          retx.push_back (m_dlInfoListBuffered.at (i).m_harqStatus.at (1) == DlInfoListElement_s::NACK);
+        }
+      if (retx.at (0) || retx.at (1))
+        {
+          // retrieve HARQ process information
+          uint16_t rnti = m_dlInfoListBuffered.at (i).m_rnti;
+          uint8_t harqId = m_dlInfoListBuffered.at (i).m_harqProcessId;
+          NS_LOG_DEBUG (this << " HARQ retx RNTI " << rnti << " harqId " << (uint16_t)harqId);
+          std::map <uint16_t, DlHarqProcessesDciBuffer_t>::iterator itHarq = m_dlHarqProcessesDciBuffer.find (rnti);
+          if (itHarq==m_dlHarqProcessesDciBuffer.end ())
+            {
+              NS_FATAL_ERROR ("No info find in HARQ buffer for UE " << rnti);
+            }
+
+          DlDciListElement_s dci = (*itHarq).second.at (harqId);
+          int rv = 0;
+          if (dci.m_rv.size ()==1)
+            {
+              rv = dci.m_rv.at (0);
+            }
+            else
+            {
+              rv = (dci.m_rv.at (0) > dci.m_rv.at (1) ? dci.m_rv.at (0) : dci.m_rv.at (1));
+            }
+            
+          if (rv == 3)
+            {
+              // maximum number of retx reached -> drop process
+              NS_LOG_DEBUG ("Max number of retransmissions reached -> drop process");
+              std::map <uint16_t, DlHarqProcessesStatus_t>::iterator it = m_dlHarqProcessesStatus.find (rnti);
+              if (it==m_dlHarqProcessesStatus.end ())
+              {
+                NS_FATAL_ERROR ("No info find in HARQ buffer for UE " << m_dlInfoListBuffered.at (i).m_rnti);
+              }
+              (*it).second.at (harqId) = 0;
+              std::map <uint16_t, DlHarqRlcPduListBuffer_t>::iterator itRlcPdu =  m_dlHarqProcessesRlcPduListBuffer.find (rnti);
+              if (itRlcPdu==m_dlHarqProcessesRlcPduListBuffer.end ())
+              {
+                NS_FATAL_ERROR ("Unable to find RlcPdcList in HARQ buffer for RNTI " << m_dlInfoListBuffered.at (i).m_rnti);
+              }
+              for (uint16_t k = 0; k < (*itRlcPdu).second.size (); k++)
+              {
+                (*itRlcPdu).second.at (k).at (harqId).clear ();
+              }
+              continue;
+            }
+          // check the feasibility of retransmitting on the same RBGs
+          // translate the DCI to Spectrum framework
+          std::vector <int> dciRbg;
+          uint32_t mask = 0x1;
+          NS_LOG_DEBUG ("Original RBGs " << dci.m_rbBitmap << " rnti " << dci.m_rnti);
+          for (int j = 0; j < 32; j++)
+            {
+              if (((dci.m_rbBitmap & mask) >> j) == 1)
+                {
+                  dciRbg.push_back (j);
+                  NS_LOG_DEBUG ("\t"<<j);
+//                   for (int k = 0; k < rbgSize; k++)
+//                     {
+//                       dciRb.push_back ((j * rbgSize) + k);
+//                       //NS_LOG_DEBUG(this << "DL-DCI allocated PRB " << (i*GetRbgSize()) + k);
+//                     }
+                }
+              mask = (mask << 1);
+            }
+          bool free = true;
+          for (uint8_t j = 0; j < dciRbg.size (); j++)
+            {
+              if (rbgMap.at (dciRbg.at (j))==true)
+                {
+                  free = false;
+                  break;
+                }
+            }
+          if (free)
+            {
+              // use the same RBGs for the retx
+              // reserve RBGs
+              for (uint8_t j = 0; j < dciRbg.size (); j++)
+                {
+                  rbgMap.at (dciRbg.at (j)) = true;
+                  NS_LOG_DEBUG ("RBG " << dciRbg.at (j) << " assigned");
+                  rbgAllocatedNum++;
+                }
+
+              NS_LOG_DEBUG (this << " Send retx in the same RBGs");
+            }
+          else
+            {
+              // find RBGs for sending HARQ retx
+              uint8_t j = 0;
+              uint8_t rbgId = (dciRbg.at (dciRbg.size () - 1) + 1) % rbgNum;
+              uint8_t startRbg = dciRbg.at (dciRbg.size () - 1) + 1;
+              std::vector <bool> rbgMapCopy = rbgMap;
+              while ((j < dciRbg.size ())&&(startRbg!=rbgId))
+                {
+                  if (rbgMapCopy.at (rbgId) == false)
+                    {
+                      rbgMapCopy.at (rbgId) = true;
+                      dciRbg.at (j) = rbgId;
+                      j++;
+                    }
+                  rbgId++;
+                }
+              if (j == dciRbg.size ())
+                {
+                  // find new RBGs -> update DCI map
+                  uint32_t rbgMask = 0;
+                  for (uint16_t k = 0; k < dciRbg.size (); k++)
+                    {
+                      rbgMask = rbgMask + (0x1 << dciRbg.at (k));
+            //           NS_LOG_DEBUG (this << " Allocated PRB " << (*itMap).second.at (k));
+                      rbgAllocatedNum++;
+                    }
+                  dci.m_rbBitmap = rbgMask;
+                  rbgMap = rbgMapCopy;
+                  NS_LOG_DEBUG (this << " Move retx in RBGs " << dciRbg.size ());
+                }
+              else
+                {
+                  // HARQ retx cannot be performed on this TTI -> store it
+                  dlInfoListUntxed.push_back (params.m_dlInfoList.at (i));
+                  NS_LOG_DEBUG (this << " No resource for this retx -> buffer it");
+                }
+            }
+          // retrieve RLC PDU list for retx TBsize and update DCI
+          BuildDataListElement_s newEl;
+          std::map <uint16_t, DlHarqRlcPduListBuffer_t>::iterator itRlcPdu =  m_dlHarqProcessesRlcPduListBuffer.find (rnti);
+          if (itRlcPdu==m_dlHarqProcessesRlcPduListBuffer.end ())
+            {
+              NS_FATAL_ERROR ("Unable to find RlcPdcList in HARQ buffer for RNTI " << rnti);
+            }
+          for (uint8_t j = 0; j < nLayers; j++)
+            {
+              if (retx.at (j))
+                {
+                  if (j >= dci.m_ndi.size ())
+                    {
+                      // for avoiding errors in MIMO transient phases
+                      dci.m_ndi.push_back (0);
+                      dci.m_rv.push_back (0);
+                      dci.m_mcs.push_back (0);
+                      dci.m_tbsSize.push_back (0);
+                      NS_LOG_DEBUG (this << " layer " << (uint16_t)j << " no txed (MIMO transition)");
+                      
+                    }
+                  else
+                    {
+                      dci.m_ndi.at (j) = 0;
+                      dci.m_rv.at (j) ++;
+                      (*itHarq).second.at (harqId).m_rv.at (j)++;
+                      NS_LOG_DEBUG (this << " layer " << (uint16_t)j << " RV " << (uint16_t)dci.m_rv.at (j));
+                      newEl.m_rlcPduList.push_back ((*itRlcPdu).second.at (j).at (dci.m_harqProcess));
+                    }
+//                   NS_ASSERT_MSG ((*itRlcPdu).second.size () >dci.m_harqProcess, " size " <<  (*itRlcPdu).second.size ());
+//                   NS_ASSERT ((*itRlcPdu).second.at (j).size () > dci.m_harqProcess);
+//                   newEl.m_rlcPduList.push_back ((*itRlcPdu).second.at (j).at (dci.m_harqProcess));
+//                   NS_LOG_DEBUG (this << " size 1 " << (*itRlcPdu).second.size () << " size 2 " << (*itRlcPdu).second.at (j).size ());
+//                   NS_ASSERT_MSG ((*itRlcPdu).second.at (j).at (dci.m_harqProcess).size () <= 1, " MIMO ERRROR 1");
+//                   for (uint16_t k = 0; k < (*itRlcPdu).second.at (j).at (dci.m_harqProcess).size (); k++)
+//                     {
+//                       NS_LOG_DEBUG (this << " k " << k);
+//                     }
+                }
+              else
+                {
+                  // empty TB of layer j
+                  dci.m_ndi.at (j) = 0;
+                  dci.m_rv.at (j) = 0;
+                  dci.m_mcs.at (j) = 0;
+                  dci.m_tbsSize.at (j) = 0;
+                  NS_LOG_DEBUG (this << " layer " << (uint16_t)j << " no retx");
+                }
+            }
+          newEl.m_rnti = rnti;
+          newEl.m_dci = dci;
+          ret.m_buildDataList.push_back (newEl);
+          rntiAllocated.insert (rnti);
+        }
+      else
+        {
+          // update HARQ process status
+          NS_LOG_DEBUG (this << " RR HARQ ACK UE " << m_dlInfoListBuffered.at (i).m_rnti);
+          std::map <uint16_t, DlHarqProcessesStatus_t>::iterator it = m_dlHarqProcessesStatus.find (m_dlInfoListBuffered.at (i).m_rnti);
+          if (it==m_dlHarqProcessesStatus.end ())
+            {
+              NS_FATAL_ERROR ("No info find in HARQ buffer for UE " << m_dlInfoListBuffered.at (i).m_rnti);
+            }
+          (*it).second.at (m_dlInfoListBuffered.at (i).m_harqProcessId) = 0;
+          std::map <uint16_t, DlHarqRlcPduListBuffer_t>::iterator itRlcPdu =  m_dlHarqProcessesRlcPduListBuffer.find (m_dlInfoListBuffered.at (i).m_rnti);
+          if (itRlcPdu==m_dlHarqProcessesRlcPduListBuffer.end ())
+            {
+              NS_FATAL_ERROR ("Unable to find RlcPdcList in HARQ buffer for RNTI " << m_dlInfoListBuffered.at (i).m_rnti);
+            }
+           for (uint16_t k = 0; k < (*itRlcPdu).second.size (); k++)
+             {
+               (*itRlcPdu).second.at (k).at (m_dlInfoListBuffered.at (i).m_harqProcessId).clear ();
+             }
+        }
+      }
+  m_dlInfoListBuffered.clear ();
+  m_dlInfoListBuffered = dlInfoListUntxed;
 
   // Get the actual active flows (queue!=0)
   std::list<FfMacSchedSapProvider::SchedDlRlcBufferReqParameters>::iterator it;
@@ -421,9 +738,11 @@
     {
 //       NS_LOG_INFO (this << " User " << (*it).m_rnti << " LC " << (uint16_t)(*it).m_logicalChannelIdentity);
       // remove old entries of this UE-LC
-      if ( ((*it).m_rlcTransmissionQueueSize > 0)
+      std::set <uint16_t>::iterator itRnti = rntiAllocated.find ((*it).m_rnti);
+      if ( (((*it).m_rlcTransmissionQueueSize > 0)
            || ((*it).m_rlcRetransmissionQueueSize > 0)
-           || ((*it).m_rlcStatusPduSize > 0) )
+           || ((*it).m_rlcStatusPduSize > 0))
+           && (itRnti == rntiAllocated.end ()) ) // UE must not be allocated for HARQ retx
         {
           std::map <uint16_t,uint8_t>::iterator itCqi = m_p10CqiRxed.find ((*it).m_rnti);
           uint8_t cqi = 0;
@@ -456,23 +775,24 @@
     
   if (nflows == 0)
     {
-      return;
+      if (ret.m_buildDataList.size ()>0)
+        {
+          m_schedSapUser->SchedDlConfigInd (ret);
+        }
+    return;
     }
   // Divide the resource equally among the active users according to
   // Resource allocation type 0 (see sec 7.1.6.1 of 36.213)
-  int rbgSize = GetRbgSize (m_cschedCellConfig.m_dlBandwidth);
-  int rbgNum = m_cschedCellConfig.m_dlBandwidth / rbgSize;
-  int rbgPerTb = rbgNum / nTbs;
+  
+  int rbgPerTb = (rbgNum - rbgAllocatedNum) / nTbs;
   if (rbgPerTb == 0)
     {
       rbgPerTb = 1;                // at least 1 rbg per TB (till available resource)
     }
   int rbgAllocated = 0;
 
-  FfMacSchedSapUser::SchedDlConfigIndParameters ret;
-  // round robin assignment to all UE-LC registered starting from the subsequent of the one
-  // served last scheduling trigger
-  //NS_LOG_DEBUG (this << " next to be served " << m_nextRntiDl << " nflows " << nflows);
+  // round robin assignment to all UEs registered starting from the subsequent of the one
+  // served last scheduling trigger event
   if (m_nextRntiDl != 0)
     {
       for (it = m_rlcBufferReq.begin (); it != m_rlcBufferReq.end (); it++)
@@ -497,9 +817,10 @@
   do
     {
       itLcRnti = lcActivesPerRnti.find ((*it).m_rnti);
-      if (itLcRnti == lcActivesPerRnti.end ())
+      std::set <uint16_t>::iterator itRnti = rntiAllocated.find ((*it).m_rnti);
+      if ((itLcRnti == lcActivesPerRnti.end ())||(itRnti!=rntiAllocated.end ()))
         {
-          // skip this entry
+          // skip this entry (no active queue or yet allocated for HARQ)
           it++;
           if (it == m_rlcBufferReq.end ())
             {
@@ -514,6 +835,7 @@
           NS_FATAL_ERROR ("No Transmission Mode info on user " << (*it).m_rnti);
         }
       int nLayer = TransmissionModesLayers::TxMode2LayerNum ((*itTxMode).second);
+      NS_LOG_DEBUG (this << " NLAYERS " << nLayer);
       int lcNum = (*itLcRnti).second;
       // create new BuildDataListElement_s for this RNTI
       BuildDataListElement_s newEl;
@@ -521,6 +843,26 @@
       // create the DlDciListElement_s
       DlDciListElement_s newDci;
       newDci.m_rnti = (*it).m_rnti;
+      if (m_harqOn == true)
+        {
+          newDci.m_harqProcess = UpdateHarqProcessId ((*it).m_rnti);
+          if (newDci.m_harqProcess>8)
+            {
+              // not valid HARQ ID -> no more HARQ proc available, stop allocation for this user
+              it++;
+              if (it == m_rlcBufferReq.end ())
+                {
+                  // restart from the first
+                  it = m_rlcBufferReq.begin ();
+                }
+              NS_LOG_DEBUG (this << " All HARQ process busy, drop UE allocation");
+              continue;
+            }
+        }
+      else
+        {
+          newDci.m_harqProcess = 0;
+        }
       newDci.m_resAlloc = 0;
       newDci.m_rbBitmap = 0;
       std::map <uint16_t,uint8_t>::iterator itCqi = m_p10CqiRxed.find (newEl.m_rnti);
@@ -535,15 +877,11 @@
               newDci.m_mcs.push_back ( m_amc->GetMcsFromCqi ((*itCqi).second) );
             }
         }
-      // group the LCs of this RNTI
-      std::vector <struct RlcPduListElement_s> newRlcPduLe;
-//       int totRbg = lcNum * rbgPerFlow;
-//       totRbg = rbgNum / nTbs;
       int tbSize = (m_amc->GetTbSizeFromMcs (newDci.m_mcs.at (0), rbgPerTb * rbgSize) / 8);
-      NS_LOG_DEBUG (this << " DL - Allocate user " << newEl.m_rnti << " LCs " << (uint16_t)(*itLcRnti).second << " bytes " << tbSize << " PRBs " <<  rbgAllocated * rbgSize << "..." << (rbgAllocated* rbgSize) + (rbgPerTb * rbgSize) - 1 << " mcs " << (uint16_t) newDci.m_mcs.at (0) << " layers " << nLayer);
       uint16_t rlcPduSize = tbSize / lcNum;
       for (int i = 0; i < lcNum ; i++)
         {
+          std::vector <struct RlcPduListElement_s> newRlcPduLe;
           for (uint8_t j = 0; j < nLayer; j++)
             {
               RlcPduListElement_s newRlcEl;
@@ -552,35 +890,61 @@
               newRlcEl.m_size = rlcPduSize;
               UpdateDlRlcBufferInfo ((*it).m_rnti, newRlcEl.m_logicalChannelIdentity, rlcPduSize);
               newRlcPduLe.push_back (newRlcEl);
+              // store RLC PDU list for HARQ
+              std::map <uint16_t, DlHarqRlcPduListBuffer_t>::iterator itRlcPdu =  m_dlHarqProcessesRlcPduListBuffer.find ((*it).m_rnti);
+              if (itRlcPdu==m_dlHarqProcessesRlcPduListBuffer.end ())
+                {
+                  NS_FATAL_ERROR ("Unable to find RlcPdcList in HARQ buffer for RNTI " << (*it).m_rnti);
+                }
+//                 NS_ASSERT_MSG ((*itRlcPdu).second.at (j).at (newDci.m_harqProcess).size () <= 1, " MIMO ERR 4" <<(*itRlcPdu).second.at (j).at (newDci.m_harqProcess).size () );
+              (*itRlcPdu).second.at (j).at (newDci.m_harqProcess).push_back (newRlcEl);
+//               NS_ASSERT_MSG ((*itRlcPdu).second.at (j).at (newDci.m_harqProcess).size () <= 1, " MIMO ERR 3" <<(*itRlcPdu).second.at (j).at (newDci.m_harqProcess).size () );
+
             }
-          it++;
-          if (it == m_rlcBufferReq.end ())
-            {
-              // restart from the first
-              it = m_rlcBufferReq.begin ();
-            }
+            newEl.m_rlcPduList.push_back (newRlcPduLe);
+            it++;
+            if (it == m_rlcBufferReq.end ())
+              {
+                // restart from the first
+                it = m_rlcBufferReq.begin ();
+              }      
         }
       uint32_t rbgMask = 0;
-      for (int i = 0; i < rbgPerTb; i++)
+      uint16_t i = 0;
+      NS_LOG_DEBUG (this << " DL - Allocate user " << newEl.m_rnti << " LCs " << (uint16_t)(*itLcRnti).second << " bytes " << tbSize << " mcs " << (uint16_t) newDci.m_mcs.at (0) << " harqId " << (uint16_t)newDci.m_harqProcess <<  " layers " << nLayer);
+      NS_LOG_DEBUG ("RBG:");
+      while (i < rbgPerTb)
         {
-          rbgMask = rbgMask + (0x1 << rbgAllocated);
-          rbgAllocated++;
+          if (rbgMap.at (rbgAllocated)==false)
+            {
+              rbgMask = rbgMask + (0x1 << rbgAllocated);
+              NS_LOG_DEBUG ("\t " << rbgAllocated);
+              i++;
+              rbgMap.at (rbgAllocated) = true;
+            }
+         rbgAllocated++; 
         }
       newDci.m_rbBitmap = rbgMask; // (32 bit bitmap see 7.1.6 of 36.213)
 
       for (int i = 0; i < nLayer; i++)
         {
           newDci.m_tbsSize.push_back (tbSize);
-          newDci.m_ndi.push_back (1); // TBD (new data indicator)
-          newDci.m_rv.push_back (0); // TBD (redundancy version)
+          newDci.m_ndi.push_back (1);
+          newDci.m_rv.push_back (0);
         }
       newEl.m_dci = newDci;
+      if (m_harqOn == true)
+        {
+          // store DCI for HARQ
+          std::map <uint16_t, DlHarqProcessesDciBuffer_t>::iterator itDci = m_dlHarqProcessesDciBuffer.find (newEl.m_rnti);
+          if (itDci==m_dlHarqProcessesDciBuffer.end ())
+            {
+              NS_FATAL_ERROR ("Unable to find RNTI entry in DCI HARQ buffer for RNTI " << (*it).m_rnti);
+            }
+          (*itDci).second.at (newDci.m_harqProcess) = newDci;
+        }
       // ...more parameters -> ignored in this version
 
-
-
-
-      newEl.m_rlcPduList.push_back (newRlcPduLe);
       ret.m_buildDataList.push_back (newEl);
       if (rbgAllocated == rbgNum)
         {
@@ -657,14 +1021,93 @@
 
 
   RefreshUlCqiMaps ();
+
+  // Generate RBs map
+  FfMacSchedSapUser::SchedUlConfigIndParameters ret;
+  std::vector <bool> rbMap;
+  uint16_t rbAllocatedNum = 0;
+  std::set <uint16_t> rntiAllocated;
+  std::vector <uint16_t> rbgAllocationMap;
+  rbgAllocationMap.resize (m_cschedCellConfig.m_ulBandwidth, 0);
+
+  rbMap.resize (m_cschedCellConfig.m_ulBandwidth, false);
+  
+//   Process UL HARQ feedback
+//   update UL HARQ proc id
+  std::map <uint16_t, uint8_t>::iterator itProcId;
+  for (itProcId = m_ulHarqCurrentProcessId.begin (); itProcId!= m_ulHarqCurrentProcessId.end (); itProcId++)
+    {
+      (*itProcId).second = ((*itProcId).second + 1) % HARQ_PROC_NUM;
+    }
+  for (uint8_t i = 0; i < params.m_ulInfoList.size (); i++)
+    {
+      if (params.m_ulInfoList.at (i).m_receptionStatus==UlInfoListElement_s::NotOk)
+        {
+          // retx correspondent block: retrieve the UL-DCI
+          uint16_t rnti = params.m_ulInfoList.at (i).m_rnti;
+          uint8_t harqId = (uint8_t)((*itProcId).second - HARQ_PERIOD) % HARQ_PROC_NUM;
+          NS_LOG_DEBUG (this << " UL-HARQ retx RNTI " << rnti << " harqId " << (uint16_t)harqId);
+          std::map <uint16_t, UlHarqProcessesDciBuffer_t>::iterator itHarq = m_ulHarqProcessesDciBuffer.find (rnti);
+          if (itHarq==m_ulHarqProcessesDciBuffer.end ())
+            {
+              NS_FATAL_ERROR ("No info find in UL-HARQ buffer for UE " << rnti);
+            }
+          itProcId = m_ulHarqCurrentProcessId.find (rnti);
+          if (itProcId==m_ulHarqCurrentProcessId.end ())
+            {
+              NS_FATAL_ERROR ("No info find in HARQ buffer for UE " << rnti);
+            }
+          UlDciListElement_s dci = (*itHarq).second.at (harqId);
+          std::map <uint16_t, UlHarqProcessesStatus_t>::iterator itStat = m_ulHarqProcessesStatus.find (rnti);
+          if (itStat==m_ulHarqProcessesStatus.end ())
+            {
+              NS_FATAL_ERROR ("No info find in HARQ buffer for UE " << rnti);
+            }
+          if ((*itStat).second.at (harqId)>3)
+            {
+              NS_LOG_DEBUG ("Max number of retransmissions reached (UL)-> drop process");
+              continue;
+            }
+          bool free = true;
+          for (int j = dci.m_rbStart; j < dci.m_rbStart + dci.m_rbLen; j++)
+            {
+              if (rbMap.at (j)==true)
+                {
+                  free = false;
+                  NS_LOG_DEBUG (this << " BUSY " << j);
+                }
+            }
+          if (free)
+            {
+              // retx on the same RBs
+              for (int j = dci.m_rbStart; j < dci.m_rbStart + dci.m_rbLen; j++)
+                {
+                  rbMap.at (j) = true;
+                  rbgAllocationMap.at (j) = dci.m_rnti;
+                  NS_LOG_DEBUG ("\t" << j);
+                  rbAllocatedNum++;
+                }
+              NS_LOG_DEBUG (this << " Send retx in the same RBGs " << (uint16_t)dci.m_rbStart << " to " << dci.m_rbStart + dci.m_rbLen);
+            }
+          else
+            {
+              NS_FATAL_ERROR ("Cannot allocare retx for UE " << rnti);
+            }
+          dci.m_ndi = 0;
+          ret.m_dciList.push_back (dci);
+          rntiAllocated.insert (dci.m_rnti);
+
+        }
+    }
   
   std::map <uint16_t,uint32_t>::iterator it; 
   int nflows = 0;
 
   for (it = m_ceBsrRxed.begin (); it != m_ceBsrRxed.end (); it++)
     {
-      // remove old entries of this UE-LC
-      if ((*it).second > 0)
+      std::set <uint16_t>::iterator itRnti = rntiAllocated.find ((*it).first);
+      // select UEs with queues not empty and not yet allocated for HARQ
+      if (((*it).second > 0)&&(itRnti == rntiAllocated.end ()))
         {
           nflows++;
         }
@@ -676,16 +1119,15 @@
     }
 
 
-  // Divide the resource equally among the active users starting from the subsequent one served last scheduling trigger
-  int rbPerFlow = m_cschedCellConfig.m_ulBandwidth / nflows;
+  // Divide the remaining resources equally among the active users starting from the subsequent one served last scheduling trigger
+  //uint16_t rbPerFlow = (m_cschedCellConfig.m_ulBandwidth - rbAllocatedNum) / nflows;
+  uint16_t rbPerFlow = (m_cschedCellConfig.m_ulBandwidth) / (nflows + rntiAllocated.size ());
   if (rbPerFlow == 0)
     {
       rbPerFlow = 1;              // at least 1 rbg per flow (till available resource)
     }
-  int rbAllocated = 0;
-
-  FfMacSchedSapUser::SchedUlConfigIndParameters ret;
-  std::vector <uint16_t> rbgAllocationMap;
+  uint16_t rbAllocated = 0;
+  
   if (m_nextRntiUl != 0)
     {
       for (it = m_ceBsrRxed.begin (); it != m_ceBsrRxed.end (); it++)
@@ -705,8 +1147,21 @@
       it = m_ceBsrRxed.begin ();
       m_nextRntiUl = (*it).first;
     }
+  NS_LOG_DEBUG (this << " rbPerFlow " << rbPerFlow);
   do
     {
+      std::set <uint16_t>::iterator itRnti = rntiAllocated.find ((*it).first);
+      if (itRnti!=rntiAllocated.end ())
+        {
+          // UE already allocated for UL-HARQ -> skip it
+          it++;
+          if (it == m_ceBsrRxed.end ())
+            {
+              // restart from the first
+              it = m_ceBsrRxed.begin ();
+            }
+          continue;
+        }
       if (rbAllocated + rbPerFlow > m_cschedCellConfig.m_ulBandwidth)
         {
           // limit to physical resources last resource assignment
@@ -715,8 +1170,47 @@
       
       UlDciListElement_s uldci;
       uldci.m_rnti = (*it).first;
-      uldci.m_rbStart = rbAllocated;
       uldci.m_rbLen = rbPerFlow;
+      bool allocated = false;
+      while ((!allocated)&&(rbAllocated<m_cschedCellConfig.m_ulBandwidth))
+        {
+          // check availability
+          bool free = true;
+          for (uint16_t j = rbAllocated; j < rbAllocated + rbPerFlow; j++)
+            {
+              if (rbMap.at (j) == true)
+                {
+                  free = false;
+                  break;
+                }
+            }
+          if (free)
+            {
+              uldci.m_rbStart = rbAllocated;
+
+              for (uint16_t j = rbAllocated; j < rbAllocated + rbPerFlow; j++)
+                {
+                  rbMap.at (j) = false;
+                  // store info on allocation for managing ul-cqi interpretation
+                  rbgAllocationMap.at (j) = (*it).first;
+                  NS_LOG_DEBUG ("\t " << j);
+                }
+              rbAllocated += rbPerFlow;
+              allocated = true;
+              break;
+            }
+          rbAllocated++;
+        }
+      if (!allocated)
+        {
+          // unable to allocate new resource: finish scheduling
+          if (ret.m_dciList.size ()>0)
+            {
+              m_schedSapUser->SchedUlConfigInd (ret);
+            }
+          m_allocationMaps.insert (std::pair <uint16_t, std::vector <uint16_t> > (params.m_sfnSf, rbgAllocationMap));
+          return;
+        }
       std::map <uint16_t, std::vector <double> >::iterator itCqi = m_ueCqi.find ((*it).first);
       int cqi = 0;
       if (itCqi == m_ueCqi.end ())
@@ -757,16 +1251,8 @@
 //           NS_LOG_DEBUG (this << " UE " <<  (*it).first << " minsinr " << minSinr << " -> mcs " << (uint16_t)uldci.m_mcs);
 
         }
-      
-      rbAllocated += rbPerFlow;
-      // store info on allocation for managing ul-cqi interpretation
-      for (int i = 0; i < rbPerFlow; i++)
-        {
-          rbgAllocationMap.push_back ((*it).first);
-        }
-        
       uldci.m_tbSize = (m_amc->GetTbSizeFromMcs (uldci.m_mcs, rbPerFlow) / 8); // MCS 0 -> UL-AMC TBD
-      NS_LOG_DEBUG (this << " UL - UE " << (*it).first << " startPRB " << (uint32_t)uldci.m_rbStart << " nPRB " << (uint32_t)uldci.m_rbLen << " CQI " << cqi << " MCS " << (uint32_t)uldci.m_mcs << " TBsize " << uldci.m_tbSize);
+
       UpdateUlRlcBufferInfo (uldci.m_rnti, uldci.m_tbSize);
       uldci.m_ndi = 1;
       uldci.m_cceIndex = 0;
@@ -781,6 +1267,21 @@
       uldci.m_freqHopping = 0;
       uldci.m_pdcchPowerOffset = 0; // not used
       ret.m_dciList.push_back (uldci);
+      // store DCI for HARQ_PERIOD
+      itProcId = m_ulHarqCurrentProcessId.find (uldci.m_rnti);
+      if (itProcId==m_ulHarqCurrentProcessId.end ())
+        {
+          NS_FATAL_ERROR ("No info find in HARQ buffer for UE " << uldci.m_rnti);
+        }
+      uint8_t harqId = (*itProcId).second;
+      std::map <uint16_t, UlHarqProcessesDciBuffer_t>::iterator itDci = m_ulHarqProcessesDciBuffer.find (uldci.m_rnti);
+      if (itDci==m_ulHarqProcessesDciBuffer.end ())
+        {
+          NS_FATAL_ERROR ("Unable to find RNTI entry in UL DCI HARQ buffer for RNTI " << uldci.m_rnti);
+        }
+      (*itDci).second.at (harqId) = uldci;
+      NS_LOG_DEBUG (this << " UL Allocation - UE " << (*it).first << " startPRB " << (uint32_t)uldci.m_rbStart << " nPRB " << (uint32_t)uldci.m_rbLen << " CQI " << cqi << " MCS " << (uint32_t)uldci.m_mcs << " TBsize " << uldci.m_tbSize << " harqId " << (uint16_t)harqId);
+      
       it++;
       if (it == m_ceBsrRxed.end ())
         {
--- a/src/lte/model/rr-ff-mac-scheduler.h	Fri Aug 31 16:49:46 2012 +0200
+++ b/src/lte/model/rr-ff-mac-scheduler.h	Mon Oct 08 17:18:22 2012 +0200
@@ -30,10 +30,21 @@
 #include <ns3/lte-common.h>
 #include <ns3/lte-amc.h>
 
+#define HARQ_PROC_NUM 8
 
 namespace ns3 {
 
 
+typedef std::vector < uint8_t > DlHarqProcessesStatus_t;
+typedef std::vector < DlDciListElement_s > DlHarqProcessesDciBuffer_t;
+typedef std::vector < std::vector <struct RlcPduListElement_s> > RlcPduList_t; // vector of the LCs and layers per UE
+typedef std::vector < RlcPduList_t > DlHarqRlcPduListBuffer_t; // vector of the 8 HARQ processes per UE
+
+typedef std::vector < UlDciListElement_s > UlHarqProcessesDciBuffer_t;
+typedef std::vector < uint8_t > UlHarqProcessesStatus_t;
+
+
+
 
 /**
  * \ingroup ff-api
@@ -129,6 +140,14 @@
   
   void UpdateDlRlcBufferInfo (uint16_t rnti, uint8_t lcid, uint16_t size);
   void UpdateUlRlcBufferInfo (uint16_t rnti, uint16_t size);
+
+  /**
+   * \brief Update and return a new process Id for the RNTI specified
+   * 
+   * \param rnti the RNTI of the UE to be updated
+   * \return the process id  value
+   */
+  uint8_t UpdateHarqProcessId (uint16_t rnti);
   
   Ptr<LteAmc> m_amc;
 
@@ -185,6 +204,27 @@
   
   std::map <uint16_t,uint8_t> m_uesTxMode; // txMode of the UEs
 
+
+  // HARQ attributes
+  /**
+  * m_harqOn when false inhibit te HARQ mechanisms (by default active)
+  */
+  bool m_harqOn;
+  std::map <uint16_t, uint8_t> m_dlHarqCurrentProcessId;
+  //HARQ status
+  // 0: process Id available
+  // x>0: process Id equal to `x` trasmission count
+  std::map <uint16_t, DlHarqProcessesStatus_t> m_dlHarqProcessesStatus;
+  std::map <uint16_t, DlHarqProcessesDciBuffer_t> m_dlHarqProcessesDciBuffer;
+  std::map <uint16_t, DlHarqRlcPduListBuffer_t> m_dlHarqProcessesRlcPduListBuffer;
+  std::vector <DlInfoListElement_s> m_dlInfoListBuffered; // HARQ retx buffered
+
+  std::map <uint16_t, uint8_t> m_ulHarqCurrentProcessId;
+  //HARQ status
+  // 0: process Id available
+  // x>0: process Id equal to `x` trasmission count
+  std::map <uint16_t, UlHarqProcessesStatus_t> m_ulHarqProcessesStatus;
+  std::map <uint16_t, UlHarqProcessesDciBuffer_t> m_ulHarqProcessesDciBuffer;
 };
 
 } // namespace ns3
--- a/src/lte/test/lte-test-entities.cc	Fri Aug 31 16:49:46 2012 +0200
+++ b/src/lte/test/lte-test-entities.cc	Mon Oct 08 17:18:22 2012 +0200
@@ -450,7 +450,7 @@
 LteTestMac::SendTxOpportunity (Time time, uint32_t bytes)
 {
   NS_LOG_FUNCTION (this << time << bytes);
-  Simulator::Schedule (time, &LteMacSapUser::NotifyTxOpportunity, m_macSapUser, bytes, 0);
+  Simulator::Schedule (time, &LteMacSapUser::NotifyTxOpportunity, m_macSapUser, bytes, 0, 0);
   if (m_txOpportunityMode == RANDOM_MODE)
   {
     if (m_txOppTime != Seconds (0))
@@ -572,17 +572,17 @@
       if (params.statusPduSize)
         {
           Simulator::Schedule (Seconds (0.1), &LteMacSapUser::NotifyTxOpportunity,
-                               m_macSapUser, params.statusPduSize + 2, 0);
+                               m_macSapUser, params.statusPduSize + 2, 0, 0);
         }
       else if (params.txQueueSize)
         {
           Simulator::Schedule (Seconds (0.1), &LteMacSapUser::NotifyTxOpportunity,
-                               m_macSapUser, params.txQueueSize + 2, 0);
+                               m_macSapUser, params.txQueueSize + 2, 0, 0);
         }
       else if (params.retxQueueSize)
         {
           Simulator::Schedule (Seconds (0.1), &LteMacSapUser::NotifyTxOpportunity,
-                               m_macSapUser, params.retxQueueSize + 2, 0);
+                               m_macSapUser, params.retxQueueSize + 2, 0, 0);
         }
     }
 }
--- a/src/lte/test/lte-test-mimo.cc	Fri Aug 31 16:49:46 2012 +0200
+++ b/src/lte/test/lte-test-mimo.cc	Mon Oct 08 17:18:22 2012 +0200
@@ -83,15 +83,15 @@
 static LenaTestMimoSuite lenaTestMimoSuite;
 
 std::string 
-LenaMimoTestCase::BuildNameString (uint16_t dist)
+LenaMimoTestCase::BuildNameString (uint16_t dist, std::string schedulerType)
 {
   std::ostringstream oss;
-  oss << " UE distance " << dist << " m";
+  oss << " UE distance " << dist << " m" << " Scheduler " << schedulerType;
   return oss.str ();
 }
 
 LenaMimoTestCase::LenaMimoTestCase (uint16_t dist, std::vector<uint32_t> estThrDl, std::string schedulerType)
-  : TestCase (BuildNameString (dist)),              
+  : TestCase (BuildNameString (dist, schedulerType)),              
     m_dist (dist),
     m_estThrDl (estThrDl),
     m_schedulerType (schedulerType)
@@ -105,7 +105,7 @@
 void
 LenaMimoTestCase::DoRun (void)
 {
-//   Config::SetDefault ("ns3::LteSpectrumPhy::PemEnabled", BooleanValue (false));
+  Config::SetDefault ("ns3::LteSpectrumPhy::DataErrorModelEnabled", BooleanValue (false));
   Config::SetDefault ("ns3::LteAmc::AmcModel", EnumValue (LteAmc::PiroEW2010));
 
 
@@ -115,6 +115,10 @@
 
 
   Ptr<LteHelper> lteHelper = CreateObject<LteHelper> ();
+  Config::SetDefault ("ns3::RrFfMacScheduler::HarqEnabled", BooleanValue (false));
+  Config::SetDefault ("ns3::PfFfMacScheduler::HarqEnabled", BooleanValue (false));
+  
+//   lteHelper->SetSchedulerAttribute ("HarqEnabled", BooleanValue (false));
   
   
   lteHelper->SetAttribute ("PathlossModel", StringValue ("ns3::HybridBuildingsPropagationLossModel"));
@@ -122,7 +126,7 @@
   lteHelper->SetPathlossModelAttribute ("ShadowSigmaIndoor", DoubleValue (0.0));
   lteHelper->SetPathlossModelAttribute ("ShadowSigmaExtWalls", DoubleValue (0.0));
   
-//   lteHelper->EnableLogComponents ();
+  lteHelper->EnableLogComponents ();
 
   // Create Nodes: eNodeB and UE
   NodeContainer enbNodes;
@@ -188,7 +192,6 @@
         {
           NS_FATAL_ERROR ("No RR Scheduler available");
         }
-      
       Simulator::Schedule (Seconds (0.2), &RrFfMacScheduler::TransmissionModeConfigurationUpdate, rrsched, rnti, 1);
       Simulator::Schedule (Seconds (0.3), &RrFfMacScheduler::TransmissionModeConfigurationUpdate, rrsched, rnti, 2);
     }
--- a/src/lte/test/lte-test-mimo.h	Fri Aug 31 16:49:46 2012 +0200
+++ b/src/lte/test/lte-test-mimo.h	Mon Oct 08 17:18:22 2012 +0200
@@ -42,7 +42,7 @@
   
   void GetRlcBufferSample (Ptr<RadioBearerStatsCalculator> rlcStats, uint64_t imsi, uint8_t rnti);
   
-  static std::string BuildNameString (uint16_t dist);
+  static std::string BuildNameString (uint16_t dist, std::string schedulerType);
   uint16_t m_nUser;
   uint16_t m_nLc;
   uint16_t m_dist;
--- a/src/lte/test/lte-test-pf-ff-mac-scheduler.cc	Fri Aug 31 16:49:46 2012 +0200
+++ b/src/lte/test/lte-test-pf-ff-mac-scheduler.cc	Mon Oct 08 17:18:22 2012 +0200
@@ -213,7 +213,7 @@
   Config::SetDefault ("ns3::LteSpectrumPhy::DataErrorModelEnabled", BooleanValue (false));  LogComponentDisableAll (LOG_LEVEL_ALL);
   //   LogComponentEnable ("LteEnbRrc", LOG_LEVEL_ALL);
   //   LogComponentEnable ("LteUeRrc", LOG_LEVEL_ALL);
-  //   LogComponentEnable ("LteEnbMac", LOG_LEVEL_ALL);
+//     LogComponentEnable ("LteEnbMac", LOG_LEVEL_ALL);
   //   LogComponentEnable ("LteUeMac", LOG_LEVEL_ALL);
 //     LogComponentEnable ("LteRlc", LOG_LEVEL_ALL);
 //
--- a/src/lte/test/lte-test-phy-error-model.cc	Fri Aug 31 16:49:46 2012 +0200
+++ b/src/lte/test/lte-test-phy-error-model.cc	Mon Oct 08 17:18:22 2012 +0200
@@ -122,7 +122,8 @@
   Config::SetDefault ("ns3::LteAmc::Ber", DoubleValue (ber));
   Config::SetDefault ("ns3::LteAmc::AmcModel", EnumValue (LteAmc::PiroEW2010));
   Config::SetDefault ("ns3::LteSpectrumPhy::CtrlErrorModelEnabled", BooleanValue (false));
-  Config::SetDefault ("ns3::LteSpectrumPhy::DataErrorModelEnabled", BooleanValue (true));  
+  Config::SetDefault ("ns3::LteSpectrumPhy::DataErrorModelEnabled", BooleanValue (true));
+  Config::SetDefault ("ns3::RrFfMacScheduler::HarqEnabled", BooleanValue (false));
 //   LogComponentEnable ("LteEnbRrc", LOG_LEVEL_ALL);
 //   LogComponentEnable ("LteUeRrc", LOG_LEVEL_ALL);
 //   LogComponentEnable ("LteEnbMac", LOG_LEVEL_ALL);
@@ -163,7 +164,7 @@
 //   LogComponentEnable ("LteMiErrorModel", LOG_LEVEL_ALL);
 //   LogComponentEnable ("LteAmc", LOG_LEVEL_ALL);
 //   
-  LogComponentDisableAll (LOG_LEVEL_ALL);
+//   LogComponentDisableAll (LOG_LEVEL_ALL);
 
   LogComponentEnable ("LenaTestPhyErrorModel", LOG_LEVEL_ALL);
 
@@ -306,7 +307,8 @@
   Config::SetDefault ("ns3::LteAmc::Ber", DoubleValue (ber));
   Config::SetDefault ("ns3::LteAmc::AmcModel", EnumValue (LteAmc::PiroEW2010));
   Config::SetDefault ("ns3::LteSpectrumPhy::CtrlErrorModelEnabled", BooleanValue (true));
-  Config::SetDefault ("ns3::LteSpectrumPhy::DataErrorModelEnabled", BooleanValue (false));  
+  Config::SetDefault ("ns3::LteSpectrumPhy::DataErrorModelEnabled", BooleanValue (false));
+  Config::SetDefault ("ns3::RrFfMacScheduler::HarqEnabled", BooleanValue (false));
   //   LogComponentEnable ("LteEnbRrc", LOG_LEVEL_ALL);
   //   LogComponentEnable ("LteUeRrc", LOG_LEVEL_ALL);
   //   LogComponentEnable ("LteEnbMac", LOG_LEVEL_ALL);
@@ -341,13 +343,13 @@
   //   LogComponentEnable ("LteEnbMac", LOG_LEVEL_ALL);
   //   LogComponentEnable ("LteEnbPhy", LOG_LEVEL_ALL);
   //   LogComponentEnable ("LteUePhy", LOG_LEVEL_ALL);
-  //   LogComponentEnable ("RrFfMacScheduler", LOG_LEVEL_ALL);
+//     LogComponentEnable ("RrFfMacScheduler", LOG_LEVEL_ALL);
   //   LogComponentEnable ("LenaHelper", LOG_LEVEL_ALL);
   //   LogComponentEnable ("BuildingsPropagationLossModel", LOG_LEVEL_ALL);
 //     LogComponentEnable ("LteMiErrorModel", LOG_LEVEL_ALL);
   //   LogComponentEnable ("LteAmc", LOG_LEVEL_ALL);
   //   
-  LogComponentDisableAll (LOG_LEVEL_ALL);
+//   LogComponentDisableAll (LOG_LEVEL_ALL);
   
   LogComponentEnable ("LenaTestPhyErrorModel", LOG_LEVEL_ALL);
   
--- a/src/lte/wscript	Fri Aug 31 16:49:46 2012 +0200
+++ b/src/lte/wscript	Mon Oct 08 17:18:22 2012 +0200
@@ -74,6 +74,7 @@
         'model/epc-enb-s1-sap.cc',
         'model/lte-as-sap.cc',
         'model/epc-ue-nas.cc',
+        'model/lte-harq-phy.cc',
         ]
 
     module_test = bld.create_ns3_module_test_library('lte')
@@ -181,6 +182,7 @@
         'model/epc-enb-s1-sap.h',
         'model/lte-as-sap.h',
         'model/epc-ue-nas.h',
+        'model/lte-harq-phy.h',
         ]
 
     if (bld.env['ENABLE_EXAMPLES']):