From 64615dcc8ef3ada3258c891027fd233a8cb2d8da Mon Sep 17 00:00:00 2001
From: Cedric Roux <cedric.roux@eurecom.fr>
Date: Fri, 18 Nov 2016 09:40:14 +0100
Subject: [PATCH] hotfix: correct PHICH generation

The PHICH generation is wrong.
HARQ process X is uplink scheduled at TTI n.
At TTI n+4 the eNB receives the data.
At TTI n+8 the eNB sends ACK/NACK on the PHICH.

The problem is that PHICH generation is done after scheduling.
And PHICH generation uses "first_rb" and "n_DMRS" to compute
"ngroup_PHICH" and "nseq_PHICH".

So at TTI n+8 if the eNB has reused the HARQ process X for
a new uplink scheduling the values "first_rb" and "n_DMRS"
may have changed.

We need to use the previous values.

One solution would have been to do PHICH generation before
scheduling. The problem is that "generate_phich_top" does more
than PHICH generation. It has to setup parameters to sort of
"emulate" a DCI0 in case of retransmission scheduled without
DCI0. So part of it has to be done after scheduling. We would
have to split the function.

The simple adopted fix is to store old values of "first_rb"
and "n_DMRS" and use those values in "generate_phich_top".

This fix has only been tested with FDD. TDD may miserably fail.
---
 openair1/PHY/LTE_TRANSPORT/defs.h       |  8 +++++++
 openair1/PHY/LTE_TRANSPORT/phich.c      | 16 ++++++++-----
 openair1/SCHED/phy_procedures_lte_eNb.c | 32 +++++++++++++++++++++++++
 3 files changed, 50 insertions(+), 6 deletions(-)

