From 97db12c9f23e17bcd1f73748b7b08a967b2f5d15 Mon Sep 17 00:00:00 2001
From: Navid Nikaein <navid.nikaein@eurecom.fr>
Date: Sun, 15 Jan 2017 20:28:07 +0100
Subject: [PATCH] better setting of aggregation level as a function of cqi and
 bw

---
 openair2/LAYER2/MAC/defs.h                    |  4 ++
 openair2/LAYER2/MAC/eNB_scheduler.c           | 10 +--
 openair2/LAYER2/MAC/eNB_scheduler_dlsch.c     | 24 ++++---
 .../LAYER2/MAC/eNB_scheduler_primitives.c     | 70 +++++++++++++++++--
 openair2/LAYER2/MAC/eNB_scheduler_ulsch.c     |  9 ++-
 openair2/LAYER2/MAC/extern.h                  |  6 ++
 .../MAC/flexran_agent_scheduler_dlsch_ue.c    | 13 ++--
 openair2/LAYER2/MAC/pre_processor.c           |  3 +-
 openair2/LAYER2/MAC/proto.h                   |  6 +-
 openair2/LAYER2/MAC/vars.h                    | 30 ++++++++
 10 files changed, 145 insertions(+), 30 deletions(-)

diff --git a/openair2/LAYER2/MAC/defs.h b/openair2/LAYER2/MAC/defs.h
index 15c0f3fb0e8..67742de4acd 100644
--- a/openair2/LAYER2/MAC/defs.h
+++ b/openair2/LAYER2/MAC/defs.h
@@ -132,6 +132,10 @@
 #define MIN_CQI_VALUE  0
 /*!\brief maximum value for channel quality indicator */
 #define MAX_CQI_VALUE  15
+/*!\briefmaximum number of supported bandwidth (1.4, 5, 10, 20 MHz) */
+#define MAX_SUPPORTED_BW  4  
+/*!\brief CQI values range from 1 to 15 (4 bits) */
+#define CQI_VALUE_RANGE 16 
 
 /*!\brief value for indicating BSR Timer is not running */
 #define MAC_UE_BSR_TIMER_NOT_RUNNING   (0xFFFF)
diff --git a/openair2/LAYER2/MAC/eNB_scheduler.c b/openair2/LAYER2/MAC/eNB_scheduler.c
index c5dc8c88b04..47971debda2 100644
--- a/openair2/LAYER2/MAC/eNB_scheduler.c
+++ b/openair2/LAYER2/MAC/eNB_scheduler.c
@@ -104,6 +104,8 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag,
   rnti_t rnti;
   void         *DLSCH_dci=NULL;
   int size_bits=0,size_bytes=0;
+  
+  LTE_eNB_UE_stats  *eNB_UE_stats   = NULL;
 
 #if defined(FLEXRAN_AGENT_SB_IF)
   Protocol__FlexranMessage *msg;
@@ -140,9 +142,9 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag,
     eNB_mac_inst[module_idP].UE_list.UE_sched_ctrl[i].ul_inactivity_timer++;
 
     eNB_mac_inst[module_idP].UE_list.UE_sched_ctrl[i].cqi_req_timer++;
-    
+    eNB_UE_stats = mac_xface->get_eNB_UE_stats(module_idP,CC_id,rnti);
 
