From 44dc8f8daa7265ab6e3667e3c5bc1254faa6ccd5 Mon Sep 17 00:00:00 2001
From: Bartosz Podrygajlo <bartosz.podrygajlo@openairinterface.org>
Date: Mon, 20 May 2024 13:39:20 +0200
Subject: [PATCH] Add google test testcases for nr_get_Pcmax.

---
 CMakeLists.txt                                |  7 +-
 openair2/LAYER2/CMakeLists.txt                |  1 +
 openair2/LAYER2/NR_MAC_UE/CMakeLists.txt      |  5 +
 openair2/LAYER2/NR_MAC_UE/mac_proto.h         | 11 ++-
 openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c  | 11 ++-
 .../LAYER2/NR_MAC_UE/nr_ue_power_procedures.c | 98 +++++++++++++------
 openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c  | 23 -----
 .../LAYER2/NR_MAC_UE/tests/CMakeLists.txt     |  6 ++
 .../tests/test_nr_ue_power_procedures.cpp     | 64 ++++++++++++
 9 files changed, 167 insertions(+), 59 deletions(-)
 create mode 100644 openair2/LAYER2/NR_MAC_UE/CMakeLists.txt
 create mode 100644 openair2/LAYER2/NR_MAC_UE/tests/CMakeLists.txt
 create mode 100644 openair2/LAYER2/NR_MAC_UE/tests/test_nr_ue_power_procedures.cpp

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 20b86b95dc9..de7e300a67b 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -463,7 +463,7 @@ add_library(f1ap
             ${F1AP_DIR}/f1ap_handlers.c
             ${F1AP_DIR}/f1ap_itti_messaging.c)
 target_include_directories(f1ap PUBLIC F1AP_DIR)
-target_link_libraries(f1ap PUBLIC asn1_f1ap)
+target_link_libraries(f1ap PUBLIC asn1_f1ap L2_NR)
 target_link_libraries(f1ap PRIVATE ngap nr_rrc HASHTABLE)
 
 # LPP