diff --git a/openair1/PHY/LTE_TRANSPORT/defs.h b/openair1/PHY/LTE_TRANSPORT/defs.h
index 83b34971d..01d6cdc44 100644
--- a/openair1/PHY/LTE_TRANSPORT/defs.h
+++ b/openair1/PHY/LTE_TRANSPORT/defs.h
@@ -360,6 +360,10 @@ typedef struct {
   uint8_t TPC;
   /// First Allocated RB
   uint16_t first_rb;
+  /// First Allocated RB - previous scheduling
+  /// This is needed for PHICH generation which
+  /// is done after a new scheduling
+  uint16_t previous_first_rb;
   /// Current Number of RBs
   uint16_t nb_rb;
   /// Transport block size
@@ -444,6 +448,10 @@ typedef struct {
   uint8_t Nsymb_initial;
   /// n_DMRS  for cyclic shift of DMRS (36.213 Table 9.1.2-2)
   uint8_t n_DMRS;
+  /// n_DMRS  for cyclic shift of DMRS (36.213 Table 9.1.2-2) - previous scheduling
+  /// This is needed for PHICH generation which
+  /// is done after a new scheduling
+  uint8_t previous_n_DMRS;
   /// n_DMRS 2 for cyclic shift of DMRS (36.211 Table 5.5.1.1.-1)
   uint8_t n_DMRS2;
   /// Flag to indicate that this ULSCH is for calibration information sent from UE (i.e. no MAC SDU to pass up)
diff --git a/openair1/PHY/LTE_TRANSPORT/phich.c b/openair1/PHY/LTE_TRANSPORT/phich.c
index 1727ec532..b0665d89c 100644
--- a/openair1/PHY/LTE_TRANSPORT/phich.c
+++ b/openair1/PHY/LTE_TRANSPORT/phich.c
@@ -1453,8 +1453,12 @@ void generate_phich_top(PHY_VARS_eNB *eNB,
         LOG_D(PHY,"[eNB][PUSCH %d/%x] Frame %d subframe %d (pusch_subframe %d,pusch_frame %d) phich active %d\n",
               harq_pid,ulsch[UE_id]->rnti,proc->frame_tx,subframe,pusch_subframe,pusch_frame,ulsch[UE_id]->harq_processes[harq_pid]->phich_active);
 
-        ngroup_PHICH = (ulsch[UE_id]->harq_processes[harq_pid]->first_rb +
-                        ulsch[UE_id]->harq_processes[harq_pid]->n_DMRS)%Ngroup_PHICH;
+        /* the HARQ process may have been reused by a new scheduling, so we use
+         * previous values of first_rb and n_DMRS to compute ngroup_PHICH and nseq_PHICH
+         */
+
+        ngroup_PHICH = (ulsch[UE_id]->harq_processes[harq_pid]->previous_first_rb +
+                        ulsch[UE_id]->harq_processes[harq_pid]->previous_n_DMRS)%Ngroup_PHICH;
 
         if ((frame_parms->tdd_config == 0) && (frame_parms->frame_type == TDD) ) {
 
@@ -1462,20 +1466,20 @@ void generate_phich_top(PHY_VARS_eNB *eNB,
             ngroup_PHICH += Ngroup_PHICH;
         }
 
-        nseq_PHICH = ((ulsch[UE_id]->harq_processes[harq_pid]->first_rb/Ngroup_PHICH) +
-                      ulsch[UE_id]->harq_processes[harq_pid]->n_DMRS)%(2*NSF_PHICH);
+        nseq_PHICH = ((ulsch[UE_id]->harq_processes[harq_pid]->previous_first_rb/Ngroup_PHICH) +
+                      ulsch[UE_id]->harq_processes[harq_pid]->previous_n_DMRS)%(2*NSF_PHICH);
         LOG_D(PHY,"[eNB %d][PUSCH %d] Frame %d subframe %d Generating PHICH, ngroup_PHICH %d/%d, nseq_PHICH %d : HI %d, first_rb %d dci_alloc %d)\n",
               eNB->Mod_id,harq_pid,proc->frame_tx,
               subframe,ngroup_PHICH,Ngroup_PHICH,nseq_PHICH,
               ulsch[UE_id]->harq_processes[harq_pid]->phich_ACK,
-              ulsch[UE_id]->harq_processes[harq_pid]->first_rb,
+              ulsch[UE_id]->harq_processes[harq_pid]->previous_first_rb,
               ulsch[UE_id]->harq_processes[harq_pid]->dci_alloc);
 
         if (ulsch[UE_id]->Msg3_active == 1) {
           LOG_D(PHY,"[eNB %d][PUSCH %d][RAPROC] Frame %d, subframe %d: Generating Msg3 PHICH for UE %d, ngroup_PHICH %d/%d, nseq_PHICH %d : HI %d, first_rb %d\n",
                 eNB->Mod_id,harq_pid,proc->frame_tx,subframe,
                 UE_id,ngroup_PHICH,Ngroup_PHICH,nseq_PHICH,ulsch[UE_id]->harq_processes[harq_pid]->phich_ACK,
-                ulsch[UE_id]->harq_processes[harq_pid]->first_rb);
+                ulsch[UE_id]->harq_processes[harq_pid]->previous_first_rb);
         }
 
         if (eNB->abstraction_flag == 0) {
diff --git a/openair1/SCHED/phy_procedures_lte_eNb.c b/openair1/SCHED/phy_procedures_lte_eNb.c
index 4163b8340..7ac6e2bf1 100644
--- a/openair1/SCHED/phy_procedures_lte_eNb.c
+++ b/openair1/SCHED/phy_procedures_lte_eNb.c
@@ -1206,6 +1206,38 @@ void phy_procedures_eNB_TX(PHY_VARS_eNB *eNB,
       eNB->dlsch[i][0]->subframe_tx[subframe] = 0;
   }
 
+  /* save old HARQ information needed for PHICH generation */
+  for (i=0; i<NUMBER_OF_UE_MAX; i++) {
+    if (eNB->ulsch[i]) {
+      /* Store first_rb and n_DMRS for correct PHICH generation below.
+       * For PHICH generation we need "old" values of last scheduling
+       * for this HARQ process. 'generate_eNB_dlsch_params' below will
+       * overwrite first_rb and n_DMRS and 'generate_phich_top', done
+       * after 'generate_eNB_dlsch_params', would use the "new" values
+       * instead of the "old" ones.
+       *
+       * This has been tested for FDD only, may be wrong for TDD.
+       *
+       * TODO: maybe we should restructure the code to be sure it
+       *       is done correctly. The main concern is if the code
+       *       changes and first_rb and n_DMRS are modified before
+       *       we reach here, then the PHICH processing will be wrong,
+       *       using wrong first_rb and n_DMRS values to compute
+       *       ngroup_PHICH and nseq_PHICH.
+       *
+       * TODO: check if that works with TDD.
+       */
+      if ((subframe_select(fp,ul_subframe)==SF_UL) ||
+          (fp->frame_type == FDD)) {
+        harq_pid = subframe2harq_pid(fp,ul_frame,ul_subframe);
+        eNB->ulsch[i]->harq_processes[harq_pid]->previous_first_rb =
+            eNB->ulsch[i]->harq_processes[harq_pid]->first_rb;
+        eNB->ulsch[i]->harq_processes[harq_pid]->previous_n_DMRS =
+            eNB->ulsch[i]->harq_processes[harq_pid]->n_DMRS;
+      }
+    }
+  }
+
 
   num_pdcch_symbols = DCI_pdu->num_pdcch_symbols;
   LOG_D(PHY,"num_pdcch_symbols %"PRIu8",(dci common %"PRIu8", dci uespec %"PRIu8"\n",num_pdcch_symbols,
-- 
GitLab