diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c
index 0b7c1de3ea101060aa12dd8ee43052e1d39c81e0..b0bd1aec42916932702a69d1abb3f1636551977b 100644
--- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c
+++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c
@@ -62,6 +62,294 @@
 const uint8_t slots_per_frame[5] = {10, 20, 40, 80, 160};
 uint16_t nr_pdcch_order_table[6] = { 31, 31, 511, 2047, 2047, 8191 };
 
+#define MAX_SSB_SCHED 8
+#define L1_RSRP_HYSTERIS 10 //considering 10 dBm as hysterisis for avoiding frequent SSB Beam Switching. !Fixme provide exact value if any
+//#define L1_DIFF_RSRP_STEP_SIZE 2
+#define MAX_NUM_SSB 128
+#define MIN_RSRP_VALUE -141
+//Measured RSRP Values Table 10.1.16.1-1 from 36.133
+//Stored all the upper limits[Max RSRP Value of corresponding index]
+//stored -1 for invalid values
+int L1_SSB_CSI_RSRP_measReport_mapping_38133_10_1_6_1_1[128] = {
+  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, //0 - 9
+    -1, -1, -1, -1, -1, -1, -140, -139, -138, -137, //10 - 19
+    -136, -135, -134, -133, -132, -131, -130, -129, -128, -127, //20 - 29
+    -126, -125, -124, -123, -122, -121, -120, -119, -118, -117, //30 - 39
+    -116, -115, -114, -113, -112, -111, -110, -109, -108, -107, //40 - 49
+    -106, -105, -104, -103, -102, -101, -100, -99, -98, -97, //50 - 59
+    -96, -95, -94, -93, -92, -91, -90, -89, -88, -87, //60 - 69
+    -86, -85, -84, -83, -82, -81, -80, -79, -78, -77, //70 - 79
+    -76, -75, -74, -73, -72, -71, -70, -69, -68, -67, //80 - 89
+    -66, -65, -64, -63, -62, -61, -60, -59, -58, -57, //90 - 99
+    -56, -55, -54, -53, -52, -51, -50, -49, -48, -47, //100 - 109
+    -46, -45, -44, -44, -1, -1, -1, -1, -1, -1, //110 - 119
+    -1, -1, -1, -1, -1, -1, -1, -1//120 - 127
+  };
+
+//Differential RSRP values Table 10.1.6.1-2 from 36.133
+//Stored the upper limits[MAX RSRP Value]
+int diff_rsrp_ssb_csi_meas_10_1_6_1_2[16] = {
+  0, -2, -4, -6, -8, -10, -12, -14, -16, -18, //0 - 9
+  -20, -22, -24, -26, -28, -30 //10 - 15
+};
+
+
+//returns the measured RSRP value (upper limit)
+int get_measured_rsrp(uint8_t index) {
+  //if index is invalid returning minimum rsrp -140
+  if((index >= 0 && index <= 15) || index >= 114)
+    return MIN_RSRP_VALUE;
+
+  return L1_SSB_CSI_RSRP_measReport_mapping_38133_10_1_6_1_1[index];
+}
+
+//returns the differential RSRP value (upper limit)
+int get_diff_rsrp(uint8_t index, int strongest_rsrp) {
+  if(strongest_rsrp != -1) {
+    return strongest_rsrp + diff_rsrp_ssb_csi_meas_10_1_6_1_2[index];
+  } else
+    return MIN_RSRP_VALUE;
+}
+
+int checkTargetSSBInFirst64TCIStates_pdschConfig(int ssb_index_t) {
+  //Need to implement once configuration is received
+  return 0;
+}
+
+int checkTargetSSBInTCIStates_pdcchConfig(int ssb_index_t) {
+  //Need to implement once configuration is received
+  return 0;
+}
+
+int ssb_index_sorted[MAX_NUM_SSB] = {0};
+int ssb_rsrp_sorted[MAX_NUM_SSB] = {0};
+//Sorts ssb_index and ssb_rsrp array data and keeps in ssb_index_sorted and
+//ssb_rsrp_sorted respectively
+int ssb_rsrp_sort(int *ssb_index, int *ssb_rsrp) {
+  int i, j;
+
+  for(i = 0; *(ssb_index+i) != 0; i++) {
+    for(j = i; *(ssb_index+j) != 0; j++) {
+      if(*(ssb_rsrp+j) >= *(ssb_rsrp+i)) {
+        ssb_index_sorted[i] = *(ssb_index+j);
+        ssb_rsrp_sorted[i] = *(ssb_rsrp+j);
+      }
+    }
+  }
+}
+
+//identifies the target SSB Beam index
+//keeps the required date for PDCCH and PDSCH TCI state activation/deactivation CE consutruction globally
+//handles triggering of PDCCH and PDSCH MAC CEs
+void tci_handling(int Mod_idP, int UE_id, int CC_id, NR_UE_sched_ctrl_t *sched_ctrl, frame_t frame, slot_t slot) {
+  int strongest_ssb_rsrp = 0;
+  int cqi_idx = 0;
+  int curr_ssb_beam_index = 0; //ToDo: yet to know how to identify the serving ssb beam index
+  uint8_t target_ssb_beam_index = curr_ssb_beam_index;
+  //uint8_t max_reported_RSRP = 16;
+  //int serving_SSB_Beam_RSRP;
+  uint8_t is_triggering_ssb_beam_switch =0;
+  uint8_t ssb_idx = 0;
+  int pdsch_bwp_id =0;
+  int ssb_index[MAX_NUM_SSB] = {0};
+  int ssb_rsrp[MAX_NUM_SSB] = {0};
+  uint8_t idx = 0;
+  int bwp_id  = 1;
+  NR_UE_list_t *UE_list = &RC.nrmac[Mod_idP]->UE_list;
+  //NR_COMMON_channels_t *cc = RC.nrmac[Mod_idP]->common_channels;
+  NR_CellGroupConfig_t *secondaryCellGroup = UE_list->secondaryCellGroup[UE_id];
+  NR_BWP_Downlink_t *bwp = secondaryCellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.array[bwp_id-1];
+  NR_CSI_MeasConfig_t *csi_MeasConfig = UE_list->secondaryCellGroup[UE_id]->spCellConfig->spCellConfigDedicated->csi_MeasConfig->choice.setup;
+  //bwp indicator
+  int n_dl_bwp = secondaryCellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.count;
+  uint8_t nb_ssb_resources_inEachSet = sched_ctrl->CSI_report[UE_id][cqi_idx].choice.ssb_cri_report.nr_ssbri_cri;
+  uint8_t nb_resource_sets = sched_ctrl->nr_of_csi_report[UE_id];
+  //uint8_t bitlen_ssbri = log (nb_resource_sets)/log (2);
+  //uint8_t max_rsrp_reported = -1;
+  int better_rsrp_reported = -140-(-0); /*minimum_measured_RSRP_value - minimum_differntail_RSRP_value*///considering the minimum RSRP value as better RSRP initially
+  uint8_t diff_rsrp_idx = 0;
+  uint8_t i, j;
+
+  if (n_dl_bwp < 4)
+    pdsch_bwp_id = bwp_id;
+  else
+    pdsch_bwp_id = bwp_id - 1; // as per table 7.3.1.1.2-1 in 38.212
+
+  /*Example:
+  CRI_SSBRI: 1 2 3 4| 5 6 7 8| 9 10 1 2|
+  nb_resource_sets = 3 //3 sets as above
+  nb_ssb_resources_inEachSet = 4 //each set has 4 elements
+  storing ssb indexes in ssb_index array as ssb_index[0] = 1 .. ssb_index[4] = 5
+  ssb_rsrp[0] = strongest rsrp in first set, ssb_rsrp[4] = strongest rsrp in second set, ..
+  idx: resource set index
+  */
+
+  //for all reported SSB
+  for (idx = 0; idx < nb_resource_sets; idx++) {
+    //if group based beam Reporting is disabled
+    if(NR_CSI_ReportConfig__groupBasedBeamReporting_PR_disabled ==
+        csi_MeasConfig->csi_ReportConfigToAddModList->list.array[0]->groupBasedBeamReporting.present ) {
+      //extracting the ssb indexes
+      for (ssb_idx = 0; ssb_idx <= nb_ssb_resources_inEachSet; ssb_idx++) {
+        ssb_index[idx * nb_resource_sets + ssb_idx] = sched_ctrl->CSI_report[UE_id][idx].choice.ssb_cri_report.CRI_SSBRI[ssb_idx];
+      }
+
+      //if strongest measured RSRP is configured
+      strongest_ssb_rsrp = get_measured_rsrp(sched_ctrl->CSI_report[UE_id][idx].choice.ssb_cri_report.RSRP);
+      ssb_rsrp[idx * nb_resource_sets] = strongest_ssb_rsrp;
+
+      //if current ssb rsrp is greater than better rsrp
+      if(ssb_rsrp[idx * nb_resource_sets] > better_rsrp_reported) {
+        better_rsrp_reported = ssb_rsrp[idx * nb_resource_sets];
+        target_ssb_beam_index = idx * nb_resource_sets;
+      }
+
+      for(diff_rsrp_idx =1; diff_rsrp_idx < nb_ssb_resources_inEachSet; diff_rsrp_idx++) {
+        ssb_rsrp[idx * nb_resource_sets + diff_rsrp_idx] = get_diff_rsrp(sched_ctrl->CSI_report[UE_id][idx].choice.ssb_cri_report.diff_RSRP[diff_rsrp_idx], strongest_ssb_rsrp);
+
+        //if current reported rsrp is greater than better rsrp
+        if(ssb_rsrp[idx * nb_resource_sets + diff_rsrp_idx] > better_rsrp_reported) {
+          better_rsrp_reported = ssb_rsrp[idx * nb_resource_sets + diff_rsrp_idx];
+          target_ssb_beam_index = idx * nb_resource_sets + diff_rsrp_idx;
+        }
+      }
+    }
+    //if group based beam reporting is enabled
+    else if (NR_CSI_ReportConfig__groupBasedBeamReporting_PR_disabled !=
+             csi_MeasConfig->csi_ReportConfigToAddModList->list.array[0]->groupBasedBeamReporting.present ) {
+      //extracting the ssb indexes
+      //for group based reporting only 2 SSB RS are reported, 38.331
+      for (ssb_idx = 0; ssb_idx < 2; ssb_idx++) {
+        ssb_index[idx * nb_resource_sets + ssb_idx] = sched_ctrl->CSI_report[UE_id][idx].choice.ssb_cri_report.CRI_SSBRI[ssb_idx];
+      }
+
+      strongest_ssb_rsrp = get_measured_rsrp(sched_ctrl->CSI_report[UE_id][idx].choice.ssb_cri_report.RSRP);
+      ssb_rsrp[idx * nb_resource_sets] = strongest_ssb_rsrp;
+
+      if(ssb_rsrp[idx * nb_resource_sets] > better_rsrp_reported) {
+        better_rsrp_reported = ssb_rsrp[idx * nb_resource_sets];
+        target_ssb_beam_index = idx * nb_resource_sets;
+      }
+
+      ssb_rsrp[idx * nb_resource_sets + 1] = get_diff_rsrp(sched_ctrl->CSI_report[UE_id][idx].choice.ssb_cri_report.diff_RSRP[diff_rsrp_idx], strongest_ssb_rsrp);
+
+      if(ssb_rsrp[idx * nb_resource_sets + 1] > better_rsrp_reported) {
+        better_rsrp_reported = ssb_rsrp[idx * nb_resource_sets + 1];
+        target_ssb_beam_index = idx * nb_resource_sets + 1;
+      }
+    }
+  }
+
+  if(ssb_index[target_ssb_beam_index] != ssb_index[curr_ssb_beam_index] && ssb_rsrp[target_ssb_beam_index] > ssb_rsrp[curr_ssb_beam_index]) {
+    if( ssb_rsrp[target_ssb_beam_index] - ssb_rsrp[curr_ssb_beam_index] > L1_RSRP_HYSTERIS) {
+      is_triggering_ssb_beam_switch = 1;
+      LOG_I(MAC, "Triggering ssb beam switching using tci\n");
+    }
+  }
+
+  if(is_triggering_ssb_beam_switch) {
+    //filling pdcch tci state activativation mac ce structure fields
+    sched_ctrl->UE_mac_ce_ctrl.pdcch_state_ind.is_scheduled = 1;
+    //OAI currently focusing on Non CA usecase hence 0 is considered as serving
+    //cell id
+    sched_ctrl->UE_mac_ce_ctrl.pdcch_state_ind.servingCellId = 0; //0 for PCell as 38.331 v15.9.0 page 353 //serving cell id for which this MAC CE applies
+    sched_ctrl->UE_mac_ce_ctrl.pdcch_state_ind.coresetId = 0; //coreset id for which the TCI State id is being indicated
+
+    /* 38.321 v15.8.0 page 66
+    TCI State ID: This field indicates the TCI state identified by TCI-StateId as specified in TS 38.331 [5] applicable
+    to the Control Resource Set identified by CORESET ID field.
+    If the field of CORESET ID is set to 0,
+      this field indicates a TCI-StateId for a TCI state of the first 64 TCI-states configured by tci-States-ToAddModList and tciStates-ToReleaseList in the PDSCH-Config in the active BWP.
+    If the field of CORESET ID is set to the other value than 0,
+     this field indicates a TCI-StateId configured by tci-StatesPDCCH-ToAddList and tciStatesPDCCH-ToReleaseList in the controlResourceSet identified by the indicated CORESET ID.
+    The length of the field is 7 bits
+     */
+    if(sched_ctrl->UE_mac_ce_ctrl.pdcch_state_ind.coresetId == 0) {
+      int tci_state_id = checkTargetSSBInFirst64TCIStates_pdschConfig(ssb_index[target_ssb_beam_index]);
+
+      if( tci_state_id != -1)
+        sched_ctrl->UE_mac_ce_ctrl.pdcch_state_ind.tciStateId = tci_state_id;
+      else {
+        //identify the best beam within first 64 TCI States of PDSCH
+        //Config TCI-states-to-addModList
+        int flag = 0;
+
+        for(i =0; ssb_index_sorted[i]!=0; i++) {
+          tci_state_id = checkTargetSSBInFirst64TCIStates_pdschConfig(ssb_index_sorted[i]);
+
+          if(tci_state_id != -1 && ssb_rsrp_sorted[i] > ssb_rsrp[curr_ssb_beam_index] && ssb_rsrp_sorted[i] - ssb_rsrp[curr_ssb_beam_index] > L1_RSRP_HYSTERIS) {
+            sched_ctrl->UE_mac_ce_ctrl.pdcch_state_ind.tciStateId = tci_state_id;
+            flag = 1;
+            break;
+          }
+        }
+
+        if(flag == 0 || ssb_rsrp_sorted[i] < ssb_rsrp[curr_ssb_beam_index] || ssb_rsrp_sorted[i] - ssb_rsrp[curr_ssb_beam_index] < L1_RSRP_HYSTERIS) {
+          sched_ctrl->UE_mac_ce_ctrl.pdcch_state_ind.is_scheduled = 0;
+        }
+      }
+    } else {
+      int tci_state_id = checkTargetSSBInTCIStates_pdcchConfig(ssb_index[target_ssb_beam_index]);
+
+      if (tci_state_id !=-1)
+        sched_ctrl->UE_mac_ce_ctrl.pdcch_state_ind.tciStateId = tci_state_id;
+      else {
+        //identify the best beam within CORESET/PDCCH
+        ////Config TCI-states-to-addModList
+        int flag = 0;
+
+        for(i =0; ssb_index_sorted[i]!=0; i++) {
+          tci_state_id = checkTargetSSBInTCIStates_pdcchConfig(ssb_index_sorted[i]);
+
+          if( tci_state_id != -1 && ssb_rsrp_sorted[i] > ssb_rsrp[curr_ssb_beam_index] && ssb_rsrp_sorted[i] - ssb_rsrp[curr_ssb_beam_index] > L1_RSRP_HYSTERIS) {
+            sched_ctrl->UE_mac_ce_ctrl.pdcch_state_ind.tciStateId = tci_state_id;
+            flag = 1;
+            break;
+          }
+        }
+
+        if(flag == 0 || ssb_rsrp_sorted[i] < ssb_rsrp[curr_ssb_beam_index] || ssb_rsrp_sorted[i] - ssb_rsrp[curr_ssb_beam_index] < L1_RSRP_HYSTERIS) {
+          sched_ctrl->UE_mac_ce_ctrl.pdcch_state_ind.is_scheduled = 0;
+        }
+      }
+    }
+
+    sched_ctrl->UE_mac_ce_ctrl.pdcch_state_ind.tci_present_inDCI = bwp->bwp_Dedicated->pdcch_Config->choice.setup->controlResourceSetToAddModList->list.array[bwp_id-1]->tci_PresentInDCI;
+
+    //filling pdsch tci state activation deactivation mac ce structure fields
+    if(sched_ctrl->UE_mac_ce_ctrl.pdcch_state_ind.tci_present_inDCI) {
+      sched_ctrl->UE_mac_ce_ctrl.pdsch_TCI_States_ActDeact.is_scheduled = 1;
+      /*
+      Serving Cell ID: This field indicates the identity of the Serving Cell for which the MAC CE applies
+      Considering only PCell exists. Serving cell index of PCell is always 0, hence configuring 0
+      */
+      sched_ctrl->UE_mac_ce_ctrl.pdsch_TCI_States_ActDeact.servingCellId = 0;
+      /*
+      BWP ID: This field indicates a DL BWP for which the MAC CE applies as the codepoint of the DCI bandwidth
+      part indicator field as specified in TS 38.212
+      */
+      sched_ctrl->UE_mac_ce_ctrl.pdsch_TCI_States_ActDeact.bwpId = pdsch_bwp_id;
+
+      /*
+       * TODO ssb_rsrp_sort() API yet to code to find 8 best beams, rrc configuration
+       * is required
+       */
+      for(i = 0; i<8; i++) {
+        sched_ctrl->UE_mac_ce_ctrl.pdsch_TCI_States_ActDeact.tciStateActDeact[i] = i;
+      }
+
+      sched_ctrl->UE_mac_ce_ctrl.pdsch_TCI_States_ActDeact.highestTciStateActivated = 8;
+
+      for(i = 0, j =0; i<MAX_TCI_STATES; i++) {
+        if(sched_ctrl->UE_mac_ce_ctrl.pdsch_TCI_States_ActDeact.tciStateActDeact[i]) {
+          sched_ctrl->UE_mac_ce_ctrl.pdsch_TCI_States_ActDeact.codepoint[j] = i;
+          j++;
+        }
+      }
+    }//tci_presentInDCI
+  }//is-triggering_beam_switch
+}//tci handling
+
 void clear_nr_nfapi_information(gNB_MAC_INST * gNB,
                                 int CC_idP,
                                 frame_t frameP,
diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h
index a5f0ce6a1243020642797ef61376e153a5905717..12f6f7f069adb44919d724bef8f520d5e1b84cf2 100644
--- a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h
+++ b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h
@@ -179,14 +179,14 @@ typedef struct {
   uint8_t vrb_map_UL[100];
   /// number of subframe allocation pattern available for MBSFN sync area
   uint8_t num_sf_allocation_pattern;
-	///Number of active SSBs
-	uint8_t num_active_ssb;
-	//Total available prach occasions per configuration period
-	uint32_t total_prach_occasions_per_config_period;
-	//Total available prach occasions
-	uint32_t total_prach_occasions;
-	//Max Association period
-	uint8_t max_association_period;
+  ///Number of active SSBs
+  uint8_t num_active_ssb;
+  //Total available prach occasions per configuration period
+  uint32_t total_prach_occasions_per_config_period;
+  //Total available prach occasions
+  uint32_t total_prach_occasions;
+  //Max Association period
+  uint8_t max_association_period;
 } NR_COMMON_channels_t;
 
 
@@ -218,8 +218,17 @@ typedef struct pdcchStateInd {
   uint8_t servingCellId;
   uint8_t coresetId;
   uint8_t tciStateId;
+  bool tci_present_inDCI;
 } pdcchStateInd_t;
 
+typedef struct pucchSpatialRelation {
+  bool is_scheduled;
+  uint8_t servingCellId;
+  uint8_t bwpId;
+  uint8_t pucchResourceId;
+  bool s0tos7_actDeact[8];
+} pucchSpatialRelation_t;
+
 typedef struct SPCSIReportingpucch {
   bool is_scheduled;
   uint8_t servingCellId;
@@ -243,12 +252,14 @@ typedef struct pdschTciStatesActDeact {
   uint8_t bwpId;
   uint8_t highestTciStateActivated;
   bool tciStateActDeact[MAX_TCI_STATES];
+  uint8_t codepoint[8];
 } pdschTciStatesActDeact_t;
 
 typedef struct UE_info {
   sp_zp_csirs_t sp_zp_csi_rs;
   csi_rs_im_t csi_im;
   pdcchStateInd_t pdcch_state_ind;
+  pucchSpatialRelation_t pucch_spatial_relation;
   SPCSIReportingpucch_t SP_CSI_reporting_pucch;
   aperiodicCSI_triggerStateSelection_t aperi_CSI_trigger;
   pdschTciStatesActDeact_t pdsch_TCI_States_ActDeact;
@@ -270,6 +281,58 @@ typedef struct NR_UE_harq {
   uint16_t feedback_slot;
 } NR_UE_harq_t;
 
+//! fixme : need to enhace for the multiple TB CQI report
+
+
+//
+/*! As per spec 38.214 section 5.2.1.4.2
+ * - if the UE is configured with the higher layer parameter groupBasedBeamReporting set to 'disabled', the UE shall report in
+  a single report nrofReportedRS (higher layer configured) different CRI or SSBRI for each report setting.
+ * - if the UE is configured with the higher layer parameter groupBasedBeamReporting set to 'enabled', the UE shall report in a
+  single reporting instance two different CRI or SSBRI for each report setting, where CSI-RS and/or SSB
+  resources can be received simultaneously by the UE either with a single spatial domain receive filter, or with
+  multiple simultaneous spatial domain receive filter
+*/
+#define MAX_NR_OF_REPORTED_RS 4
+
+typedef enum NR_CSI_Report_Config {
+  CSI_Report_PR_cri_ri_li_pmi_cqi_report,
+  CSI_Report_PR_ssb_cri_report
+} NR_CSI_Report_Config_PR;
+struct CRI_RI_LI_PMI_CQI {
+  uint8_t cri;
+  uint8_t ri;
+  uint8_t li;
+  uint8_t pmi_x1;
+  uint8_t pmi_x2;
+  uint8_t cqi;
+};
+typedef struct CRI_SSB_RSRP {
+  uint8_t nr_ssbri_cri;
+  uint8_t CRI_SSBRI[MAX_NR_OF_REPORTED_RS];
+  uint8_t RSRP;
+  uint8_t diff_RSRP[MAX_NR_OF_REPORTED_RS - 1];
+} CRI_SSB_RSRP_t;
+struct CSI_Report {
+  NR_CSI_Report_Config_PR present;
+  union Config_CSI_Report {
+    struct CRI_RI_LI_PMI_CQI cri_ri_li_pmi_cqi_report;
+    struct CRI_SSB_RSRP ssb_cri_report;
+  } choice;
+};
+
+#define MAX_SR_BITLEN 8
+typedef struct NR_UE_sr {
+  uint8_t nr_of_srs;
+  bool ul_SR [MAX_SR_BITLEN];
+} NR_UE_sr_t;
+
+/*! As per the spec 38.212 and table:  6.3.1.1.2-12 in a single UCI sequence we can have multiple CSI_report 
+  the number of CSI_report will depend on number of CSI resource sets that are configured in CSI-ResourceConfig RRC IE
+  From spec 38.331 from the IE CSI-ResourceConfig for SSB RSRP reporting we can configure only one resource set 
+  From spec 38.214 section 5.2.1.2 For periodic and semi-persistent CSI Resource Settings, the number of CSI-RS Resource Sets configured is limited to S=1
+ */
+#define MAX_CSI_RESOURCE_SET_IN_CSI_RESOURCE_CONFIG 16
 /*! \brief scheduling control information set through an API */
 typedef struct {
   uint64_t dlsch_in_slot_bitmap;  // static bitmap signaling which slot in a tdd period contains dlsch
@@ -278,6 +341,9 @@ typedef struct {
   uint16_t ta_timer;
   int16_t ta_update;
   uint8_t current_harq_pid;
+  uint8_t nr_of_csi_report[MAX_MOBILES_PER_GNB];
+  struct CSI_Report CSI_report[MAX_MOBILES_PER_GNB][MAX_CSI_RESOURCE_SET_IN_CSI_RESOURCE_CONFIG];
+  NR_UE_sr_t sr_req;
   NR_UE_harq_t harq_processes[NR_MAX_NB_HARQ_PROCESSES];
   int dummy;
   NR_UE_mac_ce_ctrl_t UE_mac_ce_ctrl;// MAC CE related information
@@ -305,7 +371,7 @@ typedef struct {
   rnti_t tc_rnti[MAX_MOBILES_PER_GNB];
   NR_preamble_ue preambles[MAX_MOBILES_PER_GNB];
   NR_CellGroupConfig_t *secondaryCellGroup[MAX_MOBILES_PER_GNB];
-	uint8_t UE_ssb_index[MAX_MOBILES_PER_GNB];
+  uint8_t UE_ssb_index[MAX_MOBILES_PER_GNB];
 } NR_UE_list_t;
 
 typedef struct {
@@ -317,7 +383,7 @@ typedef struct {
 #define MAX_NUM_OF_SSB 64
 
 typedef struct {
-	uint8_t ssb_index;
+  uint8_t ssb_index;
   int num_UEs;
   NR_SSB_UE_list_t SSB_UE_list[MAX_MOBILES_PER_GNB];
 } NR_SSB_list_t;		
diff --git a/openair2/NR_PHY_INTERFACE/NR_IF_Module.c b/openair2/NR_PHY_INTERFACE/NR_IF_Module.c
index 70fc10ab468baea6a6ef5a7ba209d079b135ac86..9351b34617aaef7d6c857ed4e7c01dbcd12b9b19 100644
--- a/openair2/NR_PHY_INTERFACE/NR_IF_Module.c
+++ b/openair2/NR_PHY_INTERFACE/NR_IF_Module.c
@@ -74,12 +74,196 @@ void handle_nr_rach(NR_UL_IND_t *UL_info) {
   }
 }
 
+//!TODO : smae function can be written to handle csi_resources
+uint8_t get_ssb_resources (NR_CSI_MeasConfig_t *csi_MeasConfig, 
+		NR_CSI_ResourceConfigId_t csi_ResourceConfigId, 
+		NR_CSI_ReportConfig__reportQuantity_PR reportQuantity_type) {
+  uint8_t idx = 0;
+  //uint8_t csi_ssb_idx =0;
+
+  for ( idx = 0; idx < csi_MeasConfig->csi_ResourceConfigToAddModList->list.count; idx++) {
+    if ( csi_MeasConfig->csi_ResourceConfigToAddModList->list.array[idx]->csi_ResourceConfigId == csi_ResourceConfigId) {
+    //Finding the CSI_RS or SSB Resources
+      if ( csi_MeasConfig->csi_ResourceConfigToAddModList->list.array[idx]->csi_RS_ResourceSetList.present == NR_CSI_ResourceConfig__csi_RS_ResourceSetList_PR_nzp_CSI_RS_SSB) {
+
+        if (NR_CSI_ReportConfig__reportQuantity_PR_ssb_Index_RSRP == reportQuantity_type )
+          return (csi_MeasConfig->csi_ResourceConfigToAddModList->list.array[idx]->csi_RS_ResourceSetList.choice.nzp_CSI_RS_SSB->csi_SSB_ResourceSetList->list.count);
+
+	else if (NR_CSI_ReportConfig__reportQuantity_PR_cri_RSRP == reportQuantity_type)
+	  return (csi_MeasConfig->csi_ResourceConfigToAddModList->list.array[idx]->csi_RS_ResourceSetList.choice.nzp_CSI_RS_SSB->nzp_CSI_RS_ResourceSetList->list.count);
+
+      } else {
+        //TODO: find the CSI_RS IM resources
+      }
+    } else {
+      AssertFatal(csi_ResourceConfigId, "csi_ResourceConfigId is not configured");
+    }
+  }
+
+  return -1;
+}
+
+
+void extract_pucch_csi_report ( NR_CSI_MeasConfig_t *csi_MeasConfig,
+                                nfapi_nr_uci_pucch_pdu_format_2_3_4_t *uci_pdu,
+                                NR_UE_sched_ctrl_t *sched_ctrl,
+                                frame_t frame,
+                                slot_t slot,
+				NR_SubcarrierSpacing_t scs
+                              ) {
+  /** From Table 6.3.1.1.2-3: RI, LI, CQI, and CRI of codebookType=typeI-SinglePanel */
+  //uint8_t bitlen_cri = (log(csi_MeasConfig->csi_ResourceConfigToAddModList->list.count)/log(2));
+  uint8_t payload_size = ceil(uci_pdu->csi_part1.csi_part1_bit_len/8);
+  uint16_t *payload = calloc (1, payload_size);
+  NR_CSI_ReportConfig__reportQuantity_PR reportQuantity_type = NR_CSI_ReportConfig__reportQuantity_PR_NOTHING;
+  uint8_t UE_id = 0;
+  uint8_t csi_report_id = 0;
+  memcpy ( payload, uci_pdu->csi_part1.csi_part1_payload, payload_size);
+
+  for ( csi_report_id =0; csi_report_id < csi_MeasConfig->csi_ReportConfigToAddModList->list.count; csi_report_id++ ) {
+    //Assuming in periodic reporting for one slot can be configured with only one CSI-ReportConfig
+    if (csi_MeasConfig->csi_ReportConfigToAddModList->list.array[csi_report_id]->reportConfigType.present == NR_CSI_ReportConfig__reportConfigType_PR_periodic) {
+      //considering 30khz scs and
+      //Has to implement according to reportSlotConfig type
+      if (((NR_SubcarrierSpacing_kHz30 == scs) && 
+		      (0 == ((frame*20) + slot) % csi_MeasConfig->csi_ReportConfigToAddModList->list.array[csi_report_id]->reportConfigType.choice.periodic->reportSlotConfig.choice.slots320))
+		      ||((NR_SubcarrierSpacing_kHz120 == scs)&&
+			      (0 == ((frame*80) + slot) % csi_MeasConfig->csi_ReportConfigToAddModList->list.array[csi_report_id]->reportConfigType.choice.periodic->reportSlotConfig.choice.slots320))){
+        reportQuantity_type = csi_MeasConfig->csi_ReportConfigToAddModList->list.array[csi_report_id]->reportQuantity.present;
+      }
+    }
+  }
+
+  if ( !(reportQuantity_type)) 
+    AssertFatal(reportQuantity_type, "reportQuantity is not configured");
+
+  if ( NR_CSI_ReportConfig__reportQuantity_PR_ssb_Index_RSRP == reportQuantity_type ) {
+    uint8_t nb_ssb_resource_set = get_ssb_resources(csi_MeasConfig,
+                               csi_MeasConfig->csi_ReportConfigToAddModList->list.array[csi_report_id]->resourcesForChannelMeasurement,
+			       reportQuantity_type);//csi_MeasConfig->csi_SSB_ResourceSetToAddModList->list.array[0]->CSI_SSB_ResourceList.list.count;
+    uint8_t idx = 0;
+    uint8_t ssb_idx = 0;
+    uint8_t diff_rsrp_idx = 0;
+    uint8_t bitlen_ssbri = log (nb_ssb_resource_set)/log (2);
+    sched_ctrl->nr_of_csi_report[UE_id] = nb_ssb_resource_set;
+
+    /*! As per the spec 38.212 and table:  6.3.1.1.2-12 in a single UCI sequence we can have multiple CSI_report
+     * the number of CSI_report will depend on number of CSI resource sets that are configured in CSI-ResourceConfig RRC IE
+     * From spec 38.331 from the IE CSI-ResourceConfig for SSB RSRP reporting we can configure only one resource set
+     * From spec 38.214 section 5.2.1.2 For periodic and semi-persistent CSI Resource Settings, the number of CSI-RS Resource Sets configured is limited to S=1
+     */
+    for (idx = 0; idx < nb_ssb_resource_set; idx++) {
+      
+      /** from 38.214 sec 5.2.1.4.2
+      - if the UE is configured with the higher layer parameter groupBasedBeamReporting set to 'disabled', the UE is
+        not required to update measurements for more than 64 CSI-RS and/or SSB resources, and the UE shall report in
+        a single report nrofReportedRS (higher layer configured) different CRI or SSBRI for each report setting
+
+      - if the UE is configured with the higher layer parameter groupBasedBeamReporting set to 'enabled', the UE is not
+      required to update measurements for more than 64 CSI-RS and/or SSB resources, and the UE shall report in a
+      single reporting instance two different CRI or SSBRI for each report setting, where CSI-RS and/or SSB
+      resources can be received simultaneously by the UE either with a single spatial domain receive filter, or with
+      multiple simultaneous spatial domain receive filter
+      */
+
+      if (NR_CSI_ReportConfig__groupBasedBeamReporting_PR_disabled ==
+          csi_MeasConfig->csi_ReportConfigToAddModList->list.array[0]->groupBasedBeamReporting.present ) {
+
+        if ((NULL != csi_MeasConfig->csi_ReportConfigToAddModList->list.array[0]->groupBasedBeamReporting.choice.disabled->nrofReportedRS) && 
+		      *(csi_MeasConfig->csi_ReportConfigToAddModList->list.array[0]->groupBasedBeamReporting.choice.disabled->nrofReportedRS)) 
+          sched_ctrl->CSI_report[UE_id][idx].choice.ssb_cri_report.nr_ssbri_cri = *(csi_MeasConfig->csi_ReportConfigToAddModList->list.array[0]->groupBasedBeamReporting.choice.disabled->nrofReportedRS);
+
+        else 
+          sched_ctrl->CSI_report[UE_id][idx].choice.ssb_cri_report.nr_ssbri_cri = NR_CSI_ReportConfig__groupBasedBeamReporting__disabled__nrofReportedRS_n1;
+
+        for (ssb_idx = 0; ssb_idx <= sched_ctrl->CSI_report[UE_id][idx].choice.ssb_cri_report.nr_ssbri_cri ; ssb_idx++) {
+          /** From Table 6.3.1.1.2-3: RI, LI, CQI, and CRI of codebookType=typeI-SinglePanel */
+          sched_ctrl->CSI_report[UE_id][idx].choice.ssb_cri_report.CRI_SSBRI [ssb_idx] = (*payload) & ~(~1<<(bitlen_ssbri-1));
+          *payload >>= bitlen_ssbri;
+        }
+
+        sched_ctrl->CSI_report[UE_id][idx].choice.ssb_cri_report.RSRP = (*payload) & 0x7f;
+
+        for ( diff_rsrp_idx =0; diff_rsrp_idx <= sched_ctrl->CSI_report[UE_id][idx].choice.ssb_cri_report.nr_ssbri_cri - 1; diff_rsrp_idx++ ) {
+          sched_ctrl->CSI_report[UE_id][idx].choice.ssb_cri_report.diff_RSRP[diff_rsrp_idx] = (*payload) & 0x0f;
+          *payload >>= 4;
+        }
+
+      } else if (NR_CSI_ReportConfig__groupBasedBeamReporting_PR_disabled !=
+                 csi_MeasConfig->csi_ReportConfigToAddModList->list.array[0]->groupBasedBeamReporting.present ) {
+          sched_ctrl->CSI_report[UE_id][idx].choice.ssb_cri_report.nr_ssbri_cri = 2;
+        for (ssb_idx = 0; ssb_idx < 2; ssb_idx++) {
+          /** From Table 6.3.1.1.2-3: RI, LI, CQI, and CRI of codebookType=typeI-SinglePanel */
+          sched_ctrl->CSI_report[UE_id][idx].choice.ssb_cri_report.CRI_SSBRI[ssb_idx] = (*payload) & ~(~1<<(bitlen_ssbri-1));
+          *payload >>= bitlen_ssbri;
+        }
+
+        sched_ctrl->CSI_report[UE_id][idx].choice.ssb_cri_report.RSRP = (*payload) & 0x7f;
+        /** From Table 6.3.1.1.2-3: RI, LI, CQI, and CRI of codebookType=typeI-SinglePanel */
+        sched_ctrl->CSI_report[UE_id][idx].choice.ssb_cri_report.diff_RSRP[0] = (*payload) & 0x0f;
+        *payload >>= 4;
+      }
+    }
+  }
+
+#if 0
+
+  if ( NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_PMI_CQI == reportQuantity_type ||
+       NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_i1 == reportQuantity_type ||
+       NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_i1_CQI == reportQuantity_type ||
+       NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_CQI == reportQuantity_type ||
+       NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_LI_PMI_CQI== reportQuantity_type) {
+    // Handling of extracting cri
+    sched_ctrl->CSI_report[UE_id][cqi_idx].choice.cri_ri_li_pmi_cqi_report.cri = calloc ( 1, ceil(bitlen_cri/8));
+    *(sched_ctrl->CSI_report[UE_id][cqi_idx].choice.cri_ri_li_pmi_cqi_report.cri) = *((uint32_t *)payload) & ~(~1<<(bitlen_cri-1));
+    *payload >>= bitlen_cri;
+
+    if ( 1 == RC.nrrrc[gnb_mod_idP]->carrier.pdsch_AntennaPorts ) {
+      /** From Table 6.3.1.1.2-3: RI, LI, CQI, and CRI of codebookType=typeI-SinglePanel */
+      sched_ctrl->CSI_report[UE_id][cqi_idx].choice.cri_ri_li_pmi_cqi_report->ri = NULL;
+    } else {
+      //Handling for the ri for multiple csi ports
+    }
+  }
+
+  if (NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_LI_PMI_CQI== reportQuantity_type) {
+    if ( 1 == RC.nrrrc[gnb_mod_idP]->carrier.pdsch_AntennaPorts )
+      /** From Table 6.3.1.1.2-3: RI, LI, CQI, and CRI of codebookType=typeI-SinglePanel */
+      sched_ctrl->CSI_report[UE_id][cqi_idx].choice.cri_ri_li_pmi_cqi_report->li = NULL;
+    else {
+      //Handle for li for multiple CSI ports
+    }
+  }
+
+  //TODO: check for zero padding if available shift payload to the number of zero padding bits
+
+  if ( NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_PMI_CQI == reportQuantity_type ||
+       NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_LI_PMI_CQI== reportQuantity_type) {
+    if ( 1 == RC.nrrrc[gnb_mod_idP]->carrier.pdsch_AntennaPorts ) {
+      /** From Table 6.3.1.1.2-3: RI, LI, CQI, and CRI of codebookType=typeI-SinglePanel */
+      sched_ctrl->CSI_report[UE_id][cqi_idx].choice.cri_ri_li_pmi_cqi_report->pmi_x1 = NULL;
+      sched_ctrl->CSI_report[UE_id][cqi_idx].choice.cri_ri_li_pmi_cqi_report->pmi_x2 = NULL;
+    }
+  }
+
+  if ( NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_PMI_CQI == reportQuantity_type ||
+       NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_i1_CQI == reportQuantity_type ||
+       NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_CQI == reportQuantity_type ||
+       NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_LI_PMI_CQI== reportQuantity_type) {
+    /** From Table 6.3.1.1.2-3: RI, LI, CQI, and CRI of codebookType=typeI-SinglePanel */
+    *(sched_ctrl->CSI_report[UE_id][cqi_idx].choice.cri_ri_li_pmi_cqi_report->cqi) = *(payload) & 0x0f;
+    *(payload) >>= 4;
+  }
+
+#endif
+}
 
 void handle_nr_uci(NR_UL_IND_t *UL_info, NR_UE_sched_ctrl_t *sched_ctrl) {
   // TODO
   int max_harq_rounds = 4; // TODO define macro
   int num_ucis = UL_info->uci_ind.num_ucis;
   nfapi_nr_uci_t *uci_list = UL_info->uci_ind.uci_list;
+  uint8_t UE_id = 0;
 
   for (int i = 0; i < num_ucis; i++) {
     switch (uci_list[i].pdu_type) {
@@ -90,6 +274,12 @@ void handle_nr_uci(NR_UL_IND_t *UL_info, NR_UE_sched_ctrl_t *sched_ctrl) {
           nfapi_nr_uci_pucch_pdu_format_0_1_t *uci_pdu = &uci_list[i].pucch_pdu_format_0_1;
           // handle harq
           int harq_idx_s = 0;
+
+        if ( uci_pdu->sr->sr_indication && !(uci_pdu->sr->sr_confidence_level)) {
+          sched_ctrl->sr_req.nr_of_srs =1;
+          sched_ctrl->sr_req.ul_SR[0] = 1;
+        }
+
           // iterate over received harq bits
           for (int harq_bit = 0; harq_bit < uci_pdu->harq->num_harq; harq_bit++) {
             // search for the right harq process
@@ -122,7 +312,78 @@ void handle_nr_uci(NR_UL_IND_t *UL_info, NR_UE_sched_ctrl_t *sched_ctrl) {
         break;
       }
 
-      case NFAPI_NR_UCI_FORMAT_2_3_4_PDU_TYPE: break;
+      case NFAPI_NR_UCI_FORMAT_2_3_4_PDU_TYPE: {
+        nfapi_nr_uci_pucch_pdu_format_2_3_4_t *uci_pdu = &uci_list[i].pucch_pdu_format_2_3_4;
+        module_id_t Mod_idP = UL_info -> module_id;
+        NR_CSI_MeasConfig_t *csi_MeasConfig = RC.nrmac[Mod_idP]->UE_list.secondaryCellGroup[UE_id]->spCellConfig->spCellConfigDedicated->csi_MeasConfig->choice.setup;
+
+        if ( uci_pdu -> pduBitmap & 0x01 ) {
+          ///Handle SR PDU
+          uint8_t sr_id = 0;
+          uint8_t payload_size = ceil(uci_pdu->sr.sr_bit_len/8);
+          uint8_t *payload = calloc (payload_size, sizeof (uint8_t));
+          memcpy (payload, uci_pdu->sr.sr_payload, payload_size);
+
+          for (sr_id = 0; sr_id < uci_pdu->sr.sr_bit_len; sr_id++) {
+            sched_ctrl->sr_req.ul_SR[sr_id] = *payload & 1;
+            *payload >>= 1;
+          }
+
+          sched_ctrl->sr_req.nr_of_srs = uci_pdu->sr.sr_bit_len;
+        }
+
+        if (uci_pdu -> pduBitmap & 0x02) {
+          ///Hadle Harq
+          int harq_idx_s = 0;
+
+          // iterate over received harq bits
+          for (int harq_bit = 0; harq_bit < uci_pdu->harq.harq_bit_len; harq_bit++) {
+            // search for the right harq process
+            for (int harq_idx = harq_idx_s; harq_idx < NR_MAX_NB_HARQ_PROCESSES-1; harq_idx++) {
+              if ((UL_info->slot-1) == sched_ctrl->harq_processes[harq_idx].feedback_slot) {
+                if ((*(uci_pdu->harq.harq_payload)&(1<<harq_bit)) == 0)
+                  sched_ctrl->harq_processes[harq_idx].round++;
+
+                if (((*(uci_pdu->harq.harq_payload) & (1 << harq_bit)) == 1) ||
+                    (sched_ctrl->harq_processes[harq_idx].round == max_harq_rounds)) {
+                  sched_ctrl->harq_processes[harq_idx].ndi ^= 1;
+                  sched_ctrl->harq_processes[harq_idx].round = 0;
+                }
+
+                sched_ctrl->harq_processes[harq_idx].is_waiting = 0;
+                harq_idx_s = harq_idx + 1;
+                break;
+              }
+              // if gNB fails to receive a ACK/NACK
+              else if (((UL_info->slot-1) > sched_ctrl->harq_processes[harq_idx].feedback_slot) &&
+                       (sched_ctrl->harq_processes[harq_idx].is_waiting)) {
+                sched_ctrl->harq_processes[harq_idx].round++;
+
+                if (sched_ctrl->harq_processes[harq_idx].round == max_harq_rounds) {
+                  sched_ctrl->harq_processes[harq_idx].ndi ^= 1;
+                  sched_ctrl->harq_processes[harq_idx].round = 0;
+                }
+
+                sched_ctrl->harq_processes[harq_idx].is_waiting = 0;
+              }
+            }
+          }
+        }
+
+        if (uci_pdu -> pduBitmap & 0x04) {
+          int bwp_id =1;
+          NR_BWP_Uplink_t *ubwp=RC.nrmac[Mod_idP]->UE_list.secondaryCellGroup[UE_id]->spCellConfig->spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList->list.array[bwp_id-1];
+          NR_SubcarrierSpacing_t scs=ubwp->bwp_Common->genericParameters.subcarrierSpacing;
+          //API to parse the csi report and store it into sched_ctrl
+          extract_pucch_csi_report (csi_MeasConfig, uci_pdu, sched_ctrl,UL_info->frame, UL_info->slot, scs);
+        }
+
+        if (uci_pdu -> pduBitmap & 0x08) {
+          ///Handle CSI Report 2
+        }
+
+        break;
+      }
     }
   }