diff --git a/README.md b/README.md index 04cb4e8db0..b5d3dc46c0 100644 --- a/README.md +++ b/README.md @@ -43,6 +43,7 @@ Please see [NOTICE](NOTICE.md) file for third party software that is included in * [General overview of documentation](./doc/README.md) * [The implemented features](./doc/FEATURE_SET.md) + * [System Requirements for Using OAI Stack](./doc/system_requirements.md) * [How to build](./doc/BUILD.md) * [How to run the modems](./doc/RUNMODEM.md) diff --git a/ci-scripts/conf_files/gnb-du.sa.band78.106prb.usrpb200.conf b/ci-scripts/conf_files/gnb-du.sa.band78.106prb.usrpb200.conf index 3bcdcf156d..e977edd5f3 100644 --- a/ci-scripts/conf_files/gnb-du.sa.band78.106prb.usrpb200.conf +++ b/ci-scripts/conf_files/gnb-du.sa.band78.106prb.usrpb200.conf @@ -22,8 +22,9 @@ gNBs = ////////// Physical parameters: - min_rxtxtime = 6; - + min_rxtxtime = 2; + do_CSIRS = 1; + do_SRS = 1; servingCellConfigCommon = ( { @@ -183,7 +184,7 @@ L1s = ( num_cc = 1; tr_n_preference = "local_mac"; prach_dtx_threshold = 200; - pucch0_dtx_threshold = 100; + pucch0_dtx_threshold = 30; ofdm_offset_divisor = 8; #set this to UINT_MAX for offset 0 } ); @@ -193,8 +194,8 @@ RUs = ( local_rf = "yes" nb_tx = 1 nb_rx = 1 - att_tx = 0 - att_rx = 0; + att_tx = 10; + att_rx = 10; bands = [78]; max_pdschReferenceSignalPower = -27; max_rxgain = 114; diff --git a/ci-scripts/conf_files/gnb.sa.band78.106prb.usrpb200.sc-fdma.conf b/ci-scripts/conf_files/gnb.sa.band78.106prb.usrpb200.sc-fdma.conf index 725e02d615..dc5c30fe50 100644 --- a/ci-scripts/conf_files/gnb.sa.band78.106prb.usrpb200.sc-fdma.conf +++ b/ci-scripts/conf_files/gnb.sa.band78.106prb.usrpb200.sc-fdma.conf @@ -184,7 +184,7 @@ L1s = ( num_cc = 1; tr_n_preference = "local_mac"; prach_dtx_threshold = 120; - pucch0_dtx_threshold = 100; + pucch0_dtx_threshold = 30; ofdm_offset_divisor = 8; #set this to UINT_MAX for offset 0 } ); @@ -194,8 +194,8 @@ RUs = ( local_rf = "yes" nb_tx = 1 nb_rx = 1 - att_tx = 14; - att_rx = 14; + att_tx = 10; + att_rx = 10; bands = [78]; max_pdschReferenceSignalPower = -27; max_rxgain = 114; diff --git a/ci-scripts/xml_files/container_4g_rfsim_fdd_05MHz.xml b/ci-scripts/xml_files/container_4g_rfsim_fdd_05MHz.xml index a60a8e2d4d..3b0b58d8ba 100644 --- a/ci-scripts/xml_files/container_4g_rfsim_fdd_05MHz.xml +++ b/ci-scripts/xml_files/container_4g_rfsim_fdd_05MHz.xml @@ -108,14 +108,14 @@ Attach_UE Attach OAI UE (Wait for IP) rfsim4g_ue - obelix + cacofonix Ping Ping Traffic-Gen from LTE-UE rfsim4g_ue - obelix + cacofonix -c 20 192.168.61.11 5 @@ -125,7 +125,7 @@ Ping LTE-UE from Traffic-Gen rfsim4g_ext_dn -c 20 12.0.0.2 - obelix + cacofonix 5 @@ -137,8 +137,8 @@ -u -t 30 -b 2M -R 25 80 - obelix - obelix + cacofonix + cacofonix @@ -149,8 +149,8 @@ -u -t 30 -b 1M 25 80 - obelix - obelix + cacofonix + cacofonix diff --git a/ci-scripts/xml_files/container_4g_rfsim_fdd_05MHz_noS1.xml b/ci-scripts/xml_files/container_4g_rfsim_fdd_05MHz_noS1.xml index d5c67c9835..abe07fa1ce 100644 --- a/ci-scripts/xml_files/container_4g_rfsim_fdd_05MHz_noS1.xml +++ b/ci-scripts/xml_files/container_4g_rfsim_fdd_05MHz_noS1.xml @@ -86,7 +86,7 @@ Ping Ping Traffic-Gen from LTE-UE rfsim4g_ue - obelix + cacofonix -c 20 10.0.1.1 5 @@ -95,7 +95,7 @@ Ping Ping LTE-UE from eNB rfsim4g_enb_nos1 - obelix + cacofonix -c 20 10.0.1.2 5 @@ -104,9 +104,9 @@ Iperf Iperf UDP DL rfsim4g_ue - obelix + cacofonix rfsim4g_enb_nos1 - obelix + cacofonix -u -t 30 -b 2M -R 25 80 @@ -116,9 +116,9 @@ Iperf Iperf UDP UL rfsim4g_ue - obelix + cacofonix rfsim4g_enb_nos1 - obelix + cacofonix -u -t 30 -b 1M 25 80 diff --git a/ci-scripts/xml_files/container_4g_rfsim_fdd_10MHz.xml b/ci-scripts/xml_files/container_4g_rfsim_fdd_10MHz.xml index 50e53c8624..68879cc622 100644 --- a/ci-scripts/xml_files/container_4g_rfsim_fdd_10MHz.xml +++ b/ci-scripts/xml_files/container_4g_rfsim_fdd_10MHz.xml @@ -108,14 +108,14 @@ Attach_UE Attach OAI UE (Wait for IP) rfsim4g_ue - obelix + cacofonix Ping Ping Traffic-Gen from LTE-UE rfsim4g_ue - obelix + cacofonix -c 20 192.168.61.11 5 @@ -124,7 +124,7 @@ Ping Ping LTE-UE from Traffic-Gen rfsim4g_ext_dn - obelix + cacofonix -c 20 12.0.0.2 5 @@ -133,9 +133,9 @@ Iperf Iperf UDP DL rfsim4g_ue - obelix + cacofonix rfsim4g_ext_dn - obelix + cacofonix -u -t 30 -b 2M -R 25 80 @@ -145,9 +145,9 @@ Iperf Iperf UDP UL rfsim4g_ue - obelix + cacofonix rfsim4g_ext_dn - obelix + cacofonix -u -t 30 -b 1M 25 80 diff --git a/ci-scripts/xml_files/container_4g_rfsim_fdd_20MHz.xml b/ci-scripts/xml_files/container_4g_rfsim_fdd_20MHz.xml index 12bf5533ba..5a58cad5f2 100644 --- a/ci-scripts/xml_files/container_4g_rfsim_fdd_20MHz.xml +++ b/ci-scripts/xml_files/container_4g_rfsim_fdd_20MHz.xml @@ -108,14 +108,14 @@ Attach_UE Attach OAI UE (Wait for IP) rfsim4g_ue - obelix + cacofonix Ping Ping Traffic-Gen from LTE-UE rfsim4g_ue - obelix + cacofonix -c 20 192.168.61.11 5 @@ -124,7 +124,7 @@ Ping Ping LTE-UE from Traffic-Gen rfsim4g_ext_dn - obelix + cacofonix -c 20 12.0.0.2 5 @@ -133,9 +133,9 @@ Iperf Iperf UDP DL rfsim4g_ue - obelix + cacofonix rfsim4g_ext_dn - obelix + cacofonix -u -t 30 -b 2M -R 25 80 @@ -145,9 +145,9 @@ Iperf Iperf UDP UL rfsim4g_ue - obelix + cacofonix rfsim4g_ext_dn - obelix + cacofonix -u -t 30 -b 1M 25 80 diff --git a/ci-scripts/xml_files/container_4g_rfsim_fembms.xml b/ci-scripts/xml_files/container_4g_rfsim_fembms.xml index 48f740b873..e63c4fac5e 100644 --- a/ci-scripts/xml_files/container_4g_rfsim_fembms.xml +++ b/ci-scripts/xml_files/container_4g_rfsim_fembms.xml @@ -83,9 +83,9 @@ Iperf2_Unidir Iperf2 UDP DL rfsim4g_ue_fembms - obelix + cacofonix rfsim4g_enb_fembms - obelix + cacofonix -u -t 30 -b 2M 25 80 diff --git a/ci-scripts/xml_files/container_4g_rfsim_mbms.xml b/ci-scripts/xml_files/container_4g_rfsim_mbms.xml index 4abf69fb3e..c26cb06878 100644 --- a/ci-scripts/xml_files/container_4g_rfsim_mbms.xml +++ b/ci-scripts/xml_files/container_4g_rfsim_mbms.xml @@ -83,9 +83,9 @@ Iperf Iperf UDP DL rfsim4g_ue - obelix + cacofonix rfsim4g_enb_nos1 - obelix + cacofonix -u -t 30 -b 2M -R 25 80 diff --git a/ci-scripts/xml_files/container_4g_rfsim_tdd_05MHz.xml b/ci-scripts/xml_files/container_4g_rfsim_tdd_05MHz.xml index fa3c6862b7..77d9f19ee9 100644 --- a/ci-scripts/xml_files/container_4g_rfsim_tdd_05MHz.xml +++ b/ci-scripts/xml_files/container_4g_rfsim_tdd_05MHz.xml @@ -108,7 +108,7 @@ Ping Ping Traffic-Gen from LTE-UE rfsim4g_ue - obelix + cacofonix -c 20 192.168.61.11 5 @@ -117,7 +117,7 @@ Ping Ping LTE-UE from Traffic-Gen rfsim4g_ext_dn - obelix + cacofonix -c 20 12.0.0.2 5 @@ -126,9 +126,9 @@ Iperf Iperf UDP DL rfsim4g_ue - obelix + cacofonix rfsim4g_ext_dn - obelix + cacofonix -u -t 30 -b 2M -R 25 80 @@ -138,9 +138,9 @@ Iperf Iperf UDP UL rfsim4g_ue - obelix + cacofonix rfsim4g_ext_dn - obelix + cacofonix -u -t 30 -b 1M 25 80 diff --git a/ci-scripts/xml_files/container_sa_aw2s_asue.xml b/ci-scripts/xml_files/container_sa_aw2s_asue.xml index 0e4e967c52..71789cca52 100644 --- a/ci-scripts/xml_files/container_sa_aw2s_asue.xml +++ b/ci-scripts/xml_files/container_sa_aw2s_asue.xml @@ -222,7 +222,7 @@ Ping: 20pings in 20sec, multi-ue amarisoft_ue_1 amarisoft_ue_2 amarisoft_ue_3 amarisoft_ue_4 amarisoft_ue_5 amarisoft_ue_6 amarisoft_ue_7 amarisoft_ue_8 amarisoft_ue_9 amarisoft_ue_10 amarisoft_ue_11 amarisoft_ue_12 amarisoft_ue_13 amarisoft_ue_14 amarisoft_ue_15 -c 20 %cn_ip% - 1 + 5 25 diff --git a/ci-scripts/yaml_files/sa_e1_b200_gnb/docker-compose.yml b/ci-scripts/yaml_files/sa_e1_b200_gnb/docker-compose.yml index 83b8360b8f..e1893765d1 100644 --- a/ci-scripts/yaml_files/sa_e1_b200_gnb/docker-compose.yml +++ b/ci-scripts/yaml_files/sa_e1_b200_gnb/docker-compose.yml @@ -67,8 +67,6 @@ services: --RUs.[0].sdr_addrs serial=30C51D4 --continuous-tx -E --telnetsrv --telnetsrv.listenport 9091 --telnetsrv.shrmod ci - --gNBs.[0].min_rxtxtime 2 --gNBs.[0].do_CSIRS 1 --gNBs.[0].do_SRS 1 - --RUs.[0].att_rx 14 --RUs.[0].att_tx 14 --log_config.global_log_options level,nocolor,time,line_num,function devices: - /dev/bus/usb/:/dev/bus/usb/ diff --git a/common/utils/nr/nr_common.c b/common/utils/nr/nr_common.c index fafc1bcd47..09dd5e7d94 100644 --- a/common/utils/nr/nr_common.c +++ b/common/utils/nr/nr_common.c @@ -36,6 +36,79 @@ #include "nr_common.h" #include +#define C_SRS_NUMBER (64) +#define B_SRS_NUMBER (4) + +/* TS 38.211 Table 6.4.1.4.3-1: SRS bandwidth configuration */ +static const unsigned short srs_bandwidth_config[C_SRS_NUMBER][B_SRS_NUMBER][2] = { + /* B_SRS = 0 B_SRS = 1 B_SRS = 2 B_SRS = 3 */ + /* C SRS m_srs0 N_0 m_srs1 N_1 m_srs2 N_2 m_srs3 N_3 */ + /* 0 */ {{4, 1}, {4, 1}, {4, 1}, {4, 1}}, + /* 1 */ {{8, 1}, {4, 2}, {4, 1}, {4, 1}}, + /* 2 */ {{12, 1}, {4, 3}, {4, 1}, {4, 1}}, + /* 3 */ {{16, 1}, {4, 4}, {4, 1}, {4, 1}}, + /* 4 */ {{16, 1}, {8, 2}, {4, 2}, {4, 1}}, + /* 5 */ {{20, 1}, {4, 5}, {4, 1}, {4, 1}}, + /* 6 */ {{24, 1}, {4, 6}, {4, 1}, {4, 1}}, + /* 7 */ {{24, 1}, {12, 2}, {4, 3}, {4, 1}}, + /* 8 */ {{28, 1}, {4, 7}, {4, 1}, {4, 1}}, + /* 9 */ {{32, 1}, {16, 2}, {8, 2}, {4, 2}}, + /* 10 */ {{36, 1}, {12, 3}, {4, 3}, {4, 1}}, + /* 11 */ {{40, 1}, {20, 2}, {4, 5}, {4, 1}}, + /* 12 */ {{48, 1}, {16, 3}, {8, 2}, {4, 2}}, + /* 13 */ {{48, 1}, {24, 2}, {12, 2}, {4, 3}}, + /* 14 */ {{52, 1}, {4, 13}, {4, 1}, {4, 1}}, + /* 15 */ {{56, 1}, {28, 2}, {4, 7}, {4, 1}}, + /* 16 */ {{60, 1}, {20, 3}, {4, 5}, {4, 1}}, + /* 17 */ {{64, 1}, {32, 2}, {16, 2}, {4, 4}}, + /* 18 */ {{72, 1}, {24, 3}, {12, 2}, {4, 3}}, + /* 19 */ {{72, 1}, {36, 2}, {12, 3}, {4, 3}}, + /* 20 */ {{76, 1}, {4, 19}, {4, 1}, {4, 1}}, + /* 21 */ {{80, 1}, {40, 2}, {20, 2}, {4, 5}}, + /* 22 */ {{88, 1}, {44, 2}, {4, 11}, {4, 1}}, + /* 23 */ {{96, 1}, {32, 3}, {16, 2}, {4, 4}}, + /* 24 */ {{96, 1}, {48, 2}, {24, 2}, {4, 6}}, + /* 25 */ {{104, 1}, {52, 2}, {4, 13}, {4, 1}}, + /* 26 */ {{112, 1}, {56, 2}, {28, 2}, {4, 7}}, + /* 27 */ {{120, 1}, {60, 2}, {20, 3}, {4, 5}}, + /* 28 */ {{120, 1}, {40, 3}, {8, 5}, {4, 2}}, + /* 29 */ {{120, 1}, {24, 5}, {12, 2}, {4, 3}}, + /* 30 */ {{128, 1}, {64, 2}, {32, 2}, {4, 8}}, + /* 31 */ {{128, 1}, {64, 2}, {16, 4}, {4, 4}}, + /* 32 */ {{128, 1}, {16, 8}, {8, 2}, {4, 2}}, + /* 33 */ {{132, 1}, {44, 3}, {4, 11}, {4, 1}}, + /* 34 */ {{136, 1}, {68, 2}, {4, 17}, {4, 1}}, + /* 35 */ {{144, 1}, {72, 2}, {36, 2}, {4, 9}}, + /* 36 */ {{144, 1}, {48, 3}, {24, 2}, {12, 2}}, + /* 37 */ {{144, 1}, {48, 3}, {16, 3}, {4, 4}}, + /* 38 */ {{144, 1}, {16, 9}, {8, 2}, {4, 2}}, + /* 39 */ {{152, 1}, {76, 2}, {4, 19}, {4, 1}}, + /* 40 */ {{160, 1}, {80, 2}, {40, 2}, {4, 10}}, + /* 41 */ {{160, 1}, {80, 2}, {20, 4}, {4, 5}}, + /* 42 */ {{160, 1}, {32, 5}, {16, 2}, {4, 4}}, + /* 43 */ {{168, 1}, {84, 2}, {28, 3}, {4, 7}}, + /* 44 */ {{176, 1}, {88, 2}, {44, 2}, {4, 11}}, + /* 45 */ {{184, 1}, {92, 2}, {4, 23}, {4, 1}}, + /* 46 */ {{192, 1}, {96, 2}, {48, 2}, {4, 12}}, + /* 47 */ {{192, 1}, {96, 2}, {24, 4}, {4, 6}}, + /* 48 */ {{192, 1}, {64, 3}, {16, 4}, {4, 4}}, + /* 49 */ {{192, 1}, {24, 8}, {8, 3}, {4, 2}}, + /* 50 */ {{208, 1}, {104, 2}, {52, 2}, {4, 13}}, + /* 51 */ {{216, 1}, {108, 2}, {36, 3}, {4, 9}}, + /* 52 */ {{224, 1}, {112, 2}, {56, 2}, {4, 14}}, + /* 53 */ {{240, 1}, {120, 2}, {60, 2}, {4, 15}}, + /* 54 */ {{240, 1}, {80, 3}, {20, 4}, {4, 5}}, + /* 55 */ {{240, 1}, {48, 5}, {16, 3}, {8, 2}}, + /* 56 */ {{240, 1}, {24, 10}, {12, 2}, {4, 3}}, + /* 57 */ {{256, 1}, {128, 2}, {64, 2}, {4, 16}}, + /* 58 */ {{256, 1}, {128, 2}, {32, 4}, {4, 8}}, + /* 59 */ {{256, 1}, {16, 16}, {8, 2}, {4, 2}}, + /* 60 */ {{264, 1}, {132, 2}, {44, 3}, {4, 11}}, + /* 61 */ {{272, 1}, {136, 2}, {68, 2}, {4, 17}}, + /* 62 */ {{272, 1}, {68, 4}, {4, 17}, {4, 1}}, + /* 63 */ {{272, 1}, {16, 17}, {8, 2}, {4, 2}}, +}; + const char *duplex_mode[]={"FDD","TDD"}; static const uint8_t bit_reverse_table_256[] = { @@ -1212,3 +1285,11 @@ void nr_timer_setup(NR_timer_t *timer, const uint32_t target, const uint32_t ste timer->step = step; nr_timer_stop(timer); } + +unsigned short get_m_srs(int c_srs, int b_srs) { + return srs_bandwidth_config[c_srs][b_srs][0]; +} + +unsigned short get_N_b_srs(int c_srs, int b_srs) { + return srs_bandwidth_config[c_srs][b_srs][1]; +} diff --git a/common/utils/nr/nr_common.h b/common/utils/nr/nr_common.h index 1e4fecc4f5..9087f335c5 100644 --- a/common/utils/nr/nr_common.h +++ b/common/utils/nr/nr_common.h @@ -250,6 +250,8 @@ int get_scan_ssb_first_sc(const double fc, void check_ssb_raster(uint64_t freq, int band, int scs); int get_smallest_supported_bandwidth_index(int scs, frequency_range_t frequency_range, int n_rbs); +unsigned short get_m_srs(int c_srs, int b_srs); +unsigned short get_N_b_srs(int c_srs, int b_srs); #define CEILIDIV(a,b) ((a+b-1)/b) #define ROUNDIDIV(a,b) (((a<<1)+b)/(b<<1)) diff --git a/doc/ORAN_FHI7.2_Tutorial.md b/doc/ORAN_FHI7.2_Tutorial.md index a7bfe56a0b..1b74e6cdd3 100644 --- a/doc/ORAN_FHI7.2_Tutorial.md +++ b/doc/ORAN_FHI7.2_Tutorial.md @@ -26,7 +26,12 @@ The hardware on which we have tried this tutorial: |Intel(R) Xeon(R) Gold 6354 36-Core, 128GB|Ubuntu 22.04.3 LTS (5.15.0-1033-realtime) |Intel X710, i40e, 9.00 0x8000cfeb 21.5.9 | |AMD EPYC 9374F 32-Core Processor, 128GB |Ubuntu 22.04.2 LTS (5.15.0-1038-realtime) |Intel E810 ,ice, 4.00 0x8001184e 1.3236.0| -**NOTE**: These are not minimum hardware requirements. This is the configuration of our servers. The NIC card should support hardware PTP time stamping. +**NOTE**: + +- These are not minimum hardware requirements. This is the configuration of our servers. +- The NIC card should support hardware PTP time stamping. +- If you are using Intel servers then use only Ice Lake or newer generations. In case of AMD use only 4th generation, Genoa or newer. +- If you try on any other server apart from the above listed, then choose a desktop/server with clock speed higher than 3.0 GHz and `avx512` capabilities. NICs we have tested so far: diff --git a/doc/clang-format.md b/doc/clang-format.md index fa751b303d..5e2f14c0b6 100644 --- a/doc/clang-format.md +++ b/doc/clang-format.md @@ -64,3 +64,7 @@ When this is done, you are set up. How to use: 6) Commit. It won't work if code is not properly formatted due to the pre-commit hook. Force committing with `git commit --no-verify` + +# Checking errors introduced by a branch + +Here is the script that can be used to detect any clang-format errors introduced by a branch [here](../tools/formatting/README.md) diff --git a/doc/system_requirements.md b/doc/system_requirements.md new file mode 100644 index 0000000000..f231f9c398 --- /dev/null +++ b/doc/system_requirements.md @@ -0,0 +1,135 @@ + + + + + + + + + + System Requirements for Using OAI Stack + + + + +This document describes the minimal and performant system requirements for OpenAirInterface (OAI) 4G/5G software stack (UE and gNB stack). The information provided in this document is based on experimentation, if you have a feedback then open an issue or send an email on the mailing list. + +**Table of Contents** + +[[_TOC_]] + +# Supported CPU Architecture + +|Architecture | +|------------------------------------------ | +|x86_64 (Intel, AMD) | +|aarch64 (Neoverse-N1, N2 and Grace hopper) | + +**Note**: + +- On `x86_64` platform the CPU should support `avx2` instruction set (Minimum requirement). + +# Supported Operating System + +|Operating System | +|-----------------| +|Ubuntu 20/22/24 | +|RHEL 9 | +|Fedora 40 | +|Debian 11 | +|Rocky 9 | + + +# Minimum Hardware Requirement for x86_64 Platforms + +The minimum hardware requirements depends on the radio unit you would like to use or the test case that you would like to execute. + +## Simulated Radio + +OAI offers an inbuilt simulated radio, [RFSimulator](../radio/rfsimulator/README.md). It can be used to familiarize oneself with OAI, for development and debugging, and offers the possibility to use basic channel models. It is not designed to do high performance testing. The below requirements are valid for both 4G and 5G RAN and UE Stack. + +The following requirements are minimum requirements for all use cases: + +### Minimum requirements for gNB Stack + +- CPU: 2 +- Minimum frequency > 2GHz +- Memory: 4Gi +- `avx2` instruction set +- `sctp` protocol should be enabled + +**NOTE**: We have not tested on Intel Atom or Celeron processors, and they +likely won't work well. + +### Minimum requirements for UE Stack + +- CPU: 2 +- Minimum frequency > 2GHz +- Memory: 3Gi +- `avx2` instruction set + +**NOTE**: We have not tested on Intel Atom or Celeron processors + +## USRP B2XX or Blade RF + +USRP B2XX or Blade RF are USB based radios recommended to use with USB 3.0. You can choose a minimum hardware to do functional testing and performance hardware for performance testing. This hardware you can find in Mini-PCs or laptops. + +The minimum requirements stated in [simulated radio](.##simulated-radio) apply. + +### Minimum requirements for both gNB and UE Stack + +- CPU: 3 +- Memory: 5Gi +- Disable CPU sleep states +- USB 3.0 +- Intel i5, AMD Ryzen 5 + +### Recommended for performance for gNB and UE Stack + +- CPU: 4 +- Boost Frequency > 3GHz +- Use only performance cores +- Disable hyper-threading +- Disable CPU sleep states +- DDR4 or DDR5 RAM, minimum 5Gi +- USB 3.0 + +Apart from this you should follow [tuning and security tips](./tuning_and_security.md) to +tune your system to get high performance. + +## USRP N3XX/X3XX/X4XX/AW2S + +USRP N3XX/X3XX/X4XX requires two dedicated 10G SFP+ connections. For these radios we only recommend having performance hardware. This hardware you can find in Desktop servers or rack/blade servers. For the gNB, the same applies in case of using AW2S radios. + +The minimum requirements stated in [simulated radio](.##simulated-radio) apply. + +Apart from this you should follow [tuning and security tips](./tuning_and_security.md) to +tune your system to get high performance. + +**NOTE**: In case you are using Mellanox NIC cards then you have to download `mlnx-ofed` and configure your NIC for performance. + +### Recommended for performance for gNB Stack + +- CPU: 8-10 +- Boost Frequency > 4GHz +- Use only performance cores +- Disable CPU sleep states +- DDR4 or DDR5 RAM, 5 Gi +- (Optional) Realtime kernel to have better Jitter statistics +- Intel x710/xx710/E-810 or Mellanox connect 5x or 6x + +### Recommended for performance for UE Stack + +- CPU: 4 +- Boost Frequency > 4GHz +- DDR4 or DDR5 RAM, 5Gi +- Use only performance cores +- Disable CPU sleep states +- (Optional) Realtime kernel to have better Jitter statistics +- Intel x710/xx710/E-810 or Mellanox connect 5x or 6x + +## O-RAN Radio Units + +We have dedicated documentation for O-RAN Radio Units. [Refer to 7.2 FH documentation](./ORAN_FHI7.2_Tutorial.md) before purchasing a Desktop server or rack/blade server. + +The minimum requirements stated in [simulated radio](.##simulated-radio) apply. diff --git a/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h b/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h index f0d9b73e63..d0d9fc9093 100644 --- a/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h +++ b/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h @@ -391,6 +391,7 @@ typedef struct { uint16_t t_srs; // SRS-Periodicity in slots [3GPP TS 38.211, Sec 6.4.1.4.4], Value: 1,2,3,4,5,8,10,16,20,32,40,64,80,160,320,640,1280,2560 uint16_t t_offset; // Slot offset value [3GPP TS 38.211, Sec 6.4.1.4.3], Value:0->2559 nfapi_nr_ue_ul_beamforming_t beamforming; + int16_t tx_power; } fapi_nr_ul_config_srs_pdu; typedef struct { diff --git a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c index fea6b930ac..7a46cd1b20 100644 --- a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c +++ b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c @@ -631,7 +631,7 @@ int nr_srs_channel_estimation( const uint8_t N_ap = 1<num_ant_ports; const uint8_t K_TC = 2<comb_size; - const uint16_t m_SRS_b = srs_bandwidth_config[srs_pdu->config_index][srs_pdu->bandwidth_index][0]; + const uint16_t m_SRS_b = get_m_srs(srs_pdu->config_index, srs_pdu->bandwidth_index); const uint16_t M_sc_b_SRS = m_SRS_b * NR_NB_SC_PER_RB/K_TC; uint8_t fd_cdm = N_ap; if (N_ap == 4 && ((K_TC == 2 && srs_pdu->cyclic_shift >= 4) || (K_TC == 4 && srs_pdu->cyclic_shift >= 6))) { diff --git a/openair1/PHY/NR_TRANSPORT/srs_rx.c b/openair1/PHY/NR_TRANSPORT/srs_rx.c index a7d975dbb7..037528b407 100644 --- a/openair1/PHY/NR_TRANSPORT/srs_rx.c +++ b/openair1/PHY/NR_TRANSPORT/srs_rx.c @@ -80,7 +80,7 @@ int nr_get_srs_signal(PHY_VARS_gNB *gNB, const uint8_t N_ap = 1<num_ant_ports; const uint8_t N_symb_SRS = 1 << srs_pdu->num_symbols; const uint8_t K_TC = 2 << srs_pdu->comb_size; - const uint16_t M_sc_b_SRS = srs_bandwidth_config[srs_pdu->config_index][srs_pdu->bandwidth_index][0] * NR_NB_SC_PER_RB/K_TC; + const uint16_t M_sc_b_SRS = get_m_srs(srs_pdu->config_index, srs_pdu->bandwidth_index) * NR_NB_SC_PER_RB / K_TC; int32_t *rx_signal; bool no_srs_signal = true; diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_demodulation.c b/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_demodulation.c index 40e8395b14..f17e309a6d 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_demodulation.c +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_demodulation.c @@ -1255,7 +1255,7 @@ static void nr_dlsch_extract_rbs(uint32_t rxdataF_sz, } static void nr_dlsch_detection_mrc(uint32_t rx_size_symbol, - short n_tx, + short nl, short n_rx, int32_t rxdataF_comp[][n_rx][rx_size_symbol * NR_SYMBOLS_PER_SLOT], int ***rho, @@ -1266,19 +1266,19 @@ static void nr_dlsch_detection_mrc(uint32_t rx_size_symbol, int length) { simde__m128i *rxdataF_comp128_0,*rxdataF_comp128_1,*dl_ch_mag128_0,*dl_ch_mag128_1,*dl_ch_mag128_0b,*dl_ch_mag128_1b,*dl_ch_mag128_0r,*dl_ch_mag128_1r; - uint32_t nb_rb_0 = length/12 + ((length%12)?1:0); + uint32_t nb_rb_0 = length / 12 + ((length % 12) ? 1 : 0); if (n_rx > 1) { - for (int aatx = 0; aatx < n_tx; aatx++) { - rxdataF_comp128_0 = (simde__m128i *)(rxdataF_comp[aatx][0] + symbol * rx_size_symbol); - dl_ch_mag128_0 = (simde__m128i *)dl_ch_mag[aatx][0]; - dl_ch_mag128_0b = (simde__m128i *)dl_ch_magb[aatx][0]; - dl_ch_mag128_0r = (simde__m128i *)dl_ch_magr[aatx][0]; + for (int l = 0; l < nl; l++) { + rxdataF_comp128_0 = (simde__m128i *)(rxdataF_comp[l][0] + symbol * rx_size_symbol); + dl_ch_mag128_0 = (simde__m128i *)dl_ch_mag[l][0]; + dl_ch_mag128_0b = (simde__m128i *)dl_ch_magb[l][0]; + dl_ch_mag128_0r = (simde__m128i *)dl_ch_magr[l][0]; for (int aarx = 1; aarx < n_rx; aarx++) { - rxdataF_comp128_1 = (simde__m128i *)(rxdataF_comp[aatx][aarx] + symbol * rx_size_symbol); - dl_ch_mag128_1 = (simde__m128i *)dl_ch_mag[aatx][aarx]; - dl_ch_mag128_1b = (simde__m128i *)dl_ch_magb[aatx][aarx]; - dl_ch_mag128_1r = (simde__m128i *)dl_ch_magr[aatx][aarx]; + rxdataF_comp128_1 = (simde__m128i *)(rxdataF_comp[l][aarx] + symbol * rx_size_symbol); + dl_ch_mag128_1 = (simde__m128i *)dl_ch_mag[l][aarx]; + dl_ch_mag128_1b = (simde__m128i *)dl_ch_magb[l][aarx]; + dl_ch_mag128_1r = (simde__m128i *)dl_ch_magr[l][aarx]; // MRC on each re of rb, both on MF output and magnitude (for 16QAM/64QAM/256 llr computation) for (int i = 0; i < nb_rb_0 * 3; i++) { @@ -1291,7 +1291,7 @@ static void nr_dlsch_detection_mrc(uint32_t rx_size_symbol, } #ifdef DEBUG_DLSCH_DEMOD for (int i = 0; i < nb_rb_0 * 3; i++) { - printf("symbol%d RB %d\n", symbol,i / 3); + printf("symbol%d RB %d\n", symbol, i / 3); rxdataF_comp128_0 = (simde__m128i *)(rxdataF_comp[0][0] + symbol * rx_size_symbol); rxdataF_comp128_1 = (simde__m128i *)(rxdataF_comp[0][n_rx] + symbol * rx_size_symbol); print_shorts("tx 1 mrc_re/mrc_Im:",(int16_t*)&rxdataF_comp128_0[i]); @@ -1675,7 +1675,7 @@ void nr_conjch0_mult_ch1(int *ch0, */ static void nr_dlsch_mmse(uint32_t rx_size_symbol, unsigned char n_rx, - unsigned char n_tx, // number of layer + unsigned char nl, // number of layer int32_t rxdataF_comp[][n_rx][rx_size_symbol * NR_SYMBOLS_PER_SLOT], int32_t dl_ch_mag[][n_rx][rx_size_symbol], int32_t dl_ch_magb[][n_rx][rx_size_symbol], @@ -1688,25 +1688,24 @@ static void nr_dlsch_mmse(uint32_t rx_size_symbol, int length, uint32_t noise_var) { - int *ch0r, *ch0c; - uint32_t nb_rb_0 = length/12 + ((length%12)?1:0); + uint32_t nb_rb_0 = length / 12 + ((length % 12) ? 1 : 0); c16_t determ_fin[12 * nb_rb_0] __attribute__((aligned(32))); ///Allocate H^*H matrix elements and sub elements - c16_t conjH_H_elements_data[n_rx][n_tx][n_tx][12 * nb_rb_0]; + c16_t conjH_H_elements_data[n_rx][nl][nl][12 * nb_rb_0]; memset(conjH_H_elements_data, 0, sizeof(conjH_H_elements_data)); - c16_t *conjH_H_elements[n_rx][n_tx][n_tx]; + c16_t *conjH_H_elements[n_rx][nl][nl]; for (int aarx = 0; aarx < n_rx; aarx++) - for (int rtx = 0; rtx < n_tx; rtx++) - for (int ctx = 0; ctx < n_tx; ctx++) + for (int rtx = 0; rtx < nl; rtx++) + for (int ctx = 0; ctx < nl; ctx++) conjH_H_elements[aarx][rtx][ctx] = conjH_H_elements_data[aarx][rtx][ctx]; //Compute H^*H matrix elements and sub elements:(1/2^log2_maxh)*conjH_H_elements - for (int rtx=0;rtx> 3); - for (int p = 0; p < n_tx; p++) { + for (int p = 0; p < nl; p++) { simde__m128i *conjH_H_128i = (simde__m128i *)conjH_H_elements[0][p][p]; for (int k = 0; k < 3 * nb_rb_0; k++) { conjH_H_128i[0] = simde_mm_add_epi32(conjH_H_128i[0], nvar_128i); @@ -1732,15 +1731,15 @@ static void nr_dlsch_mmse(uint32_t rx_size_symbol, //Compute the inverse and determinant of the H^*H matrix //Allocate the inverse matrix - c16_t *inv_H_h_H[n_tx][n_tx]; - c16_t inv_H_h_H_data[n_tx][n_tx][12 * nb_rb_0]; + c16_t *inv_H_h_H[nl][nl]; + c16_t inv_H_h_H_data[nl][nl][12 * nb_rb_0]; memset(inv_H_h_H_data, 0, sizeof(inv_H_h_H_data)); - for (int rtx = 0; rtx < n_tx; rtx++) - for (int ctx = 0; ctx < n_tx; ctx++) + for (int rtx = 0; rtx < nl; rtx++) + for (int ctx = 0; ctx < nl; ctx++) inv_H_h_H[ctx][rtx] = inv_H_h_H_data[ctx][rtx]; int fp_flag = 1;//0: float point calc 1: Fixed point calc - nr_matrix_inverse(n_tx, + nr_matrix_inverse(nl, conjH_H_elements[0], // Input matrix inv_H_h_H, // Inverse determ_fin, // determin @@ -1751,30 +1750,33 @@ static void nr_dlsch_mmse(uint32_t rx_size_symbol, // multiply Matrix inversion pf H_h_H by the rx signal vector c16_t outtemp[12 * nb_rb_0] __attribute__((aligned(32))); //Allocate rxdataF for zforcing out - c16_t rxdataF_zforcing[n_tx][12 * nb_rb_0]; + c16_t rxdataF_zforcing[nl][12 * nb_rb_0]; memset(rxdataF_zforcing, 0, sizeof(rxdataF_zforcing)); - for (int rtx=0;rtx(x))); -} - TEST(log2_approx, complete) { for (uint32_t i = 0; i < UINT32_MAX; i++) EXPECT_EQ(log2_approx(i), log2_approx_ref(i)); } +TEST(log2_approx, boundaries) +{ + for (int i = 0; i < 32; i++) { + uint32_t i2 = std::pow(2.0, i + 0.5); + EXPECT_EQ(log2_approx(i2), i) << "log2(" << i2 << ")"; + EXPECT_EQ(log2_approx(i2 + 1), i + 1) << "log2(" << i2 + 1 << ")"; + } +} + TEST(log2_approx64, boundaries) { - for (long double i = 0; i < 64; i++) { - unsigned long long i2 = std::pow(2.0L, i + 0.5L); - for (unsigned long long j = -10; j <= 10; j++) { - unsigned long long x = i2 + j; - EXPECT_EQ(log2_approx64(x), log2_approx64_ref(x)); - } + for (int i = 0; i < 64; i++) { + unsigned long long int i2 = std::pow(2.0L, i + 0.5L); + EXPECT_EQ(log2_approx64(i2), i) << "log2(" << i2 << ")"; + EXPECT_EQ(log2_approx64(i2 + 1), i + 1) << "log2(" << i2 + 1 << ")"; } } diff --git a/openair2/LAYER2/NR_MAC_COMMON/nr_mac.h b/openair2/LAYER2/NR_MAC_COMMON/nr_mac.h index f3a272330b..1dff70618e 100644 --- a/openair2/LAYER2/NR_MAC_COMMON/nr_mac.h +++ b/openair2/LAYER2/NR_MAC_COMMON/nr_mac.h @@ -577,6 +577,9 @@ typedef struct NR_UE_UL_BWP { int channel_bandwidth; // Minimum transmission power according to 38.101 6.3.1 float P_CMIN; + // SRS power control adjustment state + int h_b_f_c; + bool srs_power_control_initialized; } NR_UE_UL_BWP_t; // non-BWP serving cell configuration diff --git a/openair2/LAYER2/NR_MAC_UE/config_ue.c b/openair2/LAYER2/NR_MAC_UE/config_ue.c index fab0fb7a7c..de8fa49d48 100644 --- a/openair2/LAYER2/NR_MAC_UE/config_ue.c +++ b/openair2/LAYER2/NR_MAC_UE/config_ue.c @@ -1280,7 +1280,7 @@ static void handle_aperiodic_srs_type(struct NR_SRS_ResourceSet__resourceType__a struct NR_SRS_ResourceSet__resourceType__aperiodic__ext1__aperiodicSRS_ResourceTriggerList); } -static void setup_srsresourceset(NR_SRS_ResourceSet_t *target, NR_SRS_ResourceSet_t *source) +static void setup_srsresourceset(NR_UE_UL_BWP_t *bwp, NR_SRS_ResourceSet_t *target, NR_SRS_ResourceSet_t *source) { target->srs_ResourceSetId = source->srs_ResourceSetId; if (source->srs_ResourceIdList) @@ -1311,15 +1311,20 @@ static void setup_srsresourceset(NR_SRS_ResourceSet_t *target, NR_SRS_ResourceSe } } target->usage = source->usage; + if (source->alpha) { + bwp->h_b_f_c = 0; + } UPDATE_IE(target->alpha, source->alpha, NR_Alpha_t); - if (source->p0) + if (source->p0) { + bwp->h_b_f_c = 0; UPDATE_IE(target->p0, source->p0, long); + } if (source->pathlossReferenceRS) UPDATE_IE(target->pathlossReferenceRS, source->pathlossReferenceRS, struct NR_PathlossReferenceRS_Config); UPDATE_IE(target->srs_PowerControlAdjustmentStates, source->srs_PowerControlAdjustmentStates, long); } -static void setup_srsconfig(NR_SRS_Config_t *source, NR_SRS_Config_t *target) +static void setup_srsconfig(NR_UE_UL_BWP_t *bwp, NR_SRS_Config_t *source, NR_SRS_Config_t *target) { UPDATE_IE(target->tpc_Accumulation, source->tpc_Accumulation, long); // SRS-Resource @@ -1337,14 +1342,25 @@ static void setup_srsconfig(NR_SRS_Config_t *source, NR_SRS_Config_t *target) srs_ResourceId); } // SRS-ResourceSet - if (source->srs_ResourceSetToAddModList) { + struct NR_SRS_Config__srs_ResourceSetToAddModList *source_srs_list = source->srs_ResourceSetToAddModList; + if (source_srs_list) { if (!target->srs_ResourceSetToAddModList) target->srs_ResourceSetToAddModList = calloc(1, sizeof(*target->srs_ResourceSetToAddModList)); - ADDMOD_IE_FROMLIST_WFUNCTION(source->srs_ResourceSetToAddModList, - target->srs_ResourceSetToAddModList, - srs_ResourceSetId, - NR_SRS_ResourceSet_t, - setup_srsresourceset); + struct NR_SRS_Config__srs_ResourceSetToAddModList *target_srs_list = target->srs_ResourceSetToAddModList; + + for (int i = 0; i < source_srs_list->list.count; i++) { + long srs_resource_id = source_srs_list->list.array[i]->srs_ResourceSetId; + int j; + for (j = 0; j < target_srs_list->list.count; j++) { + if (srs_resource_id == target_srs_list->list.array[j]->srs_ResourceSetId) + break; + } + if (j == target_srs_list->list.count) { + NR_SRS_ResourceSet_t *new = calloc(1, sizeof(*new)); + ASN_SEQUENCE_ADD(&target_srs_list->list, new); + } + setup_srsresourceset(bwp, target_srs_list->list.array[j], source_srs_list->list.array[i]); + } } if (source->srs_ResourceSetToReleaseList) { RELEASE_IE_FROMLIST(source->srs_ResourceSetToReleaseList, @@ -1459,7 +1475,7 @@ static void configure_dedicated_BWP_ul(NR_UE_MAC_INST_t *mac, int bwp_id, NR_BWP if (ul_dedicated->srs_Config->present == NR_SetupRelease_SRS_Config_PR_setup) { if (!bwp->srs_Config) bwp->srs_Config = calloc(1, sizeof(*bwp->srs_Config)); - setup_srsconfig(ul_dedicated->srs_Config->choice.setup, bwp->srs_Config); + setup_srsconfig(bwp, ul_dedicated->srs_Config->choice.setup, bwp->srs_Config); } } AssertFatal(!ul_dedicated->configuredGrantConfig, "configuredGrantConfig not supported\n"); @@ -1513,6 +1529,7 @@ static void configure_common_BWP_ul(NR_UE_MAC_INST_t *mac, int bwp_id, NR_BWP_Up bwp->channel_bandwidth = get_supported_bw_mhz(mac->frequency_range, bw_index); // Minumum transmission power depends on bandwidth, precalculate it here bwp->P_CMIN = nr_get_Pcmin(bw_index); + bwp->srs_power_control_initialized = false; if (bwp_id == 0) { mac->sc_info.initial_ul_BWPSize = bwp->BWPSize; mac->sc_info.initial_ul_BWPStart = bwp->BWPStart; diff --git a/openair2/LAYER2/NR_MAC_UE/mac_defs.h b/openair2/LAYER2/NR_MAC_UE/mac_defs.h index d9c5fa2345..c913321f80 100644 --- a/openair2/LAYER2/NR_MAC_UE/mac_defs.h +++ b/openair2/LAYER2/NR_MAC_UE/mac_defs.h @@ -609,6 +609,7 @@ typedef struct NR_UE_MAC_INST_s { bool pucch_power_control_initialized; int f_b_f_c; bool pusch_power_control_initialized; + int delta_msg2; } NR_UE_MAC_INST_t; /*@}*/ diff --git a/openair2/LAYER2/NR_MAC_UE/mac_proto.h b/openair2/LAYER2/NR_MAC_UE/mac_proto.h index e2d6125145..1f53812dec 100644 --- a/openair2/LAYER2/NR_MAC_UE/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_UE/mac_proto.h @@ -240,6 +240,12 @@ int get_pusch_tx_power_ue( bool is_rar_tx_retx, bool transform_precoding); +int get_srs_tx_power_ue(NR_UE_MAC_INST_t *mac, + NR_SRS_Resource_t *srs_resource, + NR_SRS_ResourceSet_t *srs_resource_set, + int delta_srs, + bool is_configured_for_pusch_on_current_bwp); + int nr_ue_configure_pucch(NR_UE_MAC_INST_t *mac, int slot, frame_t frame, 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 36fbf3a527..70d3aacb66 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_power_procedures.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_power_procedures.c @@ -578,6 +578,7 @@ int get_pusch_tx_power_ue(NR_UE_MAC_INST_t *mac, DELTA_P_rampup = min(DELTA_P_rampup_requested, max(0, DELTA_P_rampup)); mac->f_b_f_c = DELTA_P_rampup + delta_pusch; mac->pusch_power_control_initialized = true; + mac->delta_msg2 = delta_pusch; } else { if (!((pusch_power_without_f_b_f_c + mac->f_b_f_c >= P_CMAX && delta_pusch > 0) || (pusch_power_without_f_b_f_c + mac->f_b_f_c <= P_CMIN && delta_pusch < 0))) { @@ -595,3 +596,84 @@ int get_pusch_tx_power_ue(NR_UE_MAC_INST_t *mac, f_b_f_c); return min(P_CMAX, P_O_PUSCH + M_pusch_component + alpha * pathloss + DELTA_TF + f_b_f_c); } + +int get_srs_tx_power_ue(NR_UE_MAC_INST_t *mac, + NR_SRS_Resource_t *srs_resource, + NR_SRS_ResourceSet_t *srs_resource_set, + int delta_srs, + bool is_configured_for_pusch_on_current_bwp) +{ + NR_UE_UL_BWP_t *current_UL_BWP = mac->current_UL_BWP; + AssertFatal(current_UL_BWP, "Missing configuration: need UL_BWP to calculate SRS tx power\n"); + AssertFatal(srs_resource_set->p0, "P0 mantatory present at configuration\n"); + int P_0_SRS = *srs_resource_set->p0; + + // alpha is optional, use same default as PUSCH + const float alpha_factor_table[8] = {0.0f, 0.4f, 0.5f, 0.6f, 0.7f, 0.8f, 0.9f, 1.0f}; + float alpha = srs_resource_set->alpha ? alpha_factor_table[*srs_resource_set->alpha] : 1.0f; + int m_srs_component = + 10 * log10(pow(2, current_UL_BWP->scs) * get_m_srs(srs_resource->freqHopping.c_SRS, srs_resource->freqHopping.b_SRS)); + + // The allowed MPR for SRS, PUCCH formats 0, 1, 3 and 4, and PRACH shall be as specified for QPSK modulated DFTs-OFDM of + // equivalent RB allocation. The allowed MPR for PUCCH format 2 shall be as specified for QPSK modulated CP-OFDM of equivalent RB + // allocation. + int P_CMAX = nr_get_Pcmax(mac->p_Max, + mac->nr_band, + mac->frame_type, + mac->frequency_range, + mac->current_UL_BWP->channel_bandwidth, + 2, + false, + mac->current_UL_BWP->scs, + mac->current_UL_BWP->BWPSize, + true, + get_m_srs(srs_resource->freqHopping.c_SRS, srs_resource->freqHopping.b_SRS), + 0); // TODO: Determine SRS start RB + + int16_t pathloss = compute_nr_SSB_PL(mac, mac->ssb_measurements.ssb_rsrp_dBm); + + int srs_power_without_h_b_f_c = P_0_SRS + alpha * pathloss + m_srs_component; + + // Power adjustment state + int h_b_f_c = 0; + bool use_pusch_power_adjustment_state = srs_resource_set->srs_PowerControlAdjustmentStates == NULL; + if (is_configured_for_pusch_on_current_bwp && use_pusch_power_adjustment_state) { + // Case 1: Use PUSCH power control adjustment state + h_b_f_c = mac->f_b_f_c; + } else { + // Case 2: Separate power control adjustment state + AssertFatal(srs_resource_set->srs_PowerControlAdjustmentStates == NULL + || *srs_resource_set->srs_PowerControlAdjustmentStates + != NR_SRS_ResourceSet__srs_PowerControlAdjustmentStates_sameAsFci2, + "Two PUSCH power adjustment states not supported"); + + bool is_tpc_accumulation_provided = current_UL_BWP->srs_Config != NULL && current_UL_BWP->srs_Config->tpc_Accumulation != NULL; + bool separate_pc_adjustment_state = srs_resource_set->srs_PowerControlAdjustmentStates + && *srs_resource_set->srs_PowerControlAdjustmentStates + == NR_SRS_ResourceSet__srs_PowerControlAdjustmentStates_separateClosedLoop; + + if (!is_tpc_accumulation_provided && (!is_configured_for_pusch_on_current_bwp || separate_pc_adjustment_state)) { + if (!current_UL_BWP->srs_power_control_initialized) { + NR_PRACH_RESOURCES_t *prach_resources = &mac->ra.prach_resources; + float DELTA_P_rampup_requested = + (prach_resources->RA_PREAMBLE_POWER_RAMPING_COUNTER - 1) * prach_resources->RA_PREAMBLE_POWER_RAMPING_STEP; + float DELTA_P_rampup = P_CMAX - (P_0_SRS + m_srs_component + alpha * pathloss); + DELTA_P_rampup = min(DELTA_P_rampup_requested, max(0, DELTA_P_rampup)); + current_UL_BWP->srs_power_control_initialized = true; + current_UL_BWP->h_b_f_c = DELTA_P_rampup + mac->delta_msg2; + } else { + int P_CMIN = mac->current_UL_BWP->P_CMIN; + if (!((srs_power_without_h_b_f_c + current_UL_BWP->h_b_f_c >= P_CMAX && delta_srs > 0) + || (srs_power_without_h_b_f_c + current_UL_BWP->h_b_f_c <= P_CMIN && delta_srs < 0))) { + current_UL_BWP->h_b_f_c += delta_srs; + } + } + h_b_f_c = current_UL_BWP->h_b_f_c; + } else { + // Case 3: No accumulation + h_b_f_c = delta_srs; + } + } + + return min(P_CMAX, srs_power_without_h_b_f_c + h_b_f_c); +} diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c index 84a35dcf52..a076829a8a 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c @@ -1058,7 +1058,8 @@ int configure_srs_pdu(NR_UE_MAC_INST_t *mac, NR_SRS_Resource_t *srs_resource, fapi_nr_ul_config_srs_pdu *srs_config_pdu, int period, - int offset) + int offset, + NR_SRS_ResourceSet_t *srs_resource_set) { NR_UE_UL_BWP_t *current_UL_BWP = mac->current_UL_BWP; @@ -1100,6 +1101,11 @@ int configure_srs_pdu(NR_UE_MAC_INST_t *mac, srs_config_pdu->t_offset = offset; } + bool is_configured_for_pusch_on_current_bwp = true; + int delta_srs = 0; // DCI format 2_3 not implemented + srs_config_pdu->tx_power = + get_srs_tx_power_ue(mac, srs_resource, srs_resource_set, delta_srs, is_configured_for_pusch_on_current_bwp); + #ifdef SRS_DEBUG LOG_I(NR_MAC,"Frame = %i, slot = %i\n", frame, slot); LOG_I(NR_MAC,"srs_config_pdu->rnti = 0x%04x\n", srs_config_pdu->rnti); @@ -1142,10 +1148,11 @@ void nr_ue_aperiodic_srs_scheduling(NR_UE_MAC_INST_t *mac, long resource_trigger int slot_offset = 0; NR_SRS_Resource_t *srs_resource = NULL; + NR_SRS_ResourceSet_t *srs_resource_set = NULL; for(int rs = 0; rs < srs_config->srs_ResourceSetToAddModList->list.count; rs++) { // Find aperiodic resource set - NR_SRS_ResourceSet_t *srs_resource_set = srs_config->srs_ResourceSetToAddModList->list.array[rs]; + srs_resource_set = srs_config->srs_ResourceSetToAddModList->list.array[rs]; if(srs_resource_set->resourceType.present != NR_SRS_ResourceSet__resourceType_PR_aperiodic) continue; // the resource trigger need to match the DCI one @@ -1186,7 +1193,7 @@ void nr_ue_aperiodic_srs_scheduling(NR_UE_MAC_INST_t *mac, long resource_trigger fapi_nr_ul_config_request_pdu_t *pdu = lockGet_ul_config(mac, sched_frame, sched_slot, FAPI_NR_UL_CONFIG_TYPE_SRS); if (!pdu) return; - int ret = configure_srs_pdu(mac, srs_resource, &pdu->srs_config_pdu, 0, 0); + int ret = configure_srs_pdu(mac, srs_resource, &pdu->srs_config_pdu, 0, 0, srs_resource_set); if (ret != 0) remove_ul_config_last_item(pdu); release_ul_config(pdu, false); @@ -1204,9 +1211,10 @@ static bool nr_ue_periodic_srs_scheduling(NR_UE_MAC_INST_t *mac, frame_t frame, } bool srs_scheduled = false; + NR_SRS_ResourceSet_t *srs_resource_set = NULL; for(int rs = 0; rs < srs_config->srs_ResourceSetToAddModList->list.count; rs++) { // Find periodic resource set - NR_SRS_ResourceSet_t *srs_resource_set = srs_config->srs_ResourceSetToAddModList->list.array[rs]; + srs_resource_set = srs_config->srs_ResourceSetToAddModList->list.array[rs]; if(srs_resource_set->resourceType.present != NR_SRS_ResourceSet__resourceType_PR_periodic) { continue; } @@ -1237,7 +1245,7 @@ static bool nr_ue_periodic_srs_scheduling(NR_UE_MAC_INST_t *mac, frame_t frame, fapi_nr_ul_config_request_pdu_t *pdu = lockGet_ul_config(mac, frame, slot, FAPI_NR_UL_CONFIG_TYPE_SRS); if (!pdu) return false; - int ret = configure_srs_pdu(mac, srs_resource, &pdu->srs_config_pdu, period, offset); + int ret = configure_srs_pdu(mac, srs_resource, &pdu->srs_config_pdu, period, offset, srs_resource_set); if (ret != 0) remove_ul_config_last_item(pdu); else 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 index c8467241b8..760de0df3d 100644 --- 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 @@ -594,6 +594,125 @@ TEST(test_pcmax, test_non_obvious_bwp_size) nr_get_Pcmax(23, nr_band, frame_type, FR1, channel_bandwidth, 2, false, 1, N_RB_UL, false, 6, prb_start)); } +TEST(test_srs_power, use_pusch_power_adjustment_state) +{ + NR_UE_MAC_INST_t mac = {0}; + NR_UE_UL_BWP_t current_UL_BWP = {0}; + current_UL_BWP.scs = 1; + current_UL_BWP.BWPSize = 106; + mac.current_UL_BWP = ¤t_UL_BWP; + NR_SRS_Resource_t srs_resource = {0}; + NR_SRS_ResourceSet_t srs_resource_set = {0}; + bool is_configured_for_pusch_on_current_bwp = true; + int delta_srs = 0; + srs_resource_set.srs_PowerControlAdjustmentStates = NULL; + mac.nr_band = 78; + mac.f_b_f_c = 0; + mac.pusch_power_control_initialized = true; + long p0 = 0; + srs_resource_set.p0 = &p0; + + int tx_power = get_srs_tx_power_ue(&mac, &srs_resource, &srs_resource_set, delta_srs, is_configured_for_pusch_on_current_bwp); + + mac.f_b_f_c = 4; + + int increased_tx_power = + get_srs_tx_power_ue(&mac, &srs_resource, &srs_resource_set, delta_srs, is_configured_for_pusch_on_current_bwp); + EXPECT_EQ(tx_power + mac.f_b_f_c, increased_tx_power); +} + +TEST(test_srs_power, no_support_for_two_pusch_power_adjustment_states) +{ + NR_UE_MAC_INST_t mac = {0}; + NR_UE_UL_BWP_t current_UL_BWP = {0}; + current_UL_BWP.scs = 1; + current_UL_BWP.BWPSize = 106; + mac.current_UL_BWP = ¤t_UL_BWP; + NR_SRS_Resource_t srs_resource = {0}; + NR_SRS_ResourceSet_t srs_resource_set = {0}; + long p0 = 0; + srs_resource_set.p0 = &p0; + bool is_configured_for_pusch_on_current_bwp = true; + int delta_srs = 0; + long srs_PowerControlAdjustmentStates = NR_SRS_ResourceSet__srs_PowerControlAdjustmentStates_sameAsFci2; + srs_resource_set.srs_PowerControlAdjustmentStates = &srs_PowerControlAdjustmentStates; + mac.nr_band = 78; + mac.f_b_f_c = 0; + mac.pusch_power_control_initialized = true; + + EXPECT_DEATH(get_srs_tx_power_ue(&mac, &srs_resource, &srs_resource_set, delta_srs, is_configured_for_pusch_on_current_bwp), + "Two PUSCH power adjustment states not supported"); +} + +TEST(test_srs_power, no_tpc_accumulation) +{ + NR_UE_MAC_INST_t mac = {0}; + NR_UE_UL_BWP_t current_UL_BWP = {0}; + current_UL_BWP.scs = 1; + current_UL_BWP.BWPSize = 106; + mac.current_UL_BWP = ¤t_UL_BWP; + NR_SRS_Resource_t srs_resource = {0}; + NR_SRS_ResourceSet_t srs_resource_set = {0}; + long p0 = 0; + srs_resource_set.p0 = &p0; + bool is_configured_for_pusch_on_current_bwp = true; + int delta_srs = 0; + long srs_PowerControlAdjustmentStates = NR_SRS_ResourceSet__srs_PowerControlAdjustmentStates_separateClosedLoop; + srs_resource_set.srs_PowerControlAdjustmentStates = &srs_PowerControlAdjustmentStates; + mac.nr_band = 78; + mac.f_b_f_c = 0; + mac.pusch_power_control_initialized = true; + + NR_SRS_Config_t srs_Config = {0}; + long tpc_Accumulation = 0; + srs_Config.tpc_Accumulation = &tpc_Accumulation; + current_UL_BWP.srs_Config = &srs_Config; + + int tx_power = get_srs_tx_power_ue(&mac, &srs_resource, &srs_resource_set, delta_srs, is_configured_for_pusch_on_current_bwp); + + delta_srs = 4; + + int increased_tx_power = + get_srs_tx_power_ue(&mac, &srs_resource, &srs_resource_set, delta_srs, is_configured_for_pusch_on_current_bwp); + EXPECT_EQ(tx_power + delta_srs, increased_tx_power); +} + +TEST(test_srs_power, tpc_accumulation) +{ + NR_UE_MAC_INST_t mac = {0}; + NR_UE_UL_BWP_t current_UL_BWP = {0}; + current_UL_BWP.scs = 1; + current_UL_BWP.BWPSize = 106; + mac.current_UL_BWP = ¤t_UL_BWP; + NR_SRS_Resource_t srs_resource = {0}; + NR_SRS_ResourceSet_t srs_resource_set = {0}; + long p0 = 0; + srs_resource_set.p0 = &p0; + bool is_configured_for_pusch_on_current_bwp = true; + int delta_srs = 0; + long srs_PowerControlAdjustmentStates = NR_SRS_ResourceSet__srs_PowerControlAdjustmentStates_separateClosedLoop; + srs_resource_set.srs_PowerControlAdjustmentStates = &srs_PowerControlAdjustmentStates; + mac.nr_band = 78; + mac.f_b_f_c = 0; + mac.pusch_power_control_initialized = true; + current_UL_BWP.srs_power_control_initialized = true; + + NR_SRS_Config_t srs_Config = {0}; + current_UL_BWP.srs_Config = &srs_Config; + + int tx_power = get_srs_tx_power_ue(&mac, &srs_resource, &srs_resource_set, delta_srs, is_configured_for_pusch_on_current_bwp); + + delta_srs = 4; + + int increased_tx_power = + get_srs_tx_power_ue(&mac, &srs_resource, &srs_resource_set, delta_srs, is_configured_for_pusch_on_current_bwp); + EXPECT_EQ(tx_power + delta_srs, increased_tx_power); + + int more_tx_power = + get_srs_tx_power_ue(&mac, &srs_resource, &srs_resource_set, delta_srs, is_configured_for_pusch_on_current_bwp); + EXPECT_EQ(tx_power + delta_srs * 2, more_tx_power); +} + int main(int argc, char** argv) { logInit(); diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index 6d0dc01112..4cf6da7433 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c @@ -3175,21 +3175,23 @@ void send_initial_ul_rrc_message(int rnti, const uint8_t *sdu, sdu_size_t sdu_le mac->mac_rrc.initial_ul_rrc_message_transfer(0, &ul_rrc_msg); } -void prepare_initial_ul_rrc_message(gNB_MAC_INST *mac, NR_UE_info_t *UE) +bool prepare_initial_ul_rrc_message(gNB_MAC_INST *mac, NR_UE_info_t *UE) { NR_SCHED_ENSURE_LOCKED(&mac->sched_lock); + + /* activate SRB0 */ + if (!nr_rlc_activate_srb0(UE->rnti, UE, send_initial_ul_rrc_message)) + return false; + /* create this UE's initial CellGroup */ int CC_id = 0; int srb_id = 1; const NR_ServingCellConfigCommon_t *scc = mac->common_channels[CC_id].ServingCellConfigCommon; const NR_ServingCellConfig_t *sccd = mac->common_channels[CC_id].pre_ServingCellConfig; NR_CellGroupConfig_t *cellGroupConfig = get_initial_cellGroupConfig(UE->uid, scc, sccd, &mac->radio_config); - + ASN_STRUCT_FREE(asn_DEF_NR_CellGroupConfig, UE->CellGroup); UE->CellGroup = cellGroupConfig; - /* activate SRB0 */ - nr_rlc_activate_srb0(UE->rnti, UE, send_initial_ul_rrc_message); - /* the cellGroup sent to CU specifies there is SRB1, so create it */ DevAssert(cellGroupConfig->rlc_BearerToAddModList->list.count == 1); const NR_RLC_BearerConfig_t *bearer = cellGroupConfig->rlc_BearerToAddModList->list.array[0]; @@ -3199,6 +3201,7 @@ void prepare_initial_ul_rrc_message(gNB_MAC_INST *mac, NR_UE_info_t *UE) int priority = bearer->mac_LogicalChannelConfig->ul_SpecificParameters->priority; nr_lc_config_t c = {.lcid = bearer->logicalChannelIdentity, .priority = priority}; nr_mac_add_lcid(&UE->UE_sched_ctrl, &c); + return true; } void nr_mac_trigger_release_timer(NR_UE_sched_ctrl_t *sched_ctrl, NR_SubcarrierSpacing_t subcarrier_spacing) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c index 50dd276770..cb233eae1b 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c @@ -444,20 +444,23 @@ static int nr_process_mac_pdu(instance_t module_idP, mac_len = 6; } - LOG_D(MAC, "[RAPROC] Received SDU for CCCH length %d for UE %04x\n", mac_len, UE->rnti); + LOG_I(MAC, "[RAPROC] Received SDU for CCCH length %d for UE %04x\n", mac_len, UE->rnti); - prepare_initial_ul_rrc_message(RC.nrmac[module_idP], UE); - mac_rlc_data_ind(module_idP, - UE->rnti, - module_idP, - frameP, - ENB_FLAG_YES, - MBMS_FLAG_NO, - 0, - (char *) (pduP + mac_subheader_len), - mac_len, - 1, - NULL); + if (prepare_initial_ul_rrc_message(RC.nrmac[module_idP], UE)) { + mac_rlc_data_ind(module_idP, + UE->rnti, + module_idP, + frameP, + ENB_FLAG_YES, + MBMS_FLAG_NO, + 0, + (char *) (pduP + mac_subheader_len), + mac_len, + 1, + NULL); + } else { + LOG_E(NR_MAC, "prepare_initial_ul_rrc_message() returned false, cannot forward CCCH message\n"); + } break; case UL_SCH_LCID_DTCH ... (UL_SCH_LCID_DTCH + 28): @@ -498,7 +501,7 @@ static int nr_process_mac_pdu(instance_t module_idP, break; default: - LOG_E(NR_MAC, "Received unknown MAC header (LCID = 0x%02x)\n", rx_lcid); + LOG_E(NR_MAC, "RNTI %0x, received unknown MAC header (LCID = 0x%02x)\n", UE->rnti, rx_lcid); return -1; break; } diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h index a869e172fd..756ddbb39e 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h @@ -449,7 +449,7 @@ size_t dump_mac_stats(gNB_MAC_INST *gNB, char *output, size_t strlen, bool reset long get_lcid_from_drbid(int drb_id); long get_lcid_from_srbid(int srb_id); -void prepare_initial_ul_rrc_message(gNB_MAC_INST *mac, NR_UE_info_t *UE); +bool prepare_initial_ul_rrc_message(gNB_MAC_INST *mac, NR_UE_info_t *UE); void send_initial_ul_rrc_message(int rnti, const uint8_t *sdu, sdu_size_t sdu_len, void *data); void finish_nr_dl_harq(NR_UE_sched_ctrl_t *sched_ctrl, int harq_pid); diff --git a/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.c b/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.c index 46e0da26cf..b8fd148876 100644 --- a/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.c +++ b/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.c @@ -983,10 +983,17 @@ void deliver_sdu_srb0(void *deliver_sdu_data, struct nr_rlc_entity_t *entity, s0->send_initial_ul_rrc_message(s0->ue_id, (unsigned char *)buf, size, s0->data); } -void nr_rlc_activate_srb0(int ue_id, +bool nr_rlc_activate_srb0(int ue_id, void *data, void (*send_initial_ul_rrc_message)(int ue_id, const uint8_t *sdu, sdu_size_t sdu_len, void *data)) { + nr_rlc_manager_lock(nr_rlc_ue_manager); + nr_rlc_ue_t *ue = nr_rlc_manager_get_ue(nr_rlc_ue_manager, ue_id); + if (ue->srb0 != NULL) { + LOG_W(RLC, "SRB0 already exists for UE %x, do nothing\n", ue_id); + nr_rlc_manager_unlock(nr_rlc_ue_manager); + return false; + } struct srb0_data *srb0_data = calloc(1, sizeof(struct srb0_data)); AssertFatal(srb0_data, "out of memory\n"); @@ -994,21 +1001,13 @@ void nr_rlc_activate_srb0(int ue_id, srb0_data->data = data; srb0_data->send_initial_ul_rrc_message = send_initial_ul_rrc_message; - nr_rlc_manager_lock(nr_rlc_ue_manager); - nr_rlc_ue_t *ue = nr_rlc_manager_get_ue(nr_rlc_ue_manager, ue_id); - if (ue->srb0 != NULL) { - LOG_W(RLC, "SRB0 already exists for UE %d, do nothing\n", ue_id); - free(srb0_data); - nr_rlc_manager_unlock(nr_rlc_ue_manager); - return; - } - nr_rlc_entity_t *nr_rlc_tm = new_nr_rlc_entity_tm(10000, - deliver_sdu_srb0, srb0_data); + deliver_sdu_srb0, srb0_data); nr_rlc_ue_add_srb_rlc_entity(ue, 0, nr_rlc_tm); LOG_I(RLC, "Activated srb0 for UE %d\n", ue_id); nr_rlc_manager_unlock(nr_rlc_ue_manager); + return true; } rlc_op_status_t rrc_rlc_config_req(const protocol_ctxt_t* const ctxt_pP, diff --git a/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.h b/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.h index ea47b00f03..736c42a0b7 100644 --- a/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.h +++ b/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.h @@ -62,7 +62,7 @@ void nr_rlc_activate_avg_time_to_tx(const int ue_id, const logical_chan_id_t cha void nr_rlc_srb_recv_sdu(const int ue_id, const logical_chan_id_t channel_id, unsigned char *buf, int size); -void nr_rlc_activate_srb0(int ue_id, +bool nr_rlc_activate_srb0(int ue_id, void *data, void (*send_initial_ul_rrc_message)(int rnti, const uint8_t *sdu, sdu_size_t sdu_len, void *data)); diff --git a/tools/formatting/README.md b/tools/formatting/README.md new file mode 100644 index 0000000000..fe01ed8002 --- /dev/null +++ b/tools/formatting/README.md @@ -0,0 +1,26 @@ +# Overview + +Dockerized tool to list clang-format errors introduced in a branch. + +# Usage + +Checkout the branch you want to compare. This is necessary because if there are files added by the branch +they need to be present for clang-format to analyze them. + +Then: + +``` +./tools/formatting/detect_clang_format_errors.sh +``` + +Or + +``` +docker compose up +``` + +Or (to avoid docker related lines in stdout) + +``` +docker compose run clang-formatter | tee output +``` diff --git a/tools/formatting/detect_clang_format_errors.sh b/tools/formatting/detect_clang_format_errors.sh new file mode 100755 index 0000000000..e8d0c89787 --- /dev/null +++ b/tools/formatting/detect_clang_format_errors.sh @@ -0,0 +1,5 @@ +#!/bin/bash +set -eo pipefail + +BASE_COMMIT=$(git merge-base HEAD origin/develop) +git diff -U0 --no-color $BASE_COMMIT...HEAD | clang-format-diff -p1 diff --git a/tools/formatting/docker-compose.yaml b/tools/formatting/docker-compose.yaml new file mode 100644 index 0000000000..d2fa77de72 --- /dev/null +++ b/tools/formatting/docker-compose.yaml @@ -0,0 +1,13 @@ +services: + clang-formatter: + image: clang-formatter + build: + dockerfile_inline: | + FROM ubuntu:22.04 + RUN DEBIAN_FRONTEND=noninteractive apt update && apt install -y git clang-format + volumes: + - ../../:/code/ + command: + bash -c "git config --global --add safe.directory /code && cd /code/ && \ + git config --global clangFormat.style file && \ + ./tools/formatting/detect_clang_format_errors.sh"