-    if (mac_xface->get_eNB_UE_stats(module_idP, CC_id, rnti)==NULL) {
+    if (eNB_UE_stats==NULL) {
 	//mac_remove_ue(module_idP, i, frameP, subframeP);
       //Inform the controller about the UE deactivation. Should be moved to RRC agent in the future
 #if defined(FLEXRAN_AGENT_SB_IF)
@@ -237,8 +239,8 @@ void eNB_dlsch_ulsch_scheduler(module_id_t module_idP,uint8_t cooperation_flag,
 	  add_ue_spec_dci(DCI_pdu[CC_id],
 			  DLSCH_dci,
 			  rnti,
-			    size_bytes,
-			  process_ue_cqi (module_idP,i),//aggregation,
+			  size_bytes,
+			  get_aggregation(get_bw_index(module_idP,CC_id),eNB_UE_stats->DL_cqi[0],format1A),
 			  size_bits,
 			  format1A,
 			  0);
diff --git a/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c b/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c
index 573a3401b0d..33b9aea9798 100644
--- a/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c
+++ b/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c
@@ -461,7 +461,7 @@ schedule_ue_spec(
   VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_SCHEDULE_DLSCH,VCD_FUNCTION_IN);
 
   //weight = get_ue_weight(module_idP,UE_id);
-  aggregation = 1; // set to the maximum aggregation level
+  aggregation = 2; 
 
   for (CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) {
     min_rb_unit[CC_id]=get_min_rb_unit(module_idP,CC_id);
@@ -518,7 +518,11 @@ schedule_ue_spec(
         //  mac_xface->macphy_exit("[MAC][eNB] Cannot find eNB_UE_stats\n");
         continue_flag=1;
       }
-
+      
+      aggregation = get_aggregation(get_bw_index(module_idP,CC_id), 
+				    eNB_UE_stats->DL_cqi[0],
+				    format1);
+      
       if ((ue_sched_ctl->pre_nb_available_rbs[CC_id] == 0) ||  // no RBs allocated 
 	  CCE_allocation_infeasible(module_idP,CC_id,0,subframeP,aggregation,rnti)
 	  ) {
@@ -628,9 +632,6 @@ schedule_ue_spec(
           }
 
           nb_available_rb -= nb_rb;
-          aggregation = process_ue_cqi(module_idP,UE_id);
-
-
           PHY_vars_eNB_g[module_idP][CC_id]->mu_mimo_mode[UE_id].pre_nb_available_rbs = nb_rb;
           PHY_vars_eNB_g[module_idP][CC_id]->mu_mimo_mode[UE_id].dl_pow_off = ue_sched_ctl->dl_pow_off[CC_id];
 
@@ -1118,8 +1119,7 @@ schedule_ue_spec(
           T(T_ENB_MAC_UE_DL_PDU_WITH_DATA, T_INT(module_idP), T_INT(CC_id), T_INT(rnti), T_INT(frameP), T_INT(subframeP),
             T_INT(harq_pid), T_BUFFER(UE_list->DLSCH_pdu[CC_id][0][UE_id].payload[0], TBS));
 
-          aggregation = process_ue_cqi(module_idP,UE_id);
-          UE_list->UE_template[CC_id][UE_id].nb_rb[harq_pid] = nb_rb;
+	  UE_list->UE_template[CC_id][UE_id].nb_rb[harq_pid] = nb_rb;
 
           add_ue_dlsch_info(module_idP,
                             CC_id,
@@ -1517,7 +1517,8 @@ fill_DLSCH_dci(
   eNB_MAC_INST *eNB  =&eNB_mac_inst[module_idP];
   UE_list_t    *UE_list = &eNB->UE_list;
   //RA_TEMPLATE  *RA_template;
-
+  LTE_eNB_UE_stats  *eNB_UE_stats   = NULL;
+  
   start_meas(&eNB->fill_DLSCH_dci);
   VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_FILL_DLSCH_DCI,VCD_FUNCTION_IN);
 
@@ -1544,6 +1545,7 @@ fill_DLSCH_dci(
         nb_rb = UE_list->UE_template[CC_id][UE_id].nb_rb[harq_pid];
 
         DLSCH_dci = (void *)UE_list->UE_template[CC_id][UE_id].DLSCH_DCI[harq_pid];
+	eNB_UE_stats = mac_xface->get_eNB_UE_stats(module_idP,CC_id,rnti);
 
 
         /// Synchronizing rballoc with rballoc_sub
@@ -1643,7 +1645,7 @@ fill_DLSCH_dci(
                           DLSCH_dci,
                           rnti,
                           size_bytes,
-                          process_ue_cqi (module_idP,UE_id),//aggregation,
+                          get_aggregation(get_bw_index(module_idP,CC_id),eNB_UE_stats->DL_cqi[0],format1),
                           size_bits,
                           format1,
                           0);
@@ -1736,8 +1738,8 @@ fill_DLSCH_dci(
                           DLSCH_dci,
                           rnti,
                           size_bytes,
-                          process_ue_cqi (module_idP,UE_id),//aggregation,
-                          size_bits,
+			  get_aggregation(get_bw_index(module_idP,CC_id),eNB_UE_stats->DL_cqi[0],format2A),
+			  size_bits,
                           format2A,
                           0);
 
diff --git a/openair2/LAYER2/MAC/eNB_scheduler_primitives.c b/openair2/LAYER2/MAC/eNB_scheduler_primitives.c
index ffd9630648d..28b4da7ff61 100644
--- a/openair2/LAYER2/MAC/eNB_scheduler_primitives.c
+++ b/openair2/LAYER2/MAC/eNB_scheduler_primitives.c
@@ -182,11 +182,41 @@ uint8_t find_active_UEs(module_id_t module_idP,int CC_id){
 */
 
 
-// get aggregatiob form phy for a give UE
-unsigned char process_ue_cqi (module_id_t module_idP, int ue_idP)
+// get aggregation (L) form phy for a give UE
+unsigned char get_aggregation (uint8_t bw_index, uint8_t cqi, uint8_t dci_fmt)
 {
-  unsigned char aggregation=1;
-  // check the MCS and SNR and set the aggregation accordingly
+  unsigned char aggregation=3;
+  
+  switch (dci_fmt){
+    
+  case format0:
+    aggregation = cqi2fmt0_agg[bw_index][cqi];
+    break;
+  case format1:
+  case format1A:
+  case format1B:
+  case format1D:
+    aggregation = cqi2fmt1x_agg[bw_index][cqi]; 
+    break;
+  case format2:
+  case format2A:
+  case format2B:
+  case format2C:
+  case format2D:
+    aggregation = cqi2fmt2x_agg[bw_index][cqi]; 
+    break;
+  case format1C:
+  case format1E_2A_M10PRB:
+  case format3:
+  case format3A:
+  case format4:
+  default:
+    LOG_W(MAC,"unsupported DCI format %d\n",dci_fmt);
+  }
+
+   LOG_D(MAC,"Aggregation level %d (cqi %d, bw_index %d, format %d)\n", 
+   	1<<aggregation, cqi,bw_index,dci_fmt);
+   
   return aggregation;
 }
 #ifdef CBA
@@ -766,6 +796,38 @@ uint32_t allocate_prbs(int UE_id,unsigned char nb_rb, uint32_t *rballoc)
   return(rballoc_dci);
 }
 
+int get_bw_index(module_id_t module_id, uint8_t CC_id)
+{
+
+  int bw_index=0;
+  LTE_DL_FRAME_PARMS* frame_parms = mac_xface->get_lte_frame_parms(module_id,CC_id);
+
+  switch (frame_parms->N_RB_DL) {
+  case 6: // 1.4 MHz
+    bw_index=0;
+    break;
+
+  case 25: // 5HMz
+    bw_index=1;
+    break;
+
+  case 50: // 10HMz
+    bw_index=2;
+    break;
+
+  case 100: // 20HMz
+    bw_index=3;
+    break;
+
+  default:
+    bw_index=1;
+    LOG_W(MAC,"[eNB %d] N_DL_RB %d unknown for CC_id %d, setting bw_index to 1\n", module_id, CC_id);
+    break;
+  }
+
+  return bw_index;
+}
+
 int get_min_rb_unit(module_id_t module_id, uint8_t CC_id)
 {
 
diff --git a/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c b/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c
index c37224fbfb8..da202dd3974 100644
--- a/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c
+++ b/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c
@@ -729,8 +729,7 @@ void schedule_ulsch_rnti(module_id_t   module_idP,
   ulsch_scheduler_pre_processor(module_idP,
                                 frameP,
                                 subframeP,
-                                first_rb,
-                                aggregation);
+                                first_rb);
 
   //  LOG_I(MAC,"exiting ulsch preprocesor\n");
 
@@ -767,9 +766,14 @@ void schedule_ulsch_rnti(module_id_t   module_idP,
       if (drop_ue==1)
 	continue;
 
+      aggregation=get_aggregation(get_bw_index(module_idP,CC_id), 
+				  eNB_UE_stats->DL_cqi[0],
+				  format0);
       if (CCE_allocation_infeasible(module_idP,CC_id,0,subframeP,aggregation,rnti)) {
         LOG_W(MAC,"[eNB %d] frame %d subframe %d, UE %d/%x CC %d: not enough nCCE\n", module_idP,frameP,subframeP,UE_id,rnti,CC_id);
         continue; // break;
+      } else{
+	LOG_D(MAC,"[eNB %d] frame %d subframe %d, UE %d/%x CC %d: aggregation level %d\n", module_idP,frameP,subframeP,UE_id,rnti,CC_id, 1<<aggregation);
       }
 
 
@@ -800,7 +804,6 @@ void schedule_ulsch_rnti(module_id_t   module_idP,
 		UE_sched_ctrl->ul_failure_timer);
           // reset the scheduling request
           UE_template->ul_SR = 0;
-          aggregation = process_ue_cqi(module_idP,UE_id); 
           status = mac_eNB_get_rrc_status(module_idP,rnti);
 	  if (status < RRC_CONNECTED)
 	    cqi_req = 0;
diff --git a/openair2/LAYER2/MAC/extern.h b/openair2/LAYER2/MAC/extern.h
index aed8424561c..1da6fe5a696 100644
--- a/openair2/LAYER2/MAC/extern.h
+++ b/openair2/LAYER2/MAC/extern.h
@@ -50,6 +50,12 @@ extern const uint32_t BSR_TABLE[BSR_TABLE_SIZE];
 extern const uint32_t Extended_BSR_TABLE[BSR_TABLE_SIZE];
 //extern uint32_t Extended_BSR_TABLE[63];  ----currently not used 
 
+extern const uint8_t cqi2fmt0_agg[MAX_SUPPORTED_BW][CQI_VALUE_RANGE];
+
+extern const uint8_t cqi2fmt1x_agg[MAX_SUPPORTED_BW][CQI_VALUE_RANGE];
+
+extern const uint8_t cqi2fmt2x_agg[MAX_SUPPORTED_BW][CQI_VALUE_RANGE];
+
 extern UE_MAC_INST *UE_mac_inst;
 extern eNB_MAC_INST *eNB_mac_inst;
 extern eNB_RRC_INST *eNB_rrc_inst;
diff --git a/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue.c b/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue.c
index 8975465e77b..5bdc675198c 100644
--- a/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue.c
+++ b/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue.c
@@ -125,7 +125,7 @@ flexran_schedule_ue_spec_default(mid_t   mod_id,
   VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_SCHEDULE_DLSCH,VCD_FUNCTION_IN);
 
   //weight = get_ue_weight(module_idP,UE_id);
-  aggregation = 2; // set to the maximum aggregation level
+  aggregation = 2; 
 
   for (CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) {
     min_rb_unit[CC_id] = get_min_rb_unit(mod_id, CC_id);
@@ -177,7 +177,11 @@ flexran_schedule_ue_spec_default(mid_t   mod_id,
         //  mac_xface->macphy_exit("[MAC][eNB] Cannot find eNB_UE_stats\n");
         continue;
       }
-
+      
+      aggregation = get_aggregation(get_bw_index(mod_id,CC_id), 
+				    flexran_get_ue_wcqi(mod_id, UE_id),
+				    format1);
+      
       if ((ue_sched_ctl->pre_nb_available_rbs[CC_id] == 0) ||  // no RBs allocated 
 	  CCE_allocation_infeasible(mod_id, CC_id, 0, subframe, aggregation, rnti)) {
         LOG_D(MAC,"[eNB %d] Frame %d : no RB allocated for UE %d on CC_id %d: continue \n",
@@ -290,7 +294,6 @@ flexran_schedule_ue_spec_default(mid_t   mod_id,
 	  }
 
 	  nb_available_rb -= nb_rb;
-	  aggregation = process_ue_cqi(mod_id, UE_id);
 	  
 	  PHY_vars_eNB_g[mod_id][CC_id]->mu_mimo_mode[UE_id].pre_nb_available_rbs = nb_rb;
 	  PHY_vars_eNB_g[mod_id][CC_id]->mu_mimo_mode[UE_id].dl_pow_off = ue_sched_ctl->dl_pow_off[CC_id];
@@ -489,7 +492,9 @@ flexran_schedule_ue_spec_default(mid_t   mod_id,
 	  dci_tbs = TBS;
 	  mcs = mcs_tmp;
 
-	  aggregation = process_ue_cqi(mod_id,UE_id);
+	  aggregation = get_aggregation(get_bw_index(mod_id,CC_id), 
+				    flexran_get_ue_wcqi(mod_id, UE_id),
+				    format1);
 	  dl_dci->has_aggr_level = 1;
 	  dl_dci->aggr_level = aggregation;
 	  
diff --git a/openair2/LAYER2/MAC/pre_processor.c b/openair2/LAYER2/MAC/pre_processor.c
index ed12d322c10..e75e9d617a5 100644
--- a/openair2/LAYER2/MAC/pre_processor.c
+++ b/openair2/LAYER2/MAC/pre_processor.c
@@ -919,8 +919,7 @@ void dlsch_scheduler_pre_processor_allocate (module_id_t   Mod_id,
 void ulsch_scheduler_pre_processor(module_id_t module_idP,
                                    int frameP,
                                    sub_frame_t subframeP,
-                                   uint16_t *first_rb,
-                                   uint8_t aggregation)
+                                   uint16_t *first_rb)
 {
 
   int16_t            i;
diff --git a/openair2/LAYER2/MAC/proto.h b/openair2/LAYER2/MAC/proto.h
index 5da2367cefa..1f794c0275c 100644
--- a/openair2/LAYER2/MAC/proto.h
+++ b/openair2/LAYER2/MAC/proto.h
@@ -320,7 +320,7 @@ rnti_t      UE_RNTI           (module_id_t module_idP, int UE_id);
 int         UE_PCCID          (module_id_t module_idP, int UE_id);
 uint8_t     find_active_UEs   (module_id_t module_idP);
 boolean_t   is_UE_active      (module_id_t module_idP, int UE_id);
-uint8_t     process_ue_cqi    (module_id_t module_idP, int UE_id);
+uint8_t     get_aggregation   (uint8_t bw_index, uint8_t cqi, uint8_t dci_fmt);
 
 int8_t find_active_UEs_with_traffic(module_id_t module_idP);
 
@@ -531,7 +531,7 @@ int UE_PCCID(module_id_t mod_idP,int ue_idP);
 rnti_t UE_RNTI(module_id_t mod_idP, int ue_idP);
 
 
-void ulsch_scheduler_pre_processor(module_id_t module_idP, int frameP, sub_frame_t subframeP, uint16_t *first_rb, uint8_t  aggregattion);
+void ulsch_scheduler_pre_processor(module_id_t module_idP, int frameP, sub_frame_t subframeP, uint16_t *first_rb);
 void store_ulsch_buffer(module_id_t module_idP, int frameP, sub_frame_t subframeP);
 void sort_ue_ul (module_id_t module_idP,int frameP, sub_frame_t subframeP);
 void assign_max_mcs_min_rb(module_id_t module_idP,int frameP, sub_frame_t subframeP,uint16_t *first_rb);
@@ -696,6 +696,8 @@ uint32_t allocate_prbs_sub(int nb_rb, uint8_t *rballoc);
 
 void update_ul_dci(module_id_t module_idP,uint8_t CC_id,rnti_t rnti,uint8_t dai);
 
+int get_bw_index(module_id_t module_id, uint8_t CC_id);
+
 int get_min_rb_unit(module_id_t module_idP, uint8_t CC_id);
 
 /* \brief Generate header for DL-SCH.  This function parses the desired control elements and sdus and generates the header as described
diff --git a/openair2/LAYER2/MAC/vars.h b/openair2/LAYER2/MAC/vars.h
index 236439c6e5b..edd8548e642 100644
--- a/openair2/LAYER2/MAC/vars.h
+++ b/openair2/LAYER2/MAC/vars.h
@@ -55,6 +55,36 @@ const uint32_t Extended_BSR_TABLE[BSR_TABLE_SIZE] = {0,10,13,16,19,23,29,35,43,5
                                                      1067031,1312097,1613447,1984009,2439678,3000000,
                                                      6000000};
 
+//#define MAX_SIZE_OF_AGG3   576 
+//#define MAX_SIZE_OF_AGG2   288
+//#define MAX_SIZE_OF_AGG1   144
+//#define MAX_SIZE_OF_AGG0   72
+
+/*
+ * If the CQI is low, then scheduler will use a higher aggregation level and lower aggregation level otherwise
+ * this is also dependent to transmission mode, where an offset could be defined
+ */
+// the follwoing three tables are calibrated for TXMODE 1 and 2
+const uint8_t cqi2fmt0_agg[MAX_SUPPORTED_BW][CQI_VALUE_RANGE]= { 
+  {3, 3, 3, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0}, // 1.4_DCI0_CRC_Size= 37 bits
+  //{3, 3, 3, 3, 2, 2, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0}, // 5_DCI0_CRC_SIZE = 41
+  {3, 3, 3, 3, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0}, // 5_DCI0_CRC_SIZE = 41
+  {3, 3, 3, 3, 2, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0}, // 10_DCI0_CRC_SIZE = 43
+  {3, 3, 3, 3, 2, 2, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0}   // 20_DCI0_CRC_SIZE = 44
+};
+const uint8_t cqi2fmt1x_agg[MAX_SUPPORTED_BW][CQI_VALUE_RANGE]= { 
+  {3, 3, 3, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0}, // 1.4_DCI0_CRC_Size < 38 bits
+  {3, 3, 3, 3, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0}, // 5_DCI0_CRC_SIZE  < 43
+  {3, 3, 3, 3, 2, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0}, // 10_DCI0_CRC_SIZE  < 47
+  {3, 3, 3, 3, 2, 2, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0}   // 20_DCI0_CRC_SIZE  < 55
+};
+const uint8_t cqi2fmt2x_agg[MAX_SUPPORTED_BW][CQI_VALUE_RANGE]= { 
+  {3, 3, 3, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0}, // 1.4_DCI0_CRC_Size= 47 bits
+  {3, 3, 3, 3, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0}, // 5_DCI0_CRC_SIZE = 55
+  {3, 3, 3, 3, 2, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0}, // 10_DCI0_CRC_SIZE = 59
+  {3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 1, 1, 1, 1, 0, 0}   // 20_DCI0_CRC_SIZE = 64
+};
+
 //uint32_t EBSR_Level[63]={0,10,13,16,19,23,29,35,43,53,65,80,98,120,147,181};
 
 MAC_xface *mac_xface;
-- 
GitLab