@@ -1414,7 +1414,6 @@ set (MAC_NR_SRC_UE
   ${NR_UE_MAC_DIR}/nr_ue_scheduler.c
   ${NR_UE_MAC_DIR}/nr_ue_dci_configuration.c
   ${NR_UE_MAC_DIR}/nr_ra_procedures.c
-  ${NR_UE_MAC_DIR}/nr_ue_power_procedures.c
 )
 
 set (ENB_APP_SRC
@@ -1463,7 +1462,7 @@ endif()
 
 
 add_library(MAC_UE_NR ${MAC_NR_SRC_UE})
-target_link_libraries(MAC_UE_NR PRIVATE asn1_lte_rrc_hdrs asn1_nr_rrc_hdrs)
+target_link_libraries(MAC_UE_NR PRIVATE asn1_lte_rrc_hdrs asn1_nr_rrc_hdrs PUBLIC nr_ue_power_procedures)
 
 add_library(L2_LTE ${L2_LTE_SRC})
 target_link_libraries(L2_LTE PRIVATE asn1_lte_rrc_hdrs asn1_nr_rrc_hdrs)
@@ -1517,7 +1516,7 @@ target_link_libraries(L2_UE PRIVATE asn1_lte_rrc_hdrs)
 
 add_library( NR_L2_UE ${NR_L2_SRC_UE} ${MAC_NR_SRC_UE} )
 target_link_libraries(NR_L2_UE PRIVATE f1ap nr_rlc)
-target_link_libraries(NR_L2_UE PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs nr_common)
+target_link_libraries(NR_L2_UE PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs nr_common nr_ue_power_procedures)
 
 add_library(MAC_NR_COMMON
             ${OPENAIR2_DIR}/LAYER2/NR_MAC_COMMON/nr_mac_common.c
diff --git a/openair2/LAYER2/CMakeLists.txt b/openair2/LAYER2/CMakeLists.txt
index b8bc21e78cb..9360ed7b2ba 100644
--- a/openair2/LAYER2/CMakeLists.txt
+++ b/openair2/LAYER2/CMakeLists.txt
@@ -1 +1,2 @@
 add_subdirectory(nr_rlc)
+add_subdirectory(NR_MAC_UE)
diff --git a/openair2/LAYER2/NR_MAC_UE/CMakeLists.txt b/openair2/LAYER2/NR_MAC_UE/CMakeLists.txt
new file mode 100644
index 00000000000..6589a2fda51
--- /dev/null
+++ b/openair2/LAYER2/NR_MAC_UE/CMakeLists.txt
@@ -0,0 +1,5 @@
+add_library(nr_ue_power_procedures nr_ue_power_procedures.c)
+target_link_libraries(nr_ue_power_procedures PUBLIC asn1_nr_rrc ${T_LIB} MAC_NR_COMMON nr_common)
+if (ENABLE_TESTS)
+  add_subdirectory(tests)
+endif()
diff --git a/openair2/LAYER2/NR_MAC_UE/mac_proto.h b/openair2/LAYER2/NR_MAC_UE/mac_proto.h
index a6a60fbd7f9..01f49f8319f 100644
--- a/openair2/LAYER2/NR_MAC_UE/mac_proto.h
+++ b/openair2/LAYER2/NR_MAC_UE/mac_proto.h
@@ -227,7 +227,16 @@ int nr_ue_configure_pucch(NR_UE_MAC_INST_t *mac,
                            PUCCH_sched_t *pucch,
                            fapi_nr_ul_config_pucch_pdu *pucch_pdu);
 
-int nr_get_Pcmax(NR_UE_MAC_INST_t *mac, int Qm, bool powerBoostPi2BPSK, int scs, int N_RB_UL, bool is_transform_precoding, int n_prbs, int start_prb);
+int nr_get_Pcmax(int p_Max,
+                 uint16_t nr_band,
+                 frequency_range_t frequency_range,
+                 int Qm,
+                 bool powerBoostPi2BPSK,
+                 int scs,
+                 int N_RB_UL,
+                 bool is_transform_precoding,
+                 int n_prbs,
+                 int start_prb);
 
 int get_sum_delta_pucch(NR_UE_MAC_INST_t *mac, int slot, frame_t frame);
 
diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c
index 5831bd2b113..1fc6f4b6e8a 100644
--- a/openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c
+++ b/openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c
@@ -79,7 +79,16 @@ void init_RA(NR_UE_MAC_INST_t *mac,
   int n_prbs = get_N_RA_RB(prach_scs, mac->current_UL_BWP->scs);
   int start_prb = rach_ConfigGeneric->msg1_FrequencyStart + mac->current_UL_BWP->BWPStart;
   // PRACH shall be as specified for QPSK modulated DFT-s-OFDM of equivalent RB allocation (38.101-1)
-  prach_resources->RA_PCMAX = nr_get_Pcmax(mac, 2, false, prach_scs, cfg->carrier_config.dl_grid_size[prach_scs], true, n_prbs, start_prb);
+  prach_resources->RA_PCMAX = nr_get_Pcmax(mac->p_Max,
+                                           mac->nr_band,
+                                           mac->frequency_range,
+                                           2,
+                                           false,
+                                           prach_scs,
+                                           cfg->carrier_config.dl_grid_size[prach_scs],
+                                           true,
+                                           n_prbs,
+                                           start_prb);
   prach_resources->RA_PREAMBLE_TRANSMISSION_COUNTER = 1;
   prach_resources->RA_PREAMBLE_POWER_RAMPING_COUNTER = 1;
   prach_resources->POWER_OFFSET_2STEP_RA = 0;
diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_power_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_power_procedures.c
index 3e9669775d1..e826d95e4c3 100644
--- a/openair2/LAYER2/NR_MAC_UE/nr_ue_power_procedures.c
+++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_power_procedures.c
@@ -85,16 +85,24 @@ static int get_deltatf(uint16_t nb_of_prbs,
 // -- Powerclass 3 capable UE (which is default power class unless otherwise stated)
 // -- Maximum power reduction (MPR_c) for power class 3
 // -- no additional MPR (A_MPR_c)
-int nr_get_Pcmax(NR_UE_MAC_INST_t *mac, int Qm, bool powerBoostPi2BPSK, int scs, int N_RB_UL, bool is_transform_precoding, int n_prbs, int start_prb)
+int nr_get_Pcmax(int p_Max,
+                 uint16_t nr_band,
+                 frequency_range_t frequency_range,
+                 int Qm,
+                 bool powerBoostPi2BPSK,
+                 int scs,
+                 int N_RB_UL,
+                 bool is_transform_precoding,
+                 int n_prbs,
+                 int start_prb)
 {
-  int nr_band = mac->nr_band;
-  if(mac->frequency_range == FR1) {
-
-    //TODO configure P-MAX from the upper layers according to 38.331
+  if (frequency_range == FR1) {
+    // TODO configure P-MAX from the upper layers according to 38.331
     int p_powerclass = 23; // dBm assuming poweclass 3 UE
-    int p_emax = mac->p_Max != INT_MIN ? mac->p_Max : p_powerclass;
+    int p_emax = p_Max != INT_MIN ? p_Max : p_powerclass;
     int delta_P_powerclass = 0; // for powerclass 2 needs to be changed
-    if(mac->p_Max && Qm == 1 && powerBoostPi2BPSK && (nr_band == 40 || nr_band == 41 || nr_band == 77 || nr_band == 78 || nr_band == 79)) {
+    if (p_Max && Qm == 1 && powerBoostPi2BPSK
+        && (nr_band == 40 || nr_band == 41 || nr_band == 77 || nr_band == 78 || nr_band == 79)) {
       p_emax += 3;
       delta_P_powerclass -= 3;
     }
@@ -103,54 +111,52 @@ int nr_get_Pcmax(NR_UE_MAC_INST_t *mac, int Qm, bool powerBoostPi2BPSK, int scs,
     int delta_T_IB = 0;
 
     // TODO in case of band 41 and PRB allocation within 4MHz of the upper or lower limit of the band -> delta_TC = 1.5
-    if(nr_band == 41)
+    if (nr_band == 41)
       LOG_E(NR_MAC, "Need to implement delta_TC for band 41\n");
     int delta_TC = 0;
 
     float MPR = 0;
     frame_type_t frame_type = get_frame_type(nr_band, scs);
-    if(compare_relative_ul_channel_bw(nr_band, scs, N_RB_UL, frame_type)) {
+    if (compare_relative_ul_channel_bw(nr_band, scs, N_RB_UL, frame_type)) {
       int rb_low = (n_prbs / 2) > 1 ? (n_prbs / 2) : 1;
       int rb_high = N_RB_UL - rb_low - n_prbs;
       bool is_inner_rb = start_prb >= rb_low && start_prb <= rb_high && n_prbs <= ((N_RB_UL / 2) + (N_RB_UL & 1));
       // Table 6.2.2-1 in 38.101
       switch (Qm) {
-        case 1 :
+        case 1:
           AssertFatal(false, "MPR for Pi/2 BPSK not implemented yet\n");
           break;
-        case 2 :
+        case 2:
           if (is_transform_precoding) {
-            if(!is_inner_rb)
+            if (!is_inner_rb)
               MPR = 1;
-          }
-          else {
-            if(is_inner_rb)
+          } else {
+            if (is_inner_rb)
               MPR = 1.5;
             else
               MPR = 3;
           }
           break;
-        case 4 :
+        case 4:
           if (is_transform_precoding) {
-            if(is_inner_rb)
+            if (is_inner_rb)
               MPR = 1;
             else
               MPR = 2;
-          }
-          else {
-            if(is_inner_rb)
+          } else {
+            if (is_inner_rb)
               MPR = 2;
             else
               MPR = 3;
           }
           break;
-        case 6 :
+        case 6:
           if (is_transform_precoding)
             MPR = 2.5;
           else
             MPR = 3.5;
           break;
-        case 8 :
+        case 8:
           if (is_transform_precoding)
             MPR = 4.5;
           else
@@ -170,12 +176,12 @@ int nr_get_Pcmax(NR_UE_MAC_INST_t *mac, int Qm, bool powerBoostPi2BPSK, int scs,
     if (P_MPR > total_reduction)
       total_reduction = P_MPR;
     int pcmax_high, pcmax_low;
-    if(mac->p_Max) {
+    if (p_Max) {
       pcmax_high = p_emax < (p_powerclass - delta_P_powerclass) ? p_emax : (p_powerclass - delta_P_powerclass);
-      pcmax_low = (p_emax - delta_TC) < (p_powerclass - delta_P_powerclass - total_reduction) ?
-                  (p_emax - delta_TC) : (p_powerclass - delta_P_powerclass - total_reduction);
-    }
-    else {
+      pcmax_low = (p_emax - delta_TC) < (p_powerclass - delta_P_powerclass - total_reduction)
+                      ? (p_emax - delta_TC)
+                      : (p_powerclass - delta_P_powerclass - total_reduction);
+    } else {
       pcmax_high = p_powerclass - delta_P_powerclass;
       pcmax_low = p_powerclass - delta_P_powerclass - total_reduction;
     }
@@ -183,8 +189,7 @@ int nr_get_Pcmax(NR_UE_MAC_INST_t *mac, int Qm, bool powerBoostPi2BPSK, int scs,
     int pcmax = (pcmax_low + pcmax_high) / 2;
     LOG_D(MAC, "Configured maximum output power:  %d dBm <= PCMAX %d dBm <= %d dBm \n", pcmax_low, pcmax, pcmax_high);
     return pcmax;
-  }
-  else {
+  } else {
     // FR2 TODO it is even more complex because it is radiated power
     return 23;
   }
@@ -294,7 +299,16 @@ int16_t get_pucch_tx_power_ue(NR_UE_MAC_INST_t *mac,
 
   // PUCCH shall be as specified for QPSK modulated DFT-s-OFDM of equivalent RB allocation (38.101-1)
   // TODO: P_CMAX for format 2
-  int P_CMAX = nr_get_Pcmax(mac, 2, false, mac->current_UL_BWP->scs, mac->current_UL_BWP->BWPSize, true, 1, start_prb);
+  int P_CMAX = nr_get_Pcmax(mac->p_Max,
+                            mac->nr_band,
+                            mac->frequency_range,
+                            2,
+                            false,
+                            mac->current_UL_BWP->scs,
+                            mac->current_UL_BWP->BWPSize,
+                            true,
+                            1,
+                            start_prb);
   int P_CMIN = -40; // TODO: minimum TX power, possibly 38.101-1 6.3.1
   int16_t pathloss = compute_nr_SSB_PL(mac, mac->ssb_measurements.ssb_rsrp_dBm);
 
@@ -358,3 +372,27 @@ static int get_deltatf(uint16_t nb_of_prbs,
   }
   return DELTA_TF;
 }
+
+// Returns the pathloss in dB for the active UL BWP on the selected carrier based on the DL RS associated with the PRACH transmission
+// computation according to clause 7.4 (Physical random access channel) of 3GPP TS 38.213 version 16.3.0 Release 16
+// Assumptions:
+// - PRACH transmission from a UE is not in response to a detection of a PDCCH order by the UE
+// Measurement units:
+// - referenceSignalPower:   dBm/RE (average EPRE of the resources elements that carry secondary synchronization signals in dBm)
+int16_t compute_nr_SSB_PL(NR_UE_MAC_INST_t *mac, short ssb_rsrp_dBm)
+{
+  fapi_nr_config_request_t *cfg = &mac->phy_config.config_req;
+  int referenceSignalPower = cfg->ssb_config.ss_pbch_power;
+  //TODO improve PL measurements. Probably not correct as it is.
+
+  int16_t pathloss = (int16_t)(referenceSignalPower - ssb_rsrp_dBm);
+
+  LOG_D(NR_MAC, "pathloss %d dB, referenceSignalPower %d dBm/RE (%f mW), RSRP %d dBm (%f mW)\n",
+        pathloss,
+        referenceSignalPower,
+        pow(10, referenceSignalPower/10),
+        ssb_rsrp_dBm,
+        pow(10, ssb_rsrp_dBm/10));
+
+  return pathloss;
+}
diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c
index 2a7801afb88..47464d8fb31 100644
--- a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c
+++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c
@@ -3945,26 +3945,3 @@ static void nr_ue_process_rar(NR_UE_MAC_INST_t *mac, nr_downlink_indication_t *d
   return;
 }
 
-// Returns the pathloss in dB for the active UL BWP on the selected carrier based on the DL RS associated with the PRACH transmission
-// computation according to clause 7.4 (Physical random access channel) of 3GPP TS 38.213 version 16.3.0 Release 16
-// Assumptions:
-// - PRACH transmission from a UE is not in response to a detection of a PDCCH order by the UE
-// Measurement units:
-// - referenceSignalPower:   dBm/RE (average EPRE of the resources elements that carry secondary synchronization signals in dBm)
-int16_t compute_nr_SSB_PL(NR_UE_MAC_INST_t *mac, short ssb_rsrp_dBm)
-{
-  fapi_nr_config_request_t *cfg = &mac->phy_config.config_req;
-  int referenceSignalPower = cfg->ssb_config.ss_pbch_power;
-  //TODO improve PL measurements. Probably not correct as it is.
-
-  int16_t pathloss = (int16_t)(referenceSignalPower - ssb_rsrp_dBm);
-
-  LOG_D(NR_MAC, "pathloss %d dB, referenceSignalPower %d dBm/RE (%f mW), RSRP %d dBm (%f mW)\n",
-        pathloss,
-        referenceSignalPower,
-        pow(10, referenceSignalPower/10),
-        ssb_rsrp_dBm,
-        pow(10, ssb_rsrp_dBm/10));
-
-  return pathloss;
-}
diff --git a/openair2/LAYER2/NR_MAC_UE/tests/CMakeLists.txt b/openair2/LAYER2/NR_MAC_UE/tests/CMakeLists.txt
new file mode 100644
index 00000000000..40c8c5372bf
--- /dev/null
+++ b/openair2/LAYER2/NR_MAC_UE/tests/CMakeLists.txt
@@ -0,0 +1,6 @@
+add_executable(test_nr_ue_power_procedures
+  test_nr_ue_power_procedures.cpp)
+target_link_libraries(test_nr_ue_power_procedures PRIVATE nr_ue_power_procedures GTest::gtest minimal_lib)
+add_dependencies(tests test_nr_ue_power_procedures)
+add_test(NAME test_nr_ue_power_procedures
+  COMMAND ./test_nr_ue_power_procedures)
diff --git a/openair2/LAYER2/NR_MAC_UE/tests/test_nr_ue_power_procedures.cpp b/openair2/LAYER2/NR_MAC_UE/tests/test_nr_ue_power_procedures.cpp
new file mode 100644
index 00000000000..179d94bd1b1
--- /dev/null
+++ b/openair2/LAYER2/NR_MAC_UE/tests/test_nr_ue_power_procedures.cpp
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The OpenAirInterface Software Alliance licenses this file to You under
+ * the OAI Public License, Version 1.1  (the "License"); you may not use this file
+ * except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.openairinterface.org/?page_id=698
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *-------------------------------------------------------------------------------
+ * For more information about the OpenAirInterface (OAI) Software Alliance:
+ *      contact@openairinterface.org
+ */
+
+
+#include "gtest/gtest.h"
+extern "C" {
+#include "openair2/LAYER2/NR_MAC_UE/mac_proto.h"
+#include "executables/softmodem-common.h"
+uint64_t get_softmodem_optmask(void) {return 0;}
+static softmodem_params_t softmodem_params;
+softmodem_params_t *get_softmodem_params(void) {
+  return &softmodem_params;
+
+}
+}
+#include <cstdio>
+#include "common/utils/LOG/log.h"
+
+TEST(power_procedures_fr1, test_prach_max_tx_power_mpr)
+{
+  // Inner PRB, MPR = 1.5
+  int prb_start = 4;
+  int N_RB_UL = 51; // 10Mhz
+  EXPECT_EQ(22, nr_get_Pcmax(23, 20, FR1, 2, false, 1, N_RB_UL, false, 6, prb_start));
+
+  // Outer PRB, MPR = 3
+  prb_start = 0;
+  EXPECT_EQ(21, nr_get_Pcmax(23, 20, FR1, 2, false, 1, N_RB_UL, false, 6, prb_start));
+
+  // Channel bandwidth conditon not met, no MPR
+  N_RB_UL = 106;
+  EXPECT_EQ(23, nr_get_Pcmax(23, 20, FR1, 2, false, 1, N_RB_UL, false, 6, prb_start));
+}
+
+TEST(power_procedures_fr1, test_not_implemented)
+{
+  int N_RB_UL = 51;
+  EXPECT_DEATH(nr_get_Pcmax(23, 20, FR1, 1, false, 1, N_RB_UL, false, 6, 0), "MPR for Pi/2 BPSK not implemented yet");
+}
+
+int main(int argc, char** argv)
+{
+  logInit();
+  testing::InitGoogleTest(&argc, argv);
+  return RUN_ALL_TESTS();
+}
-- 
GitLab