From 1390eeea888e0995ad7f2aa820ea72a56517ed70 Mon Sep 17 00:00:00 2001 From: dvdgrgrtt Date: Tue, 7 Dec 2021 15:41:06 +0100 Subject: [PATCH 01/62] sch_nr: Fix CRC-related bug CRC failure was not reported correctly when the TB consists of a single block. --- lib/src/phy/phch/sch_nr.c | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/src/phy/phch/sch_nr.c b/lib/src/phy/phch/sch_nr.c index d983b33d6..77d43f106 100644 --- a/lib/src/phy/phch/sch_nr.c +++ b/lib/src/phy/phch/sch_nr.c @@ -693,6 +693,7 @@ static int sch_nr_decode(srsran_sch_nr_t* q, // Not all CB are decoded, skip TB union and CRC check if (cb_ok != cfg.C) { + res->crc = false; return SRSRAN_SUCCESS; } From 3fad800ef6fc3aebc7faa0e04a211cd947b00970 Mon Sep 17 00:00:00 2001 From: dvdgrgrtt Date: Tue, 7 Dec 2021 15:45:29 +0100 Subject: [PATCH 02/62] Fix various typos and minor issues Some typos in the comments/error messages. A couple of minor bugs (should not have any impact in the performance). --- lib/src/phy/phch/phch_cfg_nr.c | 2 +- lib/src/phy/phch/ra_nr.c | 1 + lib/src/phy/phch/test/pusch_nr_test.c | 10 ++++++---- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/lib/src/phy/phch/phch_cfg_nr.c b/lib/src/phy/phch/phch_cfg_nr.c index cb34a4d8e..380d74c28 100644 --- a/lib/src/phy/phch/phch_cfg_nr.c +++ b/lib/src/phy/phch/phch_cfg_nr.c @@ -251,7 +251,7 @@ uint32_t srsran_sch_cfg_nr_info(const srsran_sch_cfg_nr_t* sch_cfg, char* str, u // Append SCH information len += phch_cfg_sch_to_str(&sch_cfg->sch_cfg, &str[len], str_len - len); - // Append SCH information + // Append reserved RE information len += phch_cfg_rvd_to_str(&sch_cfg->rvd_re, &str[len], str_len - len); // UCI configuration diff --git a/lib/src/phy/phch/ra_nr.c b/lib/src/phy/phch/ra_nr.c index 415fab60f..167cb4457 100644 --- a/lib/src/phy/phch/ra_nr.c +++ b/lib/src/phy/phch/ra_nr.c @@ -626,6 +626,7 @@ int srsran_ra_nr_fill_tb(const srsran_sch_cfg_nr_t* pdsch_cfg, uint32_t N_re_rvd = srsran_re_pattern_list_count(&pdsch_cfg->rvd_re, grant->S, grant->S + grant->L, grant->prb_idx); // Steps 2,3,4 + tb->mcs = mcs_idx; tb->tbs = (int)srsran_ra_nr_tbs(N_re, S, R, Qm, tb->N_L); tb->R = R; tb->mod = m; diff --git a/lib/src/phy/phch/test/pusch_nr_test.c b/lib/src/phy/phch/test/pusch_nr_test.c index eedae8a0c..3bdc5217f 100644 --- a/lib/src/phy/phch/test/pusch_nr_test.c +++ b/lib/src/phy/phch/test/pusch_nr_test.c @@ -156,7 +156,7 @@ int main(int argc, char** argv) goto clean_exit; } - // Set PDSCH grant without considering any procedure + // Set PUSCH grant without considering any procedure pusch_cfg.grant.nof_dmrs_cdm_groups_without_data = 1; // No need for MIMO pusch_cfg.grant.nof_layers = carrier.max_mimo_layers; pusch_cfg.grant.dci_format = srsran_dci_format_nr_1_0; @@ -196,7 +196,7 @@ int main(int argc, char** argv) pusch_cfg.grant.dci_format = srsran_dci_format_nr_0_0; if (srsran_ra_nr_fill_tb(&pusch_cfg, &pusch_cfg.grant, mcs, &pusch_cfg.grant.tb[0]) < SRSRAN_SUCCESS) { - ERROR("Error filing tb"); + ERROR("Error filling tb"); goto clean_exit; } @@ -270,10 +270,12 @@ int main(int argc, char** argv) // Check symbols Mean Square Error (MSE) uint32_t nof_re = srsran_ra_dl_nr_slot_nof_re(&pusch_cfg, &pusch_cfg.grant); if (nof_re * pusch_cfg.grant.nof_layers > 0) { - float mse = 0.0f; + float mse = 0.0f; + float mse_tmp = 0.0f; for (uint32_t i = 0; i < pusch_cfg.grant.nof_layers; i++) { for (uint32_t j = 0; j < nof_re; j++) { - mse += cabsf(pusch_tx.d[i][j] - pusch_rx.d[i][j]); + mse_tmp = cabsf(pusch_tx.d[i][j] - pusch_rx.d[i][j]); + mse += mse_tmp * mse_tmp; } } mse = mse / (nof_re * pusch_cfg.grant.nof_layers); From 6b0a3669cf89f1f072de271a6abc35255ba4e8cf Mon Sep 17 00:00:00 2001 From: dvdgrgrtt Date: Tue, 7 Dec 2021 16:11:16 +0100 Subject: [PATCH 03/62] Provide PUSCH BLER test The new test measures BLER and received throughput for the PUSCH. For now, only AWGN channel and perfect equalization are considered. --- lib/src/phy/phch/test/CMakeLists.txt | 3 + lib/src/phy/phch/test/pusch_nr_bler_test.c | 376 +++++++++++++++++++++ 2 files changed, 379 insertions(+) create mode 100644 lib/src/phy/phch/test/pusch_nr_bler_test.c diff --git a/lib/src/phy/phch/test/CMakeLists.txt b/lib/src/phy/phch/test/CMakeLists.txt index 8ce5df6dd..fdec173c3 100644 --- a/lib/src/phy/phch/test/CMakeLists.txt +++ b/lib/src/phy/phch/test/CMakeLists.txt @@ -678,6 +678,9 @@ add_nr_test(pusch_nr_ack2_csi4_test pusch_nr_test -p 50 -m 20 -A 2 -C 4) add_nr_test(pusch_nr_ack4_csi4_test pusch_nr_test -p 50 -m 20 -A 4 -C 4) add_nr_test(pusch_nr_ack20_csi4_test pusch_nr_test -p 50 -m 20 -A 20 -C 4) +add_executable(pusch_nr_bler_test EXCLUDE_FROM_ALL pusch_nr_bler_test.c) +target_link_libraries(pusch_nr_bler_test srsran_phy) +# this is just for performance evaluation, not for unit testing add_executable(pdcch_nr_test pdcch_nr_test.c) target_link_libraries(pdcch_nr_test srsran_phy) diff --git a/lib/src/phy/phch/test/pusch_nr_bler_test.c b/lib/src/phy/phch/test/pusch_nr_bler_test.c new file mode 100644 index 000000000..354f934f1 --- /dev/null +++ b/lib/src/phy/phch/test/pusch_nr_bler_test.c @@ -0,0 +1,376 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2021 Software Radio Systems Limited + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the distribution. + * + */ + +#include "srsran/phy/channel/ch_awgn.h" +#include "srsran/phy/phch/pusch_nr.h" +#include "srsran/phy/phch/ra_nr.h" +#include "srsran/phy/phch/ra_ul_nr.h" +#include "srsran/phy/utils/debug.h" +#include "srsran/phy/utils/random.h" +#include "srsran/phy/utils/vector.h" +#include + +static srsran_carrier_nr_t carrier = SRSRAN_DEFAULT_CARRIER_NR; +static uint32_t n_prb = 0; // Set to 0 for steering +static uint32_t mcs = 30; // Set to 30 for steering +static srsran_sch_cfg_nr_t pusch_cfg = {}; +static uint16_t rnti = 0x1234; +static uint32_t nof_ack_bits = 0; +static uint32_t nof_csi_bits = 0; +static float snr = 10; +static bool full_check = false; + +void usage(char* prog) +{ + printf("Usage: %s [pmTLACsv] \n", prog); + printf("\t-p Number of grant PRB, set to 0 for steering [Default %d]\n", n_prb); + printf("\t-m MCS PRB, set to >28 for steering [Default %d]\n", mcs); + printf("\t-T Provide MCS table (64qam, 256qam, 64qamLowSE) [Default %s]\n", + srsran_mcs_table_to_str(pusch_cfg.sch_cfg.mcs_table)); + printf("\t-L Provide number of layers [Default %d]\n", carrier.max_mimo_layers); + printf("\t-A Provide a number of HARQ-ACK bits [Default %d]\n", nof_ack_bits); + printf("\t-C Provide a number of CSI bits [Default %d]\n", nof_csi_bits); + printf("\t-s Signal-to-Noise Ratio in dB [Default %.1f]\n", snr); + printf("\t-f Perform full BLER check instead of CRC only [Default %s]\n", full_check ? "true" : "false"); + printf("\t-v [set srsran_verbose to debug, default none]\n"); +} + +int parse_args(int argc, char** argv) +{ + int opt = 0; + while ((opt = getopt(argc, argv, "p:m:T:L:A:C:s:fv")) != -1) { + switch (opt) { + case 'p': + n_prb = (uint32_t)strtol(optarg, NULL, 10); + break; + case 'm': + mcs = (uint32_t)strtol(optarg, NULL, 10); + break; + case 'T': + pusch_cfg.sch_cfg.mcs_table = srsran_mcs_table_from_str(optarg); + break; + case 'L': + carrier.max_mimo_layers = (uint32_t)strtol(optarg, NULL, 10); + break; + case 'A': + nof_ack_bits = (uint32_t)strtol(optarg, NULL, 10); + break; + case 'C': + nof_csi_bits = (uint32_t)strtol(optarg, NULL, 10); + break; + case 's': + snr = strtof(optarg, NULL); + break; + case 'f': + full_check = true; + break; + case 'v': + increase_srsran_verbose_level(); + break; + default: + usage(argv[0]); + return SRSRAN_ERROR; + } + } + + return SRSRAN_SUCCESS; +} + +int main(int argc, char** argv) +{ + int ret = SRSRAN_ERROR; + srsran_pusch_nr_t pusch_tx = {}; + srsran_pusch_nr_t pusch_rx = {}; + srsran_chest_dl_res_t chest = {}; + srsran_random_t rand_gen = srsran_random_init(1234); + + srsran_pusch_data_nr_t data_tx = {}; + srsran_pusch_res_nr_t data_rx = {}; + cf_t* sf_symbols_tx[SRSRAN_MAX_LAYERS_NR] = {}; + cf_t* sf_symbols_rx[SRSRAN_MAX_LAYERS_NR] = {}; + + // Set default PUSCH configuration + pusch_cfg.sch_cfg.mcs_table = srsran_mcs_table_64qam; + + if (parse_args(argc, argv) < SRSRAN_SUCCESS) { + goto clean_exit; + } + + srsran_pusch_nr_args_t pusch_args = {}; + pusch_args.sch.disable_simd = false; + pusch_args.measure_evm = true; + + if (srsran_pusch_nr_init_ue(&pusch_tx, &pusch_args) < SRSRAN_SUCCESS) { + ERROR("Error initiating PUSCH for Tx"); + goto clean_exit; + } + + if (srsran_pusch_nr_init_gnb(&pusch_rx, &pusch_args) < SRSRAN_SUCCESS) { + ERROR("Error initiating SCH NR for Rx"); + goto clean_exit; + } + + if (srsran_pusch_nr_set_carrier(&pusch_tx, &carrier)) { + ERROR("Error setting SCH NR carrier"); + goto clean_exit; + } + + if (srsran_pusch_nr_set_carrier(&pusch_rx, &carrier)) { + ERROR("Error setting SCH NR carrier"); + goto clean_exit; + } + + uint32_t slot_length = SRSRAN_SLOT_LEN_RE_NR(carrier.nof_prb); + for (uint32_t i = 0; i < carrier.max_mimo_layers; i++) { + sf_symbols_tx[i] = srsran_vec_cf_malloc(slot_length); + sf_symbols_rx[i] = srsran_vec_cf_malloc(slot_length); + if (sf_symbols_tx[i] == NULL || sf_symbols_rx[i] == NULL) { + ERROR("Error malloc"); + goto clean_exit; + } + } + + for (uint32_t i = 0; i < pusch_tx.max_cw; i++) { + data_tx.payload[i] = srsran_vec_u8_malloc(SRSRAN_SLOT_MAX_NOF_BITS_NR); + data_rx.tb[i].payload = srsran_vec_u8_malloc(SRSRAN_SLOT_MAX_NOF_BITS_NR); + if (data_tx.payload[i] == NULL || data_rx.tb[i].payload == NULL) { + ERROR("Error malloc"); + goto clean_exit; + } + } + + srsran_softbuffer_tx_t softbuffer_tx = {}; + srsran_softbuffer_rx_t softbuffer_rx = {}; + + if (srsran_softbuffer_tx_init_guru(&softbuffer_tx, SRSRAN_SCH_NR_MAX_NOF_CB_LDPC, SRSRAN_LDPC_MAX_LEN_ENCODED_CB) < + SRSRAN_SUCCESS) { + ERROR("Error init soft-buffer"); + goto clean_exit; + } + + if (srsran_softbuffer_rx_init_guru(&softbuffer_rx, SRSRAN_SCH_NR_MAX_NOF_CB_LDPC, SRSRAN_LDPC_MAX_LEN_ENCODED_CB) < + SRSRAN_SUCCESS) { + ERROR("Error init soft-buffer"); + goto clean_exit; + } + + // Use grant default A time resources with m=0 + if (srsran_ra_ul_nr_pusch_time_resource_default_A(carrier.scs, 0, &pusch_cfg.grant) < SRSRAN_SUCCESS) { + ERROR("Error loading default grant"); + goto clean_exit; + } + + // Set PUSCH grant without considering any procedure + pusch_cfg.grant.nof_dmrs_cdm_groups_without_data = 1; // No need for MIMO + pusch_cfg.grant.nof_layers = carrier.max_mimo_layers; + pusch_cfg.grant.dci_format = srsran_dci_format_nr_1_0; + pusch_cfg.grant.rnti = rnti; + + // Check input: PRB + if (n_prb > carrier.nof_prb) { + ERROR("Invalid number of PRB"); + goto clean_exit; + } + + // Check input: MCS + uint32_t mcs_end = pusch_cfg.sch_cfg.mcs_table == srsran_mcs_table_256qam ? 28 : 29; + if (mcs > mcs_end) { + ERROR("Invalid MCS"); + goto clean_exit; + } + + srsran_sch_hl_cfg_nr_t sch_hl_cfg = {}; + sch_hl_cfg.scaling = 1.0F; + sch_hl_cfg.beta_offsets.fix_ack = 12.625F; + sch_hl_cfg.beta_offsets.fix_csi1 = 2.25F; + sch_hl_cfg.beta_offsets.fix_csi2 = 2.25F; + + if (srsran_chest_dl_res_init(&chest, carrier.nof_prb) < SRSRAN_SUCCESS) { + ERROR("Initiating chest"); + goto clean_exit; + } + + for (uint32_t n = 0; n < SRSRAN_MAX_PRB_NR; n++) { + pusch_cfg.grant.prb_idx[n] = (n < n_prb); + } + pusch_cfg.grant.nof_prb = n_prb; + + pusch_cfg.grant.dci_format = srsran_dci_format_nr_0_0; + pusch_cfg.grant.nof_dmrs_cdm_groups_without_data = 2; + pusch_cfg.dmrs.type = srsran_dmrs_sch_type_1; + pusch_cfg.dmrs.length = srsran_dmrs_sch_len_1; + pusch_cfg.dmrs.additional_pos = srsran_dmrs_sch_add_pos_2; + if (srsran_ra_nr_fill_tb(&pusch_cfg, &pusch_cfg.grant, mcs, &pusch_cfg.grant.tb[0]) < SRSRAN_SUCCESS) { + ERROR("Error filling tb"); + goto clean_exit; + } + + uint32_t n_blocks = 0; + uint32_t n_errors = 0; + float evm = 0; + for (; n_blocks < 2000000 && n_errors < 100; n_blocks++) { + // Generate SCH payload + for (uint32_t tb = 0; tb < SRSRAN_MAX_TB; tb++) { + // Skip TB if no allocated + if (data_tx.payload[tb] == NULL) { + continue; + } + + // load payload with bytes + for (uint32_t i = 0; i < pusch_cfg.grant.tb[tb].tbs / 8 + 1; i++) { + data_tx.payload[tb][i] = (uint8_t)srsran_random_uniform_int_dist(rand_gen, 0, UINT8_MAX); + } + pusch_cfg.grant.tb[tb].softbuffer.tx = &softbuffer_tx; + } + + // Generate HARQ ACK bits + if (nof_ack_bits > 0) { + pusch_cfg.uci.ack.count = nof_ack_bits; + for (uint32_t i = 0; i < nof_ack_bits; i++) { + data_tx.uci.ack[i] = (uint8_t)srsran_random_uniform_int_dist(rand_gen, 0, 1); + } + } + + // Generate CSI report bits + uint8_t csi_report_tx[SRSRAN_UCI_NR_MAX_CSI1_BITS] = {}; + uint8_t csi_report_rx[SRSRAN_UCI_NR_MAX_CSI1_BITS] = {}; + if (nof_csi_bits > 0) { + pusch_cfg.uci.csi[0].cfg.quantity = SRSRAN_CSI_REPORT_QUANTITY_NONE; + pusch_cfg.uci.csi[0].K_csi_rs = nof_csi_bits; + pusch_cfg.uci.nof_csi = 1; + data_tx.uci.csi[0].none = csi_report_tx; + for (uint32_t i = 0; i < nof_csi_bits; i++) { + csi_report_tx[i] = (uint8_t)srsran_random_uniform_int_dist(rand_gen, 0, 1); + } + + data_rx.uci.csi[0].none = csi_report_rx; + } + + if (srsran_ra_ul_set_grant_uci_nr(&carrier, &sch_hl_cfg, &pusch_cfg.uci, &pusch_cfg) < SRSRAN_SUCCESS) { + ERROR("Setting UCI"); + goto clean_exit; + } + + if (srsran_pusch_nr_encode(&pusch_tx, &pusch_cfg, &pusch_cfg.grant, &data_tx, sf_symbols_tx) < SRSRAN_SUCCESS) { + ERROR("Error encoding"); + goto clean_exit; + } + + float noise_std_1d = srsran_convert_dB_to_amplitude(-snr - 3.0103F); + for (uint32_t i = 0; i < carrier.max_mimo_layers; i++) { + srsran_ch_awgn_f((float*)sf_symbols_tx[i], (float*)sf_symbols_rx[i], noise_std_1d, 2 * slot_length); + // memcpy(sf_symbols_rx[i], sf_symbols_tx[i], slot_length * sizeof(cf_t)); + } + + if (get_srsran_verbose_level() >= SRSRAN_VERBOSE_INFO) { + uint32_t nof_re_total = carrier.nof_prb * SRSRAN_NRE; + uint32_t nof_re_used = pusch_cfg.grant.nof_prb * SRSRAN_NRE; + for (int i_layer = 0; i_layer < carrier.max_mimo_layers; i_layer++) { + INFO("Layer %d", i_layer); + float tx_power = 0; + float rx_power = 0; + uint8_t n_symbols = 0; + for (int i = 0; i < SRSRAN_NSYMB_PER_SLOT_NR; i++) { + if (!pusch_tx.dmrs_re_pattern.symbol[i]) { + n_symbols++; + tx_power += srsran_vec_avg_power_cf(sf_symbols_tx[0] + i * nof_re_total, nof_re_total); + rx_power += srsran_vec_avg_power_cf(sf_symbols_rx[0] + i * nof_re_total, nof_re_total); + } + } + tx_power *= (float)nof_re_total / nof_re_used; // compensate for unused REs + INFO(" Tx power: %.3f", tx_power / n_symbols); + INFO(" Rx power: %.3f", rx_power / n_symbols); + INFO(" SNR: %.3f dB", srsran_convert_power_to_dB(tx_power / (rx_power - tx_power))); + } + } + + for (uint32_t tb = 0; tb < SRSRAN_MAX_TB; tb++) { + pusch_cfg.grant.tb[tb].softbuffer.rx = &softbuffer_rx; + srsran_softbuffer_rx_reset(pusch_cfg.grant.tb[tb].softbuffer.rx); + } + + // assume perfect channel estimation (including noise variance) + for (uint32_t i = 0; i < pusch_cfg.grant.tb->nof_re; i++) { + chest.ce[0][0][i] = 1.0F; + } + chest.nof_re = pusch_cfg.grant.tb->nof_re; + chest.noise_estimate = 4 * noise_std_1d * noise_std_1d; + + if (srsran_pusch_nr_decode(&pusch_rx, &pusch_cfg, &pusch_cfg.grant, &chest, sf_symbols_rx, &data_rx) < + SRSRAN_SUCCESS) { + ERROR("Error encoding"); + goto clean_exit; + } + + evm += data_rx.evm[0]; + // Validate UL-SCH CRC check + if (!data_rx.tb[0].crc) { + n_errors++; + printf("*"); + fflush(stdout); + if (n_errors % 20 == 0) { + printf("\n"); + } + } + + if (full_check) { + // Validate by comparing payload (recall, payload is represented in bytes) + if ((memcmp(data_rx.tb[0].payload, data_tx.payload[0], pusch_cfg.grant.tb[0].tbs * sizeof(uint8_t) / 8) == 0) != + data_rx.tb[0].crc) { + printf("\nWarning! Bit comparison and CRC do not match!\n"); + } + } + } + char str[512]; + srsran_pusch_nr_rx_info(&pusch_rx, &pusch_cfg, &pusch_cfg.grant, &data_rx, str, (uint32_t)sizeof(str)); + + char str_extra[2048]; + srsran_sch_cfg_nr_info(&pusch_cfg, str_extra, (uint32_t)sizeof(str_extra)); + printf("\nPUSCH: %s\n%s", str, str_extra); + + printf("\nNominal SNR: %.1f dB\n", snr); + printf("Average EVM: %.3f\n", evm / n_blocks); + + printf("BLER: %.3e (%d errors out of %d blocks)\n", (double)n_errors / n_blocks, n_errors, n_blocks); + printf("Tx Throughput: %.3e Mbps -- Rx Throughput: %.3e Mbps (%.2f%%)\n", + pusch_cfg.grant.tb[0].tbs / 1e3, + (n_blocks - n_errors) / 1e3 * pusch_cfg.grant.tb[0].tbs / n_blocks, + 100.0F * (n_blocks - n_errors) / n_blocks); + + ret = SRSRAN_SUCCESS; + +clean_exit: + srsran_chest_dl_res_free(&chest); + srsran_random_free(rand_gen); + srsran_pusch_nr_free(&pusch_tx); + srsran_pusch_nr_free(&pusch_rx); + for (uint32_t i = 0; i < SRSRAN_MAX_CODEWORDS; i++) { + if (data_tx.payload[i]) { + free(data_tx.payload[i]); + } + if (data_rx.tb[i].payload) { + free(data_rx.tb[i].payload); + } + } + for (uint32_t i = 0; i < SRSRAN_MAX_LAYERS_NR; i++) { + if (sf_symbols_tx[i]) { + free(sf_symbols_tx[i]); + } + if (sf_symbols_rx[i]) { + free(sf_symbols_rx[i]); + } + } + srsran_softbuffer_tx_free(&softbuffer_tx); + srsran_softbuffer_rx_free(&softbuffer_rx); + + return ret; +} From 63899ef4bca93a96290eeca86181b3782e45ccc7 Mon Sep 17 00:00:00 2001 From: dvdgrgrtt Date: Thu, 9 Dec 2021 10:46:33 +0100 Subject: [PATCH 04/62] Improve PUSCH NR BLER test output When full BLER is enabled, the code also outputs false alarm and missed detection probabilities. --- lib/src/phy/phch/test/pusch_nr_bler_test.c | 33 ++++++++++++++++++---- 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/lib/src/phy/phch/test/pusch_nr_bler_test.c b/lib/src/phy/phch/test/pusch_nr_bler_test.c index 354f934f1..5fb1af667 100644 --- a/lib/src/phy/phch/test/pusch_nr_bler_test.c +++ b/lib/src/phy/phch/test/pusch_nr_bler_test.c @@ -214,9 +214,11 @@ int main(int argc, char** argv) goto clean_exit; } - uint32_t n_blocks = 0; - uint32_t n_errors = 0; - float evm = 0; + uint32_t n_blocks = 0; + uint32_t n_errors = 0; + uint32_t crc_false_pos = 0; + uint32_t crc_false_neg = 0; + float evm = 0; for (; n_blocks < 2000000 && n_errors < 100; n_blocks++) { // Generate SCH payload for (uint32_t tb = 0; tb < SRSRAN_MAX_TB; tb++) { @@ -324,9 +326,15 @@ int main(int argc, char** argv) if (full_check) { // Validate by comparing payload (recall, payload is represented in bytes) - if ((memcmp(data_rx.tb[0].payload, data_tx.payload[0], pusch_cfg.grant.tb[0].tbs * sizeof(uint8_t) / 8) == 0) != - data_rx.tb[0].crc) { - printf("\nWarning! Bit comparison and CRC do not match!\n"); + if ((memcmp(data_rx.tb[0].payload, data_tx.payload[0], pusch_cfg.grant.tb[0].tbs * sizeof(uint8_t) / 8) == 0) && + !data_rx.tb[0].crc) { + printf("\nWARNING! Codeword OK but CRC KO!\n"); + crc_false_pos++; + } else if ((memcmp(data_rx.tb[0].payload, data_tx.payload[0], pusch_cfg.grant.tb[0].tbs * sizeof(uint8_t) / 8) != + 0) && + data_rx.tb[0].crc) { + printf("\nWarning! Codeword KO but CRC OK!\n"); + crc_false_neg++; } } } @@ -346,6 +354,19 @@ int main(int argc, char** argv) (n_blocks - n_errors) / 1e3 * pusch_cfg.grant.tb[0].tbs / n_blocks, 100.0F * (n_blocks - n_errors) / n_blocks); + if (full_check) { + uint32_t true_errors = n_errors + crc_false_neg - crc_false_pos; + printf("CRC: missed detection/Type I err. %.2f%% (%d out of %d)", + 100.0F * crc_false_neg / true_errors, + crc_false_neg, + true_errors); + printf(" -- false alarm %.2f%% (%d out of %d)", 100.0F * crc_false_pos / n_errors, crc_false_pos, n_errors); + printf(" -- Type II err. %.2f%% (%d out of %d)\n", + 100.0F * crc_false_pos / (n_blocks - true_errors), + crc_false_pos, + n_blocks - true_errors); + } + ret = SRSRAN_SUCCESS; clean_exit: From 73594cf704aaf849930b347001a9ed78dd85d3d0 Mon Sep 17 00:00:00 2001 From: dvdgrgrtt Date: Mon, 13 Dec 2021 12:16:45 +0100 Subject: [PATCH 05/62] Fix minor bug SRS_API was used instead of SRSRAN_API. Did not seem to have major consequences. --- lib/include/srsran/phy/phch/npbch.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/include/srsran/phy/phch/npbch.h b/lib/include/srsran/phy/phch/npbch.h index 11117d0d1..1449c91da 100644 --- a/lib/include/srsran/phy/phch/npbch.h +++ b/lib/include/srsran/phy/phch/npbch.h @@ -49,7 +49,7 @@ typedef struct { * * Reference: 3GPP TS 36.211 version 13.2.0 Release 13 Sec. 10.2.4 */ -typedef struct SRS_API { +typedef struct SRSRAN_API { srsran_nbiot_cell_t cell; uint32_t frame_idx; From 442f95ee8b56c40f8fcc76ac6f0358d709bea711 Mon Sep 17 00:00:00 2001 From: dvdgrgrtt Date: Mon, 13 Dec 2021 12:19:55 +0100 Subject: [PATCH 06/62] Document PUSCH NR BLER test --- lib/src/phy/phch/test/pusch_nr_bler_test.c | 28 ++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/lib/src/phy/phch/test/pusch_nr_bler_test.c b/lib/src/phy/phch/test/pusch_nr_bler_test.c index 5fb1af667..8b042a7bb 100644 --- a/lib/src/phy/phch/test/pusch_nr_bler_test.c +++ b/lib/src/phy/phch/test/pusch_nr_bler_test.c @@ -1,10 +1,30 @@ /** + * \file pusch_nr_bler_test.c + * \brief BLER and throughput test for PUSCH NR. * - * \section COPYRIGHT + * This program simulates several PUSCH transmissions in order to estimate its performance in terms of the receiver BLER + * and throughput (expressed as a percentage of the transmitted one). Specifically, the simulation runs until 100 + * transmissions fail (or after 2,000,000 transmitted transport blocks). Failures are detected by CRC verification. * - * Copyright 2013-2021 Software Radio Systems Limited + * The simulation setup can be controlled by means of the following arguments. + * - -p num: sets the number of granted PUSCH PRBs to \c num. + * - -T tab: sets the modulation and coding scheme table (valid options: \c 64qam, \c 256qam, \c 64qamLowSE). + * - -m mcs: sets the modulation and coding scheme index to \c mcs. + * - -L num: sets the number of transmission layers to \c num. + * - -A num: sets the number of HARQ-ACK bits to \c num. + * - -C num: sets the number of CSI bits to \c num. + * - -s val: sets the nominal SNR to \c val (in dB). + * - -f : activates full BLER simulations (Tx--Rx comparison as opposed to CRC-verification only). + * - -v : activates verbose output. * - * By using this file, you agree to the terms and conditions set + * Example: + * \code{.cpp} + * pusch_nr_bler_test -p 52 -m 2 -T 64qam -s -1.8 -f + * \endcode + * + * \copyright Copyright 2013-2021 Software Radio Systems Limited + * + * \copyright By using this file, you agree to the terms and conditions set * forth in the LICENSE file which can be found at the top level of * the distribution. * @@ -31,7 +51,7 @@ static bool full_check = false; void usage(char* prog) { - printf("Usage: %s [pmTLACsv] \n", prog); + printf("Usage: %s [pmTLACsfv] \n", prog); printf("\t-p Number of grant PRB, set to 0 for steering [Default %d]\n", n_prb); printf("\t-m MCS PRB, set to >28 for steering [Default %d]\n", mcs); printf("\t-T Provide MCS table (64qam, 256qam, 64qamLowSE) [Default %s]\n", From bb767814fa739209d9e936aeb1409b632bed553a Mon Sep 17 00:00:00 2001 From: dvdgrgrtt Date: Tue, 14 Dec 2021 15:43:44 +0100 Subject: [PATCH 07/62] Fix minor typo --- lib/src/phy/phch/test/pusch_nr_bler_test.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/phy/phch/test/pusch_nr_bler_test.c b/lib/src/phy/phch/test/pusch_nr_bler_test.c index 8b042a7bb..2c8959316 100644 --- a/lib/src/phy/phch/test/pusch_nr_bler_test.c +++ b/lib/src/phy/phch/test/pusch_nr_bler_test.c @@ -329,7 +329,7 @@ int main(int argc, char** argv) if (srsran_pusch_nr_decode(&pusch_rx, &pusch_cfg, &pusch_cfg.grant, &chest, sf_symbols_rx, &data_rx) < SRSRAN_SUCCESS) { - ERROR("Error encoding"); + ERROR("Error decoding"); goto clean_exit; } From b00b260605aabdcd6f3fe49cf9ade121344b49d2 Mon Sep 17 00:00:00 2001 From: dvdgrgrtt Date: Wed, 15 Dec 2021 14:58:29 +0100 Subject: [PATCH 08/62] Use copyright as file header --- lib/src/phy/phch/test/pusch_nr_bler_test.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/lib/src/phy/phch/test/pusch_nr_bler_test.c b/lib/src/phy/phch/test/pusch_nr_bler_test.c index 2c8959316..10ed2dafe 100644 --- a/lib/src/phy/phch/test/pusch_nr_bler_test.c +++ b/lib/src/phy/phch/test/pusch_nr_bler_test.c @@ -1,3 +1,12 @@ +/** + * \copyright Copyright 2013-2021 Software Radio Systems Limited + * + * \copyright By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the distribution. + * + */ + /** * \file pusch_nr_bler_test.c * \brief BLER and throughput test for PUSCH NR. @@ -22,12 +31,6 @@ * pusch_nr_bler_test -p 52 -m 2 -T 64qam -s -1.8 -f * \endcode * - * \copyright Copyright 2013-2021 Software Radio Systems Limited - * - * \copyright By using this file, you agree to the terms and conditions set - * forth in the LICENSE file which can be found at the top level of - * the distribution. - * */ #include "srsran/phy/channel/ch_awgn.h" From 69a7519cb766a52c0c310d54083f281306aba33d Mon Sep 17 00:00:00 2001 From: dvdgrgrtt Date: Mon, 17 Jan 2022 11:22:43 +0100 Subject: [PATCH 09/62] Modify pusch_nr_bler_test user interface The maximum number of simulated transport blocks is now a CLI parameter. --- lib/src/phy/phch/test/pusch_nr_bler_test.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/lib/src/phy/phch/test/pusch_nr_bler_test.c b/lib/src/phy/phch/test/pusch_nr_bler_test.c index 10ed2dafe..0e1209908 100644 --- a/lib/src/phy/phch/test/pusch_nr_bler_test.c +++ b/lib/src/phy/phch/test/pusch_nr_bler_test.c @@ -22,6 +22,7 @@ * - -L num: sets the number of transmission layers to \c num. * - -A num: sets the number of HARQ-ACK bits to \c num. * - -C num: sets the number of CSI bits to \c num. + * - -N num: sets the maximum number of simulated transport blocks to \c num. * - -s val: sets the nominal SNR to \c val (in dB). * - -f : activates full BLER simulations (Tx--Rx comparison as opposed to CRC-verification only). * - -v : activates verbose output. @@ -43,25 +44,27 @@ #include static srsran_carrier_nr_t carrier = SRSRAN_DEFAULT_CARRIER_NR; -static uint32_t n_prb = 0; // Set to 0 for steering -static uint32_t mcs = 30; // Set to 30 for steering +static uint32_t n_prb = 0; +static uint32_t mcs = 30; static srsran_sch_cfg_nr_t pusch_cfg = {}; static uint16_t rnti = 0x1234; static uint32_t nof_ack_bits = 0; static uint32_t nof_csi_bits = 0; +static uint32_t max_blocks = 2e6; // max number of simulated transport blocks static float snr = 10; static bool full_check = false; void usage(char* prog) { - printf("Usage: %s [pmTLACsfv] \n", prog); - printf("\t-p Number of grant PRB, set to 0 for steering [Default %d]\n", n_prb); - printf("\t-m MCS PRB, set to >28 for steering [Default %d]\n", mcs); + printf("Usage: %s [pmTLACNsfv] \n", prog); + printf("\t-p Number of grant PRB [Default %d]\n", n_prb); + printf("\t-m MCS PRB [Default %d]\n", mcs); printf("\t-T Provide MCS table (64qam, 256qam, 64qamLowSE) [Default %s]\n", srsran_mcs_table_to_str(pusch_cfg.sch_cfg.mcs_table)); printf("\t-L Provide number of layers [Default %d]\n", carrier.max_mimo_layers); printf("\t-A Provide a number of HARQ-ACK bits [Default %d]\n", nof_ack_bits); printf("\t-C Provide a number of CSI bits [Default %d]\n", nof_csi_bits); + printf("\t-N Maximum number of simulated transport blocks [Default %d]\n", max_blocks); printf("\t-s Signal-to-Noise Ratio in dB [Default %.1f]\n", snr); printf("\t-f Perform full BLER check instead of CRC only [Default %s]\n", full_check ? "true" : "false"); printf("\t-v [set srsran_verbose to debug, default none]\n"); @@ -70,7 +73,7 @@ void usage(char* prog) int parse_args(int argc, char** argv) { int opt = 0; - while ((opt = getopt(argc, argv, "p:m:T:L:A:C:s:fv")) != -1) { + while ((opt = getopt(argc, argv, "p:m:T:L:A:C:N:s:fv")) != -1) { switch (opt) { case 'p': n_prb = (uint32_t)strtol(optarg, NULL, 10); @@ -90,6 +93,9 @@ int parse_args(int argc, char** argv) case 'C': nof_csi_bits = (uint32_t)strtol(optarg, NULL, 10); break; + case 'N': + max_blocks = (uint32_t)strtol(optarg, NULL, 10); + break; case 's': snr = strtof(optarg, NULL); break; @@ -242,7 +248,7 @@ int main(int argc, char** argv) uint32_t crc_false_pos = 0; uint32_t crc_false_neg = 0; float evm = 0; - for (; n_blocks < 2000000 && n_errors < 100; n_blocks++) { + for (; n_blocks < max_blocks && n_errors < 100; n_blocks++) { // Generate SCH payload for (uint32_t tb = 0; tb < SRSRAN_MAX_TB; tb++) { // Skip TB if no allocated From 3e85c3bed02b3c7256541170330a20f9d50c50bd Mon Sep 17 00:00:00 2001 From: dvdgrgrtt Date: Mon, 17 Jan 2022 11:25:03 +0100 Subject: [PATCH 10/62] Improve coding style --- lib/src/phy/phch/sch_nr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/phy/phch/sch_nr.c b/lib/src/phy/phch/sch_nr.c index 77d43f106..27faacddd 100644 --- a/lib/src/phy/phch/sch_nr.c +++ b/lib/src/phy/phch/sch_nr.c @@ -596,6 +596,7 @@ static int sch_nr_decode(srsran_sch_nr_t* q, // Counter of code blocks that have matched CRC uint32_t cb_ok = 0; + res->crc = false; // For each code block... uint32_t j = 0; @@ -693,7 +694,6 @@ static int sch_nr_decode(srsran_sch_nr_t* q, // Not all CB are decoded, skip TB union and CRC check if (cb_ok != cfg.C) { - res->crc = false; return SRSRAN_SUCCESS; } From a630889d448a6bd7d8c03daad206a3f4371bb1cb Mon Sep 17 00:00:00 2001 From: dvdgrgrtt Date: Wed, 19 Jan 2022 14:18:52 +0100 Subject: [PATCH 11/62] Fix AWGN in NR PUSCH performance test Fix needed after modifying AWGN API. --- lib/src/phy/phch/test/pusch_nr_bler_test.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/src/phy/phch/test/pusch_nr_bler_test.c b/lib/src/phy/phch/test/pusch_nr_bler_test.c index 0e1209908..a0173967c 100644 --- a/lib/src/phy/phch/test/pusch_nr_bler_test.c +++ b/lib/src/phy/phch/test/pusch_nr_bler_test.c @@ -296,9 +296,9 @@ int main(int argc, char** argv) goto clean_exit; } - float noise_std_1d = srsran_convert_dB_to_amplitude(-snr - 3.0103F); + float noise_var = srsran_convert_dB_to_power(-snr); for (uint32_t i = 0; i < carrier.max_mimo_layers; i++) { - srsran_ch_awgn_f((float*)sf_symbols_tx[i], (float*)sf_symbols_rx[i], noise_std_1d, 2 * slot_length); + srsran_ch_awgn_c(sf_symbols_tx[i], sf_symbols_rx[i], noise_var, slot_length); // memcpy(sf_symbols_rx[i], sf_symbols_tx[i], slot_length * sizeof(cf_t)); } @@ -334,7 +334,7 @@ int main(int argc, char** argv) chest.ce[0][0][i] = 1.0F; } chest.nof_re = pusch_cfg.grant.tb->nof_re; - chest.noise_estimate = 4 * noise_std_1d * noise_std_1d; + chest.noise_estimate = 2 * noise_var; if (srsran_pusch_nr_decode(&pusch_rx, &pusch_cfg, &pusch_cfg.grant, &chest, sf_symbols_rx, &data_rx) < SRSRAN_SUCCESS) { From cf191d83060a4b9ad86156e770035e9816dee692 Mon Sep 17 00:00:00 2001 From: Bedran Karakoc Date: Thu, 27 Jan 2022 18:52:16 +0100 Subject: [PATCH 12/62] lib,nas_5g: Fix packing/unpacking error for ipv4 addresses --- lib/include/srsran/asn1/nas_5g_ies.h | 18 ++++++++---------- lib/src/asn1/nas_5g_ies.cc | 16 ++++++++-------- 2 files changed, 16 insertions(+), 18 deletions(-) diff --git a/lib/include/srsran/asn1/nas_5g_ies.h b/lib/include/srsran/asn1/nas_5g_ies.h index 95e40ae1d..b69f77c1b 100644 --- a/lib/include/srsran/asn1/nas_5g_ies.h +++ b/lib/include/srsran/asn1/nas_5g_ies.h @@ -275,42 +275,42 @@ public: guti_5g_s& set_guti_5g() { - set(identity_types::guti_5g); + set(identity_types::guti_5g); choice_container = srslog::detail::any{guti_5g_s()}; return *srslog::detail::any_cast(&choice_container); } imei_s& set_imei() { - set(identity_types::imei); + set(identity_types::imei); choice_container = srslog::detail::any{imei_s()}; return *srslog::detail::any_cast(&choice_container); } s_tmsi_5g_s& set_s_tmsi_5g() { - set(identity_types::s_tmsi_5g); + set(identity_types::s_tmsi_5g); choice_container = srslog::detail::any{s_tmsi_5g_s()}; return *srslog::detail::any_cast(&choice_container); } imeisv_s& set_imeisv() { - set(identity_types::imeisv); + set(identity_types::imeisv); choice_container = srslog::detail::any{imeisv_s()}; return *srslog::detail::any_cast(&choice_container); } mac_address_s& set_mac_address() { - set(identity_types::mac_address); + set(identity_types::mac_address); choice_container = srslog::detail::any{mac_address_s()}; return *srslog::detail::any_cast(&choice_container); } eui_64_s& set_eui_64() { - set(identity_types::eui_64); + set(identity_types::eui_64); choice_container = srslog::detail::any{eui_64_s()}; return *srslog::detail::any_cast(&choice_container); } @@ -430,8 +430,6 @@ public: }; // s_nssai_t - - // IE: NSSAI // Reference: 9.11.3.37 class nssai_t @@ -2276,8 +2274,8 @@ public: bool si6_lla = false; PDU_session_type_value_type pdu_session_type_value = PDU_session_type_value_type_::options::ipv4; std::array ipv4; - std::array ipv6; - std::array smf_i_pv6_link_local_address; + std::array ipv6; + std::array smf_i_pv6_link_local_address; SRSASN_CODE pack(asn1::bit_ref& bref); SRSASN_CODE unpack(asn1::cbit_ref& bref); diff --git a/lib/src/asn1/nas_5g_ies.cc b/lib/src/asn1/nas_5g_ies.cc index 286c01a9b..d7085e01d 100644 --- a/lib/src/asn1/nas_5g_ies.cc +++ b/lib/src/asn1/nas_5g_ies.cc @@ -3935,9 +3935,9 @@ SRSASN_CODE pdu_address_t::pack(asn1::bit_ref& bref) if (pdu_session_type_value == pdu_address_t::PDU_session_type_value_type_::options::ipv4) { HANDLE_CODE(bref.pack_bytes(ipv4.data(), 4)); } else if (pdu_session_type_value == pdu_address_t::PDU_session_type_value_type_::options::ipv6) { - HANDLE_CODE(bref.pack_bytes(ipv6.data(), 16)); + HANDLE_CODE(bref.pack_bytes(ipv6.data(), 8)); } else if (pdu_session_type_value == pdu_address_t::PDU_session_type_value_type_::options::ipv4v6) { - HANDLE_CODE(bref.pack_bytes(ipv6.data(), 16)); + HANDLE_CODE(bref.pack_bytes(ipv6.data(), 8)); HANDLE_CODE(bref.pack_bytes(ipv4.data(), 4)); } @@ -3976,20 +3976,20 @@ SRSASN_CODE pdu_address_t::unpack(asn1::cbit_ref& bref) HANDLE_CODE(bref.unpack_bytes(ipv4.data(), 4)); } else if (length == 9 && pdu_session_type_value == pdu_address_t::PDU_session_type_value_type_::options::ipv6 && si6_lla == false) { - HANDLE_CODE(bref.unpack_bytes(ipv6.data(), 16)); + HANDLE_CODE(bref.unpack_bytes(ipv6.data(), 8)); } else if (length == 13 && pdu_session_type_value == pdu_address_t::PDU_session_type_value_type_::options::ipv4v6 && si6_lla == false) { - HANDLE_CODE(bref.unpack_bytes(ipv6.data(), 16)); + HANDLE_CODE(bref.unpack_bytes(ipv6.data(), 8)); HANDLE_CODE(bref.unpack_bytes(ipv4.data(), 4)); } else if (length == 25 && pdu_session_type_value == pdu_address_t::PDU_session_type_value_type_::options::ipv6 && si6_lla == true) { - HANDLE_CODE(bref.unpack_bytes(ipv6.data(), 16)); - HANDLE_CODE(bref.unpack_bytes(smf_i_pv6_link_local_address.data(), 16)); + HANDLE_CODE(bref.unpack_bytes(ipv6.data(), 8)); + HANDLE_CODE(bref.unpack_bytes(smf_i_pv6_link_local_address.data(), 8)); } else if (length == 29 && pdu_session_type_value == pdu_address_t::PDU_session_type_value_type_::options::ipv4v6 && si6_lla == true) { - HANDLE_CODE(bref.unpack_bytes(ipv6.data(), 16)); + HANDLE_CODE(bref.unpack_bytes(ipv6.data(), 8)); HANDLE_CODE(bref.unpack_bytes(ipv4.data(), 4)); - HANDLE_CODE(bref.unpack_bytes(smf_i_pv6_link_local_address.data(), 16)); + HANDLE_CODE(bref.unpack_bytes(smf_i_pv6_link_local_address.data(), 8)); } else { asn1::log_error("Not expected combination of length and type field"); return SRSASN_ERROR_DECODE_FAIL; From 84c842f8c3565007d4aa545492c4b91fcf470a2b Mon Sep 17 00:00:00 2001 From: Bedran Karakoc Date: Thu, 27 Jan 2022 19:00:35 +0100 Subject: [PATCH 13/62] lib,nas_5g: Fix logging in configuration update complete message --- srsue/src/stack/upper/nas_5g.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/srsue/src/stack/upper/nas_5g.cc b/srsue/src/stack/upper/nas_5g.cc index 9478bfac5..6f98d1a7f 100644 --- a/srsue/src/stack/upper/nas_5g.cc +++ b/srsue/src/stack/upper/nas_5g.cc @@ -766,7 +766,7 @@ int nas_5g::send_configuration_update_complete() pdu->N_bytes - SEQ_5G_OFFSET, &pdu->msg[MAC_5G_OFFSET]); - logger.error("Sending Configuration Update Complete"); + logger.info("Sending Configuration Update Complete"); rrc_nr->write_sdu(std::move(pdu)); ctxt_base.tx_count++; return SRSRAN_SUCCESS; From 37280307b53d42a44f91bcd6c9a4932588df7c3e Mon Sep 17 00:00:00 2001 From: Bedran Karakoc Date: Thu, 27 Jan 2022 19:17:18 +0100 Subject: [PATCH 14/62] lib,nas_5g: Fix unpacking/packing for timezone IEs --- lib/include/srsran/asn1/nas_5g_ies.h | 11 ++++++----- lib/src/asn1/nas_5g_ies.cc | 22 ++++++++++++---------- 2 files changed, 18 insertions(+), 15 deletions(-) diff --git a/lib/include/srsran/asn1/nas_5g_ies.h b/lib/include/srsran/asn1/nas_5g_ies.h index b69f77c1b..4f0ea4c42 100644 --- a/lib/include/srsran/asn1/nas_5g_ies.h +++ b/lib/include/srsran/asn1/nas_5g_ies.h @@ -1577,11 +1577,6 @@ public: class time_zone_t { public: - uint8_t year; - uint8_t month; - uint8_t day; - uint8_t hour; - uint8_t second; uint8_t time_zone; SRSASN_CODE pack(asn1::bit_ref& bref); @@ -1594,6 +1589,12 @@ public: class time_zone_and_time_t { public: + uint8_t year; + uint8_t month; + uint8_t day; + uint8_t hour; + uint8_t minute; + uint8_t second; uint8_t time_zone; SRSASN_CODE pack(asn1::bit_ref& bref); diff --git a/lib/src/asn1/nas_5g_ies.cc b/lib/src/asn1/nas_5g_ies.cc index d7085e01d..907f30a70 100644 --- a/lib/src/asn1/nas_5g_ies.cc +++ b/lib/src/asn1/nas_5g_ies.cc @@ -2721,11 +2721,6 @@ SRSASN_CODE network_name_t::unpack(asn1::cbit_ref& bref) // Reference: 9.11.3.52 SRSASN_CODE time_zone_t::pack(asn1::bit_ref& bref) { - HANDLE_CODE(bref.pack(year, 8)); - HANDLE_CODE(bref.pack(month, 8)); - HANDLE_CODE(bref.pack(day, 8)); - HANDLE_CODE(bref.pack(hour, 8)); - HANDLE_CODE(bref.pack(second, 8)); HANDLE_CODE(bref.pack(time_zone, 8)); return SRSASN_SUCCESS; } @@ -2734,11 +2729,6 @@ SRSASN_CODE time_zone_t::pack(asn1::bit_ref& bref) // Reference: 9.11.3.52 SRSASN_CODE time_zone_t::unpack(asn1::cbit_ref& bref) { - HANDLE_CODE(bref.unpack(year, 8)); - HANDLE_CODE(bref.unpack(month, 8)); - HANDLE_CODE(bref.unpack(day, 8)); - HANDLE_CODE(bref.unpack(hour, 8)); - HANDLE_CODE(bref.unpack(second, 8)); HANDLE_CODE(bref.unpack(time_zone, 8)); return SRSASN_SUCCESS; } @@ -2747,6 +2737,12 @@ SRSASN_CODE time_zone_t::unpack(asn1::cbit_ref& bref) // Reference: 9.11.3.53 SRSASN_CODE time_zone_and_time_t::pack(asn1::bit_ref& bref) { + HANDLE_CODE(bref.pack(year, 8)); + HANDLE_CODE(bref.pack(month, 8)); + HANDLE_CODE(bref.pack(day, 8)); + HANDLE_CODE(bref.pack(hour, 8)); + HANDLE_CODE(bref.pack(minute, 8)); + HANDLE_CODE(bref.pack(second, 8)); HANDLE_CODE(bref.pack(time_zone, 8)); return SRSASN_SUCCESS; } @@ -2755,6 +2751,12 @@ SRSASN_CODE time_zone_and_time_t::pack(asn1::bit_ref& bref) // Reference: 9.11.3.53 SRSASN_CODE time_zone_and_time_t::unpack(asn1::cbit_ref& bref) { + HANDLE_CODE(bref.unpack(year, 8)); + HANDLE_CODE(bref.unpack(month, 8)); + HANDLE_CODE(bref.unpack(day, 8)); + HANDLE_CODE(bref.unpack(hour, 8)); + HANDLE_CODE(bref.unpack(minute, 8)); + HANDLE_CODE(bref.unpack(second, 8)); HANDLE_CODE(bref.unpack(time_zone, 8)); return SRSASN_SUCCESS; } From d448eac94108e522a941628cc1ab5a42419e10d6 Mon Sep 17 00:00:00 2001 From: Bedran Karakoc Date: Thu, 27 Jan 2022 19:55:51 +0100 Subject: [PATCH 15/62] ue,rrc_nr: Add dummy handler for RRC Release to avoid logging an unhandled message error --- srsue/hdr/stack/rrc_nr/rrc_nr.h | 9 +++++---- srsue/src/stack/rrc_nr/rrc_nr.cc | 12 +++++++++++- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/srsue/hdr/stack/rrc_nr/rrc_nr.h b/srsue/hdr/stack/rrc_nr/rrc_nr.h index f01525f4b..5ede655e4 100644 --- a/srsue/hdr/stack/rrc_nr/rrc_nr.h +++ b/srsue/hdr/stack/rrc_nr/rrc_nr.h @@ -148,6 +148,7 @@ private: void handle_rrc_reconfig(const asn1::rrc_nr::rrc_recfg_s& reconfig); void handle_dl_info_transfer(const asn1::rrc_nr::dl_info_transfer_s& dl_info_transfer); void handle_security_mode_command(const asn1::rrc_nr::security_mode_cmd_s& smc); + void handle_rrc_release(const asn1::rrc_nr::rrc_release_s& rrc_release); void generate_as_keys(); srsran::task_sched_handle task_sched; @@ -184,7 +185,7 @@ private: uint32_t sim_measurement_carrier_freq_r15; srsran::timer_handler::unique_timer sim_measurement_timer; - rrc_nr_state_t state = RRC_NR_STATE_IDLE; + rrc_nr_state_t state = RRC_NR_STATE_IDLE; uint8_t transaction_id = 0; @@ -251,9 +252,9 @@ private: class setup_request_proc; srsran::proc_t cell_selector; - srsran::proc_t conn_setup_proc; - srsran::proc_t conn_recfg_proc; - srsran::proc_t setup_req_proc; + srsran::proc_t conn_setup_proc; + srsran::proc_t conn_recfg_proc; + srsran::proc_t setup_req_proc; srsran::proc_manager_list_t callback_list; }; diff --git a/srsue/src/stack/rrc_nr/rrc_nr.cc b/srsue/src/stack/rrc_nr/rrc_nr.cc index 581641188..5f9876919 100644 --- a/srsue/src/stack/rrc_nr/rrc_nr.cc +++ b/srsue/src/stack/rrc_nr/rrc_nr.cc @@ -311,6 +311,11 @@ void rrc_nr::decode_dl_dcch(uint32_t lcid, unique_byte_buffer_t pdu) task_sched.defer_task([this, smc]() { handle_security_mode_command(smc); }); break; } + case dl_dcch_msg_type_c::c1_c_::types::rrc_release: { + rrc_release_s rrc_release = c1->rrc_release(); + task_sched.defer_task([this, rrc_release]() { handle_rrc_release(rrc_release); }); + break; + } default: logger.error("The provided DL-DCCH message type is not recognized or supported"); break; @@ -350,7 +355,7 @@ void rrc_nr::handle_sib1(const sib1_s& sib1) logger.info("SIB1 received, CellID=%d", meas_cells.serving_cell().get_cell_id() & 0xfff); meas_cells.serving_cell().set_sib1(sib1); - + // TODO: config basic config and remove early exit return; @@ -2117,6 +2122,11 @@ void rrc_nr::handle_security_mode_command(const asn1::rrc_nr::security_mode_cmd_ pdcp->enable_encryption(lcid, DIRECTION_TXRX); } +void rrc_nr::handle_rrc_release(const asn1::rrc_nr::rrc_release_s& rrc_release) +{ + logger.info("RRC Release not handled yet"); +} + // Security helper used by Security Mode Command and Mobility handling routines void rrc_nr::generate_as_keys() { From a74fdb84c9fb6c2e3ab5fb99d2cb72e1403064f9 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Fri, 28 Jan 2022 19:21:19 +0100 Subject: [PATCH 16/62] Added SSB encode and decode from grid, plus unit test --- lib/include/srsran/phy/sync/ssb.h | 68 +++++++--- lib/src/phy/sync/ssb.c | 115 ++++++++++++++-- lib/src/phy/sync/test/CMakeLists.txt | 7 + lib/src/phy/sync/test/ssb_grid_test.c | 180 ++++++++++++++++++++++++++ 4 files changed, 339 insertions(+), 31 deletions(-) create mode 100644 lib/src/phy/sync/test/ssb_grid_test.c diff --git a/lib/include/srsran/phy/sync/ssb.h b/lib/include/srsran/phy/sync/ssb.h index c718350d3..4d1d4bd25 100644 --- a/lib/include/srsran/phy/sync/ssb.h +++ b/lib/include/srsran/phy/sync/ssb.h @@ -89,7 +89,7 @@ typedef struct SRSRAN_API { uint32_t corr_sz; ///< Correlation size uint32_t corr_window; ///< Correlation window length uint32_t ssb_sz; ///< SSB size in samples at the configured sampling rate - int32_t f_offset; ///< Current SSB integer frequency offset (multiple of SCS) + int32_t f_offset; ///< SSB integer frequency offset (multiple of SCS) between DC and the SSB center uint32_t cp_sz; ///< CP length for the given symbol size /// Other parameters @@ -143,22 +143,6 @@ SRSRAN_API void srsran_ssb_free(srsran_ssb_t* q); * @return SRSRAN_SUCCESS if the parameters are valid, SRSRAN_ERROR code otherwise */ SRSRAN_API int srsran_ssb_set_cfg(srsran_ssb_t* q, const srsran_ssb_cfg_t* cfg); -/** - * @brief Decodes PBCH in the given time domain signal - * @note It currently expects an input buffer of half radio frame - * @param q SSB object - * @param N_id Physical Cell Identifier - * @param n_hf Number of hald radio frame, 0 or 1 - * @param ssb_idx SSB candidate index - * @param in Input baseband buffer - * @return SRSRAN_SUCCESS if the parameters are valid, SRSRAN_ERROR code otherwise - */ -SRSRAN_API int srsran_ssb_decode_pbch(srsran_ssb_t* q, - uint32_t N_id, - uint32_t n_hf, - uint32_t ssb_idx, - const cf_t* in, - srsran_pbch_msg_nr_t* msg); /** * @brief Searches for an SSB transmission and decodes the PBCH message @@ -178,6 +162,21 @@ SRSRAN_API int srsran_ssb_search(srsran_ssb_t* q, const cf_t* in, uint32_t nof_s */ SRSRAN_API bool srsran_ssb_send(srsran_ssb_t* q, uint32_t sf_idx); +/** + * + * @param q SSB object + * @param N_id Physical Cell Identifier + * @param msg NR PBCH message to transmit + * @param re_grid Resource grid pointer + * @param grid_sz_rb Resource grid bandwidth in subcarriers + * @return SRSRAN_SUCCES if inputs and data are correct, otherwise SRSRAN_ERROR code + */ +SRSRAN_API int srsran_ssb_put_grid(srsran_ssb_t* q, + uint32_t N_id, + const srsran_pbch_msg_nr_t* msg, + cf_t* re_grid, + uint32_t grid_bw_sc); + /** * @brief Adds SSB to a given signal in time domain * @param q SSB object @@ -188,6 +187,41 @@ SRSRAN_API bool srsran_ssb_send(srsran_ssb_t* q, uint32_t sf_idx); SRSRAN_API int srsran_ssb_add(srsran_ssb_t* q, uint32_t N_id, const srsran_pbch_msg_nr_t* msg, const cf_t* in, cf_t* out); +/** + * @brief Decodes PBCH in the given time domain signal + * @note It currently expects an input buffer of half radio frame + * @param q SSB object + * @param N_id Physical Cell Identifier + * @param n_hf Number of hald radio frame, 0 or 1 + * @param ssb_idx SSB candidate index + * @param in Input baseband buffer + * @return SRSRAN_SUCCESS if the parameters are valid, SRSRAN_ERROR code otherwise + */ +SRSRAN_API int srsran_ssb_decode_pbch(srsran_ssb_t* q, + uint32_t N_id, + uint32_t n_hf, + uint32_t ssb_idx, + const cf_t* grid, + srsran_pbch_msg_nr_t* msg); + +/** + * @brief Decodes PBCH in the given resource grid + * @param q SSB object + * @param N_id Physical Cell Identifier + * @param n_hf Number of hald radio frame, 0 or 1 + * @param ssb_idx SSB candidate index + * @param grid Input resource grid buffer + * @param grid_sz_rb Resource grid bandwidth in subcarriers + * @return SRSRAN_SUCCESS if the parameters are valid, SRSRAN_ERROR code otherwise + */ +SRSRAN_API int srsran_ssb_decode_grid(srsran_ssb_t* q, + uint32_t N_id, + uint32_t n_hf, + uint32_t ssb_idx, + const cf_t* in, + uint32_t grid_sz_rb, + srsran_pbch_msg_nr_t* msg); + /** * @brief Perform cell search and measurement * @note This function assumes the SSB transmission is aligned with the input base-band signal diff --git a/lib/src/phy/sync/ssb.c b/lib/src/phy/sync/ssb.c index 72e894afe..5149da502 100644 --- a/lib/src/phy/sync/ssb.c +++ b/lib/src/phy/sync/ssb.c @@ -527,21 +527,10 @@ bool srsran_ssb_send(srsran_ssb_t* q, uint32_t sf_idx) return (sf_idx % q->cfg.periodicity_ms == 0); } -int srsran_ssb_add(srsran_ssb_t* q, uint32_t N_id, const srsran_pbch_msg_nr_t* msg, const cf_t* in, cf_t* out) +static int ssb_encode(srsran_ssb_t* q, uint32_t N_id, const srsran_pbch_msg_nr_t* msg, cf_t ssb_grid[SRSRAN_SSB_NOF_RE]) { - // Verify input parameters - if (q == NULL || N_id >= SRSRAN_NOF_NID_NR || msg == NULL || in == NULL || out == NULL) { - return SRSRAN_ERROR_INVALID_INPUTS; - } - - if (!q->args.enable_encode) { - ERROR("SSB is not configured for encode"); - return SRSRAN_ERROR; - } - - uint32_t N_id_1 = SRSRAN_NID_1_NR(N_id); - uint32_t N_id_2 = SRSRAN_NID_2_NR(N_id); - cf_t ssb_grid[SRSRAN_SSB_NOF_RE] = {}; + uint32_t N_id_1 = SRSRAN_NID_1_NR(N_id); + uint32_t N_id_2 = SRSRAN_NID_2_NR(N_id); // Put PSS if (srsran_pss_nr_put(ssb_grid, N_id_2, q->cfg.beta_pss) < SRSRAN_SUCCESS) { @@ -580,6 +569,64 @@ int srsran_ssb_add(srsran_ssb_t* q, uint32_t N_id, const srsran_pbch_msg_nr_t* m return SRSRAN_ERROR; } + return SRSRAN_SUCCESS; +} + +SRSRAN_API int +srsran_ssb_put_grid(srsran_ssb_t* q, uint32_t N_id, const srsran_pbch_msg_nr_t* msg, cf_t* re_grid, uint32_t grid_bw_sc) +{ + // Verify input parameters + if (q == NULL || N_id >= SRSRAN_NOF_NID_NR || msg == NULL || re_grid == NULL || + grid_bw_sc * SRSRAN_NRE < SRSRAN_SSB_BW_SUBC) { + return SRSRAN_ERROR_INVALID_INPUTS; + } + + if (!q->args.enable_encode) { + ERROR("SSB is not configured for encode"); + return SRSRAN_ERROR; + } + + // Put signals in SSB grid + cf_t ssb_grid[SRSRAN_SSB_NOF_RE] = {}; + if (ssb_encode(q, N_id, msg, ssb_grid) < SRSRAN_SUCCESS) { + ERROR("Putting SSB in grid"); + return SRSRAN_ERROR; + } + + // First symbol in the half frame + uint32_t l_first = q->l_first[msg->ssb_idx]; + + // Frequency offset fom the bottom of the grid + uint32_t f_offset = grid_bw_sc / 2 + q->f_offset - SRSRAN_SSB_BW_SUBC / 2; + + // Put SSB grid in the actual resource grid + for (uint32_t l = 0; l < SRSRAN_SSB_DURATION_NSYMB; l++) { + srsran_vec_cf_copy( + &re_grid[grid_bw_sc * (l_first + l) + f_offset], &ssb_grid[SRSRAN_SSB_BW_SUBC * l], SRSRAN_SSB_BW_SUBC); + } + + return SRSRAN_SUCCESS; +} + +int srsran_ssb_add(srsran_ssb_t* q, uint32_t N_id, const srsran_pbch_msg_nr_t* msg, const cf_t* in, cf_t* out) +{ + // Verify input parameters + if (q == NULL || N_id >= SRSRAN_NOF_NID_NR || msg == NULL || in == NULL || out == NULL) { + return SRSRAN_ERROR_INVALID_INPUTS; + } + + if (!q->args.enable_encode) { + ERROR("SSB is not configured for encode"); + return SRSRAN_ERROR; + } + + // Put signals in SSB grid + cf_t ssb_grid[SRSRAN_SSB_NOF_RE] = {}; + if (ssb_encode(q, N_id, msg, ssb_grid) < SRSRAN_SUCCESS) { + ERROR("Putting SSB in grid"); + return SRSRAN_ERROR; + } + // Select start symbol from SSB candidate index int t_offset = ssb_get_t_offset(q, msg->ssb_idx); if (t_offset < SRSRAN_SUCCESS) { @@ -1132,6 +1179,46 @@ static int ssb_decode_pbch(srsran_ssb_t* q, return SRSRAN_SUCCESS; } +int srsran_ssb_decode_grid(srsran_ssb_t* q, + uint32_t N_id, + uint32_t n_hf, + uint32_t ssb_idx, + const cf_t* re_grid, + uint32_t grid_bw_sc, + srsran_pbch_msg_nr_t* msg) +{ + // Verify input parameters + if (q == NULL || N_id >= SRSRAN_NOF_NID_NR || msg == NULL || re_grid == NULL || grid_bw_sc < SRSRAN_SSB_BW_SUBC) { + return SRSRAN_ERROR_INVALID_INPUTS; + } + + if (!q->args.enable_encode) { + ERROR("SSB is not configured for encode"); + return SRSRAN_ERROR; + } + + // First symbol in the half frame + uint32_t l_first = q->l_first[ssb_idx]; + + // Frequency offset fom the bottom of the grid + uint32_t f_offset = grid_bw_sc / 2 + q->f_offset - SRSRAN_SSB_BW_SUBC / 2; + + // Get SSB grid from resource grid + cf_t ssb_grid[SRSRAN_SSB_NOF_RE] = {}; + for (uint32_t l = 0; l < SRSRAN_SSB_DURATION_NSYMB; l++) { + srsran_vec_cf_copy( + &ssb_grid[SRSRAN_SSB_BW_SUBC * l], &re_grid[grid_bw_sc * (l_first + l) + f_offset], SRSRAN_SSB_BW_SUBC); + } + + // Decode PBCH + if (ssb_decode_pbch(q, N_id, n_hf, ssb_idx, ssb_grid, msg) < SRSRAN_SUCCESS) { + ERROR("Error decoding"); + return SRSRAN_ERROR; + } + + return SRSRAN_SUCCESS; +} + int srsran_ssb_decode_pbch(srsran_ssb_t* q, uint32_t N_id, uint32_t n_hf, diff --git a/lib/src/phy/sync/test/CMakeLists.txt b/lib/src/phy/sync/test/CMakeLists.txt index bba52f5ea..afde5fe7b 100644 --- a/lib/src/phy/sync/test/CMakeLists.txt +++ b/lib/src/phy/sync/test/CMakeLists.txt @@ -133,6 +133,9 @@ target_link_libraries(ssb_measure_test srsran_phy) add_executable(ssb_decode_test ssb_decode_test.c) target_link_libraries(ssb_decode_test srsran_phy) +add_executable(ssb_grid_test ssb_grid_test.c) +target_link_libraries(ssb_grid_test srsran_phy) + # For 1.0 GHz and 3.5 GHz Center frequencies foreach (CELL_FREQ 1000000 3500000) # For each supported Cell/Carrier subcarrier spacing @@ -153,6 +156,10 @@ foreach (CELL_FREQ 1000000 3500000) # Test SSB PBCH decoding add_nr_test(ssb_decode_test_${CELL_FREQ}000_${CELL_SCS}_${SSB_FREQ}000_${SSB_SCS}_${SSB_PATTERN} ssb_decode_test -F ${CELL_FREQ}000 -S ${CELL_SCS} -f ${SSB_FREQ}000 -s ${SSB_SCS} -P ${SSB_PATTERN}) + + # Test SSB grid put/get decoding + add_nr_test(ssb_grid_test_${CELL_FREQ}000_${CELL_SCS}_${SSB_FREQ}000_${SSB_SCS}_${SSB_PATTERN} ssb_grid_test + -F ${CELL_FREQ}000 -S ${CELL_SCS} -f ${SSB_FREQ}000 -s ${SSB_SCS} -P ${SSB_PATTERN}) endforeach () endforeach () endforeach () diff --git a/lib/src/phy/sync/test/ssb_grid_test.c b/lib/src/phy/sync/test/ssb_grid_test.c new file mode 100644 index 000000000..2020f900e --- /dev/null +++ b/lib/src/phy/sync/test/ssb_grid_test.c @@ -0,0 +1,180 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2021 Software Radio Systems Limited + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the distribution. + * + */ + +#include "srsran/common/test_common.h" +#include "srsran/phy/channel/ch_awgn.h" +#include "srsran/phy/sync/ssb.h" +#include "srsran/phy/utils/debug.h" +#include "srsran/phy/utils/vector.h" +#include +#include +#include +#include + +// NR parameters +static srsran_subcarrier_spacing_t carrier_scs = srsran_subcarrier_spacing_15kHz; +static double carrier_freq_hz = 3.5e9 + 960e3; +static srsran_subcarrier_spacing_t ssb_scs = srsran_subcarrier_spacing_30kHz; +static double ssb_freq_hz = 3.5e9; +static srsran_ssb_patern_t ssb_pattern = SRSRAN_SSB_PATTERN_A; +static uint32_t ssb_idx = 0; // SSB candidate index to test +static uint32_t pci = 123; // N_id + +// Test context +static srsran_random_t random_gen = NULL; +static double srate_hz = 0.0f; // Base-band sampling rate +static cf_t* grid = NULL; // Resource grid +static uint32_t grid_bw_sc = 52 * SRSRAN_NRE; // Resource grid bandwidth in subcarriers + +static void usage(char* prog) +{ + printf("Usage: %s [v]\n", prog); + printf("\t-s SSB subcarrier spacing [default, %s kHz]\n", srsran_subcarrier_spacing_to_str(ssb_scs)); + printf("\t-f SSB center frequency [default, %.3f MHz]\n", ssb_freq_hz / 1e6); + printf("\t-S cell/carrier subcarrier spacing [default, %s kHz]\n", srsran_subcarrier_spacing_to_str(carrier_scs)); + printf("\t-F cell/carrier center frequency in Hz [default, %.3f MHz]\n", carrier_freq_hz / 1e6); + printf("\t-P SSB pattern [default, %s]\n", srsran_ssb_pattern_to_str(ssb_pattern)); + printf("\t-v [set srsran_verbose to debug, default none]\n"); +} + +static void parse_args(int argc, char** argv) +{ + int opt; + while ((opt = getopt(argc, argv, "SsFfPv")) != -1) { + switch (opt) { + case 's': + ssb_scs = srsran_subcarrier_spacing_from_str(argv[optind]); + if (ssb_scs == srsran_subcarrier_spacing_invalid) { + ERROR("Invalid SSB subcarrier spacing %s\n", argv[optind]); + exit(-1); + } + break; + case 'f': + ssb_freq_hz = strtod(argv[optind], NULL); + break; + case 'S': + carrier_scs = srsran_subcarrier_spacing_from_str(argv[optind]); + if (carrier_scs == srsran_subcarrier_spacing_invalid) { + ERROR("Invalid Cell/Carrier subcarrier spacing %s\n", argv[optind]); + exit(-1); + } + break; + case 'F': + carrier_freq_hz = strtod(argv[optind], NULL); + break; + case 'P': + ssb_pattern = srsran_ssb_pattern_fom_str(argv[optind]); + break; + case 'v': + increase_srsran_verbose_level(); + break; + default: + usage(argv[0]); + exit(-1); + } + } +} + +static void gen_pbch_msg(srsran_pbch_msg_nr_t* pbch_msg) +{ + // Default all to zero + SRSRAN_MEM_ZERO(pbch_msg, srsran_pbch_msg_nr_t, 1); + + // Generate payload + srsran_random_bit_vector(random_gen, pbch_msg->payload, SRSRAN_PBCH_MSG_NR_SZ); + + pbch_msg->ssb_idx = ssb_idx; + pbch_msg->crc = true; +} + +static int test_case(srsran_ssb_t* ssb) +{ + // SSB configuration + srsran_ssb_cfg_t ssb_cfg = {}; + ssb_cfg.srate_hz = srate_hz; + ssb_cfg.center_freq_hz = carrier_freq_hz; + ssb_cfg.ssb_freq_hz = ssb_freq_hz; + ssb_cfg.scs = ssb_scs; + ssb_cfg.pattern = ssb_pattern; + + TESTASSERT(srsran_ssb_set_cfg(ssb, &ssb_cfg) == SRSRAN_SUCCESS); + + // Build PBCH message + srsran_pbch_msg_nr_t pbch_msg_tx = {}; + gen_pbch_msg(&pbch_msg_tx); + + // Print encoded PBCH message + char str[512] = {}; + srsran_pbch_msg_info(&pbch_msg_tx, str, sizeof(str)); + INFO("test_case - encoded pci=%d %s", pci, str); + + // Add the SSB base-band + TESTASSERT(srsran_ssb_put_grid(ssb, pci, &pbch_msg_tx, grid, grid_bw_sc) == SRSRAN_SUCCESS); + + // Decode + srsran_pbch_msg_nr_t pbch_msg_rx = {}; + TESTASSERT(srsran_ssb_decode_grid(ssb, pci, pbch_msg_tx.hrf, pbch_msg_tx.ssb_idx, grid, grid_bw_sc, &pbch_msg_rx) == + SRSRAN_SUCCESS); + + // Print decoded PBCH message + srsran_pbch_msg_info(&pbch_msg_rx, str, sizeof(str)); + INFO("test_case - decoded pci=%d %s crc=%s", pci, str, pbch_msg_rx.crc ? "OK" : "KO"); + + // Assert PBCH message CRC + TESTASSERT(pbch_msg_rx.crc); + TESTASSERT(memcmp(&pbch_msg_rx, &pbch_msg_tx, sizeof(srsran_pbch_msg_nr_t)) == 0); + + return SRSRAN_SUCCESS; +} + +int main(int argc, char** argv) +{ + int ret = SRSRAN_ERROR; + parse_args(argc, argv); + + random_gen = srsran_random_init(1234); + srate_hz = (double)SRSRAN_SUBC_SPACING_NR(carrier_scs) * srsran_min_symbol_sz_rb(grid_bw_sc / SRSRAN_NRE); + grid = srsran_vec_cf_malloc(grid_bw_sc * SRSRAN_NSYMB_PER_SLOT_NR); + + srsran_ssb_t ssb = {}; + srsran_ssb_args_t ssb_args = {}; + ssb_args.enable_encode = true; + ssb_args.enable_decode = true; + ssb_args.enable_search = true; + + if (grid == NULL) { + ERROR("Malloc"); + goto clean_exit; + } + + if (srsran_ssb_init(&ssb, &ssb_args) < SRSRAN_SUCCESS) { + ERROR("Init"); + goto clean_exit; + } + + if (test_case(&ssb) != SRSRAN_SUCCESS) { + ERROR("test case failed"); + goto clean_exit; + } + + ret = SRSRAN_SUCCESS; + +clean_exit: + srsran_random_free(random_gen); + srsran_ssb_free(&ssb); + + if (grid) { + free(grid); + } + + return ret; +} \ No newline at end of file From 9f25a9128211dc428aac672e5edd34b060c6e8fe Mon Sep 17 00:00:00 2001 From: Carlo Galiotto Date: Mon, 31 Jan 2022 18:45:23 +0100 Subject: [PATCH 17/62] asn1: fix clang compiling issue #3827 Signed-off-by: Carlo Galiotto --- lib/include/srsran/asn1/rrc_nr.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/lib/include/srsran/asn1/rrc_nr.h b/lib/include/srsran/asn1/rrc_nr.h index 86c4106a6..0ebc417b2 100644 --- a/lib/include/srsran/asn1/rrc_nr.h +++ b/lib/include/srsran/asn1/rrc_nr.h @@ -3639,6 +3639,9 @@ struct sib1_s { uac_barr_info_s_ uac_barr_info; dyn_octstring late_non_crit_ext; + // Temporary hacky fix for Clang not being able to find dtor + ~sib1_s(){}; + // sequence methods SRSASN_CODE pack(bit_ref& bref) const; SRSASN_CODE unpack(cbit_ref& bref); @@ -20135,6 +20138,9 @@ struct mac_cell_group_cfg_s { bool csi_mask = false; copy_ptr > data_inactivity_timer; + // Temporary hacky fix for Clang not being able to find dtor + ~mac_cell_group_cfg_s(){}; + // sequence methods SRSASN_CODE pack(bit_ref& bref) const; SRSASN_CODE unpack(cbit_ref& bref); @@ -20187,6 +20193,9 @@ struct phys_cell_group_cfg_s { // group 2 copy_ptr > > pdcch_blind_detection; + // Temporary hacky fix for Clang not being able to find dtor + ~phys_cell_group_cfg_s(){}; + // sequence methods SRSASN_CODE pack(bit_ref& bref) const; SRSASN_CODE unpack(cbit_ref& bref); From d3eca325f7b64c82e09c6d0e30cb5af85c2d8562 Mon Sep 17 00:00:00 2001 From: Robert Falkenberg Date: Mon, 27 Sep 2021 09:53:42 +0200 Subject: [PATCH 18/62] Add file-based RF device for rx from arbitrary FILE* It comes with the following changes: * Add RF frontend API function "srslte_rf_open_file()" * Open file-based RF via explicit call of custom "rf_file_open_file()", instead of "srslte_rf_open_multi()" function pointer as for regular devices. * Introduce device name "file" * Introduce new SRSLTE_ERROR_RX_EOF error code * ZMQ: make update_rates() static to resolve conflicts --- lib/include/srsran/config.h | 1 + lib/include/srsran/phy/rf/rf.h | 13 + lib/src/phy/rf/CMakeLists.txt | 2 + lib/src/phy/rf/rf_dev.h | 37 ++ lib/src/phy/rf/rf_file_imp.c | 597 +++++++++++++++++++++++++++++++ lib/src/phy/rf/rf_file_imp.h | 136 +++++++ lib/src/phy/rf/rf_file_imp_rx.c | 97 +++++ lib/src/phy/rf/rf_file_imp_trx.h | 84 +++++ lib/src/phy/rf/rf_imp.c | 8 + lib/src/phy/rf/rf_zmq_imp.c | 2 +- 10 files changed, 976 insertions(+), 1 deletion(-) create mode 100644 lib/src/phy/rf/rf_file_imp.c create mode 100644 lib/src/phy/rf/rf_file_imp.h create mode 100644 lib/src/phy/rf/rf_file_imp_rx.c create mode 100644 lib/src/phy/rf/rf_file_imp_trx.h diff --git a/lib/include/srsran/config.h b/lib/include/srsran/config.h index 4bb98ff57..139d7c108 100644 --- a/lib/include/srsran/config.h +++ b/lib/include/srsran/config.h @@ -53,6 +53,7 @@ #define SRSRAN_ERROR_OUT_OF_BOUNDS -5 #define SRSRAN_ERROR_CANT_START -6 #define SRSRAN_ERROR_ALREADY_STARTED -7 +#define SRSRAN_ERROR_RX_EOF -8 // cf_t definition typedef _Complex float cf_t; diff --git a/lib/include/srsran/phy/rf/rf.h b/lib/include/srsran/phy/rf/rf.h index 7782c2f4f..f21bfe717 100644 --- a/lib/include/srsran/phy/rf/rf.h +++ b/lib/include/srsran/phy/rf/rf.h @@ -16,6 +16,7 @@ #include #include #include +#include #include #include "srsran/config.h" @@ -68,6 +69,18 @@ SRSRAN_API int srsran_rf_open_multi(srsran_rf_t* h, char* args, uint32_t nof_cha SRSRAN_API int srsran_rf_open_devname(srsran_rf_t* h, const char* devname, char* args, uint32_t nof_channels); +/** + * @brief Opens a file-based RF abstraction + * @param[out] rf Device handle + * @param[in] rx_files List of pre-opened FILE* for each RX channel; NULL to disable + * @param[in] tx_files List of pre-opened FILE* for each TX channel; NULL to disable + * @param[in] nof_channels Number of channels per direction + * @param[in] base_srate Sample rate of RX and TX files + * @return SRSRAN_SUCCESS on success, otherwise error code + */ +SRSRAN_API int +srsran_rf_open_file(srsran_rf_t* rf, FILE** rx_files, FILE** tx_files, uint32_t nof_channels, uint32_t base_srate); + SRSRAN_API const char* srsran_rf_name(srsran_rf_t* h); SRSRAN_API int srsran_rf_start_gain_thread(srsran_rf_t* rf, bool tx_gain_same_rx); diff --git a/lib/src/phy/rf/CMakeLists.txt b/lib/src/phy/rf/CMakeLists.txt index cd50b85ff..348609de7 100644 --- a/lib/src/phy/rf/CMakeLists.txt +++ b/lib/src/phy/rf/CMakeLists.txt @@ -59,6 +59,8 @@ if(RF_FOUND) list(APPEND SOURCES_RF rf_zmq_imp.c rf_zmq_imp_tx.c rf_zmq_imp_rx.c) endif (ZEROMQ_FOUND) + list(APPEND SOURCES_RF rf_file_imp.c rf_file_imp_rx.c) + add_library(srsran_rf_object OBJECT ${SOURCES_RF}) set_property(TARGET srsran_rf_object PROPERTY POSITION_INDEPENDENT_CODE 1) diff --git a/lib/src/phy/rf/rf_dev.h b/lib/src/phy/rf/rf_dev.h index 4adbdd463..75f0db383 100644 --- a/lib/src/phy/rf/rf_dev.h +++ b/lib/src/phy/rf/rf_dev.h @@ -216,6 +216,40 @@ static rf_dev_t dev_zmq = {"zmq", .srsran_rf_send_timed_multi = rf_zmq_send_timed_multi}; #endif +/* Define implementation for file-based RF */ + +#include "rf_file_imp.h" + +static rf_dev_t dev_file = {"file", + rf_file_devname, + rf_file_start_rx_stream, + rf_file_stop_rx_stream, + rf_file_flush_buffer, + rf_file_has_rssi, + rf_file_get_rssi, + rf_file_suppress_stdout, + rf_file_register_error_handler, + rf_file_open, + .srsran_rf_open_multi = rf_file_open_multi, + rf_file_close, + rf_file_set_rx_srate, + rf_file_set_rx_gain, + rf_file_set_rx_gain_ch, + rf_file_set_tx_gain, + rf_file_set_tx_gain_ch, + rf_file_get_rx_gain, + rf_file_get_tx_gain, + rf_file_get_info, + rf_file_set_rx_freq, + rf_file_set_tx_srate, + rf_file_set_tx_freq, + rf_file_get_time, + NULL, + rf_file_recv_with_time, + rf_file_recv_with_time_multi, + rf_file_send_timed, + .srsran_rf_send_timed_multi = rf_file_send_timed_multi}; + /* Define implementation for Sidekiq */ #ifdef ENABLE_SIDEKIQ @@ -267,6 +301,9 @@ static rf_dev_t dev_dummy = {"dummy", dummy_fnc, dummy_fnc, dummy_fnc, dummy_f dummy_fnc, dummy_fnc, dummy_fnc, dummy_fnc, dummy_fnc}; #endif +/** + * Collection of all currently supported RF devices + */ static rf_dev_t* available_devices[] = { #ifdef ENABLE_UHD diff --git a/lib/src/phy/rf/rf_file_imp.c b/lib/src/phy/rf/rf_file_imp.c new file mode 100644 index 000000000..f03295761 --- /dev/null +++ b/lib/src/phy/rf/rf_file_imp.c @@ -0,0 +1,597 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2021 Software Radio Systems Limited + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the distribution. + * + */ + +#ifndef SRSRAN_RF_IMP_TRX_H +#define SRSRAN_RF_IMP_TRX_H + +#include "rf_file_imp.h" +#include "rf_file_imp_trx.h" +#include "rf_helper.h" +#include +#include +#include +#include +#include +#include +#include + +typedef struct { + // Common attributes + char* devname; + srsran_rf_info_t info; + uint32_t nof_channels; + + // RF State + uint32_t srate; // radio rate configured by upper layers + uint32_t base_srate; + uint32_t decim_factor; // decimation factor between base_srate used on transport on radio's rate + double rx_gain; + uint32_t tx_freq_mhz[SRSRAN_MAX_PORTS]; + uint32_t rx_freq_mhz[SRSRAN_MAX_PORTS]; + bool tx_used; + + // FILEs + rf_file_tx_t transmitter[SRSRAN_MAX_PORTS]; + rf_file_rx_t receiver[SRSRAN_MAX_PORTS]; + + char id[PARAM_LEN_SHORT]; + + // Various sample buffers + cf_t* buffer_decimation[SRSRAN_MAX_PORTS]; + cf_t* buffer_tx; + + // Rx timestamp + uint64_t next_rx_ts; + + pthread_mutex_t tx_config_mutex; + pthread_mutex_t rx_config_mutex; + pthread_mutex_t decim_mutex; +} rf_file_handler_t; + +/* + * Static methods + */ + +static void update_rates(rf_file_handler_t* handler, double srate); + +static inline int update_ts(void* h, uint64_t* ts, int nsamples, const char* dir) +{ + int ret = SRSRAN_ERROR; + + if (h && nsamples > 0) { + rf_file_handler_t* handler = (rf_file_handler_t*)h; + + (*ts) += nsamples; + + srsran_timestamp_t _ts = {}; + srsran_timestamp_init_uint64(&_ts, *ts, handler->base_srate); + + ret = SRSRAN_SUCCESS; + } + + return ret; +} + +int rf_file_handle_error(char* id, const char* text) +{ + // Not implemented + return SRSRAN_ERROR; +} + +/* + * Public methods + */ + +const char* rf_file_devname(void* h) +{ + return DEVNAME_FILE; +} + +int rf_file_start_rx_stream(void* h, bool now) +{ + return SRSRAN_SUCCESS; +} + +int rf_file_stop_rx_stream(void* h) +{ + return SRSRAN_SUCCESS; +} + +void rf_file_flush_buffer(void* h) +{ + printf("%s\n", __FUNCTION__); +} + +bool rf_file_has_rssi(void* h) +{ + return false; +} + +float rf_file_get_rssi(void* h) +{ + return 0.0; +} + +void rf_file_suppress_stdout(void* h) +{ + // do nothing +} + +void rf_file_register_error_handler(void* h, srsran_rf_error_handler_t error_handler, void* arg) +{ + // do nothing +} + +int rf_file_open(char* args, void** h) +{ + return rf_file_open_multi(args, h, 1); +} + +int rf_file_open_multi(char* args, void** h, uint32_t nof_channels) +{ + perror("Cannot open file-based RF as regular device. Use rf_file_open_file() instead."); + return SRSRAN_ERROR_INVALID_COMMAND; +} + +int rf_file_open_file(void** h, FILE **rx_files, FILE **tx_files, uint32_t nof_channels, uint32_t base_srate) +{ + int ret = SRSRAN_ERROR; + + if (h) { + *h = NULL; + + rf_file_handler_t* handler = (rf_file_handler_t*)malloc(sizeof(rf_file_handler_t)); + if (!handler) { + perror("malloc"); + return SRSRAN_ERROR; + } + memset(handler, 0, sizeof(rf_file_handler_t)); + *h = handler; + handler->base_srate = FILE_BASERATE_DEFAULT_HZ; // Sample rate for 100 PRB cell + handler->rx_gain = 0.0; + handler->info.max_rx_gain = FILE_MAX_GAIN_DB; + handler->info.min_rx_gain = FILE_MIN_GAIN_DB; + handler->info.max_tx_gain = FILE_MAX_GAIN_DB; + handler->info.min_tx_gain = FILE_MIN_GAIN_DB; + handler->nof_channels = nof_channels; + strcpy(handler->id, "file\0"); + + rf_file_opts_t rx_opts = {}; + rf_file_opts_t tx_opts = {}; + tx_opts.id = handler->id; + rx_opts.id = handler->id; + + if (pthread_mutex_init(&handler->tx_config_mutex, NULL)) { + perror("Mutex init"); + } + if (pthread_mutex_init(&handler->rx_config_mutex, NULL)) { + perror("Mutex init"); + } + if (pthread_mutex_init(&handler->decim_mutex, NULL)) { + perror("Mutex init"); + } + + // base_srate + handler->base_srate = base_srate; + + // id + // TODO: set some meaningful ID in handler->id + + // rx_format, tx_format + // TODO: add other formats + rx_opts.sample_format = FILERF_TYPE_FC32; + tx_opts.sample_format = FILERF_TYPE_FC32; + + update_rates(handler, 1.92e6); + + // Create channels + for (int i = 0; i < handler->nof_channels; i++) { + if (rx_files != NULL) { + rx_opts.file = rx_files[i]; + if (rf_file_rx_open(&handler->receiver[i], rx_opts) != SRSRAN_SUCCESS) { + fprintf(stderr, "[file] Error: opening receiver\n"); + goto clean_exit; + } + } else { + fprintf(stdout, "[file] %s Rx file not specified. Disabling receiver.\n", handler->id); + } + if (tx_files != NULL) { + tx_opts.file = tx_files[i]; + // TX is not implemented yet + // if(rf_file_tx_open(&handler->transmitter[i], tx_opts) != SRSRAN_SUCCESS) { + // fprintf(stderr, "[file] Error: opening transmitter\n"); + // goto clean_exit; + // } + } else { + // no tx_files provided + fprintf(stdout, "[file] %s Tx file not specified. Disabling transmitter.\n", handler->id); + } + + if (!handler->transmitter[i].running && !handler->receiver[i].running) { + fprintf(stderr, "[file] Error: Neither Tx file nor Rx file specified.\n"); + goto clean_exit; + } + } + + // Create decimation and overflow buffer + for (uint32_t i = 0; i < handler->nof_channels; i++) { + handler->buffer_decimation[i] = srsran_vec_malloc(FILE_MAX_BUFFER_SIZE); + if (!handler->buffer_decimation[i]) { + fprintf(stderr, "Error: allocating decimation buffer\n"); + goto clean_exit; + } + } + + handler->buffer_tx = srsran_vec_malloc(FILE_MAX_BUFFER_SIZE); + if (!handler->buffer_tx) { + fprintf(stderr, "Error: allocating tx buffer\n"); + goto clean_exit; + } + + ret = SRSRAN_SUCCESS; + + clean_exit: + if (ret) { + rf_file_close(handler); + } + } + return ret; +} + +int rf_file_close(void* h) +{ + + rf_file_handler_t* handler = (rf_file_handler_t*)h; + + for (uint32_t i = 0; i < handler->nof_channels; i++) { + if (handler->buffer_decimation[i]) { + free(handler->buffer_decimation[i]); + } + } + + if (handler->buffer_tx) { + free(handler->buffer_tx); + } + + pthread_mutex_destroy(&handler->tx_config_mutex); + pthread_mutex_destroy(&handler->rx_config_mutex); + pthread_mutex_destroy(&handler->decim_mutex); + + // Free all + free(handler); + + return SRSRAN_SUCCESS; +} + +void update_rates(rf_file_handler_t* handler, double srate) +{ + pthread_mutex_lock(&handler->decim_mutex); + if (handler) { + // Decimation must be full integer + if (((uint64_t)handler->base_srate % (uint64_t)srate) == 0) { + handler->srate = (uint32_t)srate; + handler->decim_factor = handler->base_srate / handler->srate; + } else { + fprintf(stderr, + "Error: couldn't update sample rate. %.2f is not divisible by %.2f\n", + srate / 1e6, + handler->base_srate / 1e6); + } + printf("Current sample rate is %.2f MHz with a base rate of %.2f MHz (x%d decimation)\n", + handler->srate / 1e6, + handler->base_srate / 1e6, + handler->decim_factor); + } + pthread_mutex_unlock(&handler->decim_mutex); +} + +double rf_file_set_rx_srate(void* h, double srate) +{ + double ret = 0.0; + if (h) { + rf_file_handler_t* handler = (rf_file_handler_t*)h; + update_rates(handler, srate); + ret = handler->srate; + } + return ret; +} + +int rf_file_set_rx_gain(void* h, double gain) +{ + double ret = 0.0; + if (h) { + rf_file_handler_t* handler = (rf_file_handler_t*)h; + handler->rx_gain = gain; + ret = gain; + } + return ret; +} + +int rf_file_set_rx_gain_ch(void* h, uint32_t ch, double gain) +{ + return rf_file_set_rx_gain(h, gain); +} + +int rf_file_set_tx_gain(void* h, double gain) +{ + return 0.0; +} + +int rf_file_set_tx_gain_ch(void* h, uint32_t ch, double gain) +{ + return rf_file_set_tx_gain(h, gain); +} + +double rf_file_get_rx_gain(void* h) +{ + double ret = 0.0; + if (h) { + rf_file_handler_t* handler = (rf_file_handler_t*)h; + ret = handler->rx_gain; + } + return ret; +} + +double rf_file_get_tx_gain(void* h) +{ + return 0.0; +} + +srsran_rf_info_t* rf_file_get_info(void* h) +{ + srsran_rf_info_t* info = NULL; + if (h) { + rf_file_handler_t* handler = (rf_file_handler_t*)h; + info = &handler->info; + } + return info; +} + +double rf_file_set_rx_freq(void* h, uint32_t ch, double freq) +{ + double ret = NAN; + if (h) { + rf_file_handler_t* handler = (rf_file_handler_t*)h; + pthread_mutex_lock(&handler->rx_config_mutex); + if (ch < handler->nof_channels && isnormal(freq) && freq > 0.0) { + handler->rx_freq_mhz[ch] = (uint32_t)(freq / 1e6); + ret = freq; + } + pthread_mutex_unlock(&handler->rx_config_mutex); + } + return ret; +} + +double rf_file_set_tx_srate(void* h, double srate) +{ + double ret = 0.0; + if (h) { + rf_file_handler_t* handler = (rf_file_handler_t*)h; + update_rates(handler, srate); + ret = srate; + } + return ret; +} + +double rf_file_set_tx_freq(void* h, uint32_t ch, double freq) +{ + double ret = NAN; + if (h) { + rf_file_handler_t* handler = (rf_file_handler_t*)h; + pthread_mutex_lock(&handler->tx_config_mutex); + if (ch < handler->nof_channels && isnormal(freq) && freq > 0.0) { + handler->tx_freq_mhz[ch] = (uint32_t)(freq / 1e6); + ret = freq; + } + pthread_mutex_unlock(&handler->tx_config_mutex); + } + return ret; +} + +void rf_file_get_time(void* h, time_t* secs, double* frac_secs) +{ + if (h) { + if (secs) { + *secs = 0; + } + + if (frac_secs) { + *frac_secs = 0; + } + } +} + +int rf_file_recv_with_time(void* h, void* data, uint32_t nsamples, bool blocking, time_t* secs, double* frac_secs) +{ + void* data_multi[SRSRAN_MAX_PORTS] = {NULL}; + data_multi[0] = data; + return rf_file_recv_with_time_multi(h, data_multi, nsamples, blocking, secs, frac_secs); +} + +int rf_file_recv_with_time_multi(void* h, + void* data[SRSRAN_MAX_PORTS], + uint32_t nsamples, + bool blocking, + time_t* secs, + double* frac_secs) +{ + int ret = SRSRAN_ERROR; + + if (h) { + rf_file_handler_t* handler = (rf_file_handler_t*)h; + + // Map ports to data buffers according to the selected frequencies + pthread_mutex_lock(&handler->rx_config_mutex); + cf_t* buffers[SRSRAN_MAX_PORTS] = {}; // Buffer pointers, NULL if unmatched + for (uint32_t i = 0; i < handler->nof_channels; i++) { + bool mapped = false; + + // Find first matching frequency + for (uint32_t j = 0; j < handler->nof_channels && !mapped; j++) { + // Traverse all channels, break if mapped + if (buffers[j] == NULL && rf_file_rx_match_freq(&handler->receiver[j], handler->rx_freq_mhz[i])) { + // Available buffer and matched frequency with receiver + buffers[j] = (cf_t*)data[i]; + mapped = true; + } + } + + // If no matching frequency found; set data to zeros + if (!mapped && data[i]) { + memset(data[i], 0, sizeof(cf_t) * nsamples); + } + } + pthread_mutex_unlock(&handler->rx_config_mutex); + + // Protect the access to decim_factor since is a shared variable + pthread_mutex_lock(&handler->decim_mutex); + uint32_t decim_factor = handler->decim_factor; + pthread_mutex_unlock(&handler->decim_mutex); + + uint32_t nbytes = NSAMPLES2NBYTES(nsamples * decim_factor); + uint32_t nsamples_baserate = nsamples * decim_factor; + + // set timestamp for this reception + if (secs != NULL && frac_secs != NULL) { + srsran_timestamp_t ts = {}; + srsran_timestamp_init_uint64(&ts, handler->next_rx_ts, handler->base_srate); + *secs = ts.full_secs; + *frac_secs = ts.frac_secs; + } + + // return if receiver is turned off + if (!handler->receiver[0].running) { + update_ts(handler, &handler->next_rx_ts, nsamples_baserate, "rx"); + return nsamples; + } + + // Check available buffer size + if (nbytes > FILE_MAX_BUFFER_SIZE) { + fprintf(stderr, + "[file] Error: Trying to receive %d B but buffer is only %zu B at channel %d.\n", + nbytes, + FILE_MAX_BUFFER_SIZE, + 0); + goto clean_exit; + } + + // receive samples + srsran_timestamp_t ts_tx = {}, ts_rx = {}; + srsran_timestamp_init_uint64(&ts_tx, handler->transmitter[0].nsamples, handler->base_srate); + srsran_timestamp_init_uint64(&ts_rx, handler->next_rx_ts, handler->base_srate); + + // copy from rx buffer as many samples as requested into provided buffer + bool completed = false; + int32_t count[SRSRAN_MAX_PORTS] = {}; + while (!completed) { + uint32_t completed_count = 0; + + // Iterate channels + for (uint32_t i = 0; i < handler->nof_channels; i++) { + cf_t* ptr = (decim_factor != 1 || buffers[i] == NULL) ? handler->buffer_decimation[i] : buffers[i]; + + // Completed condition + if (count[i] < nsamples_baserate && handler->receiver[i].running) { + // Keep receiving + int32_t n = rf_file_rx_baseband(&handler->receiver[i], &ptr[count[i]], nsamples_baserate - count[i]); + if (n > 0) { + // No error + count[i] += n; + } else { + if (n != SRSRAN_ERROR_RX_EOF) { + // Other error, exit + fprintf(stderr, "Error: receiving data.\n"); + } + ret = n; + goto clean_exit; + } + } else { + // Completed, count it + completed_count++; + } + } + + // Check if all channels are completed + completed = (completed_count == handler->nof_channels); + } + + // decimate if needed + if (decim_factor != 1) { + for (uint32_t c = 0; c < handler->nof_channels; c++) { + // skip if buffer is not available + if (buffers[c]) { + cf_t* dst = buffers[c]; + cf_t* ptr = handler->buffer_decimation[c]; + + for (uint32_t i = 0, n = 0; i < nsamples; i++) { + // Averaging decimation + cf_t avg = 0.0f; + for (int j = 0; j < decim_factor; j++, n++) { + avg += ptr[n]; + } + dst[i] = avg; + } + } + } + } + + // Set gain + float scale = srsran_convert_dB_to_amplitude(handler->rx_gain); + for (uint32_t c = 0; c < handler->nof_channels; c++) { + if (buffers[c]) { + srsran_vec_sc_prod_cfc(buffers[c], scale, buffers[c], nsamples); + } + } + + // update rx time + update_ts(handler, &handler->next_rx_ts, nsamples_baserate, "rx"); + } + + ret = nsamples; + +clean_exit: + + return ret; +} + +int rf_file_send_timed(void* h, + void* data, + int nsamples, + time_t secs, + double frac_secs, + bool has_time_spec, + bool blocking, + bool is_start_of_burst, + bool is_end_of_burst) +{ + void* _data[4] = {data, NULL, NULL, NULL}; + + return rf_file_send_timed_multi( + h, _data, nsamples, secs, frac_secs, has_time_spec, blocking, is_start_of_burst, is_end_of_burst); +} + +int rf_file_send_timed_multi(void* h, + void* data[4], + int nsamples, + time_t secs, + double frac_secs, + bool has_time_spec, + bool blocking, + bool is_start_of_burst, + bool is_end_of_burst) +{ + // Not implemented + fprintf(stderr, "Error: rf_file_send_timed_multi not implemented.\n"); + return SRSRAN_ERROR; +} + +#endif diff --git a/lib/src/phy/rf/rf_file_imp.h b/lib/src/phy/rf/rf_file_imp.h new file mode 100644 index 000000000..ae2763b7a --- /dev/null +++ b/lib/src/phy/rf/rf_file_imp.h @@ -0,0 +1,136 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2021 Software Radio Systems Limited + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the distribution. + * + */ + +#ifndef SRSRAN_RF_FILE_IMP_H +#define SRSRAN_RF_FILE_IMP_H + +#include + +#include "srsran/config.h" +#include "srsran/phy/common/phy_common.h" +#include "srsran/phy/rf/rf.h" + +#define DEVNAME_FILE "file" +#define PARAM_LEN (128) +#define PARAM_LEN_SHORT (PARAM_LEN / 2) + +SRSRAN_API const char* rf_file_devname(void* h); + +SRSRAN_API int rf_file_start_rx_stream(void* h, bool now); + +// SRSRAN_API int rf_file_start_rx_stream_nsamples(void* h, uint32_t nsamples); + +SRSRAN_API int rf_file_stop_rx_stream(void* h); + +SRSRAN_API void rf_file_flush_buffer(void* h); + +SRSRAN_API bool rf_file_has_rssi(void* h); + +SRSRAN_API float rf_file_get_rssi(void* h); + +SRSRAN_API void rf_file_suppress_stdout(void* h); + +SRSRAN_API void rf_file_register_error_handler(void* h, srsran_rf_error_handler_t error_handler, void* arg); + +/** + * @brief This function is not supported for file-based RF abstraction + * + * Use @c rf_file_open_file() to open this device + * + * @param args not used + * @param h not used + * @return SRSRAN_ERROR_INVALID_COMMAND + */ +SRSRAN_API int rf_file_open(char* args, void** h); + +/** + * @brief This function is not supported for file-based RF abstraction + * + * Use @c rf_file_open_file() to open this device + * + * @param args not used + * @param h not used + * @param nof_channels not used + * @return SRSRAN_ERROR_INVALID_COMMAND + */ +SRSRAN_API int rf_file_open_multi(char* args, void** h, uint32_t nof_channels); + +SRSRAN_API int rf_file_close(void* h); + +SRSRAN_API double rf_file_set_rx_srate(void* h, double srate); + +SRSRAN_API int rf_file_set_rx_gain(void* h, double gain); + +SRSRAN_API int rf_file_set_rx_gain_ch(void* h, uint32_t ch, double gain); + +SRSRAN_API int rf_file_set_tx_gain(void* h, double gain); + +SRSRAN_API int rf_file_set_tx_gain_ch(void* h, uint32_t ch, double gain); + +SRSRAN_API double rf_file_get_rx_gain(void* h); + +SRSRAN_API double rf_file_get_tx_gain(void* h); + +SRSRAN_API srsran_rf_info_t* rf_file_get_info(void* h); + +SRSRAN_API double rf_file_set_rx_freq(void* h, uint32_t ch, double freq); + +SRSRAN_API double rf_file_set_tx_srate(void* h, double srate); + +SRSRAN_API double rf_file_set_tx_freq(void* h, uint32_t ch, double freq); + +SRSRAN_API void rf_file_get_time(void* h, time_t* secs, double* frac_secs); + +// srsran_rf_sync_pps + +SRSRAN_API int +rf_file_recv_with_time(void* h, void* data, uint32_t nsamples, bool blocking, time_t* secs, double* frac_secs); + +SRSRAN_API int rf_file_recv_with_time_multi(void* h, + void* data[SRSRAN_MAX_PORTS], + uint32_t nsamples, + bool blocking, + time_t* secs, + double* frac_secs); + +SRSRAN_API int rf_file_send_timed(void* h, + void* data, + int nsamples, + time_t secs, + double frac_secs, + bool has_time_spec, + bool blocking, + bool is_start_of_burst, + bool is_end_of_burst); + +SRSRAN_API int rf_file_send_timed_multi(void* h, + void* data[4], + int nsamples, + time_t secs, + double frac_secs, + bool has_time_spec, + bool blocking, + bool is_start_of_burst, + bool is_end_of_burst); + +/** + * @brief Dedicated function to open a file-based RF abstraction + * @param[out] h Resulting object handle + * @param[in] rx_files List of pre-opened FILE* for each RX channel; NULL to disable + * @param[in] tx_files List of pre-opened FILE* for each TX channel; NULL to disable + * @param[in] nof_channels Number of channels per direction + * @param[in] base_srate Sample rate of RX and TX files + * @return SRSRAN_SUCCESS on success, otherwise error code + */ +SRSRAN_API int rf_file_open_file(void** h, FILE** rx_files, FILE** tx_files, uint32_t nof_channels, uint32_t base_srate); + +#endif // SRSRAN_RF_FILE_IMP_H diff --git a/lib/src/phy/rf/rf_file_imp_rx.c b/lib/src/phy/rf/rf_file_imp_rx.c new file mode 100644 index 000000000..30ceb9807 --- /dev/null +++ b/lib/src/phy/rf/rf_file_imp_rx.c @@ -0,0 +1,97 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2021 Software Radio Systems Limited + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the distribution. + * + */ + +#include "rf_file_imp_trx.h" +#include +#include +#include + +int rf_file_rx_open(rf_file_rx_t* q, rf_file_opts_t opts) +{ + int ret = SRSRAN_ERROR; + + if (q) { + // Zero object + bzero(q, sizeof(rf_file_rx_t)); + + // Copy id + strncpy(q->id, opts.id, FILE_ID_STRLEN - 1); + q->id[FILE_ID_STRLEN - 1] = '\0'; + + // Assign file + q->file = opts.file; + + // Configure formats + q->sample_format = opts.sample_format; + q->frequency_mhz = opts.frequency_mhz; + + q->temp_buffer = srsran_vec_malloc(FILE_MAX_BUFFER_SIZE); + if (!q->temp_buffer) { + fprintf(stderr, "Error: allocating rx buffer\n"); + goto clean_exit; + } + + q->temp_buffer_convert = srsran_vec_malloc(FILE_MAX_BUFFER_SIZE); + if (!q->temp_buffer_convert) { + fprintf(stderr, "Error: allocating rx buffer\n"); + goto clean_exit; + } + + if (pthread_mutex_init(&q->mutex, NULL)) { + fprintf(stderr, "Error: creating mutex\n"); + goto clean_exit; + } + + q->running = true; + + ret = SRSRAN_SUCCESS; + } + +clean_exit: + return ret; +} + +int rf_file_rx_baseband(rf_file_rx_t* q, cf_t* buffer, uint32_t nsamples) +{ + uint32_t sample_sz = sizeof(cf_t); + + int ret = fread(buffer, sample_sz, nsamples, q->file); + if (ret > 0) { + return ret; + } else { + return SRSRAN_ERROR_RX_EOF; + } +} + +bool rf_file_rx_match_freq(rf_file_rx_t* q, uint32_t freq_hz) +{ + bool ret = false; + if (q) { + ret = (q->frequency_mhz == 0 || q->frequency_mhz == freq_hz); + } + return ret; +} + +void rf_file_rx_close(rf_file_rx_t* q) +{ + q->running = false; + + if (q->temp_buffer) { + free(q->temp_buffer); + } + + if (q->temp_buffer_convert) { + free(q->temp_buffer_convert); + } + + q->file = NULL; +} diff --git a/lib/src/phy/rf/rf_file_imp_trx.h b/lib/src/phy/rf/rf_file_imp_trx.h new file mode 100644 index 000000000..5c4d596a1 --- /dev/null +++ b/lib/src/phy/rf/rf_file_imp_trx.h @@ -0,0 +1,84 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2021 Software Radio Systems Limited + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the distribution. + * + */ + +#ifndef SRSRAN_RF_FILE_IMP_TRX_H +#define SRSRAN_RF_FILE_IMP_TRX_H + +#include "srsran/config.h" +#include +#include +#include +#include +#include + +/* Definitions */ +#define VERBOSE (0) +#define NSAMPLES2NBYTES(X) (((uint32_t)(X)) * sizeof(cf_t)) +#define NBYTES2NSAMPLES(X) ((X) / sizeof(cf_t)) +#define FILE_MAX_BUFFER_SIZE (NSAMPLES2NBYTES(3072000)) // 10 subframes at 20 MHz +#define FILE_TIMEOUT_MS (1000) +#define FILE_BASERATE_DEFAULT_HZ (23040000) +#define FILE_ID_STRLEN 16 +#define FILE_MAX_GAIN_DB (30.0f) +#define FILE_MIN_GAIN_DB (0.0f) + +typedef enum { FILERF_TYPE_FC32 = 0, FILERF_TYPE_SC16 } rf_file_format_t; + +typedef struct { + char id[FILE_ID_STRLEN]; + rf_file_format_t sample_format; + FILE* file; + uint64_t nsamples; + bool running; + pthread_mutex_t mutex; + cf_t* zeros; + void* temp_buffer_convert; + uint32_t frequency_hz_mhz; +} rf_file_tx_t; + +typedef struct { + char id[FILE_ID_STRLEN]; + rf_file_format_t sample_format; + FILE* file; + uint64_t nsamples; + bool running; + pthread_t thread; + pthread_mutex_t mutex; + cf_t* temp_buffer; + void* temp_buffer_convert; + uint32_t frequency_mhz; +} rf_file_rx_t; + +typedef struct { + const char* id; + rf_file_format_t sample_format; + FILE* file; + uint32_t frequency_mhz; +} rf_file_opts_t; + +/* + * Common functions + */ +SRSRAN_API int rf_file_handle_error(char* id, const char* text); + +/* + * Receiver functions + */ +SRSRAN_API int rf_file_rx_open(rf_file_rx_t* q, rf_file_opts_t opts); + +SRSRAN_API int rf_file_rx_baseband(rf_file_rx_t* q, cf_t* buffer, uint32_t nsamples); + +SRSRAN_API bool rf_file_rx_match_freq(rf_file_rx_t* q, uint32_t freq_hz); + +SRSRAN_API void rf_file_rx_close(rf_file_rx_t* q); + +#endif // SRSRAN_RF_FILE_IMP_TRX_H diff --git a/lib/src/phy/rf/rf_imp.c b/lib/src/phy/rf/rf_imp.c index 119dda93b..2b58e595e 100644 --- a/lib/src/phy/rf/rf_imp.c +++ b/lib/src/phy/rf/rf_imp.c @@ -139,6 +139,14 @@ int srsran_rf_open_devname(srsran_rf_t* rf, const char* devname, char* args, uin return SRSRAN_ERROR; } +int srsran_rf_open_file(srsran_rf_t* rf, FILE** rx_files, FILE** tx_files, uint32_t nof_channels, uint32_t base_srate) +{ + rf->dev = &dev_file; + + // file abstraction has custom "open" function with file-related args + return rf_file_open_file(&rf->handler, rx_files, tx_files, nof_channels, base_srate); +} + const char* srsran_rf_name(srsran_rf_t* rf) { return ((rf_dev_t*)rf->dev)->srsran_rf_devname(rf->handler); diff --git a/lib/src/phy/rf/rf_zmq_imp.c b/lib/src/phy/rf/rf_zmq_imp.c index 2b501a32d..ef0e535e5 100644 --- a/lib/src/phy/rf/rf_zmq_imp.c +++ b/lib/src/phy/rf/rf_zmq_imp.c @@ -57,7 +57,7 @@ typedef struct { pthread_mutex_t rx_gain_mutex; } rf_zmq_handler_t; -void update_rates(rf_zmq_handler_t* handler, double srate); +static void update_rates(rf_zmq_handler_t* handler, double srate); /* * Static Atributes From 57f84d4ca4a1b1c5d6078016ac833419f6c6528f Mon Sep 17 00:00:00 2001 From: Robert Falkenberg Date: Wed, 6 Oct 2021 14:50:30 +0200 Subject: [PATCH 19/62] Radio: add support for file-based RF device abstraction --- lib/include/srsran/common/interfaces_common.h | 3 ++ lib/include/srsran/radio/radio.h | 13 +++++ lib/src/radio/radio.cc | 48 +++++++++++++++++-- 3 files changed, 61 insertions(+), 3 deletions(-) diff --git a/lib/include/srsran/common/interfaces_common.h b/lib/include/srsran/common/interfaces_common.h index 1439b16d1..3c9cb19e6 100644 --- a/lib/include/srsran/common/interfaces_common.h +++ b/lib/include/srsran/common/interfaces_common.h @@ -56,6 +56,9 @@ struct rf_args_t { std::array ch_rx_bands; std::array ch_tx_bands; + + FILE** rx_files; // Array of pre-opened FILE* for rx instead of a real device + FILE** tx_files; // Array of pre-opened FILE* for tx instead of a real device }; class srsran_gw_config_t diff --git a/lib/include/srsran/radio/radio.h b/lib/include/srsran/radio/radio.h index defe4c84c..b0cdf01f7 100644 --- a/lib/include/srsran/radio/radio.h +++ b/lib/include/srsran/radio/radio.h @@ -158,6 +158,19 @@ private: */ bool open_dev(const uint32_t& device_idx, const std::string& device_name, const std::string& devive_args); + /** + * Helper method for opening a file-based RF device abstraction + * + * @param device_idx Device index + * @param rx_files Array of pre-opened FILE* for rx + * @param tx_files Array of pre-opened FILE* for tx + * @param nof_channels Number of elements in each array @p rx_files and @p tx_files + * @param base_srate Sampling rate in Hz + * @return it returns true if the device was opened successful, otherwise it returns false + */ + bool + open_dev(const uint32_t& device_idx, FILE** rx_files, FILE** tx_files, uint32_t nof_channels, uint32_t base_srate); + /** * Helper method for transmitting over a single RF device. This function maps automatically the logical transmit * buffers to the physical RF buffers for the given device. diff --git a/lib/src/radio/radio.cc b/lib/src/radio/radio.cc index a8694ca02..25b742117 100644 --- a/lib/src/radio/radio.cc +++ b/lib/src/radio/radio.cc @@ -103,11 +103,30 @@ int radio::init(const rf_args_t& args, phy_interface_radio* phy_) rx_channel_mapping.set_config(nof_channels_x_dev, nof_antennas); // Init and start Radios - for (uint32_t device_idx = 0; device_idx < (uint32_t)device_args_list.size(); device_idx++) { - if (not open_dev(device_idx, args.device_name, device_args_list[device_idx])) { - logger.error("Error opening RF device %d", device_idx); + if (args.device_name != "file" || device_args_list[0] != "auto") { + // regular RF device + for (uint32_t device_idx = 0; device_idx < (uint32_t)device_args_list.size(); device_idx++) { + if (not open_dev(device_idx, args.device_name, device_args_list[device_idx])) { + logger.error("Error opening RF device %d", device_idx); + return SRSRAN_ERROR; + } + } + } else { + // file-based RF device abstraction using pre-opened FILE* objects + if (args.rx_files == nullptr && args.tx_files == nullptr) { + logger.error("File-based RF device abstraction requested, but no files provided"); return SRSRAN_ERROR; } + for (uint32_t device_idx = 0; device_idx < (uint32_t)device_args_list.size(); device_idx++) { + if (not open_dev(device_idx, + &args.rx_files[device_idx * nof_channels_x_dev], + &args.tx_files[device_idx * nof_channels_x_dev], + nof_channels_x_dev, + args.srate_hz)) { + logger.error("Error opening RF device %d", device_idx); + return SRSRAN_ERROR; + } + } } is_start_of_burst = true; @@ -473,6 +492,29 @@ bool radio::open_dev(const uint32_t& device_idx, const std::string& device_name, return true; } +bool radio::open_dev(const uint32_t &device_idx, FILE** rx_files, FILE** tx_files, uint32_t nof_channels, uint32_t base_srate) +{ + srsran_rf_t* rf_device = &rf_devices[device_idx]; + + srsran::console("Opening %d channels in RF device abstraction\n"); + + if (srsran_rf_open_file(rf_device, rx_files, tx_files, nof_channels, base_srate)) { + logger.error("Error opening RF device abstraction"); + return false; + } + + // Suppress radio stdout + srsran_rf_suppress_stdout(rf_device); + + // Register handler for processing O/U/L + srsran_rf_register_error_handler(rf_device, rf_msg_callback, this); + + // Get device info + rf_info[device_idx] = *srsran_rf_get_info(rf_device); + + return true; +} + bool radio::tx_dev(const uint32_t& device_idx, rf_buffer_interface& buffer, const srsran_timestamp_t& tx_time_) { uint32_t nof_samples = buffer.get_nof_samples(); From f3d144dd59ce32b1f47462a637de06895b4a9219 Mon Sep 17 00:00:00 2001 From: Robert Falkenberg Date: Tue, 16 Nov 2021 15:32:34 +0100 Subject: [PATCH 20/62] filerf: add tx, multi-channel, open via device string and test This commits extends the file-based RF device as follows: * open device via device string * add tx to file * add multi-channel support (multiple files) * add rf_file_test.c to for testing --- lib/src/phy/rf/CMakeLists.txt | 6 +- lib/src/phy/rf/rf_dev.h | 1 + lib/src/phy/rf/rf_file_imp.c | 365 ++++++++++++++++++++++++++----- lib/src/phy/rf/rf_file_imp.h | 8 +- lib/src/phy/rf/rf_file_imp_rx.c | 5 +- lib/src/phy/rf/rf_file_imp_trx.h | 24 +- lib/src/phy/rf/rf_file_imp_tx.c | 189 ++++++++++++++++ lib/src/phy/rf/rf_file_test.c | 312 ++++++++++++++++++++++++++ 8 files changed, 847 insertions(+), 63 deletions(-) create mode 100644 lib/src/phy/rf/rf_file_imp_tx.c create mode 100644 lib/src/phy/rf/rf_file_test.c diff --git a/lib/src/phy/rf/CMakeLists.txt b/lib/src/phy/rf/CMakeLists.txt index 348609de7..77d60bfff 100644 --- a/lib/src/phy/rf/CMakeLists.txt +++ b/lib/src/phy/rf/CMakeLists.txt @@ -59,7 +59,7 @@ if(RF_FOUND) list(APPEND SOURCES_RF rf_zmq_imp.c rf_zmq_imp_tx.c rf_zmq_imp_rx.c) endif (ZEROMQ_FOUND) - list(APPEND SOURCES_RF rf_file_imp.c rf_file_imp_rx.c) + list(APPEND SOURCES_RF rf_file_imp.c rf_file_imp_tx.c rf_file_imp_rx.c) add_library(srsran_rf_object OBJECT ${SOURCES_RF}) set_property(TARGET srsran_rf_object PROPERTY POSITION_INDEPENDENT_CODE 1) @@ -100,5 +100,9 @@ if(RF_FOUND) #add_test(rf_zmq_test rf_zmq_test) endif (ZEROMQ_FOUND) + add_executable(rf_file_test rf_file_test.c) + target_link_libraries(rf_file_test srsran_rf) + add_test(rf_file_test rf_file_test) + INSTALL(TARGETS srsran_rf DESTINATION ${LIBRARY_DIR}) endif(RF_FOUND) diff --git a/lib/src/phy/rf/rf_dev.h b/lib/src/phy/rf/rf_dev.h index 75f0db383..b31e9d65d 100644 --- a/lib/src/phy/rf/rf_dev.h +++ b/lib/src/phy/rf/rf_dev.h @@ -324,4 +324,5 @@ static rf_dev_t* available_devices[] = { #ifdef ENABLE_DUMMY_DEV &dev_dummy, #endif + &dev_file, NULL}; diff --git a/lib/src/phy/rf/rf_file_imp.c b/lib/src/phy/rf/rf_file_imp.c index f03295761..b44d97bcb 100644 --- a/lib/src/phy/rf/rf_file_imp.c +++ b/lib/src/phy/rf/rf_file_imp.c @@ -16,6 +16,7 @@ #include "rf_file_imp.h" #include "rf_file_imp_trx.h" #include "rf_helper.h" +#include #include #include #include @@ -35,18 +36,18 @@ typedef struct { uint32_t base_srate; uint32_t decim_factor; // decimation factor between base_srate used on transport on radio's rate double rx_gain; - uint32_t tx_freq_mhz[SRSRAN_MAX_PORTS]; - uint32_t rx_freq_mhz[SRSRAN_MAX_PORTS]; - bool tx_used; + uint32_t tx_freq_mhz[SRSRAN_MAX_CHANNELS]; + uint32_t rx_freq_mhz[SRSRAN_MAX_CHANNELS]; + bool tx_off; + char id[RF_PARAM_LEN]; // FILEs - rf_file_tx_t transmitter[SRSRAN_MAX_PORTS]; - rf_file_rx_t receiver[SRSRAN_MAX_PORTS]; - - char id[PARAM_LEN_SHORT]; + rf_file_tx_t transmitter[SRSRAN_MAX_CHANNELS]; + rf_file_rx_t receiver[SRSRAN_MAX_CHANNELS]; + bool close_files; // Various sample buffers - cf_t* buffer_decimation[SRSRAN_MAX_PORTS]; + cf_t* buffer_decimation[SRSRAN_MAX_CHANNELS]; cf_t* buffer_tx; // Rx timestamp @@ -55,6 +56,7 @@ typedef struct { pthread_mutex_t tx_config_mutex; pthread_mutex_t rx_config_mutex; pthread_mutex_t decim_mutex; + pthread_mutex_t rx_gain_mutex; } rf_file_handler_t; /* @@ -63,6 +65,31 @@ typedef struct { static void update_rates(rf_file_handler_t* handler, double srate); +void rf_file_info(char* id, const char* format, ...) +{ +#if VERBOSE + struct timeval t; + gettimeofday(&t, NULL); + va_list args; + va_start(args, format); + printf("[%s@%02ld.%06ld] ", id ? id : "file", t.tv_sec % 10, t.tv_usec); + vprintf(format, args); + va_end(args); +#else /* VERBOSE */ + // Do nothing +#endif /* VERBOSE */ +} + +void rf_file_error(char* id, const char* format, ...) +{ + struct timeval t; + gettimeofday(&t, NULL); + va_list args; + va_start(args, format); + vfprintf(stderr, format, args); + va_end(args); +} + static inline int update_ts(void* h, uint64_t* ts, int nsamples, const char* dir) { int ret = SRSRAN_ERROR; @@ -74,6 +101,8 @@ static inline int update_ts(void* h, uint64_t* ts, int nsamples, const char* dir srsran_timestamp_t _ts = {}; srsran_timestamp_init_uint64(&_ts, *ts, handler->base_srate); + rf_file_info( + handler->id, " -> next %s time after %d samples: %d + %.3f\n", dir, nsamples, _ts.full_secs, _ts.frac_secs); ret = SRSRAN_SUCCESS; } @@ -138,11 +167,76 @@ int rf_file_open(char* args, void** h) int rf_file_open_multi(char* args, void** h, uint32_t nof_channels) { - perror("Cannot open file-based RF as regular device. Use rf_file_open_file() instead."); - return SRSRAN_ERROR_INVALID_COMMAND; + int ret = SRSRAN_ERROR; + + FILE* rx_files[SRSRAN_MAX_CHANNELS] = {NULL}; + FILE* tx_files[SRSRAN_MAX_CHANNELS] = {NULL}; + + if (h && nof_channels < SRSRAN_MAX_CHANNELS) { + uint32_t base_srate = FILE_BASERATE_DEFAULT_HZ; + + // parse args + if (args && strlen(args)) { + // base_srate + parse_uint32(args, "base_srate", -1, &base_srate); + } else { + fprintf(stderr, "[file] Error: RF device args are required for file-based no-RF module\n"); + goto clean_exit; + } + + for (int i = 0; i < nof_channels; i++) { + // rx_file + char rx_file[RF_PARAM_LEN] = {}; + parse_string(args, "rx_file", i, rx_file); + + // tx_file + char tx_file[RF_PARAM_LEN] = {}; + parse_string(args, "tx_file", i, tx_file); + + // initialize transmitter + if (strlen(tx_file) != 0) { + tx_files[i] = fopen(tx_file, "wb"); + if (tx_files[i] == NULL) { + fprintf(stderr, "[file] Error: opening tx_file%d: %s; %s\n", i, tx_file, strerror(errno)); + goto clean_exit; + } + } + + // initialize receiver + if (strlen(rx_file) != 0) { + rx_files[i] = fopen(rx_file, "rb"); + if (rx_files[i] == NULL) { + fprintf(stderr, "[file] Error: opening rx_file%d: %s; %s\n", i, rx_file, strerror(errno)); + goto clean_exit; + } + } + } + + // defer further initialization to open_file method + ret = rf_file_open_file(h, rx_files, tx_files, nof_channels, base_srate); + if (ret != SRSRAN_SUCCESS) { + goto clean_exit; + } + + // add flag to close all files when closing device + rf_file_handler_t* handler = (rf_file_handler_t*)(*h); + handler->close_files = true; + return ret; + } + +clean_exit: + for (int i = 0; i < nof_channels; i++) { + if (rx_files[i] != NULL) { + fclose(rx_files[i]); + } + if (tx_files[i] != NULL) { + fclose(tx_files[i]); + } + } + return ret; } -int rf_file_open_file(void** h, FILE **rx_files, FILE **tx_files, uint32_t nof_channels, uint32_t base_srate) +int rf_file_open_file(void** h, FILE** rx_files, FILE** tx_files, uint32_t nof_channels, uint32_t base_srate) { int ret = SRSRAN_ERROR; @@ -151,13 +245,12 @@ int rf_file_open_file(void** h, FILE **rx_files, FILE **tx_files, uint32_t nof_c rf_file_handler_t* handler = (rf_file_handler_t*)malloc(sizeof(rf_file_handler_t)); if (!handler) { - perror("malloc"); + fprintf(stderr, "malloc: %s\n", strerror(errno)); return SRSRAN_ERROR; } memset(handler, 0, sizeof(rf_file_handler_t)); *h = handler; - handler->base_srate = FILE_BASERATE_DEFAULT_HZ; // Sample rate for 100 PRB cell - handler->rx_gain = 0.0; + handler->base_srate = base_srate; handler->info.max_rx_gain = FILE_MAX_GAIN_DB; handler->info.min_rx_gain = FILE_MIN_GAIN_DB; handler->info.max_tx_gain = FILE_MAX_GAIN_DB; @@ -171,17 +264,21 @@ int rf_file_open_file(void** h, FILE **rx_files, FILE **tx_files, uint32_t nof_c rx_opts.id = handler->id; if (pthread_mutex_init(&handler->tx_config_mutex, NULL)) { - perror("Mutex init"); + fprintf(stderr, "Mutex init: %s\n", strerror(errno)); } if (pthread_mutex_init(&handler->rx_config_mutex, NULL)) { - perror("Mutex init"); + fprintf(stderr, "Mutex init: %s\n", strerror(errno)); } if (pthread_mutex_init(&handler->decim_mutex, NULL)) { - perror("Mutex init"); + fprintf(stderr, "Mutex init: %s\n", strerror(errno)); + } + if (pthread_mutex_init(&handler->rx_gain_mutex, NULL)) { + fprintf(stderr, "Mutex init: %s\n", strerror(errno)); } - // base_srate - handler->base_srate = base_srate; + pthread_mutex_lock(&handler->rx_gain_mutex); + handler->rx_gain = 0.0; + pthread_mutex_unlock(&handler->rx_gain_mutex); // id // TODO: set some meaningful ID in handler->id @@ -195,29 +292,30 @@ int rf_file_open_file(void** h, FILE **rx_files, FILE **tx_files, uint32_t nof_c // Create channels for (int i = 0; i < handler->nof_channels; i++) { - if (rx_files != NULL) { + if (rx_files != NULL && rx_files[i] != NULL) { rx_opts.file = rx_files[i]; if (rf_file_rx_open(&handler->receiver[i], rx_opts) != SRSRAN_SUCCESS) { fprintf(stderr, "[file] Error: opening receiver\n"); goto clean_exit; } } else { - fprintf(stdout, "[file] %s Rx file not specified. Disabling receiver.\n", handler->id); + // no rx_files provided + fprintf(stdout, "[file] %s rx channel %d not specified. Disabling receiver.\n", handler->id, i); } - if (tx_files != NULL) { + if (tx_files != NULL && tx_files[i] != NULL) { tx_opts.file = tx_files[i]; - // TX is not implemented yet - // if(rf_file_tx_open(&handler->transmitter[i], tx_opts) != SRSRAN_SUCCESS) { - // fprintf(stderr, "[file] Error: opening transmitter\n"); - // goto clean_exit; - // } + if (rf_file_tx_open(&handler->transmitter[i], tx_opts) != SRSRAN_SUCCESS) { + fprintf(stderr, "[file] Error: opening transmitter\n"); + goto clean_exit; + } } else { // no tx_files provided - fprintf(stdout, "[file] %s Tx file not specified. Disabling transmitter.\n", handler->id); + fprintf(stdout, "[file] %s tx channel %d not specified. Disabling transmitter.\n", handler->id, i); + handler->tx_off = true; } if (!handler->transmitter[i].running && !handler->receiver[i].running) { - fprintf(stderr, "[file] Error: Neither Tx file nor Rx file specified.\n"); + fprintf(stderr, "[file] Error: Neither tx nor rx specificed for channel %d.\n", i); goto clean_exit; } } @@ -249,9 +347,15 @@ int rf_file_open_file(void** h, FILE **rx_files, FILE **tx_files, uint32_t nof_c int rf_file_close(void* h) { - rf_file_handler_t* handler = (rf_file_handler_t*)h; + rf_file_info(handler->id, "Closing ...\n"); + + for (int i = 0; i < handler->nof_channels; i++) { + rf_file_tx_close(&handler->transmitter[i]); + rf_file_rx_close(&handler->receiver[i]); + } + for (uint32_t i = 0; i < handler->nof_channels; i++) { if (handler->buffer_decimation[i]) { free(handler->buffer_decimation[i]); @@ -265,6 +369,18 @@ int rf_file_close(void* h) pthread_mutex_destroy(&handler->tx_config_mutex); pthread_mutex_destroy(&handler->rx_config_mutex); pthread_mutex_destroy(&handler->decim_mutex); + pthread_mutex_destroy(&handler->rx_gain_mutex); + + if (handler->close_files) { + for (int i = 0; i < handler->nof_channels; i++) { + if (handler->receiver[i].file != NULL) { + fclose(handler->receiver[i].file); + } + if (handler->transmitter[i].file != NULL) { + fclose(handler->transmitter[i].file); + } + } + } // Free all free(handler); @@ -412,13 +528,11 @@ void rf_file_get_time(void* h, time_t* secs, double* frac_secs) int rf_file_recv_with_time(void* h, void* data, uint32_t nsamples, bool blocking, time_t* secs, double* frac_secs) { - void* data_multi[SRSRAN_MAX_PORTS] = {NULL}; - data_multi[0] = data; - return rf_file_recv_with_time_multi(h, data_multi, nsamples, blocking, secs, frac_secs); + return rf_file_recv_with_time_multi(h, &data, nsamples, blocking, secs, frac_secs); } int rf_file_recv_with_time_multi(void* h, - void* data[SRSRAN_MAX_PORTS], + void** data, uint32_t nsamples, bool blocking, time_t* secs, @@ -431,23 +545,28 @@ int rf_file_recv_with_time_multi(void* h, // Map ports to data buffers according to the selected frequencies pthread_mutex_lock(&handler->rx_config_mutex); - cf_t* buffers[SRSRAN_MAX_PORTS] = {}; // Buffer pointers, NULL if unmatched - for (uint32_t i = 0; i < handler->nof_channels; i++) { - bool mapped = false; - - // Find first matching frequency - for (uint32_t j = 0; j < handler->nof_channels && !mapped; j++) { - // Traverse all channels, break if mapped - if (buffers[j] == NULL && rf_file_rx_match_freq(&handler->receiver[j], handler->rx_freq_mhz[i])) { - // Available buffer and matched frequency with receiver - buffers[j] = (cf_t*)data[i]; - mapped = true; + bool mapped[SRSRAN_MAX_CHANNELS] = {}; // Mapped mask, set to true when the physical channel is used + cf_t* buffers[SRSRAN_MAX_CHANNELS] = {}; // Buffer pointers, NULL if unmatched + + // For each logical channel... + for (uint32_t logical = 0; logical < handler->nof_channels; logical++) { + bool unmatched = true; + + // For each physical channel... + for (uint32_t physical = 0; physical < handler->nof_channels; physical++) { + // Consider a match if the physical channel is NOT mapped and the frequency match + if (!mapped[physical] && rf_file_rx_match_freq(&handler->receiver[physical], handler->rx_freq_mhz[logical])) { + // Not mapped and matched frequency with receiver + buffers[physical] = (cf_t*)data[logical]; + mapped[physical] = true; + unmatched = false; + break; } } // If no matching frequency found; set data to zeros - if (!mapped && data[i]) { - memset(data[i], 0, sizeof(cf_t) * nsamples); + if (unmatched) { + srsran_vec_zero(data[logical], nsamples); } } pthread_mutex_unlock(&handler->rx_config_mutex); @@ -460,6 +579,8 @@ int rf_file_recv_with_time_multi(void* h, uint32_t nbytes = NSAMPLES2NBYTES(nsamples * decim_factor); uint32_t nsamples_baserate = nsamples * decim_factor; + rf_file_info(handler->id, "Rx %d samples (%d B)\n", nsamples, nbytes); + // set timestamp for this reception if (secs != NULL && frac_secs != NULL) { srsran_timestamp_t ts = {}; @@ -488,10 +609,19 @@ int rf_file_recv_with_time_multi(void* h, srsran_timestamp_t ts_tx = {}, ts_rx = {}; srsran_timestamp_init_uint64(&ts_tx, handler->transmitter[0].nsamples, handler->base_srate); srsran_timestamp_init_uint64(&ts_rx, handler->next_rx_ts, handler->base_srate); + rf_file_info(handler->id, " - next rx time: %d + %.3f\n", ts_rx.full_secs, ts_rx.frac_secs); + rf_file_info(handler->id, " - next tx time: %d + %.3f\n", ts_tx.full_secs, ts_tx.frac_secs); + + // check for tx gap if we're also transmitting on this radio + for (int i = 0; i < handler->nof_channels; i++) { + if (handler->transmitter[i].running) { + rf_file_tx_align(&handler->transmitter[i], handler->next_rx_ts + nsamples_baserate); + } + } // copy from rx buffer as many samples as requested into provided buffer - bool completed = false; - int32_t count[SRSRAN_MAX_PORTS] = {}; + bool completed = false; + int32_t count[SRSRAN_MAX_CHANNELS] = {}; while (!completed) { uint32_t completed_count = 0; @@ -523,6 +653,7 @@ int rf_file_recv_with_time_multi(void* h, // Check if all channels are completed completed = (completed_count == handler->nof_channels); } + rf_file_info(handler->id, " - read %d samples.\n", NBYTES2NSAMPLES(nbytes)); // decimate if needed if (decim_factor != 1) { @@ -538,14 +669,24 @@ int rf_file_recv_with_time_multi(void* h, for (int j = 0; j < decim_factor; j++, n++) { avg += ptr[n]; } - dst[i] = avg; + dst[i] = avg; // divide by decim_factor later via scale } + + rf_file_info(handler->id, + " - re-adjust bytes due to %dx decimation %d --> %d samples)\n", + decim_factor, + nsamples_baserate, + nsamples); } } } // Set gain + pthread_mutex_lock(&handler->rx_gain_mutex); float scale = srsran_convert_dB_to_amplitude(handler->rx_gain); + pthread_mutex_unlock(&handler->rx_gain_mutex); + // scale shall also incorporate decim_factor + scale = scale / decim_factor; for (uint32_t c = 0; c < handler->nof_channels; c++) { if (buffers[c]) { srsran_vec_sc_prod_cfc(buffers[c], scale, buffers[c], nsamples); @@ -589,9 +730,127 @@ int rf_file_send_timed_multi(void* h, bool is_start_of_burst, bool is_end_of_burst) { - // Not implemented - fprintf(stderr, "Error: rf_file_send_timed_multi not implemented.\n"); - return SRSRAN_ERROR; + int ret = SRSRAN_ERROR; + + if (h && data && nsamples > 0) { + rf_file_handler_t* handler = (rf_file_handler_t*)h; + + // Map ports to data buffers according to the selected frequencies + pthread_mutex_lock(&handler->tx_config_mutex); + bool mapped[SRSRAN_MAX_CHANNELS] = {}; // Mapped mask, set to true when the physical channel is used + cf_t* buffers[SRSRAN_MAX_CHANNELS] = {}; // Buffer pointers, NULL if unmatched or zero transmission + + // For each logical channel... + for (uint32_t logical = 0; logical < handler->nof_channels; logical++) { + // For each physical channel... + for (uint32_t physical = 0; physical < handler->nof_channels; physical++) { + // Consider a match if the physical channel is NOT mapped and the frequency match + if (!mapped[physical] && + rf_file_tx_match_freq(&handler->transmitter[physical], handler->tx_freq_mhz[logical])) { + // Not mapped and matched frequency with receiver + buffers[physical] = (cf_t*)data[logical]; + mapped[physical] = true; + break; + } + } + } + pthread_mutex_unlock(&handler->tx_config_mutex); + + // Protect the access to decim_factor since is a shared variable + pthread_mutex_lock(&handler->decim_mutex); + uint32_t decim_factor = handler->decim_factor; + pthread_mutex_unlock(&handler->decim_mutex); + + uint32_t nbytes = NSAMPLES2NBYTES(nsamples); + uint32_t nsamples_baseband = nsamples * decim_factor; + uint32_t nbytes_baseband = NSAMPLES2NBYTES(nsamples_baseband); + if (nbytes_baseband > FILE_MAX_BUFFER_SIZE) { + fprintf(stderr, "Error: trying to transmit too many samples (%d > %zu).\n", nbytes, FILE_MAX_BUFFER_SIZE); + goto clean_exit; + } + + rf_file_info(handler->id, "Tx %d samples (%d B)\n", nsamples, nbytes); + + // return if transmitter is switched off + if (handler->tx_off) { + return SRSRAN_SUCCESS; + } + + // check if this is a tx in the future + if (has_time_spec) { + rf_file_info(handler->id, " - tx time: %d + %.3f\n", secs, frac_secs); + + srsran_timestamp_t ts = {}; + srsran_timestamp_init(&ts, secs, frac_secs); + uint64_t tx_ts = srsran_timestamp_uint64(&ts, handler->base_srate); + int num_tx_gap_samples = 0; + + for (int i = 0; i < handler->nof_channels; i++) { + if (handler->transmitter[i].running) { + num_tx_gap_samples = rf_file_tx_align(&handler->transmitter[i], tx_ts); + } + } + + if (num_tx_gap_samples < 0) { + fprintf(stderr, + "[file] Error: tx time is %.3f ms in the past (%" PRIu64 " < %" PRIu64 ")\n", + -1000.0 * num_tx_gap_samples / handler->base_srate, + tx_ts, + handler->transmitter[0].nsamples); + goto clean_exit; + } + } + + // Send base-band samples + for (int i = 0; i < handler->nof_channels; i++) { + if (buffers[i] != NULL) { + // Select buffer pointer depending on interpolation + cf_t* buf = (decim_factor != 1) ? handler->buffer_tx : buffers[i]; + + // Interpolate if required + if (decim_factor != 1) { + rf_file_info(handler->id, + " - re-adjust bytes due to %dx interpolation %d --> %d samples)\n", + decim_factor, + nsamples, + nsamples_baseband); + + int n = 0; + cf_t* src = buffers[i]; + for (int k = 0; k < nsamples; k++) { + // perform zero order hold + for (int j = 0; j < decim_factor; j++, n++) { + buf[n] = src[k]; + } + } + + if (nsamples_baseband != n) { + fprintf(stderr, + "Number of tx samples (%d) does not match with number of interpolated samples (%d)\n", + nsamples_baseband, + n); + goto clean_exit; + } + } + + int n = rf_file_tx_baseband(&handler->transmitter[i], buf, nsamples_baseband); + if (n == SRSRAN_ERROR) { + goto clean_exit; + } + } else { + int n = rf_file_tx_zeros(&handler->transmitter[i], nsamples_baseband); + if (n == SRSRAN_ERROR) { + goto clean_exit; + } + } + } + } + + ret = SRSRAN_SUCCESS; + +clean_exit: + + return ret; } #endif diff --git a/lib/src/phy/rf/rf_file_imp.h b/lib/src/phy/rf/rf_file_imp.h index ae2763b7a..5db7e697f 100644 --- a/lib/src/phy/rf/rf_file_imp.h +++ b/lib/src/phy/rf/rf_file_imp.h @@ -95,12 +95,8 @@ SRSRAN_API void rf_file_get_time(void* h, time_t* secs, double* frac_secs); SRSRAN_API int rf_file_recv_with_time(void* h, void* data, uint32_t nsamples, bool blocking, time_t* secs, double* frac_secs); -SRSRAN_API int rf_file_recv_with_time_multi(void* h, - void* data[SRSRAN_MAX_PORTS], - uint32_t nsamples, - bool blocking, - time_t* secs, - double* frac_secs); +SRSRAN_API int +rf_file_recv_with_time_multi(void* h, void** data, uint32_t nsamples, bool blocking, time_t* secs, double* frac_secs); SRSRAN_API int rf_file_send_timed(void* h, void* data, diff --git a/lib/src/phy/rf/rf_file_imp_rx.c b/lib/src/phy/rf/rf_file_imp_rx.c index 30ceb9807..57dc98384 100644 --- a/lib/src/phy/rf/rf_file_imp_rx.c +++ b/lib/src/phy/rf/rf_file_imp_rx.c @@ -21,7 +21,7 @@ int rf_file_rx_open(rf_file_rx_t* q, rf_file_opts_t opts) if (q) { // Zero object - bzero(q, sizeof(rf_file_rx_t)); + memset(q, 0, sizeof(rf_file_rx_t)); // Copy id strncpy(q->id, opts.id, FILE_ID_STRLEN - 1); @@ -62,7 +62,7 @@ clean_exit: int rf_file_rx_baseband(rf_file_rx_t* q, cf_t* buffer, uint32_t nsamples) { - uint32_t sample_sz = sizeof(cf_t); + uint32_t sample_sz = sizeof(cf_t); int ret = fread(buffer, sample_sz, nsamples, q->file); if (ret > 0) { @@ -83,6 +83,7 @@ bool rf_file_rx_match_freq(rf_file_rx_t* q, uint32_t freq_hz) void rf_file_rx_close(rf_file_rx_t* q) { + rf_file_info(q->id, "Closing ...\n"); q->running = false; if (q->temp_buffer) { diff --git a/lib/src/phy/rf/rf_file_imp_trx.h b/lib/src/phy/rf/rf_file_imp_trx.h index 5c4d596a1..4e5cc63a8 100644 --- a/lib/src/phy/rf/rf_file_imp_trx.h +++ b/lib/src/phy/rf/rf_file_imp_trx.h @@ -42,7 +42,8 @@ typedef struct { pthread_mutex_t mutex; cf_t* zeros; void* temp_buffer_convert; - uint32_t frequency_hz_mhz; + uint32_t frequency_mhz; + int32_t sample_offset; } rf_file_tx_t; typedef struct { @@ -68,8 +69,29 @@ typedef struct { /* * Common functions */ +SRSRAN_API void rf_file_info(char* id, const char* format, ...); + +SRSRAN_API void rf_file_error(char* id, const char* format, ...); + SRSRAN_API int rf_file_handle_error(char* id, const char* text); +/* + * Transmitter functions + */ +SRSRAN_API int rf_file_tx_open(rf_file_tx_t* q, rf_file_opts_t opts); + +SRSRAN_API int rf_file_tx_align(rf_file_tx_t* q, uint64_t ts); + +SRSRAN_API int rf_file_tx_baseband(rf_file_tx_t* q, cf_t* buffer, uint32_t nsamples); + +SRSRAN_API int rf_file_tx_get_nsamples(rf_file_tx_t* q); + +SRSRAN_API int rf_file_tx_zeros(rf_file_tx_t* q, uint32_t nsamples); + +SRSRAN_API bool rf_file_tx_match_freq(rf_file_tx_t* q, uint32_t freq_hz); + +SRSRAN_API void rf_file_tx_close(rf_file_tx_t* q); + /* * Receiver functions */ diff --git a/lib/src/phy/rf/rf_file_imp_tx.c b/lib/src/phy/rf/rf_file_imp_tx.c new file mode 100644 index 000000000..d3398048b --- /dev/null +++ b/lib/src/phy/rf/rf_file_imp_tx.c @@ -0,0 +1,189 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2021 Software Radio Systems Limited + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the distribution. + * + */ + +#include "rf_file_imp_trx.h" +#include +#include +#include +#include +#include +#include + +int rf_file_tx_open(rf_file_tx_t* q, rf_file_opts_t opts) +{ + int ret = SRSRAN_ERROR; + + if (q) { + // Zero object + memset(q, 0, sizeof(rf_file_tx_t)); + + // Copy id + strncpy(q->id, opts.id, FILE_ID_STRLEN - 1); + q->id[FILE_ID_STRLEN - 1] = '\0'; + + // Assign file + q->file = opts.file; + + // Configure formats + q->sample_format = opts.sample_format; + q->frequency_mhz = opts.frequency_mhz; + + q->temp_buffer_convert = srsran_vec_malloc(FILE_MAX_BUFFER_SIZE); + if (!q->temp_buffer_convert) { + fprintf(stderr, "Error: allocating tx buffer\n"); + goto clean_exit; + } + + if (pthread_mutex_init(&q->mutex, NULL)) { + fprintf(stderr, "Error: creating mutex\n"); + goto clean_exit; + } + + q->zeros = srsran_vec_malloc(FILE_MAX_BUFFER_SIZE); + if (!q->zeros) { + fprintf(stderr, "Error: allocating zeros\n"); + goto clean_exit; + } + memset(q->zeros, 0, FILE_MAX_BUFFER_SIZE); + + q->running = true; + + ret = SRSRAN_SUCCESS; + } + +clean_exit: + return ret; +} + +static int _rf_file_tx_baseband(rf_file_tx_t* q, cf_t* buffer, uint32_t nsamples) +{ + int n = SRSRAN_ERROR; + + // convert samples if necessary + void* buf = (buffer) ? buffer : q->zeros; + uint32_t sample_sz = sizeof(cf_t); + + if (q->sample_format == FILERF_TYPE_SC16) { + buf = q->temp_buffer_convert; + sample_sz = 2 * sizeof(short); + srsran_vec_convert_fi((float*)buffer, INT16_MAX, (short*)q->temp_buffer_convert, 2 * nsamples); + } + + size_t ret = fwrite(buf, (size_t)sample_sz, (size_t)nsamples, q->file); + if (ret < (size_t)nsamples) { + rf_file_error(q->id, + "[file] Error: transmitter expected %d bytes and sent %d. %s.\n", + NSAMPLES2NBYTES(nsamples), + ret, + strerror(errno)); + n = SRSRAN_ERROR; + goto clean_exit; + } + + // Increment sample counter + q->nsamples += nsamples; + n = nsamples; + +clean_exit: + return n; +} + +int rf_file_tx_align(rf_file_tx_t* q, uint64_t ts) +{ + pthread_mutex_lock(&q->mutex); + + int64_t nsamples = (int64_t)ts - (int64_t)q->nsamples; + + if (nsamples > 0) { + rf_file_info(q->id, " - Detected Tx gap of %d samples.\n", nsamples); + _rf_file_tx_baseband(q, q->zeros, (uint32_t)nsamples); + } + + pthread_mutex_unlock(&q->mutex); + + return (int)nsamples; +} + +int rf_file_tx_baseband(rf_file_tx_t* q, cf_t* buffer, uint32_t nsamples) +{ + int n; + + pthread_mutex_lock(&q->mutex); + + if (q->sample_offset > 0) { + _rf_file_tx_baseband(q, q->zeros, (uint32_t)q->sample_offset); + q->sample_offset = 0; + } else if (q->sample_offset < 0) { + n = SRSRAN_MIN(-q->sample_offset, nsamples); + buffer += n; + nsamples -= n; + q->sample_offset += n; + if (nsamples == 0) { + return n; + } + } + + n = _rf_file_tx_baseband(q, buffer, nsamples); + + pthread_mutex_unlock(&q->mutex); + + return n; +} + +int rf_file_tx_get_nsamples(rf_file_tx_t* q) +{ + pthread_mutex_lock(&q->mutex); + int ret = q->nsamples; + pthread_mutex_unlock(&q->mutex); + return ret; +} + +int rf_file_tx_zeros(rf_file_tx_t* q, uint32_t nsamples) +{ + pthread_mutex_lock(&q->mutex); + + rf_file_info(q->id, " - Tx %d Zeros.\n", nsamples); + _rf_file_tx_baseband(q, q->zeros, (uint32_t)nsamples); + + pthread_mutex_unlock(&q->mutex); + + return (int)nsamples; +} + +bool rf_file_tx_match_freq(rf_file_tx_t* q, uint32_t freq_hz) +{ + bool ret = false; + if (q) { + ret = (q->frequency_mhz == 0 || q->frequency_mhz == freq_hz); + } + return ret; +} + +void rf_file_tx_close(rf_file_tx_t* q) +{ + rf_file_info(q->id, "Closing ...\n"); + pthread_mutex_lock(&q->mutex); + q->running = false; + pthread_mutex_unlock(&q->mutex); + + pthread_mutex_destroy(&q->mutex); + + if (q->zeros) { + free(q->zeros); + } + + if (q->temp_buffer_convert) { + free(q->temp_buffer_convert); + } + + q->file = NULL; +} diff --git a/lib/src/phy/rf/rf_file_test.c b/lib/src/phy/rf/rf_file_test.c new file mode 100644 index 000000000..a16ea2821 --- /dev/null +++ b/lib/src/phy/rf/rf_file_test.c @@ -0,0 +1,312 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2021 Software Radio Systems Limited + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the distribution. + * + */ + +#include "rf_file_imp.h" +#include "srsran/common/tsan_options.h" +#include "srsran/phy/common/timestamp.h" +#include "srsran/phy/utils/debug.h" +#include +#include +#include +#include +#include + +#define PRINT_SAMPLES 0 +#define COMPARE_BITS 0 +#define COMPARE_EPSILON (1e-6f) +#define NOF_RX_ANT 4 +#define NUM_SF (500) +#define SF_LEN (1920) +#define RF_BUFFER_SIZE (SF_LEN * NUM_SF) +#define TX_OFFSET_MS (4) + +static cf_t ue_rx_buffer[NOF_RX_ANT][RF_BUFFER_SIZE]; +static cf_t enb_tx_buffer[NOF_RX_ANT][RF_BUFFER_SIZE]; +static cf_t enb_rx_buffer[NOF_RX_ANT][RF_BUFFER_SIZE]; + +static srsran_rf_t ue_radio, enb_radio; +pthread_t rx_thread; + +void* ue_rx_thread_function(void* args) +{ + char rf_args[RF_PARAM_LEN]; + strncpy(rf_args, (char*)args, RF_PARAM_LEN - 1); + rf_args[RF_PARAM_LEN - 1] = 0; + + // sleep(1); + + printf("opening rx device with args=%s\n", rf_args); + if (srsran_rf_open_devname(&ue_radio, "file", rf_args, NOF_RX_ANT)) { + fprintf(stderr, "Error opening rf\n"); + exit(-1); + } + + // receive 5 subframes at once (i.e. mimic initial rx that receives one slot) + uint32_t num_slots = NUM_SF / 5; + uint32_t num_samps_per_slot = SF_LEN * 5; + uint32_t num_rxed_samps = 0; + for (uint32_t i = 0; i < num_slots; ++i) { + void* data_ptr[SRSRAN_MAX_PORTS] = {NULL}; + for (uint32_t c = 0; c < NOF_RX_ANT; c++) { + data_ptr[c] = &ue_rx_buffer[c][i * num_samps_per_slot]; + } + num_rxed_samps += srsran_rf_recv_with_time_multi(&ue_radio, data_ptr, num_samps_per_slot, true, NULL, NULL); + } + + printf("received %d samples.\n", num_rxed_samps); + + printf("closing ue rx device\n"); + srsran_rf_close(&ue_radio); + + return NULL; +} + +void enb_tx_function(const char* tx_args, bool timed_tx) +{ + char rf_args[RF_PARAM_LEN]; + strncpy(rf_args, tx_args, RF_PARAM_LEN - 1); + rf_args[RF_PARAM_LEN - 1] = 0; + + printf("opening tx device with args=%s\n", rf_args); + if (srsran_rf_open_devname(&enb_radio, "file", rf_args, NOF_RX_ANT)) { + fprintf(stderr, "Error opening rf\n"); + exit(-1); + } + + // generate random tx data + for (int c = 0; c < NOF_RX_ANT; c++) { + for (int i = 0; i < RF_BUFFER_SIZE; i++) { + enb_tx_buffer[c][i] = ((float)rand() / (float)RAND_MAX) + _Complex_I * ((float)rand() / (float)RAND_MAX); + } + } + + // send data subframe per subframe + uint32_t num_txed_samples = 0; + + // initial transmission without ts + void* data_ptr[SRSRAN_MAX_PORTS] = {NULL}; + for (int c = 0; c < NOF_RX_ANT; c++) { + data_ptr[c] = &enb_tx_buffer[c][num_txed_samples]; + } + int ret = srsran_rf_send_multi(&enb_radio, (void**)data_ptr, SF_LEN, true, true, false); + num_txed_samples += SF_LEN; + + // from here on, all transmissions are timed relative to the last rx time + srsran_timestamp_t rx_time, tx_time; + + for (uint32_t i = 0; i < NUM_SF - ((timed_tx) ? TX_OFFSET_MS : 1); ++i) { + // first recv samples + for (int c = 0; c < NOF_RX_ANT; c++) { + data_ptr[c] = enb_rx_buffer[c]; + } + srsran_rf_recv_with_time_multi(&enb_radio, data_ptr, SF_LEN, true, &rx_time.full_secs, &rx_time.frac_secs); + + // prepare data buffer + for (int c = 0; c < NOF_RX_ANT; c++) { + data_ptr[c] = &enb_tx_buffer[c][num_txed_samples]; + } + + if (timed_tx) { + // timed tx relative to receive time (this will cause a cap in the rx'ed samples at the UE resulting in 3 zero + // subframes) + srsran_timestamp_copy(&tx_time, &rx_time); + srsran_timestamp_add(&tx_time, 0, TX_OFFSET_MS * 1e-3); + ret = srsran_rf_send_timed_multi( + &enb_radio, (void**)data_ptr, SF_LEN, tx_time.full_secs, tx_time.frac_secs, true, true, false); + } else { + // normal tx + ret = srsran_rf_send_multi(&enb_radio, (void**)data_ptr, SF_LEN, true, true, false); + } + if (ret != SRSRAN_SUCCESS) { + fprintf(stderr, "Error sending data\n"); + exit(-1); + } + + num_txed_samples += SF_LEN; + } + + printf("transmitted %d samples in %d subframes\n", num_txed_samples, NUM_SF); + + printf("closing tx device\n"); + srsran_rf_close(&enb_radio); +} + +int run_test(const char* rx_args, const char* tx_args, bool timed_tx) +{ + int ret = SRSRAN_ERROR; + + // make sure we can receive in slots + if (NUM_SF % 5 != 0) { + fprintf(stderr, "number of subframes must be multiple of 5\n"); + goto exit; + } + + // write to file(s) + enb_tx_function(tx_args, timed_tx); + + // read from file(s) + ue_rx_thread_function((void*)rx_args); + + // channel-wise comparison + for (int c = 0; c < NOF_RX_ANT; c++) { + // subframe-wise compare tx'ed and rx'ed data (stop 3 subframes earlier for timed tx) + for (uint32_t i = 0; i < NUM_SF - (timed_tx ? 3 : 0); ++i) { + uint32_t sf_offet = 0; + if (timed_tx && i >= 1) { + // for timed transmission, the enb inserts 3 zero subframes after the first untimed tx + sf_offet = (TX_OFFSET_MS - 1) * SF_LEN; + } + +#if PRINT_SAMPLES + // print first 10 samples for each SF + printf("enb_tx_buffer sf%d:\n", i); + srsran_vec_fprint_c(stdout, &enb_tx_buffer[c][i * SF_LEN], 10); + printf("ue_rx_buffer sf%d:\n", i); + srsran_vec_fprint_c(stdout, &ue_rx_buffer[c][sf_offet + i * SF_LEN], 10); +#endif + +#if COMPARE_BITS + int d = memcmp(&ue_rx_buffer[sf_offet + i * SF_LEN], &enb_tx_buffer[i * SF_LEN], SF_LEN); + if (d) { + d = d > 0 ? d : -d; + fprintf(stderr, "data mismatch in subframe %d, sample %d\n", i, d); + printf("enb_tx_buffer sf%d:\n", i); + srsran_vec_fprint_c(stdout, &enb_tx_buffer[i * SF_LEN + d], 10); + printf("ue_rx_buffer sf%d:\n", i); + srsran_vec_fprint_c(stdout, &ue_rx_buffer[sf_offet + i * SF_LEN + d], 10); + goto exit; + } +#else + srsran_vec_sub_ccc(&ue_rx_buffer[c][sf_offet + i * SF_LEN], + &enb_tx_buffer[c][i * SF_LEN], + &ue_rx_buffer[c][sf_offet + i * SF_LEN], + SF_LEN); + uint32_t max_ix = srsran_vec_max_abs_ci(&ue_rx_buffer[c][sf_offet + i * SF_LEN], SF_LEN); + if (cabsf(ue_rx_buffer[c][sf_offet + i * SF_LEN + max_ix]) > COMPARE_EPSILON) { + fprintf(stderr, "data mismatch in subframe %d\n", i); + goto exit; + } +#endif + } + } + + ret = SRSRAN_SUCCESS; + +exit: + return ret; +} + +int param_test(const char* args_param, const int num_channels) +{ + char rf_args[RF_PARAM_LEN] = {}; + strncpy(rf_args, (char*)args_param, RF_PARAM_LEN - 1); + rf_args[RF_PARAM_LEN - 1] = 0; + + printf("opening tx device with args=%s\n", rf_args); + if (srsran_rf_open_devname(&enb_radio, "file", rf_args, num_channels)) { + fprintf(stderr, "Error opening rf\n"); + return SRSRAN_ERROR; + } + + srsran_rf_close(&enb_radio); + + return SRSRAN_SUCCESS; +} + +void create_file(const char* filename) +{ + FILE* f = fopen(filename, "w"); + fclose(f); +} + +int main() +{ + // create files for testing + create_file("rx_file0"); + create_file("rx_file1"); + create_file("rx_file2"); + create_file("rx_file3"); + + // two RX files + if (param_test("rx_file=rx_file0," + "rx_file1=rx_file1", + 2)) { + fprintf(stderr, "Param test failed!\n"); + return SRSRAN_ERROR; + } + + // multiple RX files, no channel index provided + if (param_test("rx_file=rx_file0," + "rx_file=rx_file1," + "rx_file=rx_file2," + "rx_file=rx_file3," + "base_srate=1.92e6", + 4)) { + fprintf(stderr, "Param test failed!\n"); + return SRSRAN_ERROR; + } + + // one RX, one TX and all generic options + if (param_test("rx_file0=rx_file0," + "tx_file0=tx_file0," + "base_srate=1.92e6", + 1)) { + fprintf(stderr, "Param test failed!\n"); + return SRSRAN_ERROR; + } + + // two RX, two TX + if (param_test("rx_file0=rx_file0," + "rx_file1=rx_file1," + "tx_file0=tx_file0," + "tx_file1=tx_file1", + 2)) { + fprintf(stderr, "Param test failed!\n"); + return SRSRAN_ERROR; + } + +#if NOF_RX_ANT == 1 + // single tx, single rx with continuous transmissions (no decimation, no timed tx) + if (run_test("rx_file=tx_file0,base_srate=1.92e6", "tx_file=tx_file0,base_srate=1.92e6", false) != SRSRAN_SUCCESS) { + fprintf(stderr, "Single tx, single rx test failed (no decimation, no timed tx)!\n"); + return -1; + } +#endif + + // up to 4 trx radios with continous tx (no decimation, no timed tx) + if (run_test("rx_file=tx_file0,rx_file=tx_file1,rx_file=tx_file2,rx_file=tx_file3,base_srate=1.92e6", + "tx_file=tx_file0,tx_file=tx_file1,tx_file=tx_file2,tx_file=tx_file3,base_srate=1.92e6", + false) != SRSRAN_SUCCESS) { + fprintf(stderr, "Multi TRx radio test failed (no decimation, no timed tx)!\n"); + return -1; + } + + // up to 4 trx radios with continous tx (with decimation, no timed tx) + if (run_test("rx_file=tx_file0,rx_file=tx_file1,rx_file=tx_file2,rx_file=tx_file3", + "tx_file=tx_file0,tx_file=tx_file1,tx_file=tx_file2,tx_file=tx_file3", + false) != SRSRAN_SUCCESS) { + fprintf(stderr, "Multi TRx radio test failed (with decimation, no timed tx)!\n"); + return -1; + } + + // up to 4 trx radios with continous tx (with decimation, timed tx) + if (run_test("rx_file=tx_file0,rx_file=tx_file1,rx_file=tx_file2,rx_file=tx_file3", + "tx_file=tx_file0,tx_file=tx_file1,tx_file=tx_file2,tx_file=tx_file3", + true) != SRSRAN_SUCCESS) { + fprintf(stderr, "Two TRx radio test failed (with decimation, timed tx)!\n"); + return -1; + } + + fprintf(stdout, "Test passed!\n"); + + return SRSRAN_SUCCESS; +} From c26f2b204132f0c0e1bf127d51a58d49949d33b2 Mon Sep 17 00:00:00 2001 From: Robert Falkenberg Date: Tue, 23 Nov 2021 11:17:22 +0100 Subject: [PATCH 21/62] rf_file: fix check for number of channels and cleanup after test --- lib/src/phy/rf/rf_file_imp.c | 2 +- lib/src/phy/rf/rf_file_test.c | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/lib/src/phy/rf/rf_file_imp.c b/lib/src/phy/rf/rf_file_imp.c index b44d97bcb..bea7a84fb 100644 --- a/lib/src/phy/rf/rf_file_imp.c +++ b/lib/src/phy/rf/rf_file_imp.c @@ -172,7 +172,7 @@ int rf_file_open_multi(char* args, void** h, uint32_t nof_channels) FILE* rx_files[SRSRAN_MAX_CHANNELS] = {NULL}; FILE* tx_files[SRSRAN_MAX_CHANNELS] = {NULL}; - if (h && nof_channels < SRSRAN_MAX_CHANNELS) { + if (h && nof_channels <= SRSRAN_MAX_CHANNELS) { uint32_t base_srate = FILE_BASERATE_DEFAULT_HZ; // parse args diff --git a/lib/src/phy/rf/rf_file_test.c b/lib/src/phy/rf/rf_file_test.c index a16ea2821..a6e0b4bbb 100644 --- a/lib/src/phy/rf/rf_file_test.c +++ b/lib/src/phy/rf/rf_file_test.c @@ -228,6 +228,11 @@ void create_file(const char* filename) fclose(f); } +void remove_file(const char* filename) +{ + remove(filename); +} + int main() { // create files for testing @@ -306,6 +311,16 @@ int main() return -1; } + // clean workspace + remove_file("rx_file0"); + remove_file("rx_file1"); + remove_file("rx_file2"); + remove_file("rx_file3"); + remove_file("tx_file0"); + remove_file("tx_file1"); + remove_file("tx_file2"); + remove_file("tx_file3"); + fprintf(stdout, "Test passed!\n"); return SRSRAN_SUCCESS; From 6b791168056c68086c725f5b1a55bcc86bf416ca Mon Sep 17 00:00:00 2001 From: Robert Falkenberg Date: Thu, 16 Dec 2021 09:26:26 +0100 Subject: [PATCH 22/62] rf_file: close tx/rx files properly Previously tests were failing on some machines, because receiver was unable to receive the last few samples from file. Reason: the transmitter did not close the file properly, so the last samples were (sometimes) not yet flushed to disk. --- lib/src/phy/rf/rf_file_imp.c | 3 +++ lib/src/phy/rf/rf_file_imp_rx.c | 2 +- lib/src/phy/rf/rf_file_imp_tx.c | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/src/phy/rf/rf_file_imp.c b/lib/src/phy/rf/rf_file_imp.c index bea7a84fb..16e98a5a8 100644 --- a/lib/src/phy/rf/rf_file_imp.c +++ b/lib/src/phy/rf/rf_file_imp.c @@ -351,11 +351,13 @@ int rf_file_close(void* h) rf_file_info(handler->id, "Closing ...\n"); + // close receiver+transmitter and release related resources (except for the file handles) for (int i = 0; i < handler->nof_channels; i++) { rf_file_tx_close(&handler->transmitter[i]); rf_file_rx_close(&handler->receiver[i]); } + // release other resources for (uint32_t i = 0; i < handler->nof_channels; i++) { if (handler->buffer_decimation[i]) { free(handler->buffer_decimation[i]); @@ -371,6 +373,7 @@ int rf_file_close(void* h) pthread_mutex_destroy(&handler->decim_mutex); pthread_mutex_destroy(&handler->rx_gain_mutex); + // now close the files if we opened them ourselves if (handler->close_files) { for (int i = 0; i < handler->nof_channels; i++) { if (handler->receiver[i].file != NULL) { diff --git a/lib/src/phy/rf/rf_file_imp_rx.c b/lib/src/phy/rf/rf_file_imp_rx.c index 57dc98384..71ac92430 100644 --- a/lib/src/phy/rf/rf_file_imp_rx.c +++ b/lib/src/phy/rf/rf_file_imp_rx.c @@ -94,5 +94,5 @@ void rf_file_rx_close(rf_file_rx_t* q) free(q->temp_buffer_convert); } - q->file = NULL; + // not touching q->file as we don't know if we need to close it ourselves } diff --git a/lib/src/phy/rf/rf_file_imp_tx.c b/lib/src/phy/rf/rf_file_imp_tx.c index d3398048b..b3915f3b5 100644 --- a/lib/src/phy/rf/rf_file_imp_tx.c +++ b/lib/src/phy/rf/rf_file_imp_tx.c @@ -185,5 +185,5 @@ void rf_file_tx_close(rf_file_tx_t* q) free(q->temp_buffer_convert); } - q->file = NULL; + // not touching q->file as we don't know if we need to close it ourselves } From 18f0732c6627320594749be37d68503861ceca0a Mon Sep 17 00:00:00 2001 From: Francisco Date: Tue, 1 Feb 2022 10:28:15 +0000 Subject: [PATCH 23/62] fix clang 6.0.0 compilation issue related with {} initialization --- srsgnb/src/stack/rrc/rrc_nr.cc | 4 ++-- srsgnb/src/stack/rrc/test/rrc_nr_test.cc | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/srsgnb/src/stack/rrc/rrc_nr.cc b/srsgnb/src/stack/rrc/rrc_nr.cc index 676ba17b7..967fe6e64 100644 --- a/srsgnb/src/stack/rrc/rrc_nr.cc +++ b/srsgnb/src/stack/rrc/rrc_nr.cc @@ -75,9 +75,9 @@ int rrc_nr::init(const rrc_nr_cfg_t& cfg_, } // Generate cell config structs - cell_ctxt.reset(new cell_ctxt_t{}); + cell_ctxt.reset(new cell_ctxt_t()); if (cfg.is_standalone) { - std::unique_ptr master_cell_group{new cell_group_cfg_s{}}; + std::unique_ptr master_cell_group{new cell_group_cfg_s()}; int ret = fill_master_cell_cfg_from_enb_cfg(cfg, 0, *master_cell_group); srsran_assert(ret == SRSRAN_SUCCESS, "Failed to configure MasterCellGroup"); cell_ctxt->master_cell_group = std::move(master_cell_group); diff --git a/srsgnb/src/stack/rrc/test/rrc_nr_test.cc b/srsgnb/src/stack/rrc/test/rrc_nr_test.cc index 88b61800e..89fb19ba9 100644 --- a/srsgnb/src/stack/rrc/test/rrc_nr_test.cc +++ b/srsgnb/src/stack/rrc/test/rrc_nr_test.cc @@ -49,7 +49,7 @@ void test_sib_generation() enb_bearer_manager bearer_mapper; // set cfg - rrc_nr_cfg_t rrc_cfg_nr = {}; + rrc_nr_cfg_t rrc_cfg_nr; rrc_cfg_nr.cell_list.emplace_back(); generate_default_nr_cell(rrc_cfg_nr.cell_list[0]); rrc_cfg_nr.cell_list[0].phy_cell.carrier.pci = 500; @@ -107,7 +107,7 @@ int test_rrc_setup() rrc_nr rrc_obj(&task_sched); // set cfg - rrc_nr_cfg_t rrc_cfg_nr = rrc_nr_cfg_t{}; + rrc_nr_cfg_t rrc_cfg_nr; rrc_cfg_nr.cell_list.emplace_back(); generate_default_nr_cell(rrc_cfg_nr.cell_list[0]); rrc_cfg_nr.cell_list[0].phy_cell.carrier.pci = 500; @@ -150,7 +150,7 @@ void test_rrc_sa_connection() rrc_nr rrc_obj(&task_sched); // set cfg - rrc_nr_cfg_t rrc_cfg_nr = rrc_nr_cfg_t{}; + rrc_nr_cfg_t rrc_cfg_nr; rrc_cfg_nr.cell_list.emplace_back(); generate_default_nr_cell(rrc_cfg_nr.cell_list[0]); rrc_cfg_nr.cell_list[0].phy_cell.carrier.pci = 500; From 425b956ef1c91f085ec145b46686463013a2f882 Mon Sep 17 00:00:00 2001 From: Francisco Date: Tue, 1 Feb 2022 10:41:12 +0000 Subject: [PATCH 24/62] revert hacky asn1 compilation fix related with default dtors --- lib/include/srsran/asn1/rrc_nr.h | 9 --------- 1 file changed, 9 deletions(-) diff --git a/lib/include/srsran/asn1/rrc_nr.h b/lib/include/srsran/asn1/rrc_nr.h index 0ebc417b2..86c4106a6 100644 --- a/lib/include/srsran/asn1/rrc_nr.h +++ b/lib/include/srsran/asn1/rrc_nr.h @@ -3639,9 +3639,6 @@ struct sib1_s { uac_barr_info_s_ uac_barr_info; dyn_octstring late_non_crit_ext; - // Temporary hacky fix for Clang not being able to find dtor - ~sib1_s(){}; - // sequence methods SRSASN_CODE pack(bit_ref& bref) const; SRSASN_CODE unpack(cbit_ref& bref); @@ -20138,9 +20135,6 @@ struct mac_cell_group_cfg_s { bool csi_mask = false; copy_ptr > data_inactivity_timer; - // Temporary hacky fix for Clang not being able to find dtor - ~mac_cell_group_cfg_s(){}; - // sequence methods SRSASN_CODE pack(bit_ref& bref) const; SRSASN_CODE unpack(cbit_ref& bref); @@ -20193,9 +20187,6 @@ struct phys_cell_group_cfg_s { // group 2 copy_ptr > > pdcch_blind_detection; - // Temporary hacky fix for Clang not being able to find dtor - ~phys_cell_group_cfg_s(){}; - // sequence methods SRSASN_CODE pack(bit_ref& bref) const; SRSASN_CODE unpack(cbit_ref& bref); From 03bab82cd8e72496ed1892a6d62fb2fe159bf6e3 Mon Sep 17 00:00:00 2001 From: Robert Falkenberg Date: Thu, 27 Jan 2022 09:13:54 +0100 Subject: [PATCH 25/62] zmq: apply tx_gain to transmitted signal This feature was temporary disabled in 497e183487a352c0c23103a4cdb3ff4c5caa2a86 --- lib/src/phy/rf/rf_zmq_imp.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/src/phy/rf/rf_zmq_imp.c b/lib/src/phy/rf/rf_zmq_imp.c index ef0e535e5..0bc822667 100644 --- a/lib/src/phy/rf/rf_zmq_imp.c +++ b/lib/src/phy/rf/rf_zmq_imp.c @@ -961,8 +961,7 @@ int rf_zmq_send_timed_multi(void* h, } // Scale according to current gain - // TODO: document baseband scaling for ZMQ with gain settings, etc. before enabling - // srsran_vec_sc_prod_cfc(buf, tx_gain, buf, nsamples_baseband); + srsran_vec_sc_prod_cfc(buf, tx_gain, buf, nsamples_baseband); // Finally, transmit baseband int n = rf_zmq_tx_baseband(&handler->transmitter[i], buf, nsamples_baseband); From 10aabe8763ac820e4e65526bbe8de447b7990a5d Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Mon, 31 Jan 2022 21:56:03 +0100 Subject: [PATCH 26/62] rrc_nr_utils: set search space type for RA to type1 --- lib/src/asn1/rrc_nr_utils.cc | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/src/asn1/rrc_nr_utils.cc b/lib/src/asn1/rrc_nr_utils.cc index 33c799975..b82b2499b 100644 --- a/lib/src/asn1/rrc_nr_utils.cc +++ b/lib/src/asn1/rrc_nr_utils.cc @@ -1698,8 +1698,11 @@ void fill_phy_pdcch_cfg_common(const asn1::rrc_nr::pdcch_cfg_common_s& pdcch_cfg pdcch->search_space_present[ss.search_space_id] = true; make_phy_search_space_cfg(ss, &pdcch->search_space[ss.search_space_id]); if (pdcch_cfg.ra_search_space_present and pdcch_cfg.ra_search_space == ss.search_space_id) { - pdcch->ra_search_space_present = true; - pdcch->ra_search_space = pdcch->search_space[ss.search_space_id]; + pdcch->ra_search_space_present = true; + pdcch->ra_search_space = pdcch->search_space[ss.search_space_id]; + pdcch->ra_search_space.type = srsran_search_space_type_common_1; + pdcch->ra_search_space.nof_formats = 1; + pdcch->ra_search_space.formats[1] = srsran_dci_format_nr_1_0; } } } From 71f48ee7f2d61cf39704e5d65dbe3dce094c7e96 Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Mon, 31 Jan 2022 22:04:39 +0100 Subject: [PATCH 27/62] ue,rrc: refactor PHY parameter derivation for SA * expose carrier/SSB config in RRC args * provide hard-coded values until exposed as param * remove coreless option --- srsue/hdr/stack/rrc_nr/rrc_nr.h | 1 - srsue/hdr/stack/rrc_nr/rrc_nr_config.h | 28 ++-- srsue/src/stack/rrc_nr/rrc_nr.cc | 142 +++++--------------- srsue/src/stack/rrc_nr/rrc_nr_procedures.cc | 24 ++++ srsue/src/stack/ue_stack_nr.cc | 3 - srsue/src/ue.cc | 20 ++- 6 files changed, 84 insertions(+), 134 deletions(-) diff --git a/srsue/hdr/stack/rrc_nr/rrc_nr.h b/srsue/hdr/stack/rrc_nr/rrc_nr.h index 5ede655e4..e71959a17 100644 --- a/srsue/hdr/stack/rrc_nr/rrc_nr.h +++ b/srsue/hdr/stack/rrc_nr/rrc_nr.h @@ -61,7 +61,6 @@ public: const rrc_nr_args_t& args_); void stop(); - void init_core_less(); void get_metrics(rrc_nr_metrics_t& m); diff --git a/srsue/hdr/stack/rrc_nr/rrc_nr_config.h b/srsue/hdr/stack/rrc_nr/rrc_nr_config.h index ae3b37b70..a76046b97 100644 --- a/srsue/hdr/stack/rrc_nr/rrc_nr_config.h +++ b/srsue/hdr/stack/rrc_nr/rrc_nr_config.h @@ -18,21 +18,21 @@ namespace srsue { -// Expert arguments to create GW without proper RRC -struct core_less_args_t { - std::string ip_addr; - uint8_t drb_lcid; -}; - struct rrc_nr_args_t { - core_less_args_t coreless; - uint32_t sim_nr_meas_pci; - bool pdcp_short_sn_support; - std::string supported_bands_nr_str; - std::vector supported_bands_nr; - std::vector supported_bands_eutra; - std::string log_level; - uint32_t log_hex_limit; + bool sa_mode; + uint32_t sim_nr_meas_pci; + bool pdcp_short_sn_support; + std::string supported_bands_nr_str; + std::vector supported_bands_nr; + std::vector supported_bands_eutra; + uint32_t dl_nr_arfcn; + uint32_t ssb_nr_arfcn; + uint32_t nof_prb; + uint32_t pci; + srsran_subcarrier_spacing_t scs; + srsran_subcarrier_spacing_t ssb_scs; + std::string log_level; + uint32_t log_hex_limit; }; } // namespace srsue diff --git a/srsue/src/stack/rrc_nr/rrc_nr.cc b/srsue/src/stack/rrc_nr/rrc_nr.cc index 5f9876919..3e903b212 100644 --- a/srsue/src/stack/rrc_nr/rrc_nr.cc +++ b/srsue/src/stack/rrc_nr/rrc_nr.cc @@ -70,7 +70,33 @@ int rrc_nr::init(phy_interface_rrc_nr* phy_, t310 = task_sched.get_unique_timer(); t311 = task_sched.get_unique_timer(); - plmn_is_selected = true; // short-cut SA test + if (args.sa_mode) { + plmn_is_selected = true; // short-cut SA test + + // for SA mode setup inital HARQ config and SRB0 + srsran::dl_harq_cfg_nr_t harq_cfg = {}; + harq_cfg.nof_procs = 8; + mac->set_config(harq_cfg); + + // Setup SRB0 + logical_channel_config_t lch = {}; + mac->setup_lcid(lch); + + // Carrier config + srsran::srsran_band_helper bands; + phy_cfg.carrier.dl_center_frequency_hz = bands.nr_arfcn_to_freq(args.dl_nr_arfcn); + phy_cfg.carrier.ssb_center_freq_hz = bands.nr_arfcn_to_freq(args.ssb_nr_arfcn); + phy_cfg.carrier.nof_prb = args.nof_prb; + phy_cfg.carrier.max_mimo_layers = 1; + phy_cfg.carrier.pci = args.pci; + phy_cfg.carrier.scs = args.scs; + phy_cfg.duplex.mode = bands.get_duplex_mode(bands.get_band_from_dl_arfcn(args.dl_nr_arfcn)); + + // SSB configuration + phy_cfg.ssb.periodicity_ms = 10; + phy_cfg.ssb.position_in_burst[0] = true; + phy_cfg.ssb.scs = args.ssb_scs; + } running = true; sim_measurement_timer = task_sched.get_unique_timer(); @@ -82,26 +108,6 @@ void rrc_nr::stop() running = false; } -void rrc_nr::init_core_less() -{ - logger.info("Creating dummy DRB on LCID=%d", args.coreless.drb_lcid); - srsran::rlc_config_t rlc_cnfg = srsran::rlc_config_t::default_rlc_um_nr_config(6); - rlc->add_bearer(args.coreless.drb_lcid, rlc_cnfg); - - srsran::pdcp_config_t pdcp_cnfg{args.coreless.drb_lcid, - srsran::PDCP_RB_IS_DRB, - srsran::SECURITY_DIRECTION_DOWNLINK, - srsran::SECURITY_DIRECTION_UPLINK, - srsran::PDCP_SN_LEN_18, - srsran::pdcp_t_reordering_t::ms500, - srsran::pdcp_discard_timer_t::ms100, - false, - srsran_rat_t::nr}; - - pdcp->add_bearer(args.coreless.drb_lcid, pdcp_cnfg); - return; -} - void rrc_nr::get_metrics(rrc_nr_metrics_t& m) { m.state = state; @@ -223,7 +229,6 @@ void rrc_nr::run_tti(uint32_t tti) {} // PDCP interface void rrc_nr::write_pdu(uint32_t lcid, srsran::unique_byte_buffer_t pdu) { - printf("RRC received PDU\n"); logger.debug("RX PDU, LCID: %d", lcid); switch (static_cast(lcid)) { case nr_srb::srb0: @@ -317,7 +322,7 @@ void rrc_nr::decode_dl_dcch(uint32_t lcid, unique_byte_buffer_t pdu) break; } default: - logger.error("The provided DL-DCCH message type is not recognized or supported"); + logger.error("The provided DL-DCCH message type is not recognized or supported."); break; } } @@ -352,12 +357,9 @@ void rrc_nr::decode_pdu_bcch_dlsch(srsran::unique_byte_buffer_t pdu) void rrc_nr::handle_sib1(const sib1_s& sib1) { - logger.info("SIB1 received, CellID=%d", meas_cells.serving_cell().get_cell_id() & 0xfff); - meas_cells.serving_cell().set_sib1(sib1); - // TODO: config basic config and remove early exit - return; + logger.info("SIB1 received, CellID=%d", meas_cells.serving_cell().get_cell_id() & 0xfff); // clang-format off // unhandled fields: @@ -466,94 +468,11 @@ int rrc_nr::write_sdu(srsran::unique_byte_buffer_t sdu) bool rrc_nr::is_connected() { - return false; + return state == RRC_NR_STATE_CONNECTED; } int rrc_nr::connection_request(srsran::nr_establishment_cause_t cause, srsran::unique_byte_buffer_t dedicated_info_nas_) { - // TODO: - // Assume cell has been found and SSB with MIB has been decoded - srsran::phy_cfg_nr_default_t::reference_cfg_t cfg = {}; - cfg.carrier = srsran::phy_cfg_nr_default_t::reference_cfg_t::R_CARRIER_CUSTOM_10MHZ; - cfg.duplex = srsran::phy_cfg_nr_default_t::reference_cfg_t::R_DUPLEX_FDD; - phy_cfg = srsran::phy_cfg_nr_default_t{srsran::phy_cfg_nr_default_t::reference_cfg_t{cfg}}; - - // Carrier configuration - phy_cfg.ssb.periodicity_ms = 10; - phy_cfg.carrier.ssb_center_freq_hz = 1842.05e6; - phy_cfg.carrier.dl_center_frequency_hz = 1842.5e6; - phy_cfg.carrier.ul_center_frequency_hz = 1747.5e6; - - // PRACH configuration - phy_cfg.prach.num_ra_preambles = 8; - phy_cfg.prach.config_idx = 0; - phy_cfg.prach.root_seq_idx = 1; - phy_cfg.prach.zero_corr_zone = 0; - phy_cfg.prach.is_nr = true; - phy_cfg.prach.freq_offset = 1; - - srsran::rach_cfg_nr_t rach_cfg = {}; - rach_cfg.prach_ConfigurationIndex = 0; - rach_cfg.preambleTransMax = 7; - rach_cfg.ra_responseWindow = 10; - rach_cfg.ra_ContentionResolutionTimer = 64; - mac->set_config(rach_cfg); - - srsran::dl_harq_cfg_nr_t harq_cfg = {}; - harq_cfg.nof_procs = 8; - mac->set_config(harq_cfg); - - // Setup SRB0 - logical_channel_config_t lch = {}; - mac->setup_lcid(lch); - - // Coreset0 configuration - // Get pointA and SSB absolute frequencies - double pointA_abs_freq_Hz = phy_cfg.carrier.dl_center_frequency_hz - - phy_cfg.carrier.nof_prb * SRSRAN_NRE * SRSRAN_SUBC_SPACING_NR(phy_cfg.carrier.scs) / 2; - double ssb_abs_freq_Hz = phy_cfg.carrier.ssb_center_freq_hz; - // Calculate integer SSB to pointA frequency offset in Hz - uint32_t ssb_pointA_freq_offset_Hz = - (ssb_abs_freq_Hz > pointA_abs_freq_Hz) ? (uint32_t)(ssb_abs_freq_Hz - pointA_abs_freq_Hz) : 0; - - if (srsran_coreset_zero(phy_cfg.carrier.pci, - ssb_pointA_freq_offset_Hz, - phy_cfg.ssb.scs, - phy_cfg.carrier.scs, - 6, - &phy_cfg.pdcch.coreset[0])) { - fprintf(stderr, "Error generating coreset0\n"); - } - phy_cfg.pdcch.coreset_present[0] = true; - - // RAR SS - phy_cfg.pdcch.ra_search_space_present = true; - phy_cfg.pdcch.ra_search_space.coreset_id = 0; - phy_cfg.pdcch.ra_search_space.duration = 1; - phy_cfg.pdcch.ra_search_space.type = srsran_search_space_type_common_1; - phy_cfg.pdcch.ra_search_space.nof_formats = 1; - phy_cfg.pdcch.ra_search_space.formats[1] = srsran_dci_format_nr_1_0; - phy_cfg.pdcch.ra_search_space.nof_candidates[0] = 0; - phy_cfg.pdcch.ra_search_space.nof_candidates[1] = 0; - phy_cfg.pdcch.ra_search_space.nof_candidates[2] = 1; - phy_cfg.pdcch.ra_search_space.nof_candidates[3] = 0; - phy_cfg.pdcch.ra_search_space.nof_candidates[4] = 0; - - // common1 SS - phy_cfg.pdcch.search_space_present[0] = true; - phy_cfg.pdcch.search_space[0].coreset_id = 0; - phy_cfg.pdcch.search_space[0].duration = 1; - phy_cfg.pdcch.search_space[0].nof_candidates[0] = 0; - phy_cfg.pdcch.search_space[0].nof_candidates[1] = 0; - phy_cfg.pdcch.search_space[0].nof_candidates[2] = 1; - phy_cfg.pdcch.search_space[0].nof_candidates[3] = 0; - phy_cfg.pdcch.search_space[0].nof_candidates[4] = 0; - phy_cfg.pdcch.search_space[0].type = srsran_search_space_type_common_1; - phy_cfg.pdcch.search_space[0].nof_formats = 2; - phy_cfg.pdcch.search_space[0].formats[0] = srsran_dci_format_nr_0_0; - phy_cfg.pdcch.search_space[0].formats[1] = srsran_dci_format_nr_1_0; - phy_cfg.pdcch.search_space_present[1] = false; - if (not setup_req_proc.launch(cause, std::move(dedicated_info_nas_))) { logger.error("Failed to initiate setup request procedure"); return SRSRAN_ERROR; @@ -1336,7 +1255,6 @@ bool rrc_nr::apply_dl_common_cfg(const asn1::rrc_nr::dl_cfg_common_s& dl_cfg_com } if (pdcch_cfg_common.ra_search_space_present) { if (phy_cfg.pdcch.search_space_present[pdcch_cfg_common.ra_search_space] == true) { - // phy_cfg.pdcch.ra_rnti = 0x16; //< Supposed to be deduced from PRACH configuration phy_cfg.pdcch.ra_search_space = phy_cfg.pdcch.search_space[pdcch_cfg_common.ra_search_space]; phy_cfg.pdcch.ra_search_space_present = true; phy_cfg.pdcch.ra_search_space.type = srsran_search_space_type_common_1; diff --git a/srsue/src/stack/rrc_nr/rrc_nr_procedures.cc b/srsue/src/stack/rrc_nr/rrc_nr_procedures.cc index dea59e9f7..862b2002f 100644 --- a/srsue/src/stack/rrc_nr/rrc_nr_procedures.cc +++ b/srsue/src/stack/rrc_nr/rrc_nr_procedures.cc @@ -429,6 +429,30 @@ rrc_nr::cell_selection_proc::handle_cell_search_result(const rrc_interface_phy_n // until cell selection is done, update PHY config to take the last found PCI rrc_handle.phy_cfg.carrier.pci = result.pci; + { + // Coreset0 configuration + srsran::phy_cfg_nr_t& phy_cfg = rrc_handle.phy_cfg; + + // Get pointA and SSB absolute frequencies + double pointA_abs_freq_Hz = + phy_cfg.carrier.dl_center_frequency_hz - + phy_cfg.carrier.nof_prb * SRSRAN_NRE * SRSRAN_SUBC_SPACING_NR(phy_cfg.carrier.scs) / 2; + double ssb_abs_freq_Hz = phy_cfg.carrier.ssb_center_freq_hz; + // Calculate integer SSB to pointA frequency offset in Hz + uint32_t ssb_pointA_freq_offset_Hz = + (ssb_abs_freq_Hz > pointA_abs_freq_Hz) ? (uint32_t)(ssb_abs_freq_Hz - pointA_abs_freq_Hz) : 0; + + if (srsran_coreset_zero(phy_cfg.carrier.pci, + ssb_pointA_freq_offset_Hz, + phy_cfg.ssb.scs, + phy_cfg.carrier.scs, + 6, + &phy_cfg.pdcch.coreset[0])) { + fprintf(stderr, "Error generating coreset0\n"); + } + phy_cfg.pdcch.coreset_present[0] = true; + } + // Until SI acquisition is implemented, provide hard-coded SIB for now uint8_t msg[] = {0x74, 0x81, 0x01, 0x70, 0x10, 0x40, 0x04, 0x02, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x33, 0x60, 0x38, 0x05, 0x01, 0x00, 0x40, 0x1a, 0x00, 0x00, 0x06, 0x6c, 0x6d, 0x92, 0x21, 0xf3, 0x70, 0x40, 0x20, diff --git a/srsue/src/stack/ue_stack_nr.cc b/srsue/src/stack/ue_stack_nr.cc index fa186797a..826330884 100644 --- a/srsue/src/stack/ue_stack_nr.cc +++ b/srsue/src/stack/ue_stack_nr.cc @@ -76,8 +76,6 @@ int ue_stack_nr::init(const stack_args_t& args_) rrc_nr_args_t rrc_args = {}; rrc_args.log_level = args.log.rrc_level; rrc_args.log_hex_limit = args.log.rrc_hex_limit; - rrc_args.coreless.drb_lcid = 4; - rrc_args.coreless.ip_addr = "192.168.1.3"; rrc->init(phy, mac.get(), rlc.get(), @@ -89,7 +87,6 @@ int ue_stack_nr::init(const stack_args_t& args_) task_sched.get_timer_handler(), this, rrc_args); - rrc->init_core_less(); running = true; start(STACK_MAIN_THREAD_PRIO); diff --git a/srsue/src/ue.cc b/srsue/src/ue.cc index 50a728095..1729da5aa 100644 --- a/srsue/src/ue.cc +++ b/srsue/src/ue.cc @@ -276,10 +276,22 @@ int ue::parse_args(const all_args_t& args_) return SRSRAN_ERROR; } - // Update NAS-5G args - args.stack.nas_5g.ia5g = args.stack.nas.eia; - args.stack.nas_5g.ea5g = args.stack.nas.eea; - args.stack.nas_5g.pdu_session_cfgs.push_back({args.stack.nas.apn_name}); + // SA params + if (args.phy.nof_lte_carriers == 0 && args.phy.nof_nr_carriers == 1) { + args.stack.rrc_nr.sa_mode = true; + // TODO: expose to UE config + args.stack.rrc_nr.dl_nr_arfcn = 368500; + args.stack.rrc_nr.ssb_nr_arfcn = 368410; + args.stack.rrc_nr.nof_prb = 52; + args.stack.rrc_nr.pci = 500; + args.stack.rrc_nr.scs = srsran_subcarrier_spacing_15kHz; + args.stack.rrc_nr.ssb_scs = srsran_subcarrier_spacing_15kHz; + + // Update NAS-5G args + args.stack.nas_5g.ia5g = args.stack.nas.eia; + args.stack.nas_5g.ea5g = args.stack.nas.eea; + args.stack.nas_5g.pdu_session_cfgs.push_back({args.stack.nas.apn_name}); + } return SRSRAN_SUCCESS; } From 8464a6ed6357112cf086e6ed9aa9333d5a3b28c1 Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Tue, 1 Feb 2022 10:28:51 +0100 Subject: [PATCH 28/62] srsue: refactor SA mode in RRC, don't initilize NSA-5G in NSA mode --- srsue/hdr/stack/rrc_nr/rrc_nr_config.h | 1 - srsue/hdr/stack/ue_stack_base.h | 2 +- srsue/src/stack/rrc_nr/rrc_nr.cc | 15 ++++++++++----- srsue/src/stack/rrc_nr/rrc_nr_procedures.cc | 8 ++++++-- srsue/src/stack/ue_stack_lte.cc | 10 ++++++---- srsue/src/ue.cc | 5 ++--- 6 files changed, 25 insertions(+), 16 deletions(-) diff --git a/srsue/hdr/stack/rrc_nr/rrc_nr_config.h b/srsue/hdr/stack/rrc_nr/rrc_nr_config.h index a76046b97..fc3e4a25a 100644 --- a/srsue/hdr/stack/rrc_nr/rrc_nr_config.h +++ b/srsue/hdr/stack/rrc_nr/rrc_nr_config.h @@ -19,7 +19,6 @@ namespace srsue { struct rrc_nr_args_t { - bool sa_mode; uint32_t sim_nr_meas_pci; bool pdcp_short_sn_support; std::string supported_bands_nr_str; diff --git a/srsue/hdr/stack/ue_stack_base.h b/srsue/hdr/stack/ue_stack_base.h index 8b80b4244..ac1ec3d62 100644 --- a/srsue/hdr/stack/ue_stack_base.h +++ b/srsue/hdr/stack/ue_stack_base.h @@ -66,7 +66,7 @@ typedef struct { gw_args_t gw; uint32_t sync_queue_size; // Max allowed difference between PHY and Stack clocks (in TTI) bool have_tti_time_stats; - bool attach_on_nr; + bool sa_mode; } stack_args_t; class ue_stack_base diff --git a/srsue/src/stack/rrc_nr/rrc_nr.cc b/srsue/src/stack/rrc_nr/rrc_nr.cc index 3e903b212..7fa2f4266 100644 --- a/srsue/src/stack/rrc_nr/rrc_nr.cc +++ b/srsue/src/stack/rrc_nr/rrc_nr.cc @@ -70,10 +70,11 @@ int rrc_nr::init(phy_interface_rrc_nr* phy_, t310 = task_sched.get_unique_timer(); t311 = task_sched.get_unique_timer(); - if (args.sa_mode) { - plmn_is_selected = true; // short-cut SA test + if (rrc_eutra == nullptr) { + // SA mode + plmn_is_selected = true; - // for SA mode setup inital HARQ config and SRB0 + // setup inital HARQ config srsran::dl_harq_cfg_nr_t harq_cfg = {}; harq_cfg.nof_procs = 8; mac->set_config(harq_cfg); @@ -129,7 +130,7 @@ const char* rrc_nr::get_rb_name(uint32_t lcid) void rrc_nr::timer_expired(uint32_t timeout_id) { logger.debug("Handling Timer Expired"); - if (timeout_id == sim_measurement_timer.id()) { + if (timeout_id == sim_measurement_timer.id() && rrc_eutra != nullptr) { logger.debug("Triggered simulated measurement"); phy_meas_nr_t sim_meas = {}; @@ -2072,7 +2073,11 @@ void rrc_nr::ra_completed() void rrc_nr::ra_problem() { - rrc_eutra->nr_scg_failure_information(scg_failure_cause_t::random_access_problem); + if (rrc_eutra) { + rrc_eutra->nr_scg_failure_information(scg_failure_cause_t::random_access_problem); + } else { + // TODO: handle RA problem + } } void rrc_nr::release_pucch_srs() {} diff --git a/srsue/src/stack/rrc_nr/rrc_nr_procedures.cc b/srsue/src/stack/rrc_nr/rrc_nr_procedures.cc index 862b2002f..fe307a0bb 100644 --- a/srsue/src/stack/rrc_nr/rrc_nr_procedures.cc +++ b/srsue/src/stack/rrc_nr/rrc_nr_procedures.cc @@ -142,12 +142,16 @@ void rrc_nr::connection_reconf_no_ho_proc::then(const srsran::proc_state_t& resu if (result.is_success()) { Info("Finished %s successfully", name()); srsran::console("RRC NR reconfiguration successful.\n"); - rrc_handle.rrc_eutra->nr_rrc_con_reconfig_complete(true); + if (rrc_handle.rrc_eutra) { + rrc_handle.rrc_eutra->nr_rrc_con_reconfig_complete(true); + } } else { // 5.3.5.8.2 Inability to comply with RRCReconfiguration switch (initiator) { case reconf_initiator_t::mcg_srb1: - rrc_handle.rrc_eutra->nr_notify_reconfiguration_failure(); + if (rrc_handle.rrc_eutra) { + rrc_handle.rrc_eutra->nr_notify_reconfiguration_failure(); + } break; default: Warning("Reconfiguration failure not implemented for initiator %d", initiator); diff --git a/srsue/src/stack/ue_stack_lte.cc b/srsue/src/stack/ue_stack_lte.cc index 63ddada6e..77359c4e2 100644 --- a/srsue/src/stack/ue_stack_lte.cc +++ b/srsue/src/stack/ue_stack_lte.cc @@ -221,14 +221,16 @@ int ue_stack_lte::init(const stack_args_t& args_) &pdcp_nr, gw, &nas_5g, - &rrc, + args.sa_mode ? nullptr : &rrc, usim.get(), task_sched.get_timer_handler(), this, args.rrc_nr); rrc.init(phy, &mac, &rlc, &pdcp, &nas, usim.get(), gw, &rrc_nr, args.rrc); - nas_5g.init(usim.get(), &rrc_nr, gw, args.nas_5g); + if (args.sa_mode) { + nas_5g.init(usim.get(), &rrc_nr, gw, args.nas_5g); + } running = true; start(STACK_MAIN_THREAD_PRIO); @@ -276,7 +278,7 @@ bool ue_stack_lte::switch_on() if (running) { stack_logger.info("Triggering NAS switch on"); if (!ue_task_queue.try_push([this]() { - if (args.attach_on_nr) { + if (args.sa_mode) { nas_5g.switch_on(); } else { nas.switch_on(); @@ -329,7 +331,7 @@ bool ue_stack_lte::start_service_request() { if (running) { ue_task_queue.try_push([this]() { - if (args.attach_on_nr) { + if (args.sa_mode) { nas_5g.start_service_request(); } else { nas.start_service_request(srsran::establishment_cause_t::mo_data); diff --git a/srsue/src/ue.cc b/srsue/src/ue.cc index 1729da5aa..27994309c 100644 --- a/srsue/src/ue.cc +++ b/srsue/src/ue.cc @@ -110,7 +110,7 @@ int ue::init(const all_args_t& args_) } // In SA mode, pass NR PHY pointer to stack - args.stack.attach_on_nr = true; + args.stack.sa_mode = true; if (lte_stack->init(args.stack, dummy_lte_phy.get(), nr_phy.get(), gw_ptr.get())) { srsran::console("Error initializing stack.\n"); ret = SRSRAN_ERROR; @@ -272,13 +272,12 @@ int ue::parse_args(const all_args_t& args_) // Make sure fix sampling rate is set for SA mode if (args.phy.nof_lte_carriers == 0 and not std::isnormal(args.rf.srate_hz)) { - srsran::console("Error. NR Standalone PHY requires a fix RF sampling rate.\n"); + srsran::console("Error. NR Standalone PHY requires a fixed RF sampling rate.\n"); return SRSRAN_ERROR; } // SA params if (args.phy.nof_lte_carriers == 0 && args.phy.nof_nr_carriers == 1) { - args.stack.rrc_nr.sa_mode = true; // TODO: expose to UE config args.stack.rrc_nr.dl_nr_arfcn = 368500; args.stack.rrc_nr.ssb_nr_arfcn = 368410; From 7c63da9e4defa3dc7bdbb6a766301b9d28081d04 Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Tue, 1 Feb 2022 11:28:34 +0100 Subject: [PATCH 29/62] srsue,rrc_nr: expose main carrier parameters as config * remove hard-coded ARFCN, SCS, etc * use PCI deteceted in cell search for carrier config --- srsue/hdr/stack/rrc_nr/rrc_nr_config.h | 1 - srsue/src/main.cc | 18 ++++++++++++++++-- srsue/src/stack/rrc_nr/rrc_nr.cc | 1 - srsue/src/stack/rrc_nr/rrc_nr_procedures.cc | 6 +++--- srsue/src/ue.cc | 8 -------- 5 files changed, 19 insertions(+), 15 deletions(-) diff --git a/srsue/hdr/stack/rrc_nr/rrc_nr_config.h b/srsue/hdr/stack/rrc_nr/rrc_nr_config.h index fc3e4a25a..cdc87b9d0 100644 --- a/srsue/hdr/stack/rrc_nr/rrc_nr_config.h +++ b/srsue/hdr/stack/rrc_nr/rrc_nr_config.h @@ -27,7 +27,6 @@ struct rrc_nr_args_t { uint32_t dl_nr_arfcn; uint32_t ssb_nr_arfcn; uint32_t nof_prb; - uint32_t pci; srsran_subcarrier_spacing_t scs; srsran_subcarrier_spacing_t ssb_scs; std::string log_level; diff --git a/srsue/src/main.cc b/srsue/src/main.cc index 495d49777..8d89be9b4 100644 --- a/srsue/src/main.cc +++ b/srsue/src/main.cc @@ -60,6 +60,7 @@ string config_file; static int parse_args(all_args_t* args, int argc, char* argv[]) { bool use_standard_lte_rates = false; + std::string scs_khz, ssb_scs_khz; // temporary value to store integer // Command line only options bpo::options_description general("General options"); @@ -122,9 +123,14 @@ static int parse_args(all_args_t* args, int argc, char* argv[]) ("rat.eutra.ul_freq", bpo::value(&args->phy.ul_freq)->default_value(-1), "Uplink Frequency (if positive overrides EARFCN)") ("rat.eutra.nof_carriers", bpo::value(&args->phy.nof_lte_carriers)->default_value(1), "Number of carriers") - ("rat.nr.bands", bpo::value(&args->stack.rrc_nr.supported_bands_nr_str)->default_value("78"), "Supported NR bands") + ("rat.nr.bands", bpo::value(&args->stack.rrc_nr.supported_bands_nr_str)->default_value("3"), "Supported NR bands") ("rat.nr.nof_carriers", bpo::value(&args->phy.nof_nr_carriers)->default_value(0), "Number of NR carriers") - ("rat.nr.max_nof_prb", bpo::value(&args->phy.nr_max_nof_prb)->default_value(52), "Maximum NR carrier bandwidth in PRB") + ("rat.nr.max_nof_prb", bpo::value(&args->phy.nr_max_nof_prb)->default_value(52), "Maximum NR carrier bandwidth in PRB") + ("rat.nr.dl_nr_arfcn", bpo::value(&args->stack.rrc_nr.dl_nr_arfcn)->default_value(368500), "DL ARFCN of NR cell") + ("rat.nr.ssb_nr_arfcn", bpo::value(&args->stack.rrc_nr.ssb_nr_arfcn)->default_value(368410), "SSB ARFCN of NR cell") + ("rat.nr.nof_prb", bpo::value(&args->stack.rrc_nr.nof_prb)->default_value(52), "Actual NR carrier bandwidth in PRB") + ("rat.nr.scs", bpo::value(&scs_khz)->default_value("15"), "PDSCH subcarrier spacing in kHz") + ("rat.nr.ssb_scs", bpo::value(&ssb_scs_khz)->default_value("15"), "SSB subcarrier spacing in kHz") ("rrc.feature_group", bpo::value(&args->stack.rrc.feature_group)->default_value(0xe6041000), "Hex value of the featureGroupIndicators field in the" "UECapabilityInformation message. Default 0xe6041000") @@ -620,6 +626,14 @@ static int parse_args(all_args_t* args, int argc, char* argv[]) srsran_use_standard_symbol_size(use_standard_lte_rates); + args->stack.rrc_nr.scs = srsran_subcarrier_spacing_from_str(scs_khz.c_str()); + args->stack.rrc_nr.ssb_scs = srsran_subcarrier_spacing_from_str(ssb_scs_khz.c_str()); + if (args->stack.rrc_nr.scs == srsran_subcarrier_spacing_invalid || + args->stack.rrc_nr.ssb_scs == srsran_subcarrier_spacing_invalid) { + cout << "Invalid subcarrier spacing config" << endl; + return SRSRAN_ERROR; + } + return SRSRAN_SUCCESS; } diff --git a/srsue/src/stack/rrc_nr/rrc_nr.cc b/srsue/src/stack/rrc_nr/rrc_nr.cc index 7fa2f4266..16b198756 100644 --- a/srsue/src/stack/rrc_nr/rrc_nr.cc +++ b/srsue/src/stack/rrc_nr/rrc_nr.cc @@ -89,7 +89,6 @@ int rrc_nr::init(phy_interface_rrc_nr* phy_, phy_cfg.carrier.ssb_center_freq_hz = bands.nr_arfcn_to_freq(args.ssb_nr_arfcn); phy_cfg.carrier.nof_prb = args.nof_prb; phy_cfg.carrier.max_mimo_layers = 1; - phy_cfg.carrier.pci = args.pci; phy_cfg.carrier.scs = args.scs; phy_cfg.duplex.mode = bands.get_duplex_mode(bands.get_band_from_dl_arfcn(args.dl_nr_arfcn)); diff --git a/srsue/src/stack/rrc_nr/rrc_nr_procedures.cc b/srsue/src/stack/rrc_nr/rrc_nr_procedures.cc index fe307a0bb..c699e0e65 100644 --- a/srsue/src/stack/rrc_nr/rrc_nr_procedures.cc +++ b/srsue/src/stack/rrc_nr/rrc_nr_procedures.cc @@ -426,13 +426,13 @@ rrc_nr::cell_selection_proc::handle_cell_search_result(const rrc_interface_phy_n // Transition to cell selection ignoring the cell search result state = state_t::phy_cell_select; + // until cell selection is done, update PHY config to take the last found PCI + rrc_handle.phy_cfg.carrier.pci = result.pci; + phy_interface_rrc_nr::cell_select_args_t cs_args = {}; cs_args.carrier = rrc_handle.phy_cfg.carrier; cs_args.ssb_cfg = rrc_handle.phy_cfg.get_ssb_cfg(); - // until cell selection is done, update PHY config to take the last found PCI - rrc_handle.phy_cfg.carrier.pci = result.pci; - { // Coreset0 configuration srsran::phy_cfg_nr_t& phy_cfg = rrc_handle.phy_cfg; diff --git a/srsue/src/ue.cc b/srsue/src/ue.cc index 27994309c..ef91501ce 100644 --- a/srsue/src/ue.cc +++ b/srsue/src/ue.cc @@ -278,14 +278,6 @@ int ue::parse_args(const all_args_t& args_) // SA params if (args.phy.nof_lte_carriers == 0 && args.phy.nof_nr_carriers == 1) { - // TODO: expose to UE config - args.stack.rrc_nr.dl_nr_arfcn = 368500; - args.stack.rrc_nr.ssb_nr_arfcn = 368410; - args.stack.rrc_nr.nof_prb = 52; - args.stack.rrc_nr.pci = 500; - args.stack.rrc_nr.scs = srsran_subcarrier_spacing_15kHz; - args.stack.rrc_nr.ssb_scs = srsran_subcarrier_spacing_15kHz; - // Update NAS-5G args args.stack.nas_5g.ia5g = args.stack.nas.eia; args.stack.nas_5g.ea5g = args.stack.nas.eea; From 8cf6c851e1d5f7a5a161a4e53138845b01417cb7 Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Tue, 1 Feb 2022 17:05:19 +0100 Subject: [PATCH 30/62] srsue,rrc: remove phy_cfg_default header * address Xicos comment in https://github.com/softwareradiosystems/srsLTE/pull/3836 --- srsue/src/stack/rrc_nr/rrc_nr.cc | 2 +- srsue/src/ue.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/srsue/src/stack/rrc_nr/rrc_nr.cc b/srsue/src/stack/rrc_nr/rrc_nr.cc index 16b198756..e51417e54 100644 --- a/srsue/src/stack/rrc_nr/rrc_nr.cc +++ b/srsue/src/stack/rrc_nr/rrc_nr.cc @@ -12,7 +12,6 @@ #include "srsue/hdr/stack/rrc_nr/rrc_nr.h" #include "srsran/common/band_helper.h" -#include "srsran/common/phy_cfg_nr_default.h" #include "srsran/common/security.h" #include "srsran/common/standard_streams.h" #include "srsran/interfaces/ue_pdcp_interfaces.h" @@ -23,6 +22,7 @@ using namespace asn1::rrc_nr; using namespace asn1; using namespace srsran; + namespace srsue { const static char* rrc_nr_state_text[] = {"IDLE", "CONNECTED", "CONNECTED-INACTIVE"}; diff --git a/srsue/src/ue.cc b/srsue/src/ue.cc index ef91501ce..8e6f2709f 100644 --- a/srsue/src/ue.cc +++ b/srsue/src/ue.cc @@ -277,7 +277,7 @@ int ue::parse_args(const all_args_t& args_) } // SA params - if (args.phy.nof_lte_carriers == 0 && args.phy.nof_nr_carriers == 1) { + if (args.phy.nof_lte_carriers == 0 && args.phy.nof_nr_carriers > 0) { // Update NAS-5G args args.stack.nas_5g.ia5g = args.stack.nas.eia; args.stack.nas_5g.ea5g = args.stack.nas.eea; From 96ef1beaf219e5f617189d182884485b1e7cbc0e Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Tue, 1 Feb 2022 17:06:18 +0100 Subject: [PATCH 31/62] srsue,phy,nr: only read metrics for NR rat --- srsue/hdr/phy/phy_nr_sa.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/srsue/hdr/phy/phy_nr_sa.h b/srsue/hdr/phy/phy_nr_sa.h index dc66ca806..3e6dbbc0f 100644 --- a/srsue/hdr/phy/phy_nr_sa.h +++ b/srsue/hdr/phy/phy_nr_sa.h @@ -59,7 +59,12 @@ public: bool start_cell_search(const cell_search_args_t& req) final; bool start_cell_select(const cell_select_args_t& req) final; - void get_metrics(const srsran::srsran_rat_t& rat, phy_metrics_t* m) final { return workers.get_metrics(*m); }; + void get_metrics(const srsran::srsran_rat_t& rat, phy_metrics_t* m) final + { + if (rat == srsran::srsran_rat_t::nr) { + return workers.get_metrics(*m); + } + }; void srsran_phy_logger(phy_logger_level_t log_level, char* str); private: From 986e0fc273d10bbdb155bb29d229b82078bf52a6 Mon Sep 17 00:00:00 2001 From: Pedro Alvarez Date: Wed, 2 Feb 2022 17:30:37 +0000 Subject: [PATCH 32/62] gnb,rlc_am_nr: fix generation of default AM NR configs --- lib/src/asn1/rrc_nr_utils.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/src/asn1/rrc_nr_utils.cc b/lib/src/asn1/rrc_nr_utils.cc index b82b2499b..e0e61182c 100644 --- a/lib/src/asn1/rrc_nr_utils.cc +++ b/lib/src/asn1/rrc_nr_utils.cc @@ -102,10 +102,11 @@ void make_mac_rach_cfg(const rach_cfg_common_s& asn1_type, rach_cfg_nr_t* rach_c int make_rlc_config_t(const rlc_cfg_c& asn1_type, uint8_t bearer_id, rlc_config_t* cfg_out) { - rlc_config_t rlc_cfg = rlc_config_t::default_rlc_um_nr_config(); + rlc_config_t rlc_cfg = {}; rlc_cfg.rat = srsran_rat_t::nr; switch (asn1_type.type().value) { case rlc_cfg_c::types_opts::am: + rlc_cfg = rlc_config_t::default_rlc_am_nr_config(); if (asn1_type.am().dl_am_rlc.sn_field_len_present && asn1_type.am().ul_am_rlc.sn_field_len_present && asn1_type.am().dl_am_rlc.sn_field_len != asn1_type.am().ul_am_rlc.sn_field_len) { asn1::log_warning("NR RLC sequence number length is not the same in uplink and downlink"); @@ -126,6 +127,7 @@ int make_rlc_config_t(const rlc_cfg_c& asn1_type, uint8_t bearer_id, rlc_config_ } break; case rlc_cfg_c::types_opts::um_bi_dir: + rlc_cfg = rlc_config_t::default_rlc_um_nr_config(); rlc_cfg.rlc_mode = rlc_mode_t::um; rlc_cfg.um_nr.t_reassembly_ms = asn1_type.um_bi_dir().dl_um_rlc.t_reassembly.to_number(); rlc_cfg.um_nr.bearer_id = bearer_id; From 82429d1742a928b5798fc57525a8698c9d0073e5 Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Wed, 2 Feb 2022 12:56:08 +0100 Subject: [PATCH 33/62] srsue,rrc: fix PHY config updates in SA/NSA mode * in SA the entire PHY config is applied immediately * for NSA (in some scenarios) parts of the config are applied after the RA complete This fixes #3842 --- srsue/src/stack/rrc_nr/rrc_nr.cc | 33 +++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/srsue/src/stack/rrc_nr/rrc_nr.cc b/srsue/src/stack/rrc_nr/rrc_nr.cc index e51417e54..074306f55 100644 --- a/srsue/src/stack/rrc_nr/rrc_nr.cc +++ b/srsue/src/stack/rrc_nr/rrc_nr.cc @@ -1567,7 +1567,9 @@ bool rrc_nr::apply_sp_cell_cfg(const sp_cell_cfg_s& sp_cell_cfg) bool rrc_nr::update_sp_cell_cfg(const sp_cell_cfg_s& sp_cell_cfg) { + // NSA specific handling to defer CSI, SR, SRS config until after RA (see TS 38.331, Section 5.3.5.3) srsran_csi_hl_cfg_t prev_csi = phy_cfg.csi; + if (sp_cell_cfg.recfg_with_sync_present) { const recfg_with_sync_s& recfg_with_sync = sp_cell_cfg.recfg_with_sync; mac->set_crnti(recfg_with_sync.new_ue_id); @@ -1618,7 +1620,8 @@ bool rrc_nr::update_sp_cell_cfg(const sp_cell_cfg_s& sp_cell_cfg) } } } else { - logger.warning("Reconfig with sync not present"); + // for SA this is not sent + logger.debug("Reconfig with sync not present"); } // Dedicated config @@ -1710,7 +1713,7 @@ bool rrc_nr::update_sp_cell_cfg(const sp_cell_cfg_s& sp_cell_cfg) mac->set_config(dl_harq_cfg_nr); } } else { - logger.warning("Option pdsch_serving_cell_cfg not present"); + logger.debug("Option pdsch_serving_cell_cfg not present"); } if (sp_cell_cfg.sp_cell_cfg_ded.csi_meas_cfg_present) { @@ -1732,10 +1735,15 @@ bool rrc_nr::update_sp_cell_cfg(const sp_cell_cfg_s& sp_cell_cfg) } // Configure PHY - // Note: CSI config is deferred to when RA is complete. See TS 38.331, Section 5.3.5.3 - srsran::phy_cfg_nr_t current_phycfg = phy_cfg; - current_phycfg.csi = prev_csi; - phy->set_config(current_phycfg); + if (sp_cell_cfg.recfg_with_sync_present) { + // defer CSI config until after RA complete + srsran::phy_cfg_nr_t current_phycfg = phy_cfg; + current_phycfg.csi = prev_csi; + phy->set_config(current_phycfg); + } else { + // apply full config immediately + phy->set_config(phy_cfg); + } return true; } @@ -2065,9 +2073,14 @@ void rrc_nr::protocol_failure() {} // MAC interface void rrc_nr::ra_completed() { - logger.info("RA completed. Applying remaining CSI configuration."); - phy->set_config(phy_cfg); - phy_cfg_state = PHY_CFG_STATE_RA_COMPLETED; + logger.info("RA completed."); + if (rrc_eutra) { + logger.debug("Applying remaining CSI configuration."); + phy->set_config(phy_cfg); + phy_cfg_state = PHY_CFG_STATE_RA_COMPLETED; + } else { + phy_cfg_state = PHY_CFG_STATE_NONE; + } } void rrc_nr::ra_problem() @@ -2094,8 +2107,6 @@ void rrc_nr::cell_select_completed(const rrc_interface_phy_nr::cell_select_resul void rrc_nr::set_phy_config_complete(bool status) { - logger.info("set_phy_config_complete() status=%d", status); - // inform procedures if they are running if (conn_setup_proc.is_busy()) { conn_setup_proc.trigger(status); From 1b891bb60048244afc249175712e1fd5c298a64e Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Wed, 2 Feb 2022 15:00:51 +0100 Subject: [PATCH 34/62] srsue,rrc: check present flag before parsing UCI PUSCH scaling info --- srsue/src/stack/rrc_nr/rrc_nr.cc | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/srsue/src/stack/rrc_nr/rrc_nr.cc b/srsue/src/stack/rrc_nr/rrc_nr.cc index 074306f55..ace2f9a4a 100644 --- a/srsue/src/stack/rrc_nr/rrc_nr.cc +++ b/srsue/src/stack/rrc_nr/rrc_nr.cc @@ -1537,9 +1537,11 @@ bool rrc_nr::apply_sp_cell_ded_ul_pusch(const asn1::rrc_nr::pusch_cfg_s& pusch_c logger.warning("Option beta_offsets not of type semi_static"); return false; } - if (make_phy_pusch_scaling(pusch_cfg.uci_on_pusch.setup(), &phy_cfg.pusch.scaling) == false) { - logger.warning("Warning while building scaling structure"); - return false; + if (pusch_cfg.uci_on_pusch_present) { + if (make_phy_pusch_scaling(pusch_cfg.uci_on_pusch.setup(), &phy_cfg.pusch.scaling) == false) { + logger.warning("Warning while building scaling structure"); + return false; + } } } else { logger.warning("Option beta_offsets not present"); From 98494a1ea267b896ecd07ffbcd39874cde6db781 Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Wed, 2 Feb 2022 15:01:18 +0100 Subject: [PATCH 35/62] srsue,rrc: remove timer stopping in main RRC class as this is done in procedures --- srsue/src/stack/rrc_nr/rrc_nr.cc | 3 --- 1 file changed, 3 deletions(-) diff --git a/srsue/src/stack/rrc_nr/rrc_nr.cc b/srsue/src/stack/rrc_nr/rrc_nr.cc index ace2f9a4a..0da164daa 100644 --- a/srsue/src/stack/rrc_nr/rrc_nr.cc +++ b/srsue/src/stack/rrc_nr/rrc_nr.cc @@ -1975,10 +1975,7 @@ bool rrc_nr::handle_rrc_setup(const rrc_setup_s& setup) cell_group.to_json(js); logger.debug("Containerized MasterCellGroup: %s", js.to_string().c_str()); - // Must enter CONNECT before stopping T300 state = RRC_NR_STATE_CONNECTED; - // t300.stop(); - // t302.stop(); srsran::console("RRC Connected\n"); // defer transmission of Setup Complete until PHY reconfiguration has been completed From 6e1d624a3b4ce148f3ae0236af028c4efdc28588 Mon Sep 17 00:00:00 2001 From: Carlo Galiotto Date: Fri, 28 Jan 2022 13:57:38 +0100 Subject: [PATCH 36/62] rrc-nr: add nzp RRCSetup cnf conversion for SA Signed-off-by: Carlo Galiotto --- srsgnb/src/stack/rrc/rrc_nr.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/srsgnb/src/stack/rrc/rrc_nr.cc b/srsgnb/src/stack/rrc/rrc_nr.cc index 967fe6e64..26c2c8ce9 100644 --- a/srsgnb/src/stack/rrc/rrc_nr.cc +++ b/srsgnb/src/stack/rrc/rrc_nr.cc @@ -342,7 +342,9 @@ void rrc_nr::config_mac() cell.ssb_scs = serv_cell.ssb_subcarrier_spacing; } else { cell.bwps[0].pdsch.p_zp_csi_rs_set = {}; - bzero(cell.bwps[0].pdsch.nzp_csi_rs_sets, sizeof(cell.bwps[0].pdsch.nzp_csi_rs_sets)); + bool valid_cfg = srsran::make_pdsch_cfg_from_serv_cell(cell_ctxt->master_cell_group->sp_cell_cfg.sp_cell_cfg_ded, + &cell.bwps[0].pdsch); + srsran_assert(valid_cfg, "Invalid NR cell configuration."); cell.ssb_positions_in_burst = du_cfg->cell(cc).serv_cell_cfg_common().ssb_positions_in_burst; cell.ssb_periodicity_ms = du_cfg->cell(cc).serv_cell_cfg_common().ssb_periodicity_serving_cell.to_number(); cell.ssb_scs.value = (subcarrier_spacing_e::options)cfg.cell_list[0].phy_cell.carrier.scs; From e88a4fbe18339816ca5a80539a60e82fb78b7e0d Mon Sep 17 00:00:00 2001 From: Carlo Galiotto Date: Fri, 28 Jan 2022 17:04:18 +0100 Subject: [PATCH 37/62] rrc-nr: add sr_resources RRCSetup cnf conversion Signed-off-by: Carlo Galiotto --- lib/include/srsran/asn1/rrc_nr_utils.h | 1 + lib/src/asn1/rrc_nr_utils.cc | 32 ++++++++++++++++++++++---- 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/lib/include/srsran/asn1/rrc_nr_utils.h b/lib/include/srsran/asn1/rrc_nr_utils.h index c9ca67aab..410232232 100644 --- a/lib/include/srsran/asn1/rrc_nr_utils.h +++ b/lib/include/srsran/asn1/rrc_nr_utils.h @@ -108,6 +108,7 @@ bool make_phy_res_config(const srsran_pucch_nr_resource_t& in_pucch_res, uint32_t pucch_res_id); bool make_phy_sr_resource(const asn1::rrc_nr::sched_request_res_cfg_s& sched_request_res_cfg, srsran_pucch_nr_sr_resource_t* srsran_pucch_nr_sr_resource); +bool make_phy_pucch_sched_req(const asn1::rrc_nr::pucch_cfg_s& pucch_cfg, srsran_pucch_nr_hl_cfg_t* pucch); bool make_phy_pusch_alloc_type(const asn1::rrc_nr::pusch_cfg_s& pusch_cfg, srsran_resource_alloc_t* in_srsran_resource_alloc); bool make_phy_pdsch_alloc_type(const asn1::rrc_nr::pdsch_cfg_s& pdsch_cfg, diff --git a/lib/src/asn1/rrc_nr_utils.cc b/lib/src/asn1/rrc_nr_utils.cc index e0e61182c..d1b3b9b22 100644 --- a/lib/src/asn1/rrc_nr_utils.cc +++ b/lib/src/asn1/rrc_nr_utils.cc @@ -945,6 +945,31 @@ bool make_phy_sr_resource(const sched_request_res_cfg_s& sched_request_res_cfg, return true; } +bool make_phy_pucch_sched_req(const asn1::rrc_nr::pucch_cfg_s& pucch_cfg, srsran_pucch_nr_hl_cfg_t* pucch) +{ + for (size_t n = 0; n < pucch_cfg.sched_request_res_to_add_mod_list.size(); n++) { + // fill each sr_resource's cnf + srsran_pucch_nr_sr_resource_t* sr_res = &pucch->sr_resources[n]; + auto& asn_sr_res = pucch_cfg.sched_request_res_to_add_mod_list[n]; + make_phy_sr_resource(asn_sr_res, sr_res); + + // get the pucch_resource from pucch_cfg.res_to_add_mod_list and copy it into the sr_resouce.resource + const auto& asn1_pucch_resource = pucch_cfg.res_to_add_mod_list[asn_sr_res.res]; + auto& pucch_resource = sr_res->resource; + uint32_t format2_rate = 0; + if (pucch_cfg.format2_present and + pucch_cfg.format2.type().value == asn1::setup_release_c::types_opts::setup and + pucch_cfg.format2.setup().max_code_rate_present) { + format2_rate = pucch_cfg.format2.setup().max_code_rate.to_number(); + } + if (not make_phy_res_config(asn1_pucch_resource, format2_rate, &pucch_resource)) { + return false; + } + } + + return true; +} + bool make_phy_pusch_alloc_type(const asn1::rrc_nr::pusch_cfg_s& pusch_cfg, srsran_resource_alloc_t* in_srsran_resource_alloc) { @@ -1743,9 +1768,7 @@ bool fill_phy_pucch_cfg(const asn1::rrc_nr::pucch_cfg_s& pucch_cfg, srsran_pucch } // iterate over the sets of resourceSetToAddModList - for (size_t n = 0; n < pucch_cfg.res_set_to_add_mod_list.size() and - pucch_cfg.res_set_to_add_mod_list.size() <= SRSRAN_PUCCH_NR_MAX_NOF_SETS; - n++) { + for (size_t n = 0; n < pucch_cfg.res_set_to_add_mod_list.size(); n++) { auto& res_set = pucch_cfg.res_set_to_add_mod_list[n]; pucch->sets[n].nof_resources = res_set.res_list.size(); if (res_set.max_payload_size_present) { @@ -1793,7 +1816,8 @@ bool fill_phy_pucch_cfg(const asn1::rrc_nr::pucch_cfg_s& pucch_cfg, srsran_pucch } } - return true; + // configure scheduling request resources + return make_phy_pucch_sched_req(pucch_cfg, pucch); } bool fill_phy_pdsch_cfg_common(const asn1::rrc_nr::pdsch_cfg_common_s& pdsch_cfg, srsran_sch_hl_cfg_nr_t* pdsch) From 91502c87db04cb1333d0243412a62f77c6c94c04 Mon Sep 17 00:00:00 2001 From: Carlo Galiotto Date: Wed, 2 Feb 2022 10:26:27 +0100 Subject: [PATCH 38/62] rrc-nr: rename rrc_util function and fix indexing Signed-off-by: Carlo Galiotto --- lib/include/srsran/asn1/rrc_nr_utils.h | 2 +- lib/src/asn1/rrc_nr_utils.cc | 52 +++++++++++++------------- 2 files changed, 27 insertions(+), 27 deletions(-) diff --git a/lib/include/srsran/asn1/rrc_nr_utils.h b/lib/include/srsran/asn1/rrc_nr_utils.h index 410232232..c005a7bfe 100644 --- a/lib/include/srsran/asn1/rrc_nr_utils.h +++ b/lib/include/srsran/asn1/rrc_nr_utils.h @@ -108,7 +108,6 @@ bool make_phy_res_config(const srsran_pucch_nr_resource_t& in_pucch_res, uint32_t pucch_res_id); bool make_phy_sr_resource(const asn1::rrc_nr::sched_request_res_cfg_s& sched_request_res_cfg, srsran_pucch_nr_sr_resource_t* srsran_pucch_nr_sr_resource); -bool make_phy_pucch_sched_req(const asn1::rrc_nr::pucch_cfg_s& pucch_cfg, srsran_pucch_nr_hl_cfg_t* pucch); bool make_phy_pusch_alloc_type(const asn1::rrc_nr::pusch_cfg_s& pusch_cfg, srsran_resource_alloc_t* in_srsran_resource_alloc); bool make_phy_pdsch_alloc_type(const asn1::rrc_nr::pdsch_cfg_s& pdsch_cfg, @@ -138,6 +137,7 @@ bool fill_phy_pdcch_cfg(const asn1::rrc_nr::pdcch_cfg_s& pdcch_cfg, srsran_pdcch bool fill_phy_pdsch_cfg_common(const asn1::rrc_nr::pdsch_cfg_common_s& pdsch_cfg, srsran_sch_hl_cfg_nr_t* pdsch); void fill_phy_pucch_cfg_common(const asn1::rrc_nr::pucch_cfg_common_s& pucch_cfg, srsran_pucch_nr_common_cfg_t* pucch); bool fill_phy_pucch_cfg(const asn1::rrc_nr::pucch_cfg_s& pucch_cfg, srsran_pucch_nr_hl_cfg_t* pucch); +bool fill_phy_pucch_hl_cfg(const asn1::rrc_nr::pucch_cfg_s& pucch_cfg, srsran_pucch_nr_hl_cfg_t* pucch); bool fill_phy_pusch_cfg_common(const asn1::rrc_nr::pusch_cfg_common_s& pusch_cfg, srsran_sch_hl_cfg_nr_t* pusch); void fill_phy_carrier_cfg(const asn1::rrc_nr::serving_cell_cfg_common_sib_s& serv_cell_cfg, srsran_carrier_nr_t* carrier_nr); diff --git a/lib/src/asn1/rrc_nr_utils.cc b/lib/src/asn1/rrc_nr_utils.cc index d1b3b9b22..bb6c0ee8b 100644 --- a/lib/src/asn1/rrc_nr_utils.cc +++ b/lib/src/asn1/rrc_nr_utils.cc @@ -945,31 +945,6 @@ bool make_phy_sr_resource(const sched_request_res_cfg_s& sched_request_res_cfg, return true; } -bool make_phy_pucch_sched_req(const asn1::rrc_nr::pucch_cfg_s& pucch_cfg, srsran_pucch_nr_hl_cfg_t* pucch) -{ - for (size_t n = 0; n < pucch_cfg.sched_request_res_to_add_mod_list.size(); n++) { - // fill each sr_resource's cnf - srsran_pucch_nr_sr_resource_t* sr_res = &pucch->sr_resources[n]; - auto& asn_sr_res = pucch_cfg.sched_request_res_to_add_mod_list[n]; - make_phy_sr_resource(asn_sr_res, sr_res); - - // get the pucch_resource from pucch_cfg.res_to_add_mod_list and copy it into the sr_resouce.resource - const auto& asn1_pucch_resource = pucch_cfg.res_to_add_mod_list[asn_sr_res.res]; - auto& pucch_resource = sr_res->resource; - uint32_t format2_rate = 0; - if (pucch_cfg.format2_present and - pucch_cfg.format2.type().value == asn1::setup_release_c::types_opts::setup and - pucch_cfg.format2.setup().max_code_rate_present) { - format2_rate = pucch_cfg.format2.setup().max_code_rate.to_number(); - } - if (not make_phy_res_config(asn1_pucch_resource, format2_rate, &pucch_resource)) { - return false; - } - } - - return true; -} - bool make_phy_pusch_alloc_type(const asn1::rrc_nr::pusch_cfg_s& pusch_cfg, srsran_resource_alloc_t* in_srsran_resource_alloc) { @@ -1817,7 +1792,32 @@ bool fill_phy_pucch_cfg(const asn1::rrc_nr::pucch_cfg_s& pucch_cfg, srsran_pucch } // configure scheduling request resources - return make_phy_pucch_sched_req(pucch_cfg, pucch); + return fill_phy_pucch_hl_cfg(pucch_cfg, pucch); +} + +bool fill_phy_pucch_hl_cfg(const asn1::rrc_nr::pucch_cfg_s& pucch_cfg, srsran_pucch_nr_hl_cfg_t* pucch) +{ + for (size_t n = 0; n < pucch_cfg.sched_request_res_to_add_mod_list.size(); n++) { + // fill each sr_resource's cnf + auto& asn_sr_res = pucch_cfg.sched_request_res_to_add_mod_list[n]; + srsran_pucch_nr_sr_resource_t* sr_res = &pucch->sr_resources[asn_sr_res.sched_request_res_id]; + make_phy_sr_resource(asn_sr_res, sr_res); + + // get the pucch_resource from pucch_cfg.res_to_add_mod_list and copy it into the sr_resouce.resource + const auto& asn1_pucch_resource = pucch_cfg.res_to_add_mod_list[asn_sr_res.res]; + auto& pucch_resource = sr_res->resource; + uint32_t format2_rate = 0; + if (pucch_cfg.format2_present and + pucch_cfg.format2.type().value == asn1::setup_release_c::types_opts::setup and + pucch_cfg.format2.setup().max_code_rate_present) { + format2_rate = pucch_cfg.format2.setup().max_code_rate.to_number(); + } + if (not make_phy_res_config(asn1_pucch_resource, format2_rate, &pucch_resource)) { + return false; + } + } + + return true; } bool fill_phy_pdsch_cfg_common(const asn1::rrc_nr::pdsch_cfg_common_s& pdsch_cfg, srsran_sch_hl_cfg_nr_t* pdsch) From b2075673e5dc6126f7db51a54cc2958846266899 Mon Sep 17 00:00:00 2001 From: Joaquim Broquetas Date: Fri, 4 Feb 2022 10:35:35 +0100 Subject: [PATCH 39/62] Crest Factor Reduction feature for the phy layer (#3720) * Add CFR module to the phy lib * Add dynamic threshold with PAPR estimation * Add a CFR unit test, CFR module improvements and refactoring. Swap the gain normalization before the CFR. * Add CFR config interface to srsenb * Add CFR support to pdsch_enodeb * Add DL PAPR measurement to eNB. Co-authored-by: Cristian Balint * Add test coverage to srsran_vec_gen_clip_env --- lib/examples/pdsch_enodeb.c | 202 +++++++++- .../srsran/interfaces/enb_command_interface.h | 5 + lib/include/srsran/phy/cfr/cfr.h | 118 ++++++ lib/include/srsran/phy/dft/ofdm.h | 21 +- lib/include/srsran/phy/enb/enb_dl.h | 6 +- lib/include/srsran/phy/utils/vector.h | 31 ++ lib/include/srsran/srsran.h | 1 + lib/src/phy/CMakeLists.txt | 2 + lib/src/phy/cfr/CMakeLists.txt | 13 + lib/src/phy/cfr/cfr.c | 367 ++++++++++++++++++ lib/src/phy/cfr/test/CMakeLists.txt | 17 + lib/src/phy/cfr/test/cfr_test.c | 308 +++++++++++++++ lib/src/phy/dft/ofdm.c | 57 +++ lib/src/phy/enb/enb_dl.c | 52 ++- lib/src/phy/utils/test/vector_test.c | 36 ++ lib/src/phy/utils/vector.c | 52 ++- srsenb/enb.conf.example | 26 ++ srsenb/hdr/enb.h | 2 + srsenb/hdr/phy/enb_phy_base.h | 2 + srsenb/hdr/phy/phy.h | 1 + srsenb/hdr/phy/phy_common.h | 44 +++ srsenb/hdr/phy/phy_interfaces.h | 13 + srsenb/src/enb.cc | 5 + srsenb/src/enb_cfg_parser.cc | 30 ++ srsenb/src/main.cc | 27 ++ srsenb/src/phy/lte/cc_worker.cc | 31 +- srsenb/src/phy/phy.cc | 8 + srsgnb/hdr/phy/phy_nr_interfaces.h | 1 + 28 files changed, 1442 insertions(+), 36 deletions(-) create mode 100644 lib/include/srsran/phy/cfr/cfr.h create mode 100644 lib/src/phy/cfr/CMakeLists.txt create mode 100644 lib/src/phy/cfr/cfr.c create mode 100644 lib/src/phy/cfr/test/CMakeLists.txt create mode 100644 lib/src/phy/cfr/test/cfr_test.c diff --git a/lib/examples/pdsch_enodeb.c b/lib/examples/pdsch_enodeb.c index cf647851b..291ab1f61 100644 --- a/lib/examples/pdsch_enodeb.c +++ b/lib/examples/pdsch_enodeb.c @@ -13,6 +13,7 @@ #include "srsran/common/crash_handler.h" #include "srsran/common/gen_mch_tables.h" #include "srsran/srsran.h" +#include #include #include #include @@ -43,6 +44,12 @@ static char* output_file_name = NULL; #define PAGE_UP 53 #define PAGE_DOWN 54 +#define CFR_THRES_UP_KEY 't' +#define CFR_THRES_DN_KEY 'g' + +#define CFR_THRES_STEP 0.05f +#define CFR_PAPR_STEP 0.1f + static srsran_cell_t cell = { 25, // nof_prb 1, // nof_ports @@ -70,6 +77,31 @@ static bool enable_256qam = false; static float output_file_snr = +INFINITY; static bool use_standard_lte_rate = false; +// CFR type test args +static char cfr_manual_str[] = "manual"; +static char cfr_auto_cma_str[] = "auto_cma"; +static char cfr_auto_ema_str[] = "auto_ema"; + +// CFR runtime control flags +static bool cfr_thr_inc = false; +static bool cfr_thr_dec = false; + +typedef struct { + int enable; + char* mode; + float manual_thres; + float strength; + float auto_target_papr; + float ema_alpha; +} cfr_args_t; + +static cfr_args_t cfr_args = {.enable = 0, + .mode = cfr_manual_str, + .manual_thres = 1.0f, + .strength = 1.0f, + .auto_target_papr = 8.0f, + .ema_alpha = 1.0f / (float)SRSRAN_CP_NORM_NSYMB}; + static bool null_file_sink = false; static srsran_filesink_t fsink; static srsran_ofdm_t ifft[SRSRAN_MAX_PORTS]; @@ -85,6 +117,7 @@ static srsran_softbuffer_tx_t* softbuffers[SRSRAN_MAX_CODEWORDS]; static srsran_regs_t regs; static srsran_dci_dl_t dci_dl; static int rvidx[SRSRAN_MAX_CODEWORDS] = {0, 0}; +static srsran_cfr_cfg_t cfr_config = {}; static cf_t * sf_buffer[SRSRAN_MAX_PORTS] = {NULL}, *output_buffer[SRSRAN_MAX_PORTS] = {NULL}; static uint32_t sf_n_re, sf_n_samples; @@ -134,14 +167,28 @@ static void usage(char* prog) printf("\t-s output file SNR [Default %f]\n", output_file_snr); printf("\t-q Enable/Disable 256QAM modulation (default %s)\n", enable_256qam ? "enabled" : "disabled"); printf("\t-Q Use standard LTE sample rates (default %s)\n", use_standard_lte_rate ? "enabled" : "disabled"); + printf("CFR Options:\n"); + printf("\t--enable_cfr Enable the CFR (default %s)\n", cfr_args.enable ? "enabled" : "disabled"); + printf("\t--cfr_mode CFR mode: manual, auto_cma, auto_ema. (default %s)\n", cfr_args.mode); + printf("\t--cfr_manual_thres CFR manual threshold (default %.2f)\n", cfr_args.manual_thres); + printf("\t--cfr_strength CFR strength (default %.2f)\n", cfr_args.strength); + printf("\t--cfr_auto_papr CFR PAPR target for auto modes (default %.2f)\n", cfr_args.auto_target_papr); + printf("\t--cfr_ema_alpha CFR alpha parameter for EMA mode (default %.2f)\n", cfr_args.ema_alpha); printf("\n"); printf("\t*: See 3GPP 36.212 Table 5.3.3.1.5-4 for more information\n"); } +struct option cfr_opts[] = {{"enable_cfr", no_argument, &cfr_args.enable, 1}, + {"cfr_mode", required_argument, NULL, 'C'}, + {"cfr_manual_thres", required_argument, NULL, 'T'}, + {"cfr_strength", required_argument, NULL, 'S'}, + {"cfr_auto_papr", required_argument, NULL, 'P'}, + {"cfr_ema_alpha", required_argument, NULL, 'e'}, + {0, 0, 0, 0}}; static void parse_args(int argc, char** argv) { int opt; - while ((opt = getopt(argc, argv, "IadglfmoncpqvutxbwMsBQ")) != -1) { + while ((opt = getopt_long(argc, argv, "IadglfmoncpqvutxbwMsBQ", cfr_opts, NULL)) != -1) { switch (opt) { case 'I': rf_dev = argv[optind]; @@ -206,6 +253,24 @@ static void parse_args(int argc, char** argv) case 'E': cell.cp = SRSRAN_CP_EXT; break; + case 'C': + cfr_args.mode = optarg; + break; + case 'T': + cfr_args.manual_thres = strtof(optarg, NULL); + break; + case 'S': + cfr_args.strength = strtof(optarg, NULL); + break; + case 'P': + cfr_args.auto_target_papr = strtof(optarg, NULL); + break; + case 'e': + cfr_args.ema_alpha = strtof(optarg, NULL); + break; + case 0: + /* getopt_long() set a variable, keep going */ + break; default: usage(argv[0]); exit(-1); @@ -219,6 +284,32 @@ static void parse_args(int argc, char** argv) #endif } +static int parse_cfr_args() +{ + cfr_config.cfr_enable = cfr_args.enable; + cfr_config.manual_thr = cfr_args.manual_thres; + cfr_config.max_papr_db = cfr_args.auto_target_papr; + cfr_config.alpha = cfr_args.strength; + cfr_config.ema_alpha = cfr_args.ema_alpha; + + if (!strcmp(cfr_args.mode, cfr_manual_str)) { + cfr_config.cfr_mode = SRSRAN_CFR_THR_MANUAL; + } else if (!strcmp(cfr_args.mode, cfr_auto_cma_str)) { + cfr_config.cfr_mode = SRSRAN_CFR_THR_AUTO_CMA; + } else if (!strcmp(cfr_args.mode, cfr_auto_ema_str)) { + cfr_config.cfr_mode = SRSRAN_CFR_THR_AUTO_EMA; + } else { + ERROR("CFR mode is not recognised"); + return SRSRAN_ERROR; + } + + if (!srsran_cfr_params_valid(&cfr_config)) { + ERROR("Invalid CFR parameters"); + return SRSRAN_ERROR; + } + return SRSRAN_SUCCESS; +} + static void base_init() { int i; @@ -316,6 +407,10 @@ static void base_init() } srsran_ofdm_set_normalize(&ifft[i], true); + if (srsran_ofdm_set_cfr(&ifft[i], &cfr_config)) { + ERROR("Error setting CFR object"); + exit(-1); + } } if (srsran_ofdm_tx_init_mbsfn(&ifft_mbsfn, SRSRAN_CP_EXT, sf_buffer[0], output_buffer[0], cell.nof_prb)) { @@ -324,6 +419,10 @@ static void base_init() } srsran_ofdm_set_non_mbsfn_region(&ifft_mbsfn, 2); srsran_ofdm_set_normalize(&ifft_mbsfn, true); + if (srsran_ofdm_set_cfr(&ifft_mbsfn, &cfr_config)) { + ERROR("Error setting CFR object"); + exit(-1); + } if (srsran_pbch_init(&pbch)) { ERROR("Error creating PBCH object"); @@ -474,6 +573,8 @@ static int update_radl() { ZERO_OBJECT(dci_dl); + int ret = SRSRAN_ERROR; + /* Configure cell and PDSCH in function of the transmission mode */ switch (transmission_mode) { case SRSRAN_TM1: @@ -496,7 +597,7 @@ static int update_radl() break; default: ERROR("Transmission mode not implemented."); - exit(-1); + goto exit; } dci_dl.rnti = UE_CRNTI; @@ -517,7 +618,80 @@ static int update_radl() SRSRAN_DCI_TB_DISABLE(dci_dl.tb[1]); } + // Increase the CFR threshold or target PAPR + if (cfr_thr_inc) { + cfr_thr_inc = false; // Reset the flag + if (cfr_config.cfr_enable && cfr_config.cfr_mode == SRSRAN_CFR_THR_MANUAL) { + cfr_config.manual_thr += CFR_THRES_STEP; + for (int i = 0; i < cell.nof_ports; i++) { + if (srsran_cfr_set_threshold(&ifft[i].tx_cfr, cfr_config.manual_thr) < SRSRAN_SUCCESS) { + ERROR("Setting the CFR"); + goto exit; + } + } + if (srsran_cfr_set_threshold(&ifft_mbsfn.tx_cfr, cfr_config.manual_thr) < SRSRAN_SUCCESS) { + ERROR("Setting the CFR"); + goto exit; + } + printf("CFR Thres. set to %.3f\n", cfr_config.manual_thr); + } else if (cfr_config.cfr_enable && cfr_config.cfr_mode != SRSRAN_CFR_THR_MANUAL) { + cfr_config.max_papr_db += CFR_PAPR_STEP; + for (int i = 0; i < cell.nof_ports; i++) { + if (srsran_cfr_set_papr(&ifft[i].tx_cfr, cfr_config.max_papr_db) < SRSRAN_SUCCESS) { + ERROR("Setting the CFR"); + goto exit; + } + } + if (srsran_cfr_set_papr(&ifft_mbsfn.tx_cfr, cfr_config.max_papr_db) < SRSRAN_SUCCESS) { + ERROR("Setting the CFR"); + goto exit; + } + printf("CFR target PAPR set to %.3f\n", cfr_config.max_papr_db); + } + } + + // Decrease the CFR threshold or target PAPR + if (cfr_thr_dec) { + cfr_thr_dec = false; // Reset the flag + if (cfr_config.cfr_enable && cfr_config.cfr_mode == SRSRAN_CFR_THR_MANUAL) { + if (cfr_config.manual_thr - CFR_THRES_STEP >= 0) { + cfr_config.manual_thr -= CFR_THRES_STEP; + for (int i = 0; i < cell.nof_ports; i++) { + if (srsran_cfr_set_threshold(&ifft[i].tx_cfr, cfr_config.manual_thr) < SRSRAN_SUCCESS) { + ERROR("Setting the CFR"); + goto exit; + } + } + if (srsran_cfr_set_threshold(&ifft_mbsfn.tx_cfr, cfr_config.manual_thr) < SRSRAN_SUCCESS) { + ERROR("Setting the CFR"); + goto exit; + } + printf("CFR Thres. set to %.3f\n", cfr_config.manual_thr); + } + } else if (cfr_config.cfr_enable && cfr_config.cfr_mode != SRSRAN_CFR_THR_MANUAL) { + if (cfr_config.max_papr_db - CFR_PAPR_STEP >= 0) { + cfr_config.max_papr_db -= CFR_PAPR_STEP; + for (int i = 0; i < cell.nof_ports; i++) { + if (srsran_cfr_set_papr(&ifft[i].tx_cfr, cfr_config.max_papr_db) < SRSRAN_SUCCESS) { + ERROR("Setting the CFR"); + goto exit; + } + } + if (srsran_cfr_set_papr(&ifft_mbsfn.tx_cfr, cfr_config.max_papr_db) < SRSRAN_SUCCESS) { + ERROR("Setting the CFR"); + goto exit; + } + printf("CFR target PAPR set to %.3f\n", cfr_config.max_papr_db); + } + } + } + srsran_dci_dl_fprint(stdout, &dci_dl, cell.nof_prb); + printf("\nCFR controls:\n"); + printf(" Param | INC | DEC |\n"); + printf("------------+-----+-----+\n"); + printf(" Thres/PAPR | %c | %c |\n", CFR_THRES_UP_KEY, CFR_THRES_DN_KEY); + printf("\n"); if (transmission_mode != SRSRAN_TM1) { printf("\nTransmission mode key table:\n"); printf(" Mode | 1TB | 2TB |\n"); @@ -526,13 +700,15 @@ static int update_radl() printf(" CDD | | z |\n"); printf("Multiplex | q,w,e,r | a,s |\n"); printf("\n"); - printf("Type new MCS index (0-28) or mode key and press Enter: "); + printf("Type new MCS index (0-28) or cfr/mode key and press Enter: "); } else { - printf("Type new MCS index (0-28) and press Enter: "); + printf("Type new MCS index (0-28) or cfr key and press Enter: "); } fflush(stdout); + ret = SRSRAN_SUCCESS; - return 0; +exit: + return ret; } /* Read new MCS from stdin */ @@ -626,6 +802,12 @@ static int update_control() case 'x': transmission_mode = SRSRAN_TM2; break; + case CFR_THRES_UP_KEY: + cfr_thr_inc = true; + break; + case CFR_THRES_DN_KEY: + cfr_thr_dec = true; + break; default: last_mcs_idx = mcs_idx; mcs_idx = strtol(input, NULL, 10); @@ -643,9 +825,9 @@ static int update_control() } else if (n < 0) { // error perror("select"); - return -1; + return SRSRAN_ERROR; } else { - return 0; + return SRSRAN_SUCCESS; } } @@ -719,6 +901,10 @@ int main(int argc, char** argv) #endif parse_args(argc, argv); + if (parse_cfr_args() < SRSRAN_SUCCESS) { + ERROR("Error parsing CFR args"); + exit(-1); + } srsran_use_standard_symbol_size(use_standard_lte_rate); @@ -873,7 +1059,7 @@ int main(int argc, char** argv) srsran_pcfich_encode(&pcfich, &dl_sf, sf_symbols); /* Update DL resource allocation from control port */ - if (update_control()) { + if (update_control() < SRSRAN_SUCCESS) { ERROR("Error updating parameters from control port"); } diff --git a/lib/include/srsran/interfaces/enb_command_interface.h b/lib/include/srsran/interfaces/enb_command_interface.h index 70bf82e7a..8e0e0bb3e 100644 --- a/lib/include/srsran/interfaces/enb_command_interface.h +++ b/lib/include/srsran/interfaces/enb_command_interface.h @@ -19,6 +19,11 @@ namespace srsenb { class enb_command_interface { public: + /** + * Trigger downlink singnal measurements (currently PAPR) + */ + virtual void cmd_cell_measure() = 0; + /** * Sets the relative gain of a cell from it's index (following rr.conf) order. * @param cell_id Provides a cell identifier diff --git a/lib/include/srsran/phy/cfr/cfr.h b/lib/include/srsran/phy/cfr/cfr.h new file mode 100644 index 000000000..a53204de5 --- /dev/null +++ b/lib/include/srsran/phy/cfr/cfr.h @@ -0,0 +1,118 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2021 Software Radio Systems Limited + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the distribution. + * + */ + +#ifndef SRSRAN_CFR_H +#define SRSRAN_CFR_H + +#include "srsran/config.h" +#include "srsran/phy/common/phy_common.h" +#include "srsran/phy/dft/dft.h" + +#define CFR_EMA_INIT_AVG_PWR 0.1 + +/** + * @brief CFR manual threshold or PAPR limiting with Moving Average or EMA power averaging + */ +typedef enum SRSRAN_API { + SRSRAN_CFR_THR_MANUAL = 1, + SRSRAN_CFR_THR_AUTO_CMA = 2, + SRSRAN_CFR_THR_AUTO_EMA = 3 +} srsran_cfr_mode_t; + +/** + * @brief CFR module configuration arguments + */ +typedef struct SRSRAN_API { + bool cfr_enable; + srsran_cfr_mode_t cfr_mode; + // always used (mandatory) + uint32_t symbol_bw; ///< OFDM symbol bandwidth, in FFT bins + uint32_t symbol_sz; ///< OFDM symbol size (in samples). This is the FFT size + float alpha; ///< Alpha parameter of the clipping algorithm + bool dc_sc; ///< Take into account the DC subcarrier for the filter BW + + // SRSRAN_CFR_THR_MANUAL mode parameters + float manual_thr; ///< Fixed threshold used in SRSRAN_CFR_THR_MANUAL mode + + // SRSRAN_CFR_THR_AUTO_CMA and SRSRAN_CFR_THR_AUTO_EMA mode parameters + bool measure_out_papr; ///< Enable / disable output PAPR measurement + float max_papr_db; ///< Input PAPR threshold used in SRSRAN_CFR_THR_AUTO_CMA and SRSRAN_CFR_THR_AUTO_EMA modes + float ema_alpha; ///< EMA alpha parameter for avg power calculation, used in SRSRAN_CFR_THR_AUTO_EMA mode +} srsran_cfr_cfg_t; + +typedef struct SRSRAN_API { + srsran_cfr_cfg_t cfg; + float max_papr_lin; + + srsran_dft_plan_t fft_plan; + srsran_dft_plan_t ifft_plan; + float* lpf_spectrum; ///< FFT filter spectrum + uint32_t lpf_bw; ///< Bandwidth of the LPF + + float* abs_buffer_in; ///< Store the input absolute value + float* abs_buffer_out; ///< Store the output absolute value + cf_t* peak_buffer; + + float pwr_avg_in; ///< store the avg. input power with MA or EMA averaging + float pwr_avg_out; ///< store the avg. output power with MA or EMA averaging + + // Power average buffers, used in SRSRAN_CFR_THR_AUTO_CMA mode + uint64_t cma_n; +} srsran_cfr_t; + +SRSRAN_API int srsran_cfr_init(srsran_cfr_t* q, srsran_cfr_cfg_t* cfg); + +/** + * @brief Applies the CFR algorithm to the time domain OFDM symbols + * + * @attention This function must be called once per symbol, and it will process q->symbol_sz samples + * + * @param[in] q The CFR object and configuration + * @param[in] in Input buffer containing the time domain OFDM symbol without CP + * @param[out] out Output buffer with the processed OFDM symbol + * @return SRSRAN_SUCCESS if the CFR object is initialised, otherwise SRSRAN_ERROR + */ +SRSRAN_API void srsran_cfr_process(srsran_cfr_t* q, cf_t* in, cf_t* out); + +SRSRAN_API void srsran_cfr_free(srsran_cfr_t* q); + +/** + * @brief Checks the validity of the CFR algorithm parameters. + * + * @attention Does not check symbol size and bandwidth + * + * @param[in] cfr_conf the CFR configuration + * @return true if the configuration is valid, false otherwise + */ +SRSRAN_API bool srsran_cfr_params_valid(srsran_cfr_cfg_t* cfr_conf); + +/** + * @brief Sets the manual threshold of the CFR (used in manual mode). + * + * @attention this is not thread-safe + * + * @param[in] q the CFR object + * @return SRSRAN_SUCCESS if successful, SRSRAN_ERROR or SRSRAN_ERROR_INVALID_INPUTS otherwise + */ +SRSRAN_API int srsran_cfr_set_threshold(srsran_cfr_t* q, float thres); + +/** + * @brief Sets the papr target of the CFR (used in auto modes). + * + * @attention this is not thread-safe + * + * @param[in] q the CFR object + * @return SRSRAN_SUCCESS if successful, SRSRAN_ERROR or SRSRAN_ERROR_INVALID_INPUTS otherwise + */ +SRSRAN_API int srsran_cfr_set_papr(srsran_cfr_t* q, float papr); + +#endif // SRSRAN_CFR_H diff --git a/lib/include/srsran/phy/dft/ofdm.h b/lib/include/srsran/phy/dft/ofdm.h index 767b3534e..a3a16970f 100644 --- a/lib/include/srsran/phy/dft/ofdm.h +++ b/lib/include/srsran/phy/dft/ofdm.h @@ -25,6 +25,7 @@ #include #include "srsran/config.h" +#include "srsran/phy/cfr/cfr.h" #include "srsran/phy/common/phy_common.h" #include "srsran/phy/dft/dft.h" @@ -39,18 +40,19 @@ typedef struct SRSRAN_API { // Compulsory parameters uint32_t nof_prb; ///< Number of Resource Block - cf_t* in_buffer; ///< Input bnuffer pointer + cf_t* in_buffer; ///< Input buffer pointer cf_t* out_buffer; ///< Output buffer pointer srsran_cp_t cp; ///< Cyclic prefix type // Optional parameters - srsran_sf_t sf_type; ///< Subframe type, normal or MBSFN - bool normalize; ///< Normalization flag, it divides the output by square root of the symbol size - float freq_shift_f; ///< Frequency shift, normalised by sampling rate (used in UL) - float rx_window_offset; ///< DFT Window offset in CP portion (0-1), RX only - uint32_t symbol_sz; ///< Symbol size, forces a given symbol size for the number of PRB - bool keep_dc; ///< If true, it does not remove the DC - double phase_compensation_hz; ///< Carrier frequency in Hz for phase compensation, set to 0 to disable + srsran_sf_t sf_type; ///< Subframe type, normal or MBSFN + bool normalize; ///< Normalization flag, it divides the output by square root of the symbol size + float freq_shift_f; ///< Frequency shift, normalised by sampling rate (used in UL) + float rx_window_offset; ///< DFT Window offset in CP portion (0-1), RX only + uint32_t symbol_sz; ///< Symbol size, forces a given symbol size for the number of PRB + bool keep_dc; ///< If true, it does not remove the DC + double phase_compensation_hz; ///< Carrier frequency in Hz for phase compensation, set to 0 to disable + srsran_cfr_cfg_t cfr_tx_cfg; ///< Tx CFR configuration } srsran_ofdm_cfg_t; /** @@ -76,6 +78,7 @@ typedef struct SRSRAN_API { cf_t* shift_buffer; cf_t* window_offset_buffer; cf_t phase_compensation[SRSRAN_MAX_NSYMB * SRSRAN_NOF_SLOTS_PER_SF]; + srsran_cfr_t tx_cfr; ///< Tx CFR object } srsran_ofdm_t; /** @@ -136,4 +139,6 @@ SRSRAN_API int srsran_ofdm_set_phase_compensation(srsran_ofdm_t* q, double cente SRSRAN_API void srsran_ofdm_set_non_mbsfn_region(srsran_ofdm_t* q, uint8_t non_mbsfn_region); +SRSRAN_API int srsran_ofdm_set_cfr(srsran_ofdm_t* q, srsran_cfr_cfg_t* cfr); + #endif // SRSRAN_OFDM_H diff --git a/lib/include/srsran/phy/enb/enb_dl.h b/lib/include/srsran/phy/enb/enb_dl.h index 5c1c03010..2195c7623 100644 --- a/lib/include/srsran/phy/enb/enb_dl.h +++ b/lib/include/srsran/phy/enb/enb_dl.h @@ -55,7 +55,9 @@ typedef struct SRSRAN_API { srsran_dl_sf_cfg_t dl_sf; - cf_t* sf_symbols[SRSRAN_MAX_PORTS]; + srsran_cfr_cfg_t cfr_config; + + cf_t* sf_symbols[SRSRAN_MAX_PORTS]; cf_t* out_buffer[SRSRAN_MAX_PORTS]; srsran_ofdm_t ifft[SRSRAN_MAX_PORTS]; srsran_ofdm_t ifft_mbsfn; @@ -93,6 +95,8 @@ SRSRAN_API void srsran_enb_dl_free(srsran_enb_dl_t* q); SRSRAN_API int srsran_enb_dl_set_cell(srsran_enb_dl_t* q, srsran_cell_t cell); +SRSRAN_API int srsran_enb_dl_set_cfr(srsran_enb_dl_t* q, const srsran_cfr_cfg_t* cfr); + SRSRAN_API bool srsran_enb_dl_location_is_common_ncce(srsran_enb_dl_t* q, const srsran_dci_location_t* loc); SRSRAN_API void srsran_enb_dl_put_base(srsran_enb_dl_t* q, srsran_dl_sf_cfg_t* dl_sf); diff --git a/lib/include/srsran/phy/utils/vector.h b/lib/include/srsran/phy/utils/vector.h index 20023d875..83385638a 100644 --- a/lib/include/srsran/phy/utils/vector.h +++ b/lib/include/srsran/phy/utils/vector.h @@ -224,6 +224,7 @@ SRSRAN_API void srsran_vec_conj_cc(const cf_t* x, cf_t* y, const uint32_t len); SRSRAN_API float srsran_vec_avg_power_cf(const cf_t* x, const uint32_t len); SRSRAN_API float srsran_vec_avg_power_sf(const int16_t* x, const uint32_t len); SRSRAN_API float srsran_vec_avg_power_bf(const int8_t* x, const uint32_t len); +SRSRAN_API float srsran_vec_avg_power_ff(const float* x, const uint32_t len); /* Correlation between complex vectors x and y */ SRSRAN_API float srsran_vec_corr_ccc(const cf_t* x, cf_t* y, const uint32_t len); @@ -352,6 +353,36 @@ SRSRAN_API void srsran_vec_apply_cfo(const cf_t* x, float cfo, cf_t* z, int len) SRSRAN_API float srsran_vec_estimate_frequency(const cf_t* x, int len); +/*! + * @brief Generates an amplitude envelope that, multiplied point-wise with a vector, results in clipping + * by a specified amplitude threshold. + * @param[in] x_abs Absolute value vector of the signal to be clipped + * @param[in] thres Clipping threshold + * @param[out] clip_env The generated clipping envelope + * @param[in] len Length of the vector. + */ +SRSRAN_API void +srsran_vec_gen_clip_env(const float* x_abs, const float thres, const float alpha, float* env, const int len); + +/*! + * @brief Calculates the PAPR of a complex vector + * @param[in] in Input vector + * @param[in] len Vector length. + */ +SRSRAN_API float srsran_vec_papr_c(const cf_t* in, const int len); + +/*! + * @brief Calculates the ACPR of a signal using its baseband spectrum + * @attention The spectrum passed by x_f needs to be in FFT form + * @param[in] x_f Spectrum of the signal + * @param[in] win_pos_len Channel frequency window for the positive side of the spectrum + * @param[in] win_neg_len Channel frequency window for the negative side of the spectrum + * @param[in] len Length of the x_f vector + * @returns The ACPR in linear form + */ +SRSRAN_API float +srsran_vec_acpr_c(const cf_t* x_f, const uint32_t win_pos_len, const uint32_t win_neg_len, const uint32_t len); + #ifdef __cplusplus } #endif diff --git a/lib/include/srsran/srsran.h b/lib/include/srsran/srsran.h index d9be8b910..7bcd2eb90 100644 --- a/lib/include/srsran/srsran.h +++ b/lib/include/srsran/srsran.h @@ -52,6 +52,7 @@ extern "C" { #include "srsran/phy/channel/ch_awgn.h" +#include "srsran/phy/cfr/cfr.h" #include "srsran/phy/dft/dft.h" #include "srsran/phy/dft/dft_precoding.h" #include "srsran/phy/dft/ofdm.h" diff --git a/lib/src/phy/CMakeLists.txt b/lib/src/phy/CMakeLists.txt index 66018f1dc..880e9ef09 100644 --- a/lib/src/phy/CMakeLists.txt +++ b/lib/src/phy/CMakeLists.txt @@ -24,6 +24,7 @@ add_subdirectory(scrambling) add_subdirectory(ue) add_subdirectory(enb) add_subdirectory(gnb) +add_subdirectory(cfr) set(srsran_srcs $ $ $ @@ -41,6 +42,7 @@ set(srsran_srcs $ $ $ $ + $ ) add_library(srsran_phy STATIC ${srsran_srcs} ) diff --git a/lib/src/phy/cfr/CMakeLists.txt b/lib/src/phy/cfr/CMakeLists.txt new file mode 100644 index 000000000..4de435223 --- /dev/null +++ b/lib/src/phy/cfr/CMakeLists.txt @@ -0,0 +1,13 @@ +# +# Copyright 2013-2021 Software Radio Systems Limited +# +# By using this file, you agree to the terms and conditions set +# forth in the LICENSE file which can be found at the top level of +# the distribution. +# + +set(SRCS cfr.c) +add_library(srsran_cfr OBJECT ${SRCS}) + +add_subdirectory(test) + diff --git a/lib/src/phy/cfr/cfr.c b/lib/src/phy/cfr/cfr.c new file mode 100644 index 000000000..325c3cc2a --- /dev/null +++ b/lib/src/phy/cfr/cfr.c @@ -0,0 +1,367 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2021 Software Radio Systems Limited + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the distribution. + * + */ + +#include "srsran/phy/cfr/cfr.h" +#include "srsran/phy/utils/debug.h" +#include "srsran/phy/utils/vector.h" + +// Uncomment this to use a literal implementation of the CFR algorithm +// #define CFR_PEAK_EXTRACTION + +// Uncomment this to filter by zeroing the FFT bins instead of applying a frequency window +#define CFR_LPF_WITH_ZEROS + +static inline float cfr_symb_peak(float* in_abs, int len); + +void srsran_cfr_process(srsran_cfr_t* q, cf_t* in, cf_t* out) +{ + if (q == NULL || in == NULL || out == NULL) { + return; + } + if (!q->cfg.cfr_enable) { + // If no processing, copy the input samples into the output buffer + if (in != out) { + srsran_vec_cf_copy(out, in, q->cfg.symbol_sz); + } + return; + } + + const float alpha = q->cfg.alpha; + const uint32_t symbol_sz = q->cfg.symbol_sz; + float beta = 0.0f; + + // Calculate absolute input values + srsran_vec_abs_cf(in, q->abs_buffer_in, symbol_sz); + + // In auto modes, the beta threshold is calculated based on the measured PAPR + if (q->cfg.cfr_mode == SRSRAN_CFR_THR_MANUAL) { + beta = q->cfg.manual_thr; + } else { + const float symb_peak = cfr_symb_peak(q->abs_buffer_in, q->cfg.symbol_sz); + const float pwr_symb_peak = symb_peak * symb_peak; + const float pwr_symb_avg = srsran_vec_avg_power_ff(q->abs_buffer_in, q->cfg.symbol_sz); + float symb_papr = 0.0f; + + if (isnormal(pwr_symb_avg) && isnormal(pwr_symb_peak)) { + if (q->cfg.cfr_mode == SRSRAN_CFR_THR_AUTO_CMA) { + // Once cma_n reaches its max value, stop incrementing to prevent overflow. + // This turns the averaging into a de-facto EMA with an extremely slow time constant + q->pwr_avg_in = SRSRAN_VEC_CMA(pwr_symb_avg, q->pwr_avg_in, q->cma_n++); + q->cma_n = q->cma_n & UINT64_MAX ? q->cma_n : UINT64_MAX; + } else if (q->cfg.cfr_mode == SRSRAN_CFR_THR_AUTO_EMA) { + q->pwr_avg_in = SRSRAN_VEC_EMA(pwr_symb_avg, q->pwr_avg_in, q->cfg.ema_alpha); + } + + symb_papr = pwr_symb_peak / q->pwr_avg_in; + } + float papr_reduction = symb_papr / q->max_papr_lin; + beta = (papr_reduction > 1) ? symb_peak / sqrtf(papr_reduction) : 0; + } + + // Clipping algorithm + if (isnormal(beta)) { +#ifdef CFR_PEAK_EXTRACTION + srsran_vec_cf_zero(q->peak_buffer, symbol_sz); + cf_t clip_thr = 0; + for (int i = 0; i < symbol_sz; i++) { + if (q->abs_buffer_in[i] > beta) { + clip_thr = beta * (in[i] / q->abs_buffer_in[i]); + q->peak_buffer[i] = in[i] - clip_thr; + } + } + + // Apply FFT filter to the peak signal + srsran_dft_run_c(&q->fft_plan, q->peak_buffer, q->peak_buffer); +#ifdef CFR_LPF_WITH_ZEROS + srsran_vec_cf_zero(q->peak_buffer + q->lpf_bw / 2 + q->cfg.dc_sc, symbol_sz - q->cfg.symbol_bw - q->cfg.dc_sc); +#else /* CFR_LPF_WITH_ZEROS */ + srsran_vec_prod_cfc(q->peak_buffer, q->lpf_spectrum, q->peak_buffer, symbol_sz); +#endif /* CFR_LPF_WITH_ZEROS */ + srsran_dft_run_c(&q->ifft_plan, q->peak_buffer, q->peak_buffer); + + // Scale the peak signal according to alpha + srsran_vec_sc_prod_cfc(q->peak_buffer, alpha, q->peak_buffer, symbol_sz); + + // Apply the filtered clipping + srsran_vec_sub_ccc(in, q->peak_buffer, out, symbol_sz); +#else /* CFR_PEAK_EXTRACTION */ + + // Generate a clipping envelope and clip the signal + srsran_vec_gen_clip_env(q->abs_buffer_in, beta, alpha, q->abs_buffer_in, symbol_sz); + srsran_vec_prod_cfc(in, q->abs_buffer_in, out, symbol_sz); + + // FFT filter + srsran_dft_run_c(&q->fft_plan, out, out); +#ifdef CFR_LPF_WITH_ZEROS + srsran_vec_cf_zero(out + q->lpf_bw / 2 + q->cfg.dc_sc, symbol_sz - q->cfg.symbol_bw - q->cfg.dc_sc); +#else /* CFR_LPF_WITH_ZEROS */ + srsran_vec_prod_cfc(out, q->lpf_spectrum, out, symbol_sz); +#endif /* CFR_LPF_WITH_ZEROS */ + srsran_dft_run_c(&q->ifft_plan, out, out); +#endif /* CFR_PEAK_EXTRACTION */ + + } else { + // If no processing, copy the input samples into the output buffer + if (in != out) { + srsran_vec_cf_copy(out, in, symbol_sz); + } + } + if (q->cfg.cfr_mode != SRSRAN_CFR_THR_MANUAL && q->cfg.measure_out_papr) { + srsran_vec_abs_cf(in, q->abs_buffer_out, symbol_sz); + + const float symb_peak = cfr_symb_peak(q->abs_buffer_out, q->cfg.symbol_sz); + const float pwr_symb_peak = symb_peak * symb_peak; + const float pwr_symb_avg = srsran_vec_avg_power_ff(q->abs_buffer_out, q->cfg.symbol_sz); + float symb_papr = 0.0f; + + if (isnormal(pwr_symb_avg) && isnormal(pwr_symb_peak)) { + if (q->cfg.cfr_mode == SRSRAN_CFR_THR_AUTO_CMA) { + // Do not increment cma_n here, as it is being done when calculating input PAPR + q->pwr_avg_out = SRSRAN_VEC_CMA(pwr_symb_avg, q->pwr_avg_out, q->cma_n); + } + + else if (q->cfg.cfr_mode == SRSRAN_CFR_THR_AUTO_EMA) { + q->pwr_avg_out = SRSRAN_VEC_EMA(pwr_symb_avg, q->pwr_avg_out, q->cfg.ema_alpha); + } + + symb_papr = pwr_symb_peak / q->pwr_avg_out; + } + + const float papr_out_db = srsran_convert_power_to_dB(symb_papr); + printf("Output PAPR: %f dB\n", papr_out_db); + } +} + +int srsran_cfr_init(srsran_cfr_t* q, srsran_cfr_cfg_t* cfg) +{ + int ret = SRSRAN_ERROR; + if (q == NULL || cfg == NULL) { + ERROR("Error, invalid inputs"); + ret = SRSRAN_ERROR_INVALID_INPUTS; + goto clean_exit; + } + if (!cfg->symbol_sz || !cfg->symbol_bw || cfg->alpha < 0 || cfg->alpha > 1) { + ERROR("Error, invalid configuration"); + goto clean_exit; + } + if (cfg->cfr_mode == SRSRAN_CFR_THR_MANUAL && cfg->manual_thr <= 0) { + ERROR("Error, invalid configuration for manual threshold"); + goto clean_exit; + } + if (cfg->cfr_mode == SRSRAN_CFR_THR_AUTO_CMA && (cfg->max_papr_db <= 0)) { + ERROR("Error, invalid configuration for CMA averaging"); + goto clean_exit; + } + if (cfg->cfr_mode == SRSRAN_CFR_THR_AUTO_EMA && + (cfg->max_papr_db <= 0 || (cfg->ema_alpha < 0 || cfg->ema_alpha > 1))) { + ERROR("Error, invalid configuration for EMA averaging"); + goto clean_exit; + } + + // Copy all the configuration parameters + q->cfg = *cfg; + q->max_papr_lin = srsran_convert_dB_to_power(q->cfg.max_papr_db); + q->pwr_avg_in = CFR_EMA_INIT_AVG_PWR; + q->cma_n = 0; + + if (q->cfg.measure_out_papr) { + q->pwr_avg_out = CFR_EMA_INIT_AVG_PWR; + } + + if (q->abs_buffer_in) { + free(q->abs_buffer_in); + } + q->abs_buffer_in = srsran_vec_f_malloc(q->cfg.symbol_sz); + if (!q->abs_buffer_in) { + ERROR("Error allocating abs_buffer_in"); + goto clean_exit; + } + + if (q->abs_buffer_out) { + free(q->abs_buffer_out); + } + q->abs_buffer_out = srsran_vec_f_malloc(q->cfg.symbol_sz); + if (!q->abs_buffer_out) { + ERROR("Error allocating abs_buffer_out"); + goto clean_exit; + } + + if (q->peak_buffer) { + free(q->peak_buffer); + } + q->peak_buffer = srsran_vec_cf_malloc(q->cfg.symbol_sz); + if (!q->peak_buffer) { + ERROR("Error allocating peak_buffer"); + goto clean_exit; + } + + // Allocate the filter + if (q->lpf_spectrum) { + free(q->lpf_spectrum); + } + q->lpf_spectrum = srsran_vec_f_malloc(q->cfg.symbol_sz); + if (!q->lpf_spectrum) { + ERROR("Error allocating lpf_spectrum"); + goto clean_exit; + } + + // The LPF bandwidth is exactly the OFDM symbol bandwidth, in number of FFT bins + q->lpf_bw = q->cfg.symbol_bw; + + // Initialise the filter + srsran_vec_f_zero(q->lpf_spectrum, q->cfg.symbol_sz); + + // DC subcarrier is in position 0, so the OFDM symbol can go from index 1 to q->lpf_bw / 2 + 1 + for (uint32_t i = 0; i < q->lpf_bw / 2 + q->cfg.dc_sc; i++) { + q->lpf_spectrum[i] = 1; + } + for (uint32_t i = q->cfg.symbol_sz - q->lpf_bw / 2; i < q->cfg.symbol_sz; i++) { + q->lpf_spectrum[i] = 1; + } + + // FFT plans, for 1 OFDM symbol + if (q->fft_plan.size) { + // Replan if it was initialised previously with bigger FFT size + if (q->fft_plan.size >= q->cfg.symbol_sz) { + if (srsran_dft_replan(&q->fft_plan, q->cfg.symbol_sz)) { + ERROR("Replaning DFT plan"); + goto clean_exit; + } + } else { + srsran_dft_plan_free(&q->fft_plan); + if (srsran_dft_plan_c(&q->fft_plan, q->cfg.symbol_sz, SRSRAN_DFT_FORWARD)) { + ERROR("Creating DFT plan"); + goto clean_exit; + } + } + } else { + // Create plan from zero otherwise + if (srsran_dft_plan_c(&q->fft_plan, q->cfg.symbol_sz, SRSRAN_DFT_FORWARD)) { + ERROR("Creating DFT plan"); + goto clean_exit; + } + } + + if (q->ifft_plan.size) { + if (q->ifft_plan.size >= q->cfg.symbol_sz) { + // Replan if it was initialised previously with bigger FFT size + if (srsran_dft_replan(&q->ifft_plan, q->cfg.symbol_sz)) { + ERROR("Replaning DFT plan"); + goto clean_exit; + } + } else { + srsran_dft_plan_free(&q->ifft_plan); + if (srsran_dft_plan_c(&q->ifft_plan, q->cfg.symbol_sz, SRSRAN_DFT_BACKWARD)) { + ERROR("Creating DFT plan"); + goto clean_exit; + } + } + } else { + // Create plan from zero otherwise + if (srsran_dft_plan_c(&q->ifft_plan, q->cfg.symbol_sz, SRSRAN_DFT_BACKWARD)) { + ERROR("Creating DFT plan"); + goto clean_exit; + } + } + + srsran_dft_plan_set_norm(&q->fft_plan, true); + srsran_dft_plan_set_norm(&q->ifft_plan, true); + + srsran_vec_cf_zero(q->peak_buffer, q->cfg.symbol_sz); + srsran_vec_f_zero(q->abs_buffer_in, q->cfg.symbol_sz); + srsran_vec_f_zero(q->abs_buffer_out, q->cfg.symbol_sz); + ret = SRSRAN_SUCCESS; + +clean_exit: + if (ret < SRSRAN_SUCCESS) { + srsran_cfr_free(q); + } + return ret; +} + +void srsran_cfr_free(srsran_cfr_t* q) +{ + if (q) { + srsran_dft_plan_free(&q->fft_plan); + srsran_dft_plan_free(&q->ifft_plan); + if (q->abs_buffer_in) { + free(q->abs_buffer_in); + } + if (q->abs_buffer_out) { + free(q->abs_buffer_out); + } + if (q->peak_buffer) { + free(q->peak_buffer); + } + if (q->lpf_spectrum) { + free(q->lpf_spectrum); + } + SRSRAN_MEM_ZERO(q, srsran_cfr_t, 1); + } +} + +// Find the peak absolute value of an OFDM symbol +static inline float cfr_symb_peak(float* in_abs, int len) +{ + const uint32_t max_index = srsran_vec_max_fi(in_abs, len); + return in_abs[max_index]; +} + +bool srsran_cfr_params_valid(srsran_cfr_cfg_t* cfr_conf) +{ + if (cfr_conf == NULL) { + return false; + } + if (cfr_conf->alpha < 0 || cfr_conf->alpha > 1) { + return false; + } + if (cfr_conf->cfr_mode == SRSRAN_CFR_THR_MANUAL && cfr_conf->manual_thr <= 0) { + return false; + } + if (cfr_conf->cfr_mode == SRSRAN_CFR_THR_AUTO_CMA && (cfr_conf->max_papr_db <= 0)) { + return false; + } + if (cfr_conf->cfr_mode == SRSRAN_CFR_THR_AUTO_EMA && + (cfr_conf->max_papr_db <= 0 || (cfr_conf->ema_alpha < 0 || cfr_conf->ema_alpha > 1))) { + return false; + } + return true; +} + +int srsran_cfr_set_threshold(srsran_cfr_t* q, float thres) +{ + if (q == NULL) { + ERROR("Invalid CFR object"); + return SRSRAN_ERROR_INVALID_INPUTS; + } + if (thres <= 0.0f) { + ERROR("Invalid CFR threshold"); + return SRSRAN_ERROR; + } + q->cfg.manual_thr = thres; + return SRSRAN_SUCCESS; +} + +int srsran_cfr_set_papr(srsran_cfr_t* q, float papr) +{ + if (q == NULL) { + ERROR("Invalid CFR object"); + return SRSRAN_ERROR_INVALID_INPUTS; + } + if (papr <= 0.0f) { + ERROR("Invalid CFR configuration"); + return SRSRAN_ERROR; + } + q->cfg.max_papr_db = papr; + q->max_papr_lin = srsran_convert_dB_to_power(q->cfg.max_papr_db); + return SRSRAN_SUCCESS; +} diff --git a/lib/src/phy/cfr/test/CMakeLists.txt b/lib/src/phy/cfr/test/CMakeLists.txt new file mode 100644 index 000000000..34be8ede3 --- /dev/null +++ b/lib/src/phy/cfr/test/CMakeLists.txt @@ -0,0 +1,17 @@ +# +# Copyright 2013-2021 Software Radio Systems Limited +# +# By using this file, you agree to the terms and conditions set +# forth in the LICENSE file which can be found at the top level of +# the distribution. +# + +######################################################################## +# CFR Test +######################################################################## + +add_executable(cfr_test cfr_test.c) +target_link_libraries(cfr_test srsran_phy) + +add_test(cfr_test_default cfr_test) + diff --git a/lib/src/phy/cfr/test/cfr_test.c b/lib/src/phy/cfr/test/cfr_test.c new file mode 100644 index 000000000..368178457 --- /dev/null +++ b/lib/src/phy/cfr/test/cfr_test.c @@ -0,0 +1,308 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2021 Software Radio Systems Limited + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the distribution. + * + */ + +#include +#include +#include +#include +#include + +#include "srsran/phy/utils/random.h" +#include "srsran/srsran.h" + +#define MAX_ACPR_DB -100 + +// CFR type test args +static char cfr_manual_str[] = "manual"; +static char cfr_auto_cma_str[] = "auto_cma"; +static char cfr_auto_ema_str[] = "auto_ema"; + +// Default CFR type +static char* cfr_type_arg = cfr_manual_str; + +static int nof_prb = -1; +static srsran_cp_t cp = SRSRAN_CP_NORM; +static int nof_repetitions = 1; +static int nof_frames = 10; +static srsran_cfr_mode_t cfr_mode = SRSRAN_CFR_THR_MANUAL; +static float alpha = 1.0f; +static bool dc_empty = true; +static float thr_manual = 1.5f; +static float max_papr_db = 8.0f; +static float ema_alpha = (float)1 / (float)SRSRAN_CP_NORM_NSYMB; + +static uint32_t force_symbol_sz = 0; +static double elapsed_us(struct timeval* ts_start, struct timeval* ts_end) +{ + if (ts_end->tv_usec > ts_start->tv_usec) { + return ((double)ts_end->tv_sec - (double)ts_start->tv_sec) * 1000000 + (double)ts_end->tv_usec - + (double)ts_start->tv_usec; + } else { + return ((double)ts_end->tv_sec - (double)ts_start->tv_sec - 1) * 1000000 + ((double)ts_end->tv_usec + 1000000) - + (double)ts_start->tv_usec; + } +} + +static void usage(char* prog) +{ + printf("Usage: %s\n", prog); + printf("\t-N Force symbol size, 0 for auto [Default %d]\n", force_symbol_sz); + printf("\t-n Force number of Resource blocks [Default All]\n"); + printf("\t-e extended cyclic prefix [Default Normal]\n"); + printf("\t-f Number of frames [Default %d]\n", nof_frames); + printf("\t-r Number of repetitions [Default %d]\n", nof_repetitions); + printf("\t-m CFR mode: %s, %s, %s [Default %s]\n", cfr_manual_str, cfr_auto_cma_str, cfr_auto_ema_str, cfr_type_arg); + printf("\t-d Use DC subcarrier: [Default DC empty]\n"); + printf("\t-a CFR alpha: [Default %.2f]\n", alpha); + printf("\t-t CFR manual threshold: [Default %.2f]\n", thr_manual); + printf("\t-p CFR Max PAPR in dB (auto modes): [Default %.2f]\n", max_papr_db); + printf("\t-E Power avg EMA alpha (EMA mode): [Default %.2f]\n", ema_alpha); +} + +static int parse_args(int argc, char** argv) +{ + int opt; + while ((opt = getopt(argc, argv, "NnerfmatdpE")) != -1) { + switch (opt) { + case 'n': + nof_prb = (int)strtol(argv[optind], NULL, 10); + break; + case 'N': + force_symbol_sz = (uint32_t)strtol(argv[optind], NULL, 10); + break; + case 'e': + cp = SRSRAN_CP_EXT; + break; + case 'r': + nof_repetitions = (int)strtol(argv[optind], NULL, 10); + break; + case 'f': + nof_frames = (int)strtol(argv[optind], NULL, 10); + break; + case 'm': + cfr_type_arg = argv[optind]; + break; + case 'a': + alpha = strtof(argv[optind], NULL); + break; + case 't': + thr_manual = strtof(argv[optind], NULL); + break; + case 'd': + dc_empty = false; + break; + case 'p': + max_papr_db = strtof(argv[optind], NULL); + break; + case 'E': + ema_alpha = strtof(argv[optind], NULL); + break; + default: + usage(argv[0]); + return SRSRAN_ERROR; + } + } + return SRSRAN_SUCCESS; +} + +int main(int argc, char** argv) +{ + int ret = SRSRAN_ERROR; + + srsran_random_t random_gen = srsran_random_init(0); + struct timeval start, end; + srsran_cfr_t cfr = {}; + cf_t* input = NULL; + cf_t* output = NULL; + cf_t* error = NULL; + float* acpr_buff = NULL; + float mse_dB = 0.0f; + float nmse_dB = 0.0f; + float evm = 0.0f; + int max_prb = 0.0f; + float acpr_in_dB = 0.0f; + float acpr_out_dB = 0.0f; + + srsran_dft_plan_t ofdm_ifft = {}; + srsran_dft_plan_t ofdm_fft = {}; + + if (parse_args(argc, argv) < SRSRAN_SUCCESS) { + ERROR("Error in parse_args"); + goto clean_exit; + } + + if (!strcmp(cfr_type_arg, cfr_manual_str)) { + cfr_mode = SRSRAN_CFR_THR_MANUAL; + } else if (!strcmp(cfr_type_arg, cfr_auto_cma_str)) { + cfr_mode = SRSRAN_CFR_THR_AUTO_CMA; + } else if (!strcmp(cfr_type_arg, cfr_auto_ema_str)) { + cfr_mode = SRSRAN_CFR_THR_AUTO_EMA; + } else { + ERROR("CFR mode is not recognised"); + goto clean_exit; + } + + if (nof_prb == -1) { + nof_prb = 6; + max_prb = SRSRAN_MAX_PRB; + } else { + max_prb = nof_prb; + } + while (nof_prb <= max_prb) { + const uint32_t symbol_sz = (force_symbol_sz) ? force_symbol_sz : (uint32_t)srsran_symbol_sz(nof_prb); + const uint32_t symbol_bw = nof_prb * SRSRAN_NRE; + const uint32_t nof_symb_slot = SRSRAN_CP_NSYMB(cp); + const uint32_t nof_symb_frame = nof_symb_slot * SRSRAN_NOF_SLOTS_PER_SF * SRSRAN_NOF_SF_X_FRAME; + const uint32_t frame_sz = symbol_sz * nof_symb_frame; + const uint32_t total_nof_re = frame_sz * nof_frames; + const uint32_t total_nof_symb = nof_symb_frame * nof_frames; + printf("Running test for %d PRB, %d Frames: \t", nof_prb, nof_frames); + fflush(stdout); + + input = srsran_vec_cf_malloc(total_nof_re); + output = srsran_vec_cf_malloc(total_nof_re); + error = srsran_vec_cf_malloc(total_nof_re); + acpr_buff = srsran_vec_f_malloc(total_nof_symb); + if (!input || !output || !error || !acpr_buff) { + perror("malloc"); + goto clean_exit; + } + srsran_vec_cf_zero(input, total_nof_re); + srsran_vec_cf_zero(output, total_nof_re); + srsran_vec_cf_zero(error, total_nof_re); + srsran_vec_f_zero(acpr_buff, total_nof_symb); + + // Set the parameters for the CFR. + srsran_cfr_cfg_t cfr_tx_cfg = {}; + cfr_tx_cfg.cfr_enable = true; + cfr_tx_cfg.symbol_sz = symbol_sz; + cfr_tx_cfg.symbol_bw = nof_prb * SRSRAN_NRE; + cfr_tx_cfg.cfr_mode = cfr_mode; + cfr_tx_cfg.max_papr_db = max_papr_db; + cfr_tx_cfg.alpha = alpha; + cfr_tx_cfg.manual_thr = thr_manual; + cfr_tx_cfg.ema_alpha = ema_alpha; + cfr_tx_cfg.dc_sc = dc_empty; + + if (srsran_cfr_init(&cfr, &cfr_tx_cfg)) { + ERROR("Error initializing CFR"); + goto clean_exit; + } + + if (srsran_dft_plan_c(&ofdm_ifft, (int)symbol_sz, SRSRAN_DFT_BACKWARD)) { + ERROR("Creating IFFT plan"); + goto clean_exit; + } + srsran_dft_plan_set_norm(&ofdm_ifft, true); + if (srsran_dft_plan_c(&ofdm_fft, (int)symbol_sz, SRSRAN_DFT_FORWARD)) { + ERROR("Creating FFT plan"); + goto clean_exit; + } + srsran_dft_plan_set_norm(&ofdm_fft, true); + + // Generate Random data + cf_t* ofdm_symb = NULL; + for (int i = 0; i < total_nof_symb; i++) { + ofdm_symb = input + i * symbol_sz; + srsran_random_uniform_complex_dist_vector(random_gen, ofdm_symb + dc_empty, symbol_bw / 2, -1.0f, +1.0f); + srsran_random_uniform_complex_dist_vector( + random_gen, ofdm_symb + symbol_sz - symbol_bw / 2, symbol_bw / 2, -1.0f, +1.0f); + acpr_buff[i] = srsran_vec_acpr_c(ofdm_symb, symbol_bw / 2 + dc_empty, symbol_bw / 2, symbol_sz); + srsran_dft_run_c(&ofdm_ifft, ofdm_symb, ofdm_symb); + } + // compute the average intput ACPR + acpr_in_dB = srsran_vec_acc_ff(acpr_buff, total_nof_symb) / (float)total_nof_symb; + acpr_in_dB = srsran_convert_power_to_dB(acpr_in_dB); + + // Execute CFR + gettimeofday(&start, NULL); + for (uint32_t i = 0; i < nof_repetitions; i++) { + for (uint32_t j = 0; j < nof_frames; j++) { + for (uint32_t k = 0; k < nof_symb_frame; k++) { + srsran_cfr_process(&cfr, + input + (size_t)((k * symbol_sz) + (j * frame_sz)), + output + (size_t)((k * symbol_sz) + (j * frame_sz))); + } + } + } + gettimeofday(&end, NULL); + printf("%.1fMsps \t", (float)(total_nof_re * nof_repetitions) / elapsed_us(&start, &end)); + + // Compute metrics + srsran_vec_sub_ccc(input, output, error, total_nof_re); + + float power_in = srsran_vec_avg_power_cf(input, total_nof_re); + float power_err = srsran_vec_avg_power_cf(error, total_nof_re); + + mse_dB = srsran_convert_power_to_dB(power_err); + nmse_dB = srsran_convert_power_to_dB(power_err / power_in); + evm = 100 * sqrtf(power_err / power_in); + + float snr_dB = srsran_convert_power_to_dB(power_in / power_err); + + float papr_in = srsran_convert_power_to_dB(srsran_vec_papr_c(input, total_nof_re)); + float papr_out = srsran_convert_power_to_dB(srsran_vec_papr_c(output, total_nof_re)); + + ofdm_symb = NULL; + for (int i = 0; i < total_nof_symb; i++) { + ofdm_symb = output + i * symbol_sz; + srsran_dft_run_c(&ofdm_fft, ofdm_symb, ofdm_symb); + acpr_buff[i] = srsran_vec_acpr_c(ofdm_symb, symbol_bw / 2 + dc_empty, symbol_bw / 2, symbol_sz); + } + + // Compute the output average ACPR + acpr_out_dB = srsran_vec_acc_ff(acpr_buff, total_nof_symb) / (float)total_nof_symb; + acpr_out_dB = srsran_convert_power_to_dB(acpr_out_dB); + + printf("MSE=%.3fdB NMSE=%.3fdB EVM=%.3f%% SNR=%.3fdB", mse_dB, nmse_dB, evm, snr_dB); + printf(" In-PAPR=%.3fdB Out-PAPR=%.3fdB", papr_in, papr_out); + printf(" In-ACPR=%.3fdB Out-ACPR=%.3fdB\n", acpr_in_dB, acpr_out_dB); + + srsran_dft_plan_free(&ofdm_ifft); + srsran_dft_plan_free(&ofdm_fft); + free(input); + free(output); + free(error); + free(acpr_buff); + input = NULL; + output = NULL; + error = NULL; + acpr_buff = NULL; + + ++nof_prb; + if (acpr_out_dB > MAX_ACPR_DB) { + printf("ACPR too large \n"); + goto clean_exit; + } + } + ret = SRSRAN_SUCCESS; + + // Free resources +clean_exit: + srsran_random_free(random_gen); + srsran_cfr_free(&cfr); + srsran_dft_plan_free(&ofdm_ifft); + srsran_dft_plan_free(&ofdm_fft); + if (input) { + free(input); + } + if (output) { + free(output); + } + if (error) { + free(error); + } + if (acpr_buff) { + free(acpr_buff); + } + return ret; +} diff --git a/lib/src/phy/dft/ofdm.c b/lib/src/phy/dft/ofdm.c index 1b1856873..fa349fb31 100644 --- a/lib/src/phy/dft/ofdm.c +++ b/lib/src/phy/dft/ofdm.c @@ -68,6 +68,19 @@ static int ofdm_init_mbsfn_(srsran_ofdm_t* q, srsran_ofdm_cfg_t* cfg, srsran_dft q->slot_sz = (uint32_t)SRSRAN_SLOT_LEN(q->cfg.symbol_sz); q->sf_sz = (uint32_t)SRSRAN_SF_LEN(q->cfg.symbol_sz); + // Set the CFR parameters related to OFDM symbol and FFT size + q->cfg.cfr_tx_cfg.symbol_sz = symbol_sz; + q->cfg.cfr_tx_cfg.symbol_bw = q->nof_re; + + // in the DL, the DC carrier is empty but still counts when designing the filter BW + q->cfg.cfr_tx_cfg.dc_sc = (!q->cfg.keep_dc) && (!isnormal(q->cfg.freq_shift_f)); + if (q->cfg.cfr_tx_cfg.cfr_enable) { + if (srsran_cfr_init(&q->tx_cfr, &q->cfg.cfr_tx_cfg) < SRSRAN_SUCCESS) { + ERROR("Error while initialising CFR module"); + return SRSRAN_ERROR; + } + } + // Plan MBSFN if (q->fft_plan.size) { // Replan if it was initialised previously @@ -242,6 +255,7 @@ void srsran_ofdm_free_(srsran_ofdm_t* q) if (q->window_offset_buffer) { free(q->window_offset_buffer); } + srsran_cfr_free(&q->tx_cfr); SRSRAN_MEM_ZERO(q, srsran_ofdm_t, 1); } @@ -289,6 +303,10 @@ int srsran_ofdm_tx_init(srsran_ofdm_t* q, srsran_cp_t cp, cf_t* in_buffer, cf_t* int srsran_ofdm_tx_init_cfg(srsran_ofdm_t* q, srsran_ofdm_cfg_t* cfg) { + if (q == NULL || cfg == NULL) { + ERROR("Error, invalid inputs"); + return SRSRAN_ERROR_INVALID_INPUTS; + } return ofdm_init_mbsfn_(q, cfg, SRSRAN_DFT_BACKWARD); } @@ -610,6 +628,11 @@ static void ofdm_tx_slot(srsran_ofdm_t* q, int slot_in_sf) srsran_vec_sc_prod_cfc(&output[cp_len], norm, &output[cp_len], symbol_sz); } + // CFR: Process the time-domain signal without the CP + if (q->cfg.cfr_tx_cfg.cfr_enable) { + srsran_cfr_process(&q->tx_cfr, output + cp_len, output + cp_len); + } + /* add CP */ srsran_vec_cf_copy(output, &output[symbol_sz], cp_len); output += symbol_sz + cp_len; @@ -656,3 +679,37 @@ void srsran_ofdm_tx_sf(srsran_ofdm_t* q) srsran_vec_prod_ccc(q->cfg.out_buffer, q->shift_buffer, q->cfg.out_buffer, q->sf_sz); } } + +int srsran_ofdm_set_cfr(srsran_ofdm_t* q, srsran_cfr_cfg_t* cfr) +{ + if (q == NULL || cfr == NULL) { + ERROR("Error, invalid inputs"); + return SRSRAN_ERROR_INVALID_INPUTS; + } + if (!q->max_prb) { + ERROR("Error, ofdm object not initialised"); + return SRSRAN_ERROR; + } + // Check if there is nothing to configure + if (memcmp(&q->cfg.cfr_tx_cfg, cfr, sizeof(srsran_cfr_cfg_t)) == 0) { + return SRSRAN_SUCCESS; + } + + // Copy the CFR config into the OFDM object + q->cfg.cfr_tx_cfg = *cfr; + + // Set the CFR parameters related to OFDM symbol and FFT size + q->cfg.cfr_tx_cfg.symbol_sz = q->cfg.symbol_sz; + q->cfg.cfr_tx_cfg.symbol_bw = q->nof_re; + + // in the DL, the DC carrier is empty but still counts when designing the filter BW + q->cfg.cfr_tx_cfg.dc_sc = (!q->cfg.keep_dc) && (!isnormal(q->cfg.freq_shift_f)); + if (q->cfg.cfr_tx_cfg.cfr_enable) { + if (srsran_cfr_init(&q->tx_cfr, &q->cfg.cfr_tx_cfg) < SRSRAN_SUCCESS) { + ERROR("Error while initialising CFR module"); + return SRSRAN_ERROR; + } + } + + return SRSRAN_SUCCESS; +} diff --git a/lib/src/phy/enb/enb_dl.c b/lib/src/phy/enb/enb_dl.c index 5c079aab8..941b0492b 100644 --- a/lib/src/phy/enb/enb_dl.c +++ b/lib/src/phy/enb/enb_dl.c @@ -49,9 +49,9 @@ int srsran_enb_dl_init(srsran_enb_dl_t* q, cf_t* out_buffer[SRSRAN_MAX_PORTS], u ofdm_cfg.nof_prb = max_prb; ofdm_cfg.cp = SRSRAN_CP_EXT; ofdm_cfg.normalize = false; - ofdm_cfg.in_buffer = q->sf_symbols[0]; - ofdm_cfg.out_buffer = out_buffer[0]; - ofdm_cfg.sf_type = SRSRAN_SF_MBSFN; + ofdm_cfg.in_buffer = q->sf_symbols[0]; + ofdm_cfg.out_buffer = out_buffer[0]; + ofdm_cfg.sf_type = SRSRAN_SF_MBSFN; if (srsran_ofdm_tx_init_cfg(&q->ifft_mbsfn, &ofdm_cfg)) { ERROR("Error initiating FFT"); goto clean_exit; @@ -142,7 +142,7 @@ int srsran_enb_dl_set_cell(srsran_enb_dl_t* q, srsran_cell_t cell) if (q->cell.nof_prb != 0) { srsran_regs_free(&q->regs); } - q->cell = cell; + q->cell = cell; srsran_ofdm_cfg_t ofdm_cfg = {}; ofdm_cfg.nof_prb = q->cell.nof_prb; ofdm_cfg.cp = cell.cp; @@ -151,6 +151,7 @@ int srsran_enb_dl_set_cell(srsran_enb_dl_t* q, srsran_cell_t cell) ofdm_cfg.in_buffer = q->sf_symbols[i]; ofdm_cfg.out_buffer = q->out_buffer[i]; ofdm_cfg.sf_type = SRSRAN_SF_NORM; + ofdm_cfg.cfr_tx_cfg = q->cfr_config; if (srsran_ofdm_tx_init_cfg(&q->ifft[i], &ofdm_cfg)) { ERROR("Error initiating FFT (%d)", i); return SRSRAN_ERROR; @@ -229,6 +230,31 @@ int srsran_enb_dl_set_cell(srsran_enb_dl_t* q, srsran_cell_t cell) return ret; } +int srsran_enb_dl_set_cfr(srsran_enb_dl_t* q, const srsran_cfr_cfg_t* cfr) +{ + if (q == NULL || cfr == NULL) { + ERROR("Error, invalid inputs"); + return SRSRAN_ERROR_INVALID_INPUTS; + } + + // Copy the cfr config into the eNB + q->cfr_config = *cfr; + + // Set the cfr for the ifft's + if (srsran_ofdm_set_cfr(&q->ifft_mbsfn, &q->cfr_config) < SRSRAN_SUCCESS) { + ERROR("Error setting the CFR for ifft_mbsfn"); + return SRSRAN_ERROR; + } + for (int i = 0; i < SRSRAN_MAX_PORTS; i++) { + if (srsran_ofdm_set_cfr(&q->ifft[i], &q->cfr_config) < SRSRAN_SUCCESS) { + ERROR("Error setting the CFR for the IFFT (%d)", i); + return SRSRAN_ERROR; + } + } + + return SRSRAN_SUCCESS; +} + #ifdef resolve void srsran_enb_dl_apply_power_allocation(srsran_enb_dl_t* q) { @@ -410,22 +436,22 @@ int srsran_enb_dl_put_pmch(srsran_enb_dl_t* q, srsran_pmch_cfg_t* pmch_cfg, uint void srsran_enb_dl_gen_signal(srsran_enb_dl_t* q) { - // TODO: PAPR control float norm_factor = enb_dl_get_norm_factor(q->cell.nof_prb); + // First apply the amplitude normalization, then perform the IFFT and optional CFR reduction if (q->dl_sf.sf_type == SRSRAN_SF_MBSFN) { - srsran_ofdm_tx_sf(&q->ifft_mbsfn); - srsran_vec_sc_prod_cfc(q->ifft_mbsfn.cfg.out_buffer, + srsran_vec_sc_prod_cfc(q->ifft_mbsfn.cfg.in_buffer, norm_factor, - q->ifft_mbsfn.cfg.out_buffer, - (uint32_t)SRSRAN_SF_LEN_PRB(q->cell.nof_prb)); + q->ifft_mbsfn.cfg.in_buffer, + SRSRAN_NOF_SLOTS_PER_SF * q->cell.nof_prb * SRSRAN_NRE * SRSRAN_CP_NSYMB(q->cell.cp)); + srsran_ofdm_tx_sf(&q->ifft_mbsfn); } else { for (int i = 0; i < q->cell.nof_ports; i++) { - srsran_ofdm_tx_sf(&q->ifft[i]); - srsran_vec_sc_prod_cfc(q->ifft[i].cfg.out_buffer, + srsran_vec_sc_prod_cfc(q->ifft[i].cfg.in_buffer, norm_factor, - q->ifft[i].cfg.out_buffer, - (uint32_t)SRSRAN_SF_LEN_PRB(q->cell.nof_prb)); + q->ifft[i].cfg.in_buffer, + SRSRAN_NOF_SLOTS_PER_SF * q->cell.nof_prb * SRSRAN_NRE * SRSRAN_CP_NSYMB(q->cell.cp)); + srsran_ofdm_tx_sf(&q->ifft[i]); } } } diff --git a/lib/src/phy/utils/test/vector_test.c b/lib/src/phy/utils/test/vector_test.c index 50bb1bdbc..ebaaa5d0d 100644 --- a/lib/src/phy/utils/test/vector_test.c +++ b/lib/src/phy/utils/test/vector_test.c @@ -836,6 +836,38 @@ TEST( free(z); srsran_cfo_free(&srsran_cfo);) +// This test compares the clipping method used for the CFR module in its default configuration to the original CFR +// algorithm. The original algorithm can still be used by defining CFR_PEAK_EXTRACTION in the CFR module. +TEST( + srsran_vec_gen_clip_env, MALLOC(cf_t, x); MALLOC(float, x_abs); MALLOC(float, env); float thres = 0.5f; + float alpha = 0.5f; + cf_t gold = 0.0f; + + for (int i = 0; i < block_size; i++) { + x[i] = RANDOM_F(); + env[i] = 0.0f; + x_abs[i] = cabsf(x[i]); + } + + // current implementation generates an amplitude envelope which is then multiplied with the signal + TEST_CALL(srsran_vec_gen_clip_env(x_abs, thres, alpha, env, block_size)) + + // Recreates the original method for clipping the signal, skipping the low-pass filtering + for (int i = 0; i < block_size; i++) { + if (x_abs[i] <= thres) { + gold = x[i]; + } else { + cf_t peak = x[i] - (thres * x[i] / x_abs[i]); // extract the peak + gold = x[i] - alpha * peak; // subtract the peak from the signal, scaled by alpha + } + // Compare the two clipping methods by applying the envelope to x and determining the error + mse += cabsf(gold - env[i] * x[i]); + } if (isnormal(mse)) { mse /= block_size; } + + free(x); + free(x_abs); + free(env);) + int main(int argc, char** argv) { char func_names[MAX_FUNCTIONS][32]; @@ -1014,6 +1046,10 @@ int main(int argc, char** argv) test_srsran_cfo_correct_change(func_names[func_count], &timmings[func_count][size_count], block_size); func_count++; + passed[func_count][size_count] = + test_srsran_vec_gen_clip_env(func_names[func_count], &timmings[func_count][size_count], block_size); + func_count++; + sizes[size_count] = block_size; size_count++; } diff --git a/lib/src/phy/utils/vector.c b/lib/src/phy/utils/vector.c index 6ca8294ad..4259c91ce 100644 --- a/lib/src/phy/utils/vector.c +++ b/lib/src/phy/utils/vector.c @@ -580,7 +580,11 @@ int32_t srsran_vec_dot_prod_sss(const int16_t* x, const int16_t* y, const uint32 float srsran_vec_avg_power_cf(const cf_t* x, const uint32_t len) { - return crealf(srsran_vec_dot_prod_conj_ccc(x, x, len)) / len; + if (!len) { + return 0; + } else { + return crealf(srsran_vec_dot_prod_conj_ccc(x, x, len)) / len; + } } float srsran_vec_avg_power_sf(const int16_t* x, const uint32_t len) @@ -627,6 +631,17 @@ float srsran_vec_avg_power_bf(const int8_t* x, const uint32_t len) return acc; } +float srsran_vec_avg_power_ff(const float* x, const uint32_t len) +{ + if (!len) { + return 0; + } else { + float pwr_symb_avg = srsran_vec_dot_prod_fff(x, x, len); + pwr_symb_avg /= (float)len; + return pwr_symb_avg; + } +} + // Correlation assumes zero-mean x and y float srsran_vec_corr_ccc(const cf_t* x, cf_t* y, const uint32_t len) { @@ -837,3 +852,38 @@ float srsran_vec_estimate_frequency(const cf_t* x, int len) { return srsran_vec_estimate_frequency_simd(x, len); } + +// TODO: implement with SIMD +void srsran_vec_gen_clip_env(const float* x_abs, const float thres, const float alpha, float* env, const int len) +{ + for (int i = 0; i < len; i++) { + env[i] = (x_abs[i] > thres) ? (1 - alpha) + alpha * thres / x_abs[i] : 1; + } +} + +float srsran_vec_papr_c(const cf_t* in, const int len) +{ + uint32_t max = srsran_vec_max_abs_ci(in, len); + float peak = SRSRAN_CSQABS(in[max]); + return peak / srsran_vec_avg_power_cf(in, len); +} + +float srsran_vec_acpr_c(const cf_t* x_f, const uint32_t win_pos_len, const uint32_t win_neg_len, const uint32_t len) +{ + // The adjacent channel cannot extend beyond the FFT len + const uint32_t ch_len = win_pos_len + win_neg_len; + const uint32_t adj_ch_len = ch_len > len / 2 ? len - ch_len : ch_len; + + // Integrate positive half of the signal power spectrum + float signal_pwr = srsran_vec_dot_prod_conj_ccc(x_f, x_f, win_pos_len); + // Integrate negative halt of the signal power spectrum + signal_pwr += srsran_vec_dot_prod_conj_ccc(x_f + len - win_neg_len, x_f + len - win_neg_len, win_neg_len); + + const float adj_ch_pwr = srsran_vec_dot_prod_conj_ccc(x_f + win_pos_len, x_f + win_pos_len, adj_ch_len); + + if (isnormal(signal_pwr)) { + return adj_ch_pwr / signal_pwr; + } else { + return 0; + } +} diff --git a/srsenb/enb.conf.example b/srsenb/enb.conf.example index 63e42c82f..4d5cce198 100644 --- a/srsenb/enb.conf.example +++ b/srsenb/enb.conf.example @@ -326,6 +326,32 @@ enable = false #fd_hz = -750.0 #init_time_s = 0.0 +##################################################################### +# CFR configuration options +# +# The CFR module provides crest factor reduction for the transmitted signal. +# +# enable: Enable or disable the CFR. Default: disabled +# +# mode: manual: CFR threshold is set by cfr_manual_thres (default). +# auto_ema: CFR threshold is adaptive based on the signal PAPR. Power avg. with Exponential Moving Average. +# The time constant of the averaging can be tweaked with the ema_alpha parameter. +# auto_cma: CFR threshold is adaptive based on the signal PAPR. Power avg. with Cumulative Moving Average. +# Use with care, as CMA's increasingly slow response may be unsuitable for most use cases. +# +# strength: Ratio between amplitude-limited vs unprocessed signal (0 to 1). Default: 1 +# manual_thres: Fixed manual clipping threshold for CFR manual mode. Default: 0.5 +# auto_target_papr: Signal PAPR target (in dB) in CFR auto modes. output PAPR can be higher due to peak smoothing. Default: 8 +# ema_alpha: Alpha coefficient for the power average in auto_ema mode. Default: 1/7 +# +##################################################################### +[cfr] +#enable = false +#mode = manual +#manual_thres = 0.5 +#strength = 1 +#auto_target_papr = 8 +#ema_alpha = 0.0143 ##################################################################### # Expert configuration options diff --git a/srsenb/hdr/enb.h b/srsenb/hdr/enb.h index 44ceac557..3bc690713 100644 --- a/srsenb/hdr/enb.h +++ b/srsenb/hdr/enb.h @@ -142,6 +142,8 @@ public: // eNodeB command interface void cmd_cell_gain(uint32_t cell_id, float gain) override; + void cmd_cell_measure() override; + void toggle_padding() override; void tti_clock() override; diff --git a/srsenb/hdr/phy/enb_phy_base.h b/srsenb/hdr/phy/enb_phy_base.h index 5d4ee4af8..57cf87159 100644 --- a/srsenb/hdr/phy/enb_phy_base.h +++ b/srsenb/hdr/phy/enb_phy_base.h @@ -38,6 +38,8 @@ public: virtual void get_metrics(std::vector& m) = 0; virtual void cmd_cell_gain(uint32_t cell_idx, float gain_db) = 0; + + virtual void cmd_cell_measure() = 0; }; } // namespace srsenb diff --git a/srsenb/hdr/phy/phy.h b/srsenb/hdr/phy/phy.h index ade136bc3..8bef23ebb 100644 --- a/srsenb/hdr/phy/phy.h +++ b/srsenb/hdr/phy/phy.h @@ -66,6 +66,7 @@ public: void get_metrics(std::vector& metrics) override; void cmd_cell_gain(uint32_t cell_id, float gain_db) override; + void cmd_cell_measure() override; void radio_overflow() override{}; void radio_failure() override{}; diff --git a/srsenb/hdr/phy/phy_common.h b/srsenb/hdr/phy/phy_common.h index e929c1a46..925567904 100644 --- a/srsenb/hdr/phy/phy_common.h +++ b/srsenb/hdr/phy/phy_common.h @@ -166,6 +166,45 @@ public: return c; } + void set_cell_measure_trigger() + { + // Trigger on LTE cell + for (auto it_lte = cell_list_lte.begin(); it_lte != cell_list_lte.end(); ++it_lte) { + it_lte->dl_measure = true; + } + + // Trigger on NR cell + for (auto it_nr = cell_list_nr.begin(); it_nr != cell_list_nr.end(); ++it_nr) { + it_nr->dl_measure = true; + } + } + + bool get_cell_measure_trigger(uint32_t cc_idx) + { + if (cc_idx < cell_list_lte.size()) { + return cell_list_lte.at(cc_idx).dl_measure; + } + + cc_idx -= cell_list_lte.size(); + if (cc_idx < cell_list_nr.size()) { + return cell_list_nr.at(cc_idx).dl_measure; + } + + return false; + } + + void clear_cell_measure_trigger(uint32_t cc_idx) + { + if (cc_idx < cell_list_lte.size()) { + cell_list_lte.at(cc_idx).dl_measure = false; + } + + cc_idx -= cell_list_lte.size(); + if (cc_idx < cell_list_nr.size()) { + cell_list_nr.at(cc_idx).dl_measure = false; + } + } + void set_cell_gain(uint32_t cell_id, float gain_db) { // Find LTE cell @@ -208,6 +247,11 @@ public: return 0.0f; } + // Common CFR configuration + srsran_cfr_cfg_t cfr_config = {}; + void set_cfr_config(srsran_cfr_cfg_t cfr_cfg) { cfr_config = cfr_cfg; } + srsran_cfr_cfg_t get_cfr_config() { return cfr_config; } + // Common Physical Uplink DMRS configuration srsran_refsignal_dmrs_pusch_cfg_t dmrs_pusch_cfg = {}; diff --git a/srsenb/hdr/phy/phy_interfaces.h b/srsenb/hdr/phy/phy_interfaces.h index 02eb00020..0caf92528 100644 --- a/srsenb/hdr/phy/phy_interfaces.h +++ b/srsenb/hdr/phy/phy_interfaces.h @@ -32,10 +32,20 @@ struct phy_cell_cfg_t { uint32_t root_seq_idx; uint32_t num_ra_preambles; float gain_db; + bool dl_measure; }; typedef std::vector phy_cell_cfg_list_t; +struct cfr_args_t { + bool enable = false; + srsran_cfr_mode_t mode = SRSRAN_CFR_THR_MANUAL; + float manual_thres = 0.5f; + float strength = 1.0f; + float auto_target_papr = 8.0f; + float ema_alpha = 1.0f / (float)SRSRAN_CP_NORM_NSYMB; +}; + struct phy_args_t { std::string type; srsran::phy_log_args_t log; @@ -56,6 +66,7 @@ struct phy_args_t { bool extended_cp = false; srsran::channel::args_t dl_channel_args; srsran::channel::args_t ul_channel_args; + cfr_args_t cfr_args; }; struct phy_cfg_t { @@ -69,6 +80,8 @@ struct phy_cfg_t { asn1::rrc::pusch_cfg_common_s pusch_cnfg; asn1::rrc::pucch_cfg_common_s pucch_cnfg; asn1::rrc::srs_ul_cfg_common_c srs_ul_cnfg; + + srsran_cfr_cfg_t cfr_config; }; } // namespace srsenb diff --git a/srsenb/src/enb.cc b/srsenb/src/enb.cc index 215a0354e..5b1a8c5ae 100644 --- a/srsenb/src/enb.cc +++ b/srsenb/src/enb.cc @@ -219,6 +219,11 @@ void enb::cmd_cell_gain(uint32_t cell_id, float gain) phy->cmd_cell_gain(cell_id, gain); } +void enb::cmd_cell_measure() +{ + phy->cmd_cell_measure(); +} + std::string enb::get_build_mode() { return std::string(srsran_get_build_mode()); diff --git a/srsenb/src/enb_cfg_parser.cc b/srsenb/src/enb_cfg_parser.cc index 45eeb5738..aa1b17655 100644 --- a/srsenb/src/enb_cfg_parser.cc +++ b/srsenb/src/enb_cfg_parser.cc @@ -1153,6 +1153,30 @@ int parse_cell_cfg(all_args_t* args_, srsran_cell_t* cell) return SRSRAN_SUCCESS; } +// Parse the relevant CFR configuration params +int parse_cfr_args(all_args_t* args, srsran_cfr_cfg_t* cfr_config) +{ + cfr_config->cfr_enable = args->phy.cfr_args.enable; + cfr_config->cfr_mode = args->phy.cfr_args.mode; + cfr_config->alpha = args->phy.cfr_args.strength; + cfr_config->manual_thr = args->phy.cfr_args.manual_thres; + cfr_config->max_papr_db = args->phy.cfr_args.auto_target_papr; + cfr_config->ema_alpha = args->phy.cfr_args.ema_alpha; + + if (!srsran_cfr_params_valid(cfr_config)) { + fprintf(stderr, + "Invalid CFR parameters: cfr_mode=%d, alpha=%.2f, manual_thr=%.2f, \n " + "max_papr_db=%.2f, ema_alpha=%.2f\n", + cfr_config->cfr_mode, + cfr_config->alpha, + cfr_config->manual_thr, + cfr_config->max_papr_db, + cfr_config->ema_alpha); + return SRSRAN_ERROR; + } + return SRSRAN_SUCCESS; +} + int parse_cfg_files(all_args_t* args_, rrc_cfg_t* rrc_cfg_, rrc_nr_cfg_t* rrc_nr_cfg_, phy_cfg_t* phy_cfg_) { // Parse config files @@ -1272,6 +1296,12 @@ int parse_cfg_files(all_args_t* args_, rrc_cfg_t* rrc_cfg_, rrc_nr_cfg_t* rrc_nr } } + // Parse CFR args + if (parse_cfr_args(args_, &phy_cfg_->cfr_config) < SRSRAN_SUCCESS) { + fprintf(stderr, "Error parsing CFR configuration\n"); + return SRSRAN_ERROR; + } + return SRSRAN_SUCCESS; } diff --git a/srsenb/src/main.cc b/srsenb/src/main.cc index 1ed0b4a4b..0cc0e0db9 100644 --- a/srsenb/src/main.cc +++ b/srsenb/src/main.cc @@ -56,6 +56,7 @@ void parse_args(all_args_t* args, int argc, char* argv[]) string mcc; string mnc; string enb_id; + string cfr_mode; bool use_standard_lte_rates = false; // Command line only options @@ -212,6 +213,14 @@ void parse_args(all_args_t* args, int argc, char* argv[]) ("channel.ul.hst.fd_hz", bpo::value(&args->phy.ul_channel_args.hst_fd_hz)->default_value(+750.0f), "Doppler frequency in Hz") ("channel.ul.hst.init_time_s", bpo::value(&args->phy.ul_channel_args.hst_init_time_s)->default_value(0), "Initial time in seconds") + /* CFR section */ + ("cfr.enable", bpo::value(&args->phy.cfr_args.enable)->default_value(args->phy.cfr_args.enable), "CFR enable") + ("cfr.mode", bpo::value(&cfr_mode)->default_value("manual"), "CFR mode") + ("cfr.manual_thres", bpo::value(&args->phy.cfr_args.manual_thres)->default_value(args->phy.cfr_args.manual_thres), "Fixed manual clipping threshold for CFR manual mode") + ("cfr.strength", bpo::value(&args->phy.cfr_args.strength)->default_value(args->phy.cfr_args.strength), "CFR ratio between amplitude-limited vs original signal (0 to 1)") + ("cfr.auto_target_papr", bpo::value(&args->phy.cfr_args.auto_target_papr)->default_value(args->phy.cfr_args.auto_target_papr), "Signal PAPR target (in dB) in CFR auto modes") + ("cfr.ema_alpha", bpo::value(&args->phy.cfr_args.ema_alpha)->default_value(args->phy.cfr_args.ema_alpha), "Alpha coefficient for the power average in auto_ema mode (0 to 1)") + /* Expert section */ ("expert.metrics_period_secs", bpo::value(&args->general.metrics_period_secs)->default_value(1.0), "Periodicity for metrics in seconds.") ("expert.metrics_csv_enable", bpo::value(&args->general.metrics_csv_enable)->default_value(false), "Write metrics to CSV file.") @@ -369,6 +378,20 @@ void parse_args(all_args_t* args, int argc, char* argv[]) exit(1); } + // convert CFR mode + if (!cfr_mode.empty()) { + if (cfr_mode == "manual") { + args->phy.cfr_args.mode = SRSRAN_CFR_THR_MANUAL; + } else if (cfr_mode == "auto_cma") { + args->phy.cfr_args.mode = SRSRAN_CFR_THR_AUTO_CMA; + } else if (cfr_mode == "auto_ema") { + args->phy.cfr_args.mode = SRSRAN_CFR_THR_AUTO_EMA; + } else { + cout << "Error, invalid CFR mode: " << cfr_mode << endl; + exit(1); + } + } + // Apply all_level to any unset layers if (vm.count("log.all_level")) { if (!vm.count("log.rf_level")) { @@ -465,6 +488,9 @@ static void execute_cmd(metrics_stdout* metrics, srsenb::enb_command_interface* cout << "Enter t to restart trace." << endl; } metrics->toggle_print(do_metrics); + } else if (cmd[0] == "m") { + // Trigger cell measurements + control->cmd_cell_measure(); } else if (cmd[0] == "sleep") { if (cmd.size() != 2) { cout << "Usage: " << cmd[0] << " [number of seconds]" << endl; @@ -507,6 +533,7 @@ static void execute_cmd(metrics_stdout* metrics, srsenb::enb_command_interface* } else { cout << "Available commands: " << endl; cout << " t: starts console trace" << endl; + cout << " m: downlink signal measurements" << endl; cout << " q: quit srsenb" << endl; cout << " cell_gain: set relative cell gain" << endl; cout << " sleep: pauses the commmand line operation for a given time in seconds" << endl; diff --git a/srsenb/src/phy/lte/cc_worker.cc b/srsenb/src/phy/lte/cc_worker.cc index 46ce668a3..aa17fb709 100644 --- a/srsenb/src/phy/lte/cc_worker.cc +++ b/srsenb/src/phy/lte/cc_worker.cc @@ -10,6 +10,8 @@ * */ +#include + #include "srsran/common/threads.h" #include "srsran/srsran.h" @@ -77,11 +79,12 @@ FILE* f; void cc_worker::init(phy_common* phy_, uint32_t cc_idx_) { - phy = phy_; - cc_idx = cc_idx_; - srsran_cell_t cell = phy_->get_cell(cc_idx); - uint32_t nof_prb = phy_->get_nof_prb(cc_idx); - uint32_t sf_len = SRSRAN_SF_LEN_PRB(nof_prb); + phy = phy_; + cc_idx = cc_idx_; + srsran_cell_t cell = phy_->get_cell(cc_idx); + uint32_t nof_prb = phy_->get_nof_prb(cc_idx); + uint32_t sf_len = SRSRAN_SF_LEN_PRB(nof_prb); + srsran_cfr_cfg_t cfr_config = phy_->get_cfr_config(); // Init cell here for (uint32_t p = 0; p < phy->get_nof_ports(cc_idx); p++) { @@ -106,6 +109,10 @@ void cc_worker::init(phy_common* phy_, uint32_t cc_idx_) ERROR("Error initiating ENB DL (cc=%d)", cc_idx); return; } + if (srsran_enb_dl_set_cfr(&enb_dl, &cfr_config) < SRSRAN_SUCCESS) { + ERROR("Error setting the CFR"); + return; + } if (srsran_enb_ul_init(&enb_ul, signal_buffer_rx[0], nof_prb)) { ERROR("Error initiating ENB UL"); return; @@ -251,6 +258,20 @@ void cc_worker::work_dl(const srsran_dl_sf_cfg_t& dl_sf_cfg, srsran_vec_sc_prod_cfc(signal_buffer_tx[i], scale, signal_buffer_tx[i], sf_len); } } + + // Measure PAPR if flag was triggered + bool cell_meas_flag = phy->get_cell_measure_trigger(cc_idx); + if (cell_meas_flag) { + uint32_t sf_len = SRSRAN_SF_LEN_PRB(enb_dl.cell.nof_prb); + for (uint32_t i = 0; i < enb_dl.cell.nof_ports; i++) { + // PAPR measure + float papr_db = 10.0f * log10(srsran_vec_papr_c(signal_buffer_tx[i], sf_len)); + std::cout << "Cell #" << cc_idx << " port #" << i << " PAPR = " << std::setprecision(4) << papr_db << " dB " + << std::endl; + } + // clear measurement flag on cell + phy->clear_cell_measure_trigger(cc_idx); + } } bool cc_worker::decode_pusch_rnti(stack_interface_phy_lte::ul_sched_grant_t& ul_grant, diff --git a/srsenb/src/phy/phy.cc b/srsenb/src/phy/phy.cc index aba1cfa30..8a185187a 100644 --- a/srsenb/src/phy/phy.cc +++ b/srsenb/src/phy/phy.cc @@ -165,6 +165,9 @@ int phy::init_lte(const phy_args_t& args, workers_common.params = args; workers_common.init(cfg.phy_cell_cfg, cfg.phy_cell_cfg_nr, radio, stack_lte_); + if (cfg.cfr_config.cfr_enable) { + workers_common.set_cfr_config(cfg.cfr_config); + } parse_common_config(cfg); @@ -272,6 +275,11 @@ void phy::cmd_cell_gain(uint32_t cell_id, float gain_db) workers_common.set_cell_gain(cell_id, gain_db); } +void phy::cmd_cell_measure() +{ + workers_common.set_cell_measure_trigger(); +} + /***** RRC->PHY interface **********/ void phy::set_config(uint16_t rnti, const phy_rrc_cfg_list_t& phy_cfg_list) diff --git a/srsgnb/hdr/phy/phy_nr_interfaces.h b/srsgnb/hdr/phy/phy_nr_interfaces.h index 9248d06b0..6784909fc 100644 --- a/srsgnb/hdr/phy/phy_nr_interfaces.h +++ b/srsgnb/hdr/phy/phy_nr_interfaces.h @@ -30,6 +30,7 @@ struct phy_cell_cfg_nr_t { srsran_pdcch_cfg_nr_t pdcch = {}; ///< Common CORESET and Search Space configuration srsran_pdsch_cfg_t pdsch = {}; srsran_prach_cfg_t prach = {}; + bool dl_measure; }; using phy_cell_cfg_list_nr_t = std::vector; From 83ad98c58b67c8eea12d7027fa403a08886cfbe9 Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Thu, 3 Feb 2022 14:55:11 +0100 Subject: [PATCH 40/62] srsue,rrc_nr: add helper to configure default PHY layer parameters --- srsue/hdr/stack/rrc_nr/rrc_nr.h | 1 + srsue/src/stack/rrc_nr/rrc_nr.cc | 28 +++++++++++++++++++++++++++- 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/srsue/hdr/stack/rrc_nr/rrc_nr.h b/srsue/hdr/stack/rrc_nr/rrc_nr.h index e71959a17..c9d8e9655 100644 --- a/srsue/hdr/stack/rrc_nr/rrc_nr.h +++ b/srsue/hdr/stack/rrc_nr/rrc_nr.h @@ -142,6 +142,7 @@ private: void send_security_mode_complete(); // helpers + void set_phy_default_config(); void handle_sib1(const asn1::rrc_nr::sib1_s& sib1); bool handle_rrc_setup(const asn1::rrc_nr::rrc_setup_s& setup); void handle_rrc_reconfig(const asn1::rrc_nr::rrc_recfg_s& reconfig); diff --git a/srsue/src/stack/rrc_nr/rrc_nr.cc b/srsue/src/stack/rrc_nr/rrc_nr.cc index 0da164daa..7593f6afd 100644 --- a/srsue/src/stack/rrc_nr/rrc_nr.cc +++ b/srsue/src/stack/rrc_nr/rrc_nr.cc @@ -35,7 +35,9 @@ rrc_nr::rrc_nr(srsran::task_sched_handle task_sched_) : setup_req_proc(*this), cell_selector(*this), meas_cells(task_sched_) -{} +{ + set_phy_default_config(); +} rrc_nr::~rrc_nr() = default; @@ -355,6 +357,30 @@ void rrc_nr::decode_pdu_bcch_dlsch(srsran::unique_byte_buffer_t pdu) } } +void rrc_nr::set_phy_default_config() +{ + phy_cfg = {}; + + // uses default values provided in 38.311 TS 138 331 V16.6 page 361 + if (make_phy_beta_offsets({}, &phy_cfg.pusch.beta_offsets) == false) { + logger.warning("Couldn't set default beta_offsets config"); + } + + // no default value provided, asume factor 1.0 + uci_on_pusch_s uci_on_pusch = {}; + uci_on_pusch.scaling = uci_on_pusch_s::scaling_opts::f1; + if (make_phy_pusch_scaling(uci_on_pusch, &phy_cfg.pusch.scaling) == false) { + logger.warning("Couldn't set default scaling config"); + } + + // no default value specified, use dynamic + phys_cell_group_cfg_s phys_cell_group_cfg = {}; + phys_cell_group_cfg.pdsch_harq_ack_codebook = phys_cell_group_cfg_s::pdsch_harq_ack_codebook_opts::dynamic_value; + if (make_phy_harq_ack_cfg(phys_cell_group_cfg, &phy_cfg.harq_ack) == false) { + logger.warning("Couldn't set default HARQ ack config"); + } +} + void rrc_nr::handle_sib1(const sib1_s& sib1) { meas_cells.serving_cell().set_sib1(sib1); From b259dbedb1b385eb21c6522ccbfcfd4803473551 Mon Sep 17 00:00:00 2001 From: Carlo Galiotto Date: Fri, 4 Feb 2022 19:05:34 +0100 Subject: [PATCH 41/62] enb: tentative fix for ubuntu18.04 compile error Signed-off-by: Carlo Galiotto --- srsenb/src/enb_cfg_parser.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/srsenb/src/enb_cfg_parser.cc b/srsenb/src/enb_cfg_parser.cc index aa1b17655..343376f34 100644 --- a/srsenb/src/enb_cfg_parser.cc +++ b/srsenb/src/enb_cfg_parser.cc @@ -1090,9 +1090,9 @@ static int parse_nr_cell_list(all_args_t* args, rrc_nr_cfg_t* rrc_cfg_nr, rrc_cf if (it->ul_arfcn != 0) { // Check if ul_arfcn is valid for the given band bool ul_arfcn_valid = false; - std::vector bands = band_helper.get_bands_nr(it->ul_arfcn); - for (uint32_t band_idx = 0; band_idx < bands.size(); band_idx++) { - if (bands.at(band_idx) == it->band) { + std::vector ul_bands = band_helper.get_bands_nr(it->ul_arfcn); + for (uint32_t band_idx = 0; band_idx < ul_bands.size(); band_idx++) { + if (ul_bands.at(band_idx) == it->band) { ul_arfcn_valid = true; } } From bb2777536a136e793350da6d64b5e6b53ba41775 Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Fri, 4 Feb 2022 10:06:28 +0100 Subject: [PATCH 42/62] rrc_nr: reduce loglevel to debug for some reconfig parsing messages --- srsue/src/stack/rrc_nr/rrc_nr.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/srsue/src/stack/rrc_nr/rrc_nr.cc b/srsue/src/stack/rrc_nr/rrc_nr.cc index 7593f6afd..8c3c4c8a3 100644 --- a/srsue/src/stack/rrc_nr/rrc_nr.cc +++ b/srsue/src/stack/rrc_nr/rrc_nr.cc @@ -1635,7 +1635,7 @@ bool rrc_nr::update_sp_cell_cfg(const sp_cell_cfg_s& sp_cell_cfg) return false; } if (recfg_with_sync.sp_cell_cfg_common.tdd_ul_dl_cfg_common_present) { - logger.info("TDD UL DL config present, using TDD"); + logger.debug("TDD UL DL config present, using TDD"); srsran_duplex_config_nr_t duplex; if (make_phy_tdd_cfg(recfg_with_sync.sp_cell_cfg_common.tdd_ul_dl_cfg_common, &duplex) == true) { phy_cfg.duplex = duplex; @@ -1644,7 +1644,7 @@ bool rrc_nr::update_sp_cell_cfg(const sp_cell_cfg_s& sp_cell_cfg) return false; } } else { - logger.info("TDD UL DL config not present, using FDD"); + logger.debug("TDD UL DL config not present, using FDD"); } } } else { From 1fb4a54b28d17d63322be7b788b62709ad9e66b5 Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Fri, 4 Feb 2022 10:06:55 +0100 Subject: [PATCH 43/62] srsue,rrc_nr_procedures: only send reconfig complete in SA mode --- srsue/src/stack/rrc_nr/rrc_nr_procedures.cc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/srsue/src/stack/rrc_nr/rrc_nr_procedures.cc b/srsue/src/stack/rrc_nr/rrc_nr_procedures.cc index c699e0e65..864eb5fe0 100644 --- a/srsue/src/stack/rrc_nr/rrc_nr_procedures.cc +++ b/srsue/src/stack/rrc_nr/rrc_nr_procedures.cc @@ -98,7 +98,10 @@ proc_outcome_t rrc_nr::connection_reconf_no_ho_proc::init(const reconf_initiator } } - rrc_handle.send_rrc_reconfig_complete(); + // only send reconfig complete in SA mode + if (rrc_handle.rrc_eutra == nullptr) { + rrc_handle.send_rrc_reconfig_complete(); + } // Handle NAS messages if (rrc_nr_reconf.crit_exts.rrc_recfg().non_crit_ext.ded_nas_msg_list.size() > 0) { From d65ae322d39a08974b5d55890ed256f91d4cb28a Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Fri, 4 Feb 2022 14:40:14 +0100 Subject: [PATCH 44/62] ue,rrc: fix UL center freq setting --- srsue/src/stack/rrc_nr/rrc_nr.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/srsue/src/stack/rrc_nr/rrc_nr.cc b/srsue/src/stack/rrc_nr/rrc_nr.cc index 8c3c4c8a3..fc788a206 100644 --- a/srsue/src/stack/rrc_nr/rrc_nr.cc +++ b/srsue/src/stack/rrc_nr/rrc_nr.cc @@ -88,6 +88,7 @@ int rrc_nr::init(phy_interface_rrc_nr* phy_, // Carrier config srsran::srsran_band_helper bands; phy_cfg.carrier.dl_center_frequency_hz = bands.nr_arfcn_to_freq(args.dl_nr_arfcn); + phy_cfg.carrier.ul_center_frequency_hz = bands.nr_arfcn_to_freq(bands.get_ul_arfcn_from_dl_arfcn(args.dl_nr_arfcn)); phy_cfg.carrier.ssb_center_freq_hz = bands.nr_arfcn_to_freq(args.ssb_nr_arfcn); phy_cfg.carrier.nof_prb = args.nof_prb; phy_cfg.carrier.max_mimo_layers = 1; From 26f3f6109b731bd9ff201ba3d90993afcbdd07cc Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Thu, 3 Feb 2022 21:10:04 +0100 Subject: [PATCH 45/62] gw,pdcp,rlc,mac: log rate metrics in debug mode reduce periodic log spam for L2 in info level --- lib/src/pdcp/pdcp.cc | 12 ++++++------ lib/src/rlc/rlc.cc | 18 +++++++++--------- srsue/src/stack/mac/mac.cc | 10 +++++----- srsue/src/stack/upper/gw.cc | 10 +++++----- 4 files changed, 25 insertions(+), 25 deletions(-) diff --git a/lib/src/pdcp/pdcp.cc b/lib/src/pdcp/pdcp.cc index 9a5ec950c..36c6f674b 100644 --- a/lib/src/pdcp/pdcp.cc +++ b/lib/src/pdcp/pdcp.cc @@ -362,12 +362,12 @@ void pdcp::get_metrics(pdcp_metrics_t& m, const uint32_t nof_tti) double rx_rate_mbps = (nof_tti > 0) ? ((metrics.num_rx_pdu_bytes * 8 / (double)1e6) / (nof_tti / 1000.0)) : 0.0; double tx_rate_mbps = (nof_tti > 0) ? ((metrics.num_tx_pdu_bytes * 8 / (double)1e6) / (nof_tti / 1000.0)) : 0.0; - logger.info("lcid=%d, rx_rate_mbps=%4.2f (real=%4.2f), tx_rate_mbps=%4.2f (real=%4.2f)", - it->first, - rx_rate_mbps, - rx_rate_mbps_real_time, - tx_rate_mbps, - tx_rate_mbps_real_time); + logger.debug("lcid=%d, rx_rate_mbps=%4.2f (real=%4.2f), tx_rate_mbps=%4.2f (real=%4.2f)", + it->first, + rx_rate_mbps, + rx_rate_mbps_real_time, + tx_rate_mbps, + tx_rate_mbps_real_time); m.bearer[it->first] = metrics; } diff --git a/lib/src/rlc/rlc.cc b/lib/src/rlc/rlc.cc index 570ca2691..60186068b 100644 --- a/lib/src/rlc/rlc.cc +++ b/lib/src/rlc/rlc.cc @@ -99,21 +99,21 @@ void rlc::get_metrics(rlc_metrics_t& m, const uint32_t nof_tti) double rx_rate_mbps = (nof_tti > 0) ? ((metrics.num_rx_pdu_bytes * 8 / (double)1e6) / (nof_tti / 1000.0)) : 0.0; double tx_rate_mbps = (nof_tti > 0) ? ((metrics.num_tx_pdu_bytes * 8 / (double)1e6) / (nof_tti / 1000.0)) : 0.0; - logger.info("lcid=%d, rx_rate_mbps=%4.2f (real=%4.2f), tx_rate_mbps=%4.2f (real=%4.2f)", - it->first, - rx_rate_mbps, - rx_rate_mbps_real_time, - tx_rate_mbps, - tx_rate_mbps_real_time); + logger.debug("lcid=%d, rx_rate_mbps=%4.2f (real=%4.2f), tx_rate_mbps=%4.2f (real=%4.2f)", + it->first, + rx_rate_mbps, + rx_rate_mbps_real_time, + tx_rate_mbps, + tx_rate_mbps_real_time); m.bearer[it->first] = metrics; } // Add multicast metrics for (rlc_map_t::iterator it = rlc_array_mrb.begin(); it != rlc_array_mrb.end(); ++it) { rlc_bearer_metrics_t metrics = it->second->get_metrics(); - logger.info("MCH_LCID=%d, rx_rate_mbps=%4.2f", - it->first, - (metrics.num_rx_pdu_bytes * 8 / static_cast(1e6)) / secs.count()); + logger.debug("MCH_LCID=%d, rx_rate_mbps=%4.2f", + it->first, + (metrics.num_rx_pdu_bytes * 8 / static_cast(1e6)) / secs.count()); m.bearer[it->first] = metrics; } diff --git a/srsue/src/stack/mac/mac.cc b/srsue/src/stack/mac/mac.cc index 82b4119f5..d3da40a0f 100644 --- a/srsue/src/stack/mac/mac.cc +++ b/srsue/src/stack/mac/mac.cc @@ -668,11 +668,11 @@ void mac::get_metrics(mac_metrics_t m[SRSRAN_MAX_CARRIERS]) dl_avg_ret /= dl_avg_ret_count; } - Info("DL retx: %.2f \%%, perpkt: %.2f, UL retx: %.2f \%% perpkt: %.2f", - rx_pkts ? ((float)100 * rx_errors / rx_pkts) : 0.0f, - dl_avg_ret, - tx_pkts ? ((float)100 * tx_errors / tx_pkts) : 0.0f, - ul_harq.at(PCELL_CC_IDX)->get_average_retx()); + Debug("DL retx: %.2f \%%, perpkt: %.2f, UL retx: %.2f \%% perpkt: %.2f", + rx_pkts ? ((float)100 * rx_errors / rx_pkts) : 0.0f, + dl_avg_ret, + tx_pkts ? ((float)100 * tx_errors / tx_pkts) : 0.0f, + ul_harq.at(PCELL_CC_IDX)->get_average_retx()); metrics[PCELL_CC_IDX].ul_buffer = (int)bsr_procedure.get_buffer_state(); memcpy(m, metrics, sizeof(mac_metrics_t) * SRSRAN_MAX_CARRIERS); diff --git a/srsue/src/stack/upper/gw.cc b/srsue/src/stack/upper/gw.cc index 7a0da339e..606b79d72 100644 --- a/srsue/src/stack/upper/gw.cc +++ b/srsue/src/stack/upper/gw.cc @@ -109,11 +109,11 @@ void gw::get_metrics(gw_metrics_t& m, const uint32_t nof_tti) m.dl_tput_mbps = (nof_tti > 0) ? ((dl_tput_bytes * 8 / (double)1e6) / (nof_tti / 1000.0)) : 0.0; m.ul_tput_mbps = (nof_tti > 0) ? ((ul_tput_bytes * 8 / (double)1e6) / (nof_tti / 1000.0)) : 0.0; - logger.info("gw_rx_rate_mbps=%4.2f (real=%4.2f), gw_tx_rate_mbps=%4.2f (real=%4.2f)", - m.dl_tput_mbps, - dl_tput_mbps_real_time, - m.ul_tput_mbps, - ul_tput_mbps_real_time); + logger.debug("gw_rx_rate_mbps=%4.2f (real=%4.2f), gw_tx_rate_mbps=%4.2f (real=%4.2f)", + m.dl_tput_mbps, + dl_tput_mbps_real_time, + m.ul_tput_mbps, + ul_tput_mbps_real_time); // reset counters and store time metrics_tp = std::chrono::high_resolution_clock::now(); From ace6026d242c29f9920a57f9ea17774b6116fd7e Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Fri, 4 Feb 2022 17:16:45 +0100 Subject: [PATCH 46/62] UE-PHY: Skip PUCCH-NR transmission if there is no PUCCH resource available --- srsue/src/phy/nr/cc_worker.cc | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/srsue/src/phy/nr/cc_worker.cc b/srsue/src/phy/nr/cc_worker.cc index cce8fa4fb..c8b3f68e9 100644 --- a/srsue/src/phy/nr/cc_worker.cc +++ b/srsue/src/phy/nr/cc_worker.cc @@ -669,6 +669,21 @@ bool cc_worker::work_ul() phy.set_ul_metrics(ul_m); } else if (srsran_uci_nr_total_bits(&uci_data.cfg) > 0) { + // Currently, default PUCCH is not supported, in this case log it and pretend no UCI was available + if (not cfg.pucch.enabled) { + if (logger.info.enabled()) { + std::array str; + srsran_uci_nr_info(&uci_data, str.data(), str.size()); + logger.info( + "PUCCH: No PUCCH resource to transmit UCI cc=%d, %s, tti_tx=%d", cc_idx, str.data(), ul_slot_cfg.idx); + } + + // No NR signal shall be transmitted + srsran_vec_cf_zero(tx_buffer[0], ue_ul.ifft.sf_sz); + + return true; + } + // Get PUCCH resource srsran_pucch_nr_resource_t resource = {}; if (srsran_ra_ul_nr_pucch_resource(&cfg.pucch, &uci_data.cfg, &resource) < SRSRAN_SUCCESS) { From 094d0198830623a64a8c07f1344a33963467a5d1 Mon Sep 17 00:00:00 2001 From: Francisco Date: Wed, 2 Feb 2022 13:16:30 +0000 Subject: [PATCH 47/62] remove extra branches in the rrc cell asn1 cfg generation --- srsgnb/src/stack/rrc/cell_asn1_config.cc | 140 +++++++++++------------ srsgnb/src/stack/rrc/rrc_nr.cc | 13 +-- 2 files changed, 71 insertions(+), 82 deletions(-) diff --git a/srsgnb/src/stack/rrc/cell_asn1_config.cc b/srsgnb/src/stack/rrc/cell_asn1_config.cc index d94fbdf62..d50f1d3d8 100644 --- a/srsgnb/src/stack/rrc/cell_asn1_config.cc +++ b/srsgnb/src/stack/rrc/cell_asn1_config.cc @@ -746,23 +746,7 @@ int fill_serv_cell_from_enb_cfg(const rrc_nr_cfg_t& cfg, uint32_t cc, serving_ce return SRSRAN_SUCCESS; } -int fill_pdcch_cfg_common_from_enb_cfg(const rrc_nr_cfg_t& cfg, uint32_t cc, pdcch_cfg_common_s& pdcch_cfg_common) -{ - pdcch_cfg_common.common_ctrl_res_set_present = true; - set_coreset_from_phy_cfg(cfg.cell_list[cc].phy_cell.pdcch.coreset[1], pdcch_cfg_common.common_ctrl_res_set); - - pdcch_cfg_common.common_search_space_list.push_back({}); - set_search_space_from_phy_cfg(cfg.cell_list[cc].phy_cell.pdcch.search_space[1], - pdcch_cfg_common.common_search_space_list.back()); - pdcch_cfg_common.ra_search_space_present = true; - pdcch_cfg_common.ra_search_space = cfg.cell_list[cc].phy_cell.pdcch.ra_search_space.id; - - if (cfg.cell_list[cc].duplex_mode == SRSRAN_DUPLEX_MODE_TDD) { - pdcch_cfg_common.ext = false; - } - - return SRSRAN_SUCCESS; -} +void fill_pdcch_cfg_common(const rrc_nr_cfg_t& cfg, uint32_t cc, pdcch_cfg_common_s& out); /// Fill FrequencyInfoDL with gNB config int fill_freq_info_dl_from_enb_cfg(const rrc_nr_cfg_t& cfg, uint32_t cc, freq_info_dl_s& freq_info_dl) @@ -794,9 +778,8 @@ int fill_freq_info_dl_from_enb_cfg(const rrc_nr_cfg_t& cfg, uint32_t cc, freq_in int fill_init_dl_bwp_common_from_enb_cfg(const rrc_nr_cfg_t& cfg, uint32_t cc, bwp_dl_common_s& init_dl_bwp) { init_dl_bwp.pdcch_cfg_common_present = true; - HANDLE_ERROR(fill_pdcch_cfg_common_from_enb_cfg(cfg, cc, init_dl_bwp.pdcch_cfg_common.set_setup())); + fill_pdcch_cfg_common(cfg, cc, init_dl_bwp.pdcch_cfg_common.set_setup()); // TODO: ADD missing fields - return SRSRAN_SUCCESS; } @@ -1086,26 +1069,30 @@ int fill_mib_from_enb_cfg(const rrc_cell_cfg_nr_t& cell_cfg, asn1::rrc_nr::mib_s return SRSRAN_SUCCESS; } -void fill_pdcch_cfg_common(const rrc_cell_cfg_nr_t& cell_cfg, pdcch_cfg_common_s& cfg) +// Called for SA +void fill_pdcch_cfg_common(const rrc_nr_cfg_t& cfg, uint32_t cc, pdcch_cfg_common_s& out) { - cfg.ctrl_res_set_zero_present = true; // may be disabled later if called by sib1 generation - cfg.ctrl_res_set_zero = 0; - cfg.common_ctrl_res_set_present = false; - - cfg.search_space_zero_present = true; - cfg.search_space_zero = 0; - - cfg.common_search_space_list.resize(1); - set_search_space_from_phy_cfg(cell_cfg.phy_cell.pdcch.search_space[1], cfg.common_search_space_list[0]); - - cfg.search_space_sib1_present = true; - cfg.search_space_sib1 = 0; - cfg.search_space_other_sys_info_present = true; - cfg.search_space_other_sys_info = 1; - cfg.paging_search_space_present = true; - cfg.paging_search_space = 1; - cfg.ra_search_space_present = true; - cfg.ra_search_space = 1; + auto& cell_cfg = cfg.cell_list[cc]; + + out.ctrl_res_set_zero_present = false; + out.search_space_zero_present = false; + + if (not cfg.is_standalone) { + // In NSA, Common CORESET is passed in RRC Reconfiguration + out.common_ctrl_res_set_present = true; + set_coreset_from_phy_cfg(cfg.cell_list[cc].phy_cell.pdcch.coreset[1], out.common_ctrl_res_set); + } + out.common_search_space_list.resize(1); + set_search_space_from_phy_cfg(cell_cfg.phy_cell.pdcch.search_space[1], out.common_search_space_list.back()); + + out.search_space_sib1_present = true; + out.search_space_sib1 = 0; + out.search_space_other_sys_info_present = true; + out.search_space_other_sys_info = 1; + out.paging_search_space_present = true; + out.paging_search_space = 1; + out.ra_search_space_present = true; + out.ra_search_space = 1; } void fill_pdsch_cfg_common(const rrc_cell_cfg_nr_t& cell_cfg, pdsch_cfg_common_s& cfg) @@ -1115,46 +1102,51 @@ void fill_pdsch_cfg_common(const rrc_cell_cfg_nr_t& cell_cfg, pdsch_cfg_common_s cfg.pdsch_time_domain_alloc_list[0].start_symbol_and_len = 40; } -void fill_init_dl_bwp(const rrc_cell_cfg_nr_t& cell_cfg, bwp_dl_common_s& cfg) +// Called for SA +void fill_init_dl_bwp(const rrc_nr_cfg_t& cfg, uint32_t cc, bwp_dl_common_s& out) { - cfg.generic_params.location_and_bw = 14025; - cfg.generic_params.subcarrier_spacing = (subcarrier_spacing_opts::options)cell_cfg.phy_cell.carrier.scs; + auto& cell_cfg = cfg.cell_list[cc]; - cfg.pdcch_cfg_common_present = true; - fill_pdcch_cfg_common(cell_cfg, cfg.pdcch_cfg_common.set_setup()); - cfg.pdsch_cfg_common_present = true; - fill_pdsch_cfg_common(cell_cfg, cfg.pdsch_cfg_common.set_setup()); + out.generic_params.location_and_bw = 14025; + out.generic_params.subcarrier_spacing = (subcarrier_spacing_opts::options)cell_cfg.phy_cell.carrier.scs; + + out.pdcch_cfg_common_present = true; + fill_pdcch_cfg_common(cfg, cc, out.pdcch_cfg_common.set_setup()); + out.pdsch_cfg_common_present = true; + fill_pdsch_cfg_common(cell_cfg, out.pdsch_cfg_common.set_setup()); } -void fill_dl_cfg_common_sib(const rrc_cell_cfg_nr_t& cell_cfg, dl_cfg_common_sib_s& cfg) +void fill_dl_cfg_common_sib(const rrc_nr_cfg_t& cfg, uint32_t cc, dl_cfg_common_sib_s& out) { + auto& cell_cfg = cfg.cell_list[cc]; + uint32_t scs_hz = SRSRAN_SUBC_SPACING_NR(cell_cfg.phy_cell.carrier.scs); uint32_t prb_bw = scs_hz * SRSRAN_NRE; srsran::srsran_band_helper band_helper; - cfg.freq_info_dl.freq_band_list.resize(1); - cfg.freq_info_dl.freq_band_list[0].freq_band_ind_nr_present = true; - cfg.freq_info_dl.freq_band_list[0].freq_band_ind_nr = cell_cfg.band; + out.freq_info_dl.freq_band_list.resize(1); + out.freq_info_dl.freq_band_list[0].freq_band_ind_nr_present = true; + out.freq_info_dl.freq_band_list[0].freq_band_ind_nr = cell_cfg.band; double ssb_freq_start = cell_cfg.ssb_freq_hz - SRSRAN_SSB_BW_SUBC * scs_hz / 2; double offset_point_a_hz = ssb_freq_start - band_helper.nr_arfcn_to_freq(cell_cfg.dl_absolute_freq_point_a); uint32_t offset_point_a_prbs = offset_point_a_hz / prb_bw; - cfg.freq_info_dl.offset_to_point_a = offset_point_a_prbs; - cfg.freq_info_dl.scs_specific_carrier_list.resize(1); - cfg.freq_info_dl.scs_specific_carrier_list[0].offset_to_carrier = cell_cfg.phy_cell.carrier.offset_to_carrier; - cfg.freq_info_dl.scs_specific_carrier_list[0].subcarrier_spacing = + out.freq_info_dl.offset_to_point_a = offset_point_a_prbs; + out.freq_info_dl.scs_specific_carrier_list.resize(1); + out.freq_info_dl.scs_specific_carrier_list[0].offset_to_carrier = cell_cfg.phy_cell.carrier.offset_to_carrier; + out.freq_info_dl.scs_specific_carrier_list[0].subcarrier_spacing = (subcarrier_spacing_opts::options)cell_cfg.phy_cell.carrier.scs; - cfg.freq_info_dl.scs_specific_carrier_list[0].carrier_bw = cell_cfg.phy_cell.carrier.nof_prb; + out.freq_info_dl.scs_specific_carrier_list[0].carrier_bw = cell_cfg.phy_cell.carrier.nof_prb; - fill_init_dl_bwp(cell_cfg, cfg.init_dl_bwp); + fill_init_dl_bwp(cfg, cc, out.init_dl_bwp); // disable InitialBWP-Only fields - cfg.init_dl_bwp.pdcch_cfg_common.setup().ctrl_res_set_zero_present = false; - cfg.init_dl_bwp.pdcch_cfg_common.setup().search_space_zero_present = false; + out.init_dl_bwp.pdcch_cfg_common.setup().ctrl_res_set_zero_present = false; + out.init_dl_bwp.pdcch_cfg_common.setup().search_space_zero_present = false; - cfg.bcch_cfg.mod_period_coeff.value = bcch_cfg_s::mod_period_coeff_opts::n4; + out.bcch_cfg.mod_period_coeff.value = bcch_cfg_s::mod_period_coeff_opts::n4; - cfg.pcch_cfg.default_paging_cycle.value = paging_cycle_opts::rf128; - cfg.pcch_cfg.nand_paging_frame_offset.set_one_t(); - cfg.pcch_cfg.ns.value = pcch_cfg_s::ns_opts::one; + out.pcch_cfg.default_paging_cycle.value = paging_cycle_opts::rf128; + out.pcch_cfg.nand_paging_frame_offset.set_one_t(); + out.pcch_cfg.ns.value = pcch_cfg_s::ns_opts::one; } void fill_ul_cfg_common_sib(const rrc_cell_cfg_nr_t& cell_cfg, ul_cfg_common_sib_s& cfg) @@ -1206,28 +1198,30 @@ void fill_ul_cfg_common_sib(const rrc_cell_cfg_nr_t& cell_cfg, ul_cfg_common_sib cfg.time_align_timer_common.value = time_align_timer_opts::infinity; } -int fill_serv_cell_cfg_common_sib(const rrc_cell_cfg_nr_t& cell_cfg, serving_cell_cfg_common_sib_s& cfg) +int fill_serv_cell_cfg_common_sib(const rrc_nr_cfg_t& cfg, uint32_t cc, serving_cell_cfg_common_sib_s& out) { - fill_dl_cfg_common_sib(cell_cfg, cfg.dl_cfg_common); + auto& cell_cfg = cfg.cell_list[cc]; + + fill_dl_cfg_common_sib(cfg, cc, out.dl_cfg_common); - cfg.ul_cfg_common_present = true; - fill_ul_cfg_common_sib(cell_cfg, cfg.ul_cfg_common); + out.ul_cfg_common_present = true; + fill_ul_cfg_common_sib(cell_cfg, out.ul_cfg_common); - cfg.ssb_positions_in_burst.in_one_group.from_number(0x80); + out.ssb_positions_in_burst.in_one_group.from_number(0x80); - cfg.ssb_periodicity_serving_cell.value = serving_cell_cfg_common_sib_s::ssb_periodicity_serving_cell_opts::ms10; + out.ssb_periodicity_serving_cell.value = serving_cell_cfg_common_sib_s::ssb_periodicity_serving_cell_opts::ms10; // The time advance offset is not supported by the current PHY - cfg.n_timing_advance_offset_present = true; - cfg.n_timing_advance_offset = serving_cell_cfg_common_sib_s::n_timing_advance_offset_opts::n0; + out.n_timing_advance_offset_present = true; + out.n_timing_advance_offset = serving_cell_cfg_common_sib_s::n_timing_advance_offset_opts::n0; // TDD UL-DL config if (cell_cfg.duplex_mode == SRSRAN_DUPLEX_MODE_TDD) { - cfg.tdd_ul_dl_cfg_common_present = true; - fill_tdd_ul_dl_config_common(cell_cfg, cfg.tdd_ul_dl_cfg_common); + out.tdd_ul_dl_cfg_common_present = true; + fill_tdd_ul_dl_config_common(cell_cfg, out.tdd_ul_dl_cfg_common); } - cfg.ss_pbch_block_pwr = cell_cfg.phy_cell.pdsch.rs_power; + out.ss_pbch_block_pwr = cell_cfg.phy_cell.pdsch.rs_power; return SRSRAN_SUCCESS; } @@ -1274,7 +1268,7 @@ int fill_sib1_from_enb_cfg(const rrc_nr_cfg_t& cfg, uint32_t cc, asn1::rrc_nr::s // sib1.si_sched_info.sched_info_list[0].sib_map_info[0].value_tag = 0; sib1.serving_cell_cfg_common_present = true; - HANDLE_ERROR(fill_serv_cell_cfg_common_sib(cell_cfg, sib1.serving_cell_cfg_common)); + HANDLE_ERROR(fill_serv_cell_cfg_common_sib(cfg, cc, sib1.serving_cell_cfg_common)); sib1.ue_timers_and_consts_present = true; sib1.ue_timers_and_consts.t300.value = ue_timers_and_consts_s::t300_opts::ms1000; diff --git a/srsgnb/src/stack/rrc/rrc_nr.cc b/srsgnb/src/stack/rrc/rrc_nr.cc index 26c2c8ce9..6e7a62e3c 100644 --- a/srsgnb/src/stack/rrc/rrc_nr.cc +++ b/srsgnb/src/stack/rrc/rrc_nr.cc @@ -71,7 +71,8 @@ int rrc_nr::init(const rrc_nr_cfg_t& cfg_, du_cfg = std::make_unique(cfg); for (uint32_t i = 0; i < cfg.cell_list.size(); ++i) { - du_cfg->add_cell(); + int ret = du_cfg->add_cell(); + srsran_assert(ret == SRSRAN_SUCCESS, "Failed to configure NR cell %d", i); } // Generate cell config structs @@ -95,14 +96,8 @@ int rrc_nr::init(const rrc_nr_cfg_t& cfg_, int ret = fill_sp_cell_cfg_from_enb_cfg(cfg, UE_PSCELL_CC_IDX, base_sp_cell_cfg); srsran_assert(ret == SRSRAN_SUCCESS, "Failed to configure cell"); - const pdcch_cfg_common_s* asn1_pdcch; - if (not cfg.is_standalone) { - // Fill rrc_nr_cfg with UE-specific search spaces and coresets - asn1_pdcch = - &base_sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common.dl_cfg_common.init_dl_bwp.pdcch_cfg_common.setup(); - } else { - asn1_pdcch = &du_cfg->cell(0).serv_cell_cfg_common().dl_cfg_common.init_dl_bwp.pdcch_cfg_common.setup(); - } + const pdcch_cfg_common_s* asn1_pdcch = + &du_cfg->cell(0).serv_cell_cfg_common().dl_cfg_common.init_dl_bwp.pdcch_cfg_common.setup(); srsran_assert(check_nr_phy_cell_cfg_valid(cfg.cell_list[0].phy_cell) == SRSRAN_SUCCESS, "Invalid PhyCell Config"); config_phy(); // if PHY is not yet initialized, config will be stored and applied on initialization From 301848002f4e8950d5e0332695687c57e3b5873a Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Fri, 4 Feb 2022 11:03:55 +0000 Subject: [PATCH 48/62] rrc,gnb: remove uneeded cell config parameters from rrc_nr main class --- srsgnb/hdr/stack/rrc/rrc_nr.h | 7 ++-- srsgnb/src/stack/rrc/cell_asn1_config.cc | 5 +-- srsgnb/src/stack/rrc/rrc_nr.cc | 43 +++++++++--------------- 3 files changed, 21 insertions(+), 34 deletions(-) diff --git a/srsgnb/hdr/stack/rrc/rrc_nr.h b/srsgnb/hdr/stack/rrc/rrc_nr.h index 969671baa..85508d457 100644 --- a/srsgnb/hdr/stack/rrc/rrc_nr.h +++ b/srsgnb/hdr/stack/rrc/rrc_nr.h @@ -138,16 +138,13 @@ private: srsran::task_sched_handle task_sched; // derived - uint32_t slot_dur_ms = 0; - srslog::basic_logger& logger; - asn1::rrc_nr::sp_cell_cfg_s base_sp_cell_cfg; + uint32_t slot_dur_ms = 0; + srslog::basic_logger& logger; // vars std::unique_ptr du_cfg; struct cell_ctxt_t { - asn1::rrc_nr::sib1_s sib1; asn1::rrc_nr::sys_info_ies_s::sib_type_and_info_l_ sibs; - srsran::unique_byte_buffer_t mib_buffer = nullptr; std::vector sib_buffer; std::unique_ptr master_cell_group; srsran::phy_cfg_nr_t default_phy_ue_cfg_nr; diff --git a/srsgnb/src/stack/rrc/cell_asn1_config.cc b/srsgnb/src/stack/rrc/cell_asn1_config.cc index d50f1d3d8..a79188f0c 100644 --- a/srsgnb/src/stack/rrc/cell_asn1_config.cc +++ b/srsgnb/src/stack/rrc/cell_asn1_config.cc @@ -909,7 +909,9 @@ int fill_recfg_with_sync_from_enb_cfg(const rrc_nr_cfg_t& cfg, uint32_t cc, recf /// Fill spCellConfig with gNB config int fill_sp_cell_cfg_from_enb_cfg(const rrc_nr_cfg_t& cfg, uint32_t cc, sp_cell_cfg_s& sp_cell) { - sp_cell.recfg_with_sync_present = true; + if (not cfg.is_standalone) { + sp_cell.recfg_with_sync_present = true; + } HANDLE_ERROR(fill_recfg_with_sync_from_enb_cfg(cfg, cc, sp_cell.recfg_with_sync)); sp_cell.sp_cell_cfg_ded_present = true; @@ -1037,7 +1039,6 @@ int fill_master_cell_cfg_from_enb_cfg(const rrc_nr_cfg_t& cfg, uint32_t cc, asn1 // spCellConfig -- Need M out.sp_cell_cfg_present = true; fill_sp_cell_cfg_from_enb_cfg(cfg, cc, out.sp_cell_cfg); - out.sp_cell_cfg.recfg_with_sync_present = false; return SRSRAN_SUCCESS; } diff --git a/srsgnb/src/stack/rrc/rrc_nr.cc b/srsgnb/src/stack/rrc/rrc_nr.cc index 6e7a62e3c..160637b4c 100644 --- a/srsgnb/src/stack/rrc/rrc_nr.cc +++ b/srsgnb/src/stack/rrc/rrc_nr.cc @@ -77,12 +77,10 @@ int rrc_nr::init(const rrc_nr_cfg_t& cfg_, // Generate cell config structs cell_ctxt.reset(new cell_ctxt_t()); - if (cfg.is_standalone) { - std::unique_ptr master_cell_group{new cell_group_cfg_s()}; - int ret = fill_master_cell_cfg_from_enb_cfg(cfg, 0, *master_cell_group); - srsran_assert(ret == SRSRAN_SUCCESS, "Failed to configure MasterCellGroup"); - cell_ctxt->master_cell_group = std::move(master_cell_group); - } + std::unique_ptr master_cell_group{new cell_group_cfg_s()}; + int ret = fill_master_cell_cfg_from_enb_cfg(cfg, 0, *master_cell_group); + srsran_assert(ret == SRSRAN_SUCCESS, "Failed to configure MasterCellGroup"); + cell_ctxt->master_cell_group = std::move(master_cell_group); // derived slot_dur_ms = 1; @@ -92,12 +90,6 @@ int rrc_nr::init(const rrc_nr_cfg_t& cfg_, return SRSRAN_ERROR; } - // Fill base ASN1 cell config. - int ret = fill_sp_cell_cfg_from_enb_cfg(cfg, UE_PSCELL_CC_IDX, base_sp_cell_cfg); - srsran_assert(ret == SRSRAN_SUCCESS, "Failed to configure cell"); - - const pdcch_cfg_common_s* asn1_pdcch = - &du_cfg->cell(0).serv_cell_cfg_common().dl_cfg_common.init_dl_bwp.pdcch_cfg_common.setup(); srsran_assert(check_nr_phy_cell_cfg_valid(cfg.cell_list[0].phy_cell) == SRSRAN_SUCCESS, "Invalid PhyCell Config"); config_phy(); // if PHY is not yet initialized, config will be stored and applied on initialization @@ -327,19 +319,17 @@ void rrc_nr::config_mac() cell.dl_cfg_common = du_cfg->cell(cc).serv_cell_cfg_common().dl_cfg_common; cell.ul_cfg_common = du_cfg->cell(cc).serv_cell_cfg_common().ul_cfg_common; cell.ss_pbch_block_power = du_cfg->cell(cc).serv_cell_cfg_common().ss_pbch_block_pwr; + bool valid_cfg = srsran::make_pdsch_cfg_from_serv_cell(cell_ctxt->master_cell_group->sp_cell_cfg.sp_cell_cfg_ded, + &cell.bwps[0].pdsch); + srsran_assert(valid_cfg, "Invalid NR cell configuration."); if (not cfg.is_standalone) { - const serving_cell_cfg_common_s& serv_cell = base_sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common; + const serving_cell_cfg_common_s& serv_cell = + cell_ctxt->master_cell_group->sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common; // Derive cell config from ASN1 - bool valid_cfg = srsran::make_pdsch_cfg_from_serv_cell(base_sp_cell_cfg.sp_cell_cfg_ded, &cell.bwps[0].pdsch); - srsran_assert(valid_cfg, "Invalid NR cell configuration."); cell.ssb_positions_in_burst.in_one_group.set(0, true); cell.ssb_periodicity_ms = serv_cell.ssb_periodicity_serving_cell.to_number(); cell.ssb_scs = serv_cell.ssb_subcarrier_spacing; } else { - cell.bwps[0].pdsch.p_zp_csi_rs_set = {}; - bool valid_cfg = srsran::make_pdsch_cfg_from_serv_cell(cell_ctxt->master_cell_group->sp_cell_cfg.sp_cell_cfg_ded, - &cell.bwps[0].pdsch); - srsran_assert(valid_cfg, "Invalid NR cell configuration."); cell.ssb_positions_in_burst = du_cfg->cell(cc).serv_cell_cfg_common().ssb_positions_in_burst; cell.ssb_periodicity_ms = du_cfg->cell(cc).serv_cell_cfg_common().ssb_periodicity_serving_cell.to_number(); cell.ssb_scs.value = (subcarrier_spacing_e::options)cfg.cell_list[0].phy_cell.carrier.scs; @@ -353,8 +343,8 @@ void rrc_nr::config_mac() cell.sibs[i].period_rf = 16; // SIB1 is always 16 rf cell.sibs[i].si_window_slots = 160; } else { - cell.sibs[i].period_rf = cell_ctxt->sib1.si_sched_info.sched_info_list[i - 1].si_periodicity.to_number(); - cell.sibs[i].si_window_slots = cell_ctxt->sib1.si_sched_info.si_win_len.to_number(); + cell.sibs[i].period_rf = du_cfg->cell(0).sib1.si_sched_info.sched_info_list[i - 1].si_periodicity.to_number(); + cell.sibs[i].si_window_slots = du_cfg->cell(0).sib1.si_sched_info.si_win_len.to_number(); } } @@ -372,8 +362,7 @@ int32_t rrc_nr::generate_sibs() } // SIB1 packing - fill_sib1_from_enb_cfg(cfg, 0, cell_ctxt->sib1); - si_sched_info_s::sched_info_list_l_& sched_info = cell_ctxt->sib1.si_sched_info.sched_info_list; + const si_sched_info_s::sched_info_list_l_& sched_info = du_cfg->cell(0).sib1.si_sched_info.sched_info_list; // SI messages packing cell_ctxt->sibs.resize(1); @@ -383,12 +372,12 @@ int32_t rrc_nr::generate_sibs() // msg is array of SI messages, each SI message msg[i] may contain multiple SIBs // all SIBs in a SI message msg[i] share the same periodicity const uint32_t nof_messages = - cell_ctxt->sib1.si_sched_info_present ? cell_ctxt->sib1.si_sched_info.sched_info_list.size() : 0; + du_cfg->cell(0).sib1.si_sched_info_present ? du_cfg->cell(0).sib1.si_sched_info.sched_info_list.size() : 0; cell_ctxt->sib_buffer.reserve(nof_messages + 1); asn1::dyn_array msg(nof_messages + 1); // Copy SIB1 to first SI message - msg[0].msg.set_c1().set_sib_type1() = cell_ctxt->sib1; + msg[0].msg.set_c1().set_sib_type1() = du_cfg->cell(0).sib1; // Copy rest of SIBs for (uint32_t sched_info_elem = 0; sched_info_elem < nof_messages; sched_info_elem++) { @@ -431,10 +420,10 @@ int32_t rrc_nr::generate_sibs() int rrc_nr::read_pdu_bcch_bch(const uint32_t tti, srsran::byte_buffer_t& buffer) { - if (cell_ctxt->mib_buffer == nullptr || buffer.get_tailroom() < cell_ctxt->mib_buffer->N_bytes) { + if (du_cfg->cell(0).packed_mib == nullptr || buffer.get_tailroom() < du_cfg->cell(0).packed_mib->N_bytes) { return SRSRAN_ERROR; } - buffer = *cell_ctxt->mib_buffer; + buffer = *du_cfg->cell(0).packed_mib; return SRSRAN_SUCCESS; } From 88a95e8e57cffb2f026a2c0b81e11a185105fdf7 Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Fri, 4 Feb 2022 13:12:37 +0000 Subject: [PATCH 49/62] rrc,gnb: remove uneeded flat phy cfg fields from rrc_nr_cfg_t --- lib/include/srsran/asn1/rrc_nr_utils.h | 8 +++ lib/src/asn1/rrc_nr_utils.cc | 85 ++++++++++++++++++++++++++ srsgnb/hdr/stack/rrc/rrc_nr_config.h | 11 ---- srsgnb/src/stack/rrc/rrc_nr.cc | 36 +++++------ 4 files changed, 107 insertions(+), 33 deletions(-) diff --git a/lib/include/srsran/asn1/rrc_nr_utils.h b/lib/include/srsran/asn1/rrc_nr_utils.h index c005a7bfe..a303f7815 100644 --- a/lib/include/srsran/asn1/rrc_nr_utils.h +++ b/lib/include/srsran/asn1/rrc_nr_utils.h @@ -124,6 +124,14 @@ bool make_phy_zp_csi_rs_resource(const asn1::rrc_nr::zp_csi_rs_res_s& zp_csi_rs_ bool make_phy_nzp_csi_rs_resource(const asn1::rrc_nr::nzp_csi_rs_res_s& nzp_csi_rs_res, srsran_csi_rs_nzp_resource_t* csi_rs_nzp_resource); bool make_phy_carrier_cfg(const asn1::rrc_nr::freq_info_dl_s& freq_info_dl, srsran_carrier_nr_t* carrier_nr); +bool fill_phy_ssb_cfg(const srsran_carrier_nr_t& carrier, + const asn1::rrc_nr::serving_cell_cfg_common_sib_s& serv_cell_cfg, + phy_cfg_nr_t::ssb_cfg_t* out_ssb); +void fill_ssb_pos_in_burst(const asn1::rrc_nr::serving_cell_cfg_common_sib_s& ssb_pos, + phy_cfg_nr_t::ssb_cfg_t* out_ssb); +bool fill_phy_ssb_cfg(const srsran_carrier_nr_t& carrier, + const asn1::rrc_nr::serving_cell_cfg_common_sib_s& serv_cell_cfg, + srsran_ssb_cfg_t* out_ssb); bool make_phy_ssb_cfg(const srsran_carrier_nr_t& carrier, const asn1::rrc_nr::serving_cell_cfg_common_s& serv_cell_cfg, phy_cfg_nr_t::ssb_cfg_t* ssb); diff --git a/lib/src/asn1/rrc_nr_utils.cc b/lib/src/asn1/rrc_nr_utils.cc index bb6c0ee8b..c48c41706 100644 --- a/lib/src/asn1/rrc_nr_utils.cc +++ b/lib/src/asn1/rrc_nr_utils.cc @@ -1494,6 +1494,91 @@ static inline void make_ssb_positions_in_burst(const bitstring_t& } } +void fill_ssb_pos_in_burst(const asn1::rrc_nr::serving_cell_cfg_common_sib_s& cfg, phy_cfg_nr_t::ssb_cfg_t* out_ssb) +{ + auto& ssb_pos = cfg.ssb_positions_in_burst; + + out_ssb->position_in_burst = {}; + uint32_t N = ssb_pos.in_one_group.length(); + for (uint32_t i = 0; i < N; ++i) { + out_ssb->position_in_burst[i] = ssb_pos.in_one_group.get(i); + } + if (ssb_pos.group_presence_present) { + for (uint32_t i = 1; i < ssb_pos.group_presence.length(); ++i) { + if (ssb_pos.group_presence.get(i)) { + std::copy(out_ssb->position_in_burst.begin(), + out_ssb->position_in_burst.begin() + N, + out_ssb->position_in_burst.begin() + i * N); + } + } + } +} + +bool fill_ssb_pattern_scs(const srsran_carrier_nr_t& carrier, + srsran_ssb_patern_t* pattern, + srsran_subcarrier_spacing_t* ssb_scs) +{ + srsran::srsran_band_helper bands; + uint16_t band = bands.get_band_from_dl_freq_Hz(carrier.ssb_center_freq_hz); + if (band == UINT16_MAX) { + asn1::log_error("Invalid band for SSB frequency %.3f MHz", carrier.ssb_center_freq_hz); + return false; + } + + // TODO: Generalize conversion for other SCS + *pattern = bands.get_ssb_pattern(band, srsran_subcarrier_spacing_15kHz); + if (*pattern == SRSRAN_SSB_PATTERN_A) { + *ssb_scs = carrier.scs; + } else { + // try to optain SSB pattern for same band with 30kHz SCS + *pattern = bands.get_ssb_pattern(band, srsran_subcarrier_spacing_30kHz); + if (*pattern == SRSRAN_SSB_PATTERN_B || *pattern == SRSRAN_SSB_PATTERN_C) { + // SSB SCS is 30 kHz + *ssb_scs = srsran_subcarrier_spacing_30kHz; + } else { + asn1::log_error("Can't derive SSB pattern from band %d", band); + return false; + } + } + return true; +} + +bool fill_phy_ssb_cfg(const srsran_carrier_nr_t& carrier, + const asn1::rrc_nr::serving_cell_cfg_common_sib_s& serv_cell_cfg, + srsran_ssb_cfg_t* out_ssb) +{ + *out_ssb = {}; + + out_ssb->center_freq_hz = carrier.dl_center_frequency_hz; + out_ssb->ssb_freq_hz = carrier.ssb_center_freq_hz; + if (not fill_ssb_pattern_scs(carrier, &out_ssb->pattern, &out_ssb->scs)) { + return false; + } + + out_ssb->duplex_mode = SRSRAN_DUPLEX_MODE_FDD; + if (serv_cell_cfg.tdd_ul_dl_cfg_common_present) { + out_ssb->duplex_mode = SRSRAN_DUPLEX_MODE_TDD; + } + + out_ssb->periodicity_ms = serv_cell_cfg.ssb_periodicity_serving_cell.to_number(); + return true; +} + +// SA case +bool fill_phy_ssb_cfg(const srsran_carrier_nr_t& carrier, + const asn1::rrc_nr::serving_cell_cfg_common_sib_s& serv_cell_cfg, + phy_cfg_nr_t::ssb_cfg_t* out_ssb) +{ + // Derive SSB pattern and SCS + if (not fill_ssb_pattern_scs(carrier, &out_ssb->pattern, &out_ssb->scs)) { + return false; + } + fill_ssb_pos_in_burst(serv_cell_cfg, out_ssb); + out_ssb->periodicity_ms = (uint32_t)serv_cell_cfg.ssb_periodicity_serving_cell.to_number(); + + return true; +} + bool make_phy_ssb_cfg(const srsran_carrier_nr_t& carrier, const asn1::rrc_nr::serving_cell_cfg_common_s& serv_cell_cfg, phy_cfg_nr_t::ssb_cfg_t* out_ssb) diff --git a/srsgnb/hdr/stack/rrc/rrc_nr_config.h b/srsgnb/hdr/stack/rrc/rrc_nr_config.h index 0bf40b583..5312f6b5b 100644 --- a/srsgnb/hdr/stack/rrc/rrc_nr_config.h +++ b/srsgnb/hdr/stack/rrc/rrc_nr_config.h @@ -21,15 +21,6 @@ namespace srsenb { -// TODO: Make this common to NR and LTE -struct rrc_nr_cfg_sr_t { - uint32_t period; - // asn1::rrc::sched_request_cfg_c::setup_s_::dsr_trans_max_e_ dsr_max; - uint32_t nof_prb; - uint32_t sf_mapping[80]; - uint32_t nof_subframes; -}; - // Cell/Sector configuration for NR cells struct rrc_cell_cfg_nr_t { phy_cell_cfg_nr_t phy_cell; // already contains all PHY-related parameters (i.e. RF port, PCI, etc.) @@ -50,8 +41,6 @@ struct rrc_cell_cfg_nr_t { typedef std::vector rrc_cell_list_nr_t; struct rrc_nr_cfg_t { - rrc_nr_cfg_sr_t sr_cfg; - rrc_cfg_cqi_t cqi_cfg; rrc_cell_list_nr_t cell_list; uint32_t inactivity_timeout_ms = 100000; uint32_t enb_id; diff --git a/srsgnb/src/stack/rrc/rrc_nr.cc b/srsgnb/src/stack/rrc/rrc_nr.cc index 160637b4c..b7a0afc8d 100644 --- a/srsgnb/src/stack/rrc/rrc_nr.cc +++ b/srsgnb/src/stack/rrc/rrc_nr.cc @@ -76,9 +76,9 @@ int rrc_nr::init(const rrc_nr_cfg_t& cfg_, } // Generate cell config structs - cell_ctxt.reset(new cell_ctxt_t()); - std::unique_ptr master_cell_group{new cell_group_cfg_s()}; - int ret = fill_master_cell_cfg_from_enb_cfg(cfg, 0, *master_cell_group); + cell_ctxt = std::make_unique(); + std::unique_ptr master_cell_group = std::make_unique(); + int ret = fill_master_cell_cfg_from_enb_cfg(cfg, 0, *master_cell_group); srsran_assert(ret == SRSRAN_SUCCESS, "Failed to configure MasterCellGroup"); cell_ctxt->master_cell_group = std::move(master_cell_group); @@ -175,15 +175,14 @@ int rrc_nr::add_user(uint16_t rnti, uint32_t pcell_cc_idx, bool start_msg3_timer { if (users.contains(rnti) == 0) { // If in the ue ctor, "start_msg3_timer" is set to true, this will start the MSG3 RX TIMEOUT at ue creation - users.insert(rnti, std::unique_ptr(new ue(this, rnti, pcell_cc_idx, start_msg3_timer))); + users.insert(rnti, std::make_unique(this, rnti, pcell_cc_idx, start_msg3_timer)); rlc->add_user(rnti); pdcp->add_user(rnti); logger.info("Added new user rnti=0x%x", rnti); return SRSRAN_SUCCESS; - } else { - logger.error("Adding user rnti=0x%x (already exists)", rnti); - return SRSRAN_ERROR; } + logger.error("Adding user rnti=0x%x (already exists)", rnti); + return SRSRAN_ERROR; } /* @brief PUBLIC function, gets called by mac_nr::rach_detected @@ -277,13 +276,9 @@ void rrc_nr::config_phy() common_cfg.pdcch = cfg.cell_list[0].phy_cell.pdcch; common_cfg.prach = cfg.cell_list[0].phy_cell.prach; common_cfg.duplex_mode = cfg.cell_list[0].duplex_mode; - common_cfg.ssb = {}; - common_cfg.ssb.center_freq_hz = cfg.cell_list[0].phy_cell.dl_freq_hz; - common_cfg.ssb.ssb_freq_hz = cfg.cell_list[0].ssb_freq_hz; - common_cfg.ssb.scs = cfg.cell_list[0].ssb_scs; - common_cfg.ssb.pattern = cfg.cell_list[0].ssb_pattern; - common_cfg.ssb.duplex_mode = cfg.cell_list[0].duplex_mode; - common_cfg.ssb.periodicity_ms = du_cfg->cell(0).serv_cell_cfg_common().ssb_periodicity_serving_cell.to_number(); + bool ret = srsran::fill_phy_ssb_cfg( + cfg.cell_list[0].phy_cell.carrier, du_cfg->cell(0).serv_cell_cfg_common(), &common_cfg.ssb); + srsran_assert(ret, "Failed to generate PHY config"); if (phy->set_common_cfg(common_cfg) < SRSRAN_SUCCESS) { logger.error("Couldn't set common PHY config"); return; @@ -322,17 +317,14 @@ void rrc_nr::config_mac() bool valid_cfg = srsran::make_pdsch_cfg_from_serv_cell(cell_ctxt->master_cell_group->sp_cell_cfg.sp_cell_cfg_ded, &cell.bwps[0].pdsch); srsran_assert(valid_cfg, "Invalid NR cell configuration."); + cell.ssb_positions_in_burst = du_cfg->cell(cc).serv_cell_cfg_common().ssb_positions_in_burst; + cell.ssb_periodicity_ms = du_cfg->cell(cc).serv_cell_cfg_common().ssb_periodicity_serving_cell.to_number(); + cell.ssb_scs.value = (subcarrier_spacing_e::options)cfg.cell_list[0].phy_cell.carrier.scs; if (not cfg.is_standalone) { const serving_cell_cfg_common_s& serv_cell = cell_ctxt->master_cell_group->sp_cell_cfg.recfg_with_sync.sp_cell_cfg_common; // Derive cell config from ASN1 - cell.ssb_positions_in_burst.in_one_group.set(0, true); - cell.ssb_periodicity_ms = serv_cell.ssb_periodicity_serving_cell.to_number(); - cell.ssb_scs = serv_cell.ssb_subcarrier_spacing; - } else { - cell.ssb_positions_in_burst = du_cfg->cell(cc).serv_cell_cfg_common().ssb_positions_in_burst; - cell.ssb_periodicity_ms = du_cfg->cell(cc).serv_cell_cfg_common().ssb_periodicity_serving_cell.to_number(); - cell.ssb_scs.value = (subcarrier_spacing_e::options)cfg.cell_list[0].phy_cell.carrier.scs; + cell.ssb_scs = serv_cell.ssb_subcarrier_spacing; } // Set SIB1 and SI messages @@ -367,7 +359,7 @@ int32_t rrc_nr::generate_sibs() // SI messages packing cell_ctxt->sibs.resize(1); sib2_s& sib2 = cell_ctxt->sibs[0].set_sib2(); - sib2.cell_resel_info_common.q_hyst.value = asn1::rrc_nr::sib2_s::cell_resel_info_common_s_::q_hyst_opts::db5; + sib2.cell_resel_info_common.q_hyst.value = sib2_s::cell_resel_info_common_s_::q_hyst_opts::db5; // msg is array of SI messages, each SI message msg[i] may contain multiple SIBs // all SIBs in a SI message msg[i] share the same periodicity From 532a4b54e7c27a434774e6f31d8ae82bbac5d5f6 Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Fri, 4 Feb 2022 18:10:45 +0000 Subject: [PATCH 50/62] rrc,gnb: remove phy flat pdcch cfg struct from rrc nr cfg --- lib/include/srsran/asn1/rrc_nr_utils.h | 5 +- lib/src/asn1/rrc_nr_utils.cc | 8 +- srsgnb/hdr/phy/phy_nr_interfaces.h | 1 - srsgnb/hdr/stack/rrc/rrc_nr_config.h | 28 +-- srsgnb/hdr/stack/rrc/rrc_nr_du_manager.h | 7 + srsgnb/src/stack/rrc/cell_asn1_config.cc | 42 +--- srsgnb/src/stack/rrc/rrc_nr.cc | 16 +- srsgnb/src/stack/rrc/rrc_nr_config_utils.cc | 221 ++++++++++---------- srsgnb/src/stack/rrc/rrc_nr_du_manager.cc | 53 +++++ srsgnb/src/stack/rrc/rrc_nr_ue.cc | 10 +- test/phy/nr_phy_test.cc | 1 - 11 files changed, 223 insertions(+), 169 deletions(-) diff --git a/lib/include/srsran/asn1/rrc_nr_utils.h b/lib/include/srsran/asn1/rrc_nr_utils.h index a303f7815..d08dce7ae 100644 --- a/lib/include/srsran/asn1/rrc_nr_utils.h +++ b/lib/include/srsran/asn1/rrc_nr_utils.h @@ -129,6 +129,9 @@ bool fill_phy_ssb_cfg(const srsran_carrier_nr_t& carrier phy_cfg_nr_t::ssb_cfg_t* out_ssb); void fill_ssb_pos_in_burst(const asn1::rrc_nr::serving_cell_cfg_common_sib_s& ssb_pos, phy_cfg_nr_t::ssb_cfg_t* out_ssb); +bool fill_ssb_pattern_scs(const srsran_carrier_nr_t& carrier, + srsran_ssb_patern_t* pattern, + srsran_subcarrier_spacing_t* ssb_scs); bool fill_phy_ssb_cfg(const srsran_carrier_nr_t& carrier, const asn1::rrc_nr::serving_cell_cfg_common_sib_s& serv_cell_cfg, srsran_ssb_cfg_t* out_ssb); @@ -140,7 +143,7 @@ bool make_pdsch_cfg_from_serv_cell(const asn1::rrc_nr::serving_cell_cfg_s& serv_ bool make_csi_cfg_from_serv_cell(const asn1::rrc_nr::serving_cell_cfg_s& serv_cell, srsran_csi_hl_cfg_t* csi_hl); bool make_duplex_cfg_from_serv_cell(const asn1::rrc_nr::serving_cell_cfg_common_s& serv_cell, srsran_duplex_config_nr_t* duplex_cfg); -void fill_phy_pdcch_cfg_common(const asn1::rrc_nr::pdcch_cfg_common_s& pdcch_cfg, srsran_pdcch_cfg_nr_t* pdcch); +bool fill_phy_pdcch_cfg_common(const asn1::rrc_nr::pdcch_cfg_common_s& pdcch_cfg, srsran_pdcch_cfg_nr_t* pdcch); bool fill_phy_pdcch_cfg(const asn1::rrc_nr::pdcch_cfg_s& pdcch_cfg, srsran_pdcch_cfg_nr_t* pdcch); bool fill_phy_pdsch_cfg_common(const asn1::rrc_nr::pdsch_cfg_common_s& pdsch_cfg, srsran_sch_hl_cfg_nr_t* pdsch); void fill_phy_pucch_cfg_common(const asn1::rrc_nr::pucch_cfg_common_s& pucch_cfg, srsran_pucch_nr_common_cfg_t* pucch); diff --git a/lib/src/asn1/rrc_nr_utils.cc b/lib/src/asn1/rrc_nr_utils.cc index c48c41706..204b9a9b7 100644 --- a/lib/src/asn1/rrc_nr_utils.cc +++ b/lib/src/asn1/rrc_nr_utils.cc @@ -1775,7 +1775,7 @@ bool fill_phy_pdcch_cfg(const asn1::rrc_nr::pdcch_cfg_s& pdcch_cfg, srsran_pdcch return true; } -void fill_phy_pdcch_cfg_common(const asn1::rrc_nr::pdcch_cfg_common_s& pdcch_cfg, srsran_pdcch_cfg_nr_t* pdcch) +bool fill_phy_pdcch_cfg_common(const asn1::rrc_nr::pdcch_cfg_common_s& pdcch_cfg, srsran_pdcch_cfg_nr_t* pdcch) { if (pdcch_cfg.common_ctrl_res_set_present) { pdcch->coreset_present[pdcch_cfg.common_ctrl_res_set.ctrl_res_set_id] = true; @@ -1783,7 +1783,10 @@ void fill_phy_pdcch_cfg_common(const asn1::rrc_nr::pdcch_cfg_common_s& pdcch_cfg } for (const search_space_s& ss : pdcch_cfg.common_search_space_list) { pdcch->search_space_present[ss.search_space_id] = true; - make_phy_search_space_cfg(ss, &pdcch->search_space[ss.search_space_id]); + if (not make_phy_search_space_cfg(ss, &pdcch->search_space[ss.search_space_id])) { + asn1::log_error("Failed to convert SearchSpace Configuration"); + return false; + } if (pdcch_cfg.ra_search_space_present and pdcch_cfg.ra_search_space == ss.search_space_id) { pdcch->ra_search_space_present = true; pdcch->ra_search_space = pdcch->search_space[ss.search_space_id]; @@ -1792,6 +1795,7 @@ void fill_phy_pdcch_cfg_common(const asn1::rrc_nr::pdcch_cfg_common_s& pdcch_cfg pdcch->ra_search_space.formats[1] = srsran_dci_format_nr_1_0; } } + return true; } void fill_phy_pucch_cfg_common(const asn1::rrc_nr::pucch_cfg_common_s& pucch_cfg, srsran_pucch_nr_common_cfg_t* pucch) diff --git a/srsgnb/hdr/phy/phy_nr_interfaces.h b/srsgnb/hdr/phy/phy_nr_interfaces.h index 6784909fc..4f91fb479 100644 --- a/srsgnb/hdr/phy/phy_nr_interfaces.h +++ b/srsgnb/hdr/phy/phy_nr_interfaces.h @@ -27,7 +27,6 @@ struct phy_cell_cfg_nr_t { uint32_t root_seq_idx; uint32_t num_ra_preambles; float gain_db; - srsran_pdcch_cfg_nr_t pdcch = {}; ///< Common CORESET and Search Space configuration srsran_pdsch_cfg_t pdsch = {}; srsran_prach_cfg_t prach = {}; bool dl_measure; diff --git a/srsgnb/hdr/stack/rrc/rrc_nr_config.h b/srsgnb/hdr/stack/rrc/rrc_nr_config.h index 5312f6b5b..95cfe1dae 100644 --- a/srsgnb/hdr/stack/rrc/rrc_nr_config.h +++ b/srsgnb/hdr/stack/rrc/rrc_nr_config.h @@ -23,19 +23,21 @@ namespace srsenb { // Cell/Sector configuration for NR cells struct rrc_cell_cfg_nr_t { - phy_cell_cfg_nr_t phy_cell; // already contains all PHY-related parameters (i.e. RF port, PCI, etc.) - uint32_t tac; // Tracking area code - uint32_t dl_arfcn; // DL freq already included in phy_cell - uint32_t ul_arfcn; // UL freq also in phy_cell - uint32_t dl_absolute_freq_point_a; // derived from DL ARFCN - uint32_t ul_absolute_freq_point_a; // derived from UL ARFCN - uint32_t band; - uint32_t coreset0_idx; // Table 13-{1,...15} row index - srsran_duplex_mode_t duplex_mode; - double ssb_freq_hz; - uint32_t ssb_absolute_freq_point; // derived from DL ARFCN (SSB arfcn) - srsran_subcarrier_spacing_t ssb_scs; - srsran_ssb_patern_t ssb_pattern; + phy_cell_cfg_nr_t phy_cell; // already contains all PHY-related parameters (i.e. RF port, PCI, etc.) + uint32_t tac; // Tracking area code + uint32_t dl_arfcn; // DL freq already included in phy_cell + uint32_t ul_arfcn; // UL freq also in phy_cell + uint32_t dl_absolute_freq_point_a; // derived from DL ARFCN + uint32_t ul_absolute_freq_point_a; // derived from UL ARFCN + uint32_t band; + uint32_t coreset0_idx; // Table 13-{1,...15} row index + srsran_duplex_mode_t duplex_mode; + double ssb_freq_hz; + uint32_t ssb_absolute_freq_point; // derived from DL ARFCN (SSB arfcn) + srsran_subcarrier_spacing_t ssb_scs; + srsran_ssb_patern_t ssb_pattern; + asn1::rrc_nr::pdcch_cfg_common_s pdcch_cfg_common; + asn1::rrc_nr::pdcch_cfg_s pdcch_cfg_ded; }; typedef std::vector rrc_cell_list_nr_t; diff --git a/srsgnb/hdr/stack/rrc/rrc_nr_du_manager.h b/srsgnb/hdr/stack/rrc/rrc_nr_du_manager.h index 05e063e4f..d0f930a8a 100644 --- a/srsgnb/hdr/stack/rrc/rrc_nr_du_manager.h +++ b/srsgnb/hdr/stack/rrc/rrc_nr_du_manager.h @@ -31,6 +31,11 @@ public: asn1::rrc_nr::sib1_s sib1; srsran::unique_byte_buffer_t packed_sib1; + asn1::rrc_nr::subcarrier_spacing_e ssb_scs; + srsran_ssb_patern_t ssb_pattern; + double ssb_center_freq_hz; + double dl_freq_hz; + const asn1::rrc_nr::serving_cell_cfg_common_sib_s& serv_cell_cfg_common() const { return sib1.serving_cell_cfg_common; @@ -63,6 +68,8 @@ private: std::vector > cells; }; +void fill_phy_pdcch_cfg_common(const du_cell_config& cell, srsran_pdcch_cfg_nr_t* pdcch); + } // namespace srsenb #endif // SRSRAN_RRC_NR_DU_MANAGER_H diff --git a/srsgnb/src/stack/rrc/cell_asn1_config.cc b/srsgnb/src/stack/rrc/cell_asn1_config.cc index a79188f0c..4080a5fd2 100644 --- a/srsgnb/src/stack/rrc/cell_asn1_config.cc +++ b/srsgnb/src/stack/rrc/cell_asn1_config.cc @@ -499,32 +499,6 @@ int fill_csi_meas_from_enb_cfg(const rrc_nr_cfg_t& cfg, csi_meas_cfg_s& csi_meas return SRSRAN_SUCCESS; } -/// Fill InitDlBwp with gNB config -int fill_pdcch_cfg_from_enb_cfg(const rrc_nr_cfg_t& cfg, uint32_t cc, pdcch_cfg_s& pdcch_cfg) -{ - auto& cell_cfg = cfg.cell_list.at(cc); - for (uint32_t ss_idx = 1; ss_idx < SRSRAN_UE_DL_NR_MAX_NOF_SEARCH_SPACE; ss_idx++) { - if (cell_cfg.phy_cell.pdcch.search_space_present[ss_idx]) { - auto& search_space_cfg = cell_cfg.phy_cell.pdcch.search_space[ss_idx]; - if (search_space_cfg.type != srsran_search_space_type_ue) { - // Only add UE-specific search spaces at this stage - continue; - } - - // Add UE-specific SearchSpace - pdcch_cfg.search_spaces_to_add_mod_list.push_back({}); - set_search_space_from_phy_cfg(search_space_cfg, pdcch_cfg.search_spaces_to_add_mod_list.back()); - - // Add CORESET associated with SearchSpace - uint32_t coreset_id = search_space_cfg.coreset_id; - auto& coreset_cfg = cell_cfg.phy_cell.pdcch.coreset[coreset_id]; - pdcch_cfg.ctrl_res_set_to_add_mod_list.push_back({}); - set_coreset_from_phy_cfg(coreset_cfg, pdcch_cfg.ctrl_res_set_to_add_mod_list.back()); - } - } - return SRSRAN_SUCCESS; -} - void fill_pdsch_cfg_from_enb_cfg(const rrc_nr_cfg_t& cfg, uint32_t cc, pdsch_cfg_s& out) { out.dmrs_dl_for_pdsch_map_type_a_present = true; @@ -571,8 +545,8 @@ void fill_pdsch_cfg_from_enb_cfg(const rrc_nr_cfg_t& cfg, uint32_t cc, pdsch_cfg /// Fill InitDlBwp with gNB config int fill_init_dl_bwp_from_enb_cfg(const rrc_nr_cfg_t& cfg, uint32_t cc, bwp_dl_ded_s& init_dl_bwp) { - init_dl_bwp.pdcch_cfg_present = true; - HANDLE_ERROR(fill_pdcch_cfg_from_enb_cfg(cfg, cc, init_dl_bwp.pdcch_cfg.set_setup())); + init_dl_bwp.pdcch_cfg_present = true; + init_dl_bwp.pdcch_cfg.set_setup() = cfg.cell_list[cc].pdcch_cfg_ded; init_dl_bwp.pdsch_cfg_present = true; fill_pdsch_cfg_from_enb_cfg(cfg, cc, init_dl_bwp.pdsch_cfg.set_setup()); @@ -1070,7 +1044,7 @@ int fill_mib_from_enb_cfg(const rrc_cell_cfg_nr_t& cell_cfg, asn1::rrc_nr::mib_s return SRSRAN_SUCCESS; } -// Called for SA +// Called for SA and NSA void fill_pdcch_cfg_common(const rrc_nr_cfg_t& cfg, uint32_t cc, pdcch_cfg_common_s& out) { auto& cell_cfg = cfg.cell_list[cc]; @@ -1078,13 +1052,9 @@ void fill_pdcch_cfg_common(const rrc_nr_cfg_t& cfg, uint32_t cc, pdcch_cfg_commo out.ctrl_res_set_zero_present = false; out.search_space_zero_present = false; - if (not cfg.is_standalone) { - // In NSA, Common CORESET is passed in RRC Reconfiguration - out.common_ctrl_res_set_present = true; - set_coreset_from_phy_cfg(cfg.cell_list[cc].phy_cell.pdcch.coreset[1], out.common_ctrl_res_set); - } - out.common_search_space_list.resize(1); - set_search_space_from_phy_cfg(cell_cfg.phy_cell.pdcch.search_space[1], out.common_search_space_list.back()); + out.common_ctrl_res_set_present = cell_cfg.pdcch_cfg_common.common_ctrl_res_set_present; + out.common_ctrl_res_set = cell_cfg.pdcch_cfg_common.common_ctrl_res_set; + out.common_search_space_list = cell_cfg.pdcch_cfg_ded.search_spaces_to_add_mod_list; out.search_space_sib1_present = true; out.search_space_sib1 = 0; diff --git a/srsgnb/src/stack/rrc/rrc_nr.cc b/srsgnb/src/stack/rrc/rrc_nr.cc index b7a0afc8d..9ab5cc2a4 100644 --- a/srsgnb/src/stack/rrc/rrc_nr.cc +++ b/srsgnb/src/stack/rrc/rrc_nr.cc @@ -273,10 +273,13 @@ void rrc_nr::config_phy() { srsenb::phy_interface_rrc_nr::common_cfg_t common_cfg = {}; common_cfg.carrier = cfg.cell_list[0].phy_cell.carrier; - common_cfg.pdcch = cfg.cell_list[0].phy_cell.pdcch; - common_cfg.prach = cfg.cell_list[0].phy_cell.prach; - common_cfg.duplex_mode = cfg.cell_list[0].duplex_mode; - bool ret = srsran::fill_phy_ssb_cfg( + fill_phy_pdcch_cfg_common(du_cfg->cell(0), &common_cfg.pdcch); + bool ret = srsran::fill_phy_pdcch_cfg( + cell_ctxt->master_cell_group->sp_cell_cfg.sp_cell_cfg_ded.init_dl_bwp.pdcch_cfg.setup(), &common_cfg.pdcch); + srsran_assert(ret, "Failed to generate Dedicated PDCCH config"); + common_cfg.prach = cfg.cell_list[0].phy_cell.prach; + common_cfg.duplex_mode = cfg.cell_list[0].duplex_mode; + ret = srsran::fill_phy_ssb_cfg( cfg.cell_list[0].phy_cell.carrier, du_cfg->cell(0).serv_cell_cfg_common(), &common_cfg.ssb); srsran_assert(ret, "Failed to generate PHY config"); if (phy->set_common_cfg(common_cfg) < SRSRAN_SUCCESS) { @@ -298,7 +301,10 @@ void rrc_nr::config_mac() sched_nr_cell_cfg_t& cell = sched_cells_cfg[cc]; // Derive cell config from rrc_nr_cfg_t - cell.bwps[0].pdcch = cfg.cell_list[cc].phy_cell.pdcch; + fill_phy_pdcch_cfg_common(du_cfg->cell(cc), &cell.bwps[0].pdcch); + bool ret = srsran::fill_phy_pdcch_cfg( + cell_ctxt->master_cell_group->sp_cell_cfg.sp_cell_cfg_ded.init_dl_bwp.pdcch_cfg.setup(), &cell.bwps[0].pdcch); + srsran_assert(ret, "Failed to generate Dedicated PDCCH config"); cell.pci = cfg.cell_list[cc].phy_cell.carrier.pci; cell.nof_layers = cfg.cell_list[cc].phy_cell.carrier.max_mimo_layers; cell.dl_cell_nof_prb = cfg.cell_list[cc].phy_cell.carrier.nof_prb; diff --git a/srsgnb/src/stack/rrc/rrc_nr_config_utils.cc b/srsgnb/src/stack/rrc/rrc_nr_config_utils.cc index 77ac0e6dd..fbf29d151 100644 --- a/srsgnb/src/stack/rrc/rrc_nr_config_utils.cc +++ b/srsgnb/src/stack/rrc/rrc_nr_config_utils.cc @@ -30,6 +30,33 @@ namespace srsenb { +uint32_t coreset_get_bw(const asn1::rrc_nr::ctrl_res_set_s& coreset) +{ + uint32_t prb_count = 0; + + // Iterate all the frequency domain resources bit-map... + for (uint32_t i = 0; i < SRSRAN_CORESET_FREQ_DOMAIN_RES_SIZE; i++) { + // ... and count 6 PRB for every frequency domain resource that it is enabled + if (coreset.freq_domain_res.get(i)) { + prb_count += 6; + } + } + + // Return the total count of physical resource blocks + return prb_count; +} + +int coreset_get_pdcch_nr_max_candidates(const asn1::rrc_nr::ctrl_res_set_s& coreset, uint32_t aggregation_level) +{ + uint32_t coreset_bw = coreset_get_bw(coreset); + uint32_t nof_cce = (coreset_bw * coreset.dur) / 6; + + uint32_t L = 1U << aggregation_level; + uint32_t nof_candidates = nof_cce / L; + + return SRSRAN_MIN(nof_candidates, SRSRAN_SEARCH_SPACE_MAX_NOF_CANDIDATES_NR); +} + /// Generate default phy cell configuration void generate_default_nr_phy_cell(phy_cell_cfg_nr_t& phy_cell) { @@ -50,35 +77,9 @@ void generate_default_nr_phy_cell(phy_cell_cfg_nr_t& phy_cell) phy_cell.prach.freq_offset = 1; // msg1-FrequencyStart (zero not supported with current PRACH implementation) phy_cell.prach.zero_corr_zone = 0; phy_cell.prach.num_ra_preambles = phy_cell.num_ra_preambles; - phy_cell.prach.hs_flag = false; + phy_cell.prach.hs_flag = false; phy_cell.prach.tdd_config.configured = false; - // PDCCH - // - Add CORESET#2 as UE-specific - phy_cell.pdcch.coreset_present[2] = true; - phy_cell.pdcch.coreset[2].id = 2; - phy_cell.pdcch.coreset[2].duration = 1; - phy_cell.pdcch.coreset[2].mapping_type = srsran_coreset_mapping_type_non_interleaved; - phy_cell.pdcch.coreset[2].precoder_granularity = srsran_coreset_precoder_granularity_reg_bundle; - // Generate frequency resources for the full BW - for (uint32_t i = 0; i < SRSRAN_CORESET_FREQ_DOMAIN_RES_SIZE; i++) { - phy_cell.pdcch.coreset[2].freq_resources[i] = i < SRSRAN_FLOOR(phy_cell.carrier.nof_prb, 6); - } - // - Add SearchSpace#2 as UE-specific - phy_cell.pdcch.search_space_present[2] = true; - phy_cell.pdcch.search_space[2].id = 2; - phy_cell.pdcch.search_space[2].coreset_id = 2; - phy_cell.pdcch.search_space[2].type = srsran_search_space_type_ue; - // Generate frequency resources for the full BW - for (uint32_t L = 0; L < SRSRAN_SEARCH_SPACE_NOF_AGGREGATION_LEVELS_NR; L++) { - phy_cell.pdcch.search_space[2].nof_candidates[L] = - SRSRAN_MIN(2, srsran_pdcch_nr_max_candidates_coreset(&phy_cell.pdcch.coreset[2], L)); - } - phy_cell.pdcch.search_space[2].nof_formats = 2; - phy_cell.pdcch.search_space[2].formats[0] = srsran_dci_format_nr_0_0; // DCI format for PUSCH - phy_cell.pdcch.search_space[2].formats[1] = srsran_dci_format_nr_1_0; // DCI format for PDSCH - phy_cell.pdcch.search_space[2].duration = 1; - // PDSCH phy_cell.pdsch.rs_power = 0; phy_cell.pdsch.p_b = 0; @@ -91,29 +92,45 @@ void generate_default_nr_cell(rrc_cell_cfg_nr_t& cell) cell.coreset0_idx = 6; cell.ssb_absolute_freq_point = 0; // auto derived generate_default_nr_phy_cell(cell.phy_cell); -} -/// Generate CORESET#0 and SSB absolute frequency (if not specified) -int derive_coreset0_params(rrc_cell_cfg_nr_t& cell) -{ - // Generate CORESET#0 - cell.phy_cell.pdcch.coreset_present[0] = true; - // Get pointA and SSB absolute frequencies - double pointA_abs_freq_Hz = - cell.phy_cell.carrier.dl_center_frequency_hz - - cell.phy_cell.carrier.nof_prb * SRSRAN_NRE * SRSRAN_SUBC_SPACING_NR(cell.phy_cell.carrier.scs) / 2; - double ssb_abs_freq_Hz = cell.phy_cell.carrier.ssb_center_freq_hz; - // Calculate integer SSB to pointA frequency offset in Hz - uint32_t ssb_pointA_freq_offset_Hz = - (ssb_abs_freq_Hz > pointA_abs_freq_Hz) ? (uint32_t)(ssb_abs_freq_Hz - pointA_abs_freq_Hz) : 0; - int ret = srsran_coreset_zero(cell.phy_cell.carrier.pci, - ssb_pointA_freq_offset_Hz, - cell.ssb_scs, - cell.phy_cell.carrier.scs, - cell.coreset0_idx, - &cell.phy_cell.pdcch.coreset[0]); - ERROR_IF_NOT(ret == SRSRAN_SUCCESS, "Failed to generate CORESET#0"); - return SRSRAN_SUCCESS; + // PDCCH + // - Add CORESET#2 as UE-specific + cell.pdcch_cfg_ded.ctrl_res_set_to_add_mod_list.resize(1); + auto& coreset2 = cell.pdcch_cfg_ded.ctrl_res_set_to_add_mod_list[0]; + coreset2.ctrl_res_set_id = 2; + // Generate frequency resources for the full BW + for (uint32_t i = 0; i < SRSRAN_CORESET_FREQ_DOMAIN_RES_SIZE; i++) { + coreset2.freq_domain_res.set(i, i < SRSRAN_FLOOR(cell.phy_cell.carrier.nof_prb, 6)); + } + coreset2.dur = 1; + coreset2.cce_reg_map_type.set_non_interleaved(); + coreset2.precoder_granularity.value = asn1::rrc_nr::ctrl_res_set_s::precoder_granularity_opts::same_as_reg_bundle; + + // - Add SearchSpace#2 as UE-specific -> CORESET#2 + cell.pdcch_cfg_ded.search_spaces_to_add_mod_list.resize(1); + auto& ss2 = cell.pdcch_cfg_ded.search_spaces_to_add_mod_list[0]; + ss2.search_space_id = 2; + ss2.ctrl_res_set_id_present = true; + ss2.ctrl_res_set_id = coreset2.ctrl_res_set_id; + ss2.dur_present = false; // false for duration=1 + ss2.monitoring_slot_periodicity_and_offset_present = true; + ss2.monitoring_slot_periodicity_and_offset.set_sl1(); + ss2.monitoring_symbols_within_slot_present = true; + ss2.monitoring_symbols_within_slot.from_number(0b10000000000000); + ss2.search_space_type_present = true; + ss2.search_space_type.set_ue_specific().dci_formats.value = asn1::rrc_nr::search_space_s::search_space_type_c_:: + ue_specific_s_::dci_formats_opts::formats0_minus0_and_minus1_minus0; + ss2.nrof_candidates_present = true; + uint32_t nof_cand = SRSRAN_MIN(coreset_get_pdcch_nr_max_candidates(coreset2, 0), 2); + asn1::number_to_enum(ss2.nrof_candidates.aggregation_level1, nof_cand); + nof_cand = SRSRAN_MIN(coreset_get_pdcch_nr_max_candidates(coreset2, 1), 2); + asn1::number_to_enum(ss2.nrof_candidates.aggregation_level2, nof_cand); + nof_cand = SRSRAN_MIN(coreset_get_pdcch_nr_max_candidates(coreset2, 2), 2); + asn1::number_to_enum(ss2.nrof_candidates.aggregation_level4, nof_cand); + nof_cand = SRSRAN_MIN(coreset_get_pdcch_nr_max_candidates(coreset2, 3), 2); + asn1::number_to_enum(ss2.nrof_candidates.aggregation_level8, nof_cand); + nof_cand = SRSRAN_MIN(coreset_get_pdcch_nr_max_candidates(coreset2, 4), 2); + asn1::number_to_enum(ss2.nrof_candidates.aggregation_level16, nof_cand); } int derive_ssb_params(bool is_sa, @@ -243,66 +260,65 @@ int set_derived_nr_cell_params(bool is_sa, rrc_cell_cfg_nr_t& cell) cell.ssb_absolute_freq_point = band_helper.freq_to_nr_arfcn(cell.ssb_freq_hz); // Derive remaining config params + cell.pdcch_cfg_common.common_search_space_list.resize(1); // SearchSpace#1 + auto& ss1 = cell.pdcch_cfg_common.common_search_space_list[0]; + ss1.search_space_id = 1; + ss1.dur_present = false; // false for duration=1 + ss1.monitoring_slot_periodicity_and_offset_present = true; + ss1.monitoring_slot_periodicity_and_offset.set_sl1(); + ss1.monitoring_symbols_within_slot_present = true; + ss1.monitoring_symbols_within_slot.from_number(0b10000000000000); + ss1.nrof_candidates_present = true; + ss1.search_space_type_present = true; + ss1.search_space_type.set_common().dci_format0_minus0_and_format1_minus0_present = true; + cell.pdcch_cfg_common.ra_search_space_present = true; + cell.pdcch_cfg_common.ra_search_space = cell.pdcch_cfg_common.common_search_space_list[0].search_space_id; if (is_sa) { - derive_coreset0_params(cell); - cell.phy_cell.pdcch.search_space_present[0] = true; - cell.phy_cell.pdcch.search_space[0].id = 0; - cell.phy_cell.pdcch.search_space[0].coreset_id = 0; - cell.phy_cell.pdcch.search_space[0].type = srsran_search_space_type_common_0; - cell.phy_cell.pdcch.search_space[0].nof_candidates[0] = 1; - cell.phy_cell.pdcch.search_space[0].nof_candidates[1] = 1; - cell.phy_cell.pdcch.search_space[0].nof_candidates[2] = 1; - cell.phy_cell.pdcch.search_space[0].nof_candidates[3] = 0; - cell.phy_cell.pdcch.search_space[0].nof_candidates[4] = 0; - cell.phy_cell.pdcch.search_space[0].nof_formats = 1; - cell.phy_cell.pdcch.search_space[0].formats[0] = srsran_dci_format_nr_1_0; - cell.phy_cell.pdcch.search_space[0].duration = 1; - cell.phy_cell.pdcch.search_space_present[1] = true; - cell.phy_cell.pdcch.search_space[1].id = 1; - cell.phy_cell.pdcch.search_space[1].coreset_id = 0; - cell.phy_cell.pdcch.search_space[1].type = srsran_search_space_type_common_1; - cell.phy_cell.pdcch.search_space[1].nof_candidates[0] = 0; - cell.phy_cell.pdcch.search_space[1].nof_candidates[1] = 0; - cell.phy_cell.pdcch.search_space[1].nof_candidates[2] = 1; - cell.phy_cell.pdcch.search_space[1].nof_candidates[3] = 0; - cell.phy_cell.pdcch.search_space[1].nof_candidates[4] = 0; - cell.phy_cell.pdcch.search_space[1].nof_formats = 2; - cell.phy_cell.pdcch.search_space[1].formats[0] = srsran_dci_format_nr_0_0; // DCI format for PUSCH - cell.phy_cell.pdcch.search_space[1].formats[1] = srsran_dci_format_nr_1_0; // DCI format for PDSCH - cell.phy_cell.pdcch.search_space[1].duration = 1; + // Configure SearchSpace#1 -> CORESET#0 + ss1.ctrl_res_set_id_present = true; + ss1.ctrl_res_set_id = 0; + ss1.nrof_candidates.aggregation_level1.value = + asn1::rrc_nr::search_space_s::nrof_candidates_s_::aggregation_level1_opts::n0; + ss1.nrof_candidates.aggregation_level2.value = + asn1::rrc_nr::search_space_s::nrof_candidates_s_::aggregation_level2_opts::n0; + ss1.nrof_candidates.aggregation_level4.value = + asn1::rrc_nr::search_space_s::nrof_candidates_s_::aggregation_level4_opts::n1; + ss1.nrof_candidates.aggregation_level8.value = + asn1::rrc_nr::search_space_s::nrof_candidates_s_::aggregation_level8_opts::n0; + ss1.nrof_candidates.aggregation_level16.value = + asn1::rrc_nr::search_space_s::nrof_candidates_s_::aggregation_level16_opts::n0; } else { // Configure CORESET#1 - cell.phy_cell.pdcch.coreset_present[1] = true; - cell.phy_cell.pdcch.coreset[1].id = 1; - cell.phy_cell.pdcch.coreset[1].duration = 1; - cell.phy_cell.pdcch.coreset[1].mapping_type = srsran_coreset_mapping_type_non_interleaved; - cell.phy_cell.pdcch.coreset[1].precoder_granularity = srsran_coreset_precoder_granularity_reg_bundle; - + // Note: In NSA, Common CORESET is passed in RRC Reconfiguration + cell.pdcch_cfg_common.common_ctrl_res_set_present = true; + auto& coreset1 = cell.pdcch_cfg_common.common_ctrl_res_set; + coreset1.ctrl_res_set_id = 1; // Generate frequency resources for the full BW - for (uint32_t i = 0; i < SRSRAN_CORESET_FREQ_DOMAIN_RES_SIZE; i++) { - cell.phy_cell.pdcch.coreset[1].freq_resources[i] = i < SRSRAN_FLOOR(cell.phy_cell.carrier.nof_prb, 6); + for (uint32_t i = 0; i < SRSRAN_CORESET_FREQ_DOMAIN_RES_SIZE; ++i) { + coreset1.freq_domain_res.set(i, i < SRSRAN_FLOOR(cell.phy_cell.carrier.nof_prb, 6)); } + coreset1.dur = 1; + coreset1.cce_reg_map_type.set_non_interleaved(); + coreset1.precoder_granularity.value = asn1::rrc_nr::ctrl_res_set_s::precoder_granularity_opts::same_as_reg_bundle; // Configure SearchSpace#1 -> CORESET#1 - cell.phy_cell.pdcch.search_space_present[1] = true; - cell.phy_cell.pdcch.search_space[1].id = 1; - cell.phy_cell.pdcch.search_space[1].coreset_id = 1; - cell.phy_cell.pdcch.search_space[1].type = srsran_search_space_type_common_3; - // Generate frequency resources for the full BW - for (uint32_t L = 0; L < SRSRAN_SEARCH_SPACE_NOF_AGGREGATION_LEVELS_NR; L++) { - cell.phy_cell.pdcch.search_space[1].nof_candidates[L] = - SRSRAN_MIN(2, srsran_pdcch_nr_max_candidates_coreset(&cell.phy_cell.pdcch.coreset[1], L)); - } - cell.phy_cell.pdcch.search_space[1].nof_formats = 2; - cell.phy_cell.pdcch.search_space[1].formats[0] = srsran_dci_format_nr_0_0; // DCI format for PUSCH - cell.phy_cell.pdcch.search_space[1].formats[1] = srsran_dci_format_nr_1_0; // DCI format for PDSCH - cell.phy_cell.pdcch.search_space[1].duration = 1; + ss1.ctrl_res_set_id_present = true; + ss1.ctrl_res_set_id = coreset1.ctrl_res_set_id; + uint32_t nof_cand = SRSRAN_MIN(coreset_get_pdcch_nr_max_candidates(coreset1, 0), 2); + asn1::number_to_enum(ss1.nrof_candidates.aggregation_level1, nof_cand); + nof_cand = SRSRAN_MIN(coreset_get_pdcch_nr_max_candidates(coreset1, 1), 2); + asn1::number_to_enum(ss1.nrof_candidates.aggregation_level2, nof_cand); + nof_cand = SRSRAN_MIN(coreset_get_pdcch_nr_max_candidates(coreset1, 2), 2); + asn1::number_to_enum(ss1.nrof_candidates.aggregation_level4, nof_cand); + nof_cand = SRSRAN_MIN(coreset_get_pdcch_nr_max_candidates(coreset1, 3), 2); + asn1::number_to_enum(ss1.nrof_candidates.aggregation_level8, nof_cand); + nof_cand = SRSRAN_MIN(coreset_get_pdcch_nr_max_candidates(coreset1, 4), 2); + asn1::number_to_enum(ss1.nrof_candidates.aggregation_level16, nof_cand); + ss1.search_space_type_present = true; + ss1.search_space_type.set_common().dci_format0_minus0_and_format1_minus0_present = true; + // cell.phy_cell.pdcch.search_space[1].type = srsran_search_space_type_common_3; } - cell.phy_cell.pdcch.ra_search_space_present = true; - cell.phy_cell.pdcch.ra_search_space = cell.phy_cell.pdcch.search_space[1]; - cell.phy_cell.pdcch.ra_search_space.type = srsran_search_space_type_common_1; - // Derive remaining PHY cell params cell.phy_cell.prach.num_ra_preambles = cell.phy_cell.num_ra_preambles; cell.phy_cell.prach.tdd_config.configured = (cell.duplex_mode == SRSRAN_DUPLEX_MODE_TDD); @@ -327,16 +343,11 @@ int check_nr_cell_cfg_valid(const rrc_cell_cfg_nr_t& cell, bool is_sa) // verify SSB params are consistent HANDLE_ERROR(check_nr_phy_cell_cfg_valid(cell.phy_cell)); - if (is_sa) { - ERROR_IF_NOT(cell.phy_cell.pdcch.coreset_present[0], "CORESET#0 must be defined in Standalone mode"); - } - return SRSRAN_SUCCESS; } int check_nr_phy_cell_cfg_valid(const phy_cell_cfg_nr_t& phy_cell) { - HANDLE_ERROR(check_nr_pdcch_cfg_valid(phy_cell.pdcch)); return SRSRAN_SUCCESS; } diff --git a/srsgnb/src/stack/rrc/rrc_nr_du_manager.cc b/srsgnb/src/stack/rrc/rrc_nr_du_manager.cc index 7faf37b17..0b8f2f4f0 100644 --- a/srsgnb/src/stack/rrc/rrc_nr_du_manager.cc +++ b/srsgnb/src/stack/rrc/rrc_nr_du_manager.cc @@ -12,6 +12,7 @@ #include "srsgnb/hdr/stack/rrc/rrc_nr_du_manager.h" #include "srsgnb/hdr/stack/rrc/cell_asn1_config.h" +#include "srsran/asn1/rrc_nr_utils.h" #include "srsran/common/string_helpers.h" using namespace asn1::rrc_nr; @@ -89,8 +90,60 @@ int du_config_manager::add_cell() cell.sib1.to_json(js); logger.info("SIB1 content: %s", js.to_string().c_str()); + // Generate SSB SCS + srsran_subcarrier_spacing_t ssb_scs; + if (not srsran::fill_ssb_pattern_scs(cfg.cell_list[cell.cc].phy_cell.carrier, &cell.ssb_pattern, &ssb_scs)) { + return SRSRAN_ERROR; + } + cell.ssb_scs.value = (subcarrier_spacing_e::options)ssb_scs; + cell.ssb_center_freq_hz = cfg.cell_list[cell.cc].ssb_freq_hz; + cell.dl_freq_hz = cfg.cell_list[cell.cc].phy_cell.carrier.dl_center_frequency_hz; + cells.push_back(std::move(obj)); return SRSRAN_SUCCESS; } +void fill_phy_pdcch_cfg_common(const du_cell_config& cell, srsran_pdcch_cfg_nr_t* pdcch) +{ + const serving_cell_cfg_common_sib_s& serv_cell = cell.serv_cell_cfg_common(); + const pdcch_cfg_common_s& pdcch_common = serv_cell.dl_cfg_common.init_dl_bwp.pdcch_cfg_common.setup(); + + bool is_sa = pdcch_common.ctrl_res_set_zero_present; + uint8_t coreset0_idx = pdcch_common.ctrl_res_set_zero; + auto scs = (srsran_subcarrier_spacing_t)serv_cell.dl_cfg_common.init_dl_bwp.generic_params.subcarrier_spacing.value; + auto ssb_scs = (srsran_subcarrier_spacing_t)cell.ssb_scs.value; + uint32_t nof_prb = serv_cell.dl_cfg_common.freq_info_dl.scs_specific_carrier_list[0].carrier_bw; + + if (is_sa) { + // Generate CORESET#0 + pdcch->coreset_present[0] = true; + // Get pointA and SSB absolute frequencies + double pointA_abs_freq_Hz = cell.dl_freq_hz - nof_prb * SRSRAN_NRE * SRSRAN_SUBC_SPACING_NR(scs) / 2; + double ssb_abs_freq_Hz = cell.ssb_center_freq_hz; + // Calculate integer SSB to pointA frequency offset in Hz + uint32_t ssb_pointA_freq_offset_Hz = + (ssb_abs_freq_Hz > pointA_abs_freq_Hz) ? (uint32_t)(ssb_abs_freq_Hz - pointA_abs_freq_Hz) : 0; + int ret = srsran_coreset_zero(cell.pci, ssb_pointA_freq_offset_Hz, ssb_scs, scs, coreset0_idx, &pdcch->coreset[0]); + srsran_assert(ret == SRSRAN_SUCCESS, "Failed to generate CORESET#0"); + + // Generate SearchSpace#0 + pdcch->search_space_present[0] = true; + pdcch->search_space[0].id = 0; + pdcch->search_space[0].coreset_id = 0; + pdcch->search_space[0].type = srsran_search_space_type_common_0; + pdcch->search_space[0].nof_candidates[0] = 1; + pdcch->search_space[0].nof_candidates[1] = 1; + pdcch->search_space[0].nof_candidates[2] = 1; + pdcch->search_space[0].nof_candidates[3] = 0; + pdcch->search_space[0].nof_candidates[4] = 0; + pdcch->search_space[0].nof_formats = 1; + pdcch->search_space[0].formats[0] = srsran_dci_format_nr_1_0; + pdcch->search_space[0].duration = 1; + } + + // Generate Common CORESETs and Search Spaces + bool ret = srsran::fill_phy_pdcch_cfg_common(pdcch_common, pdcch); + srsran_assert(ret, "PDCCH Config Common"); +} + } // namespace srsenb \ No newline at end of file diff --git a/srsgnb/src/stack/rrc/rrc_nr_ue.cc b/srsgnb/src/stack/rrc/rrc_nr_ue.cc index 194e36d1a..9a7cb2601 100644 --- a/srsgnb/src/stack/rrc/rrc_nr_ue.cc +++ b/srsgnb/src/stack/rrc/rrc_nr_ue.cc @@ -39,7 +39,9 @@ rrc_nr::ue::ue(rrc_nr* parent_, uint16_t rnti_, uint32_t pcell_cc_idx, bool star if (not parent->cfg.is_standalone) { // Add the final PDCCH config in case of NSA - uecfg.phy_cfg.pdcch = parent->cfg.cell_list[0].phy_cell.pdcch; + srsran::fill_phy_pdcch_cfg( + parent->cell_ctxt->master_cell_group->sp_cell_cfg.sp_cell_cfg_ded.init_dl_bwp.pdcch_cfg.setup(), + &uecfg.phy_cfg.pdcch); } else { cell_group_cfg = *parent->cell_ctxt->master_cell_group; next_cell_group_cfg = cell_group_cfg; @@ -1479,13 +1481,11 @@ int rrc_nr::ue::update_mac(const cell_group_cfg_s& cell_group_config, bool is_co auto& pdcch = cell_group_config.sp_cell_cfg.sp_cell_cfg_ded.init_dl_bwp.pdcch_cfg.setup(); for (auto& ss : pdcch.search_spaces_to_add_mod_list) { uecfg.phy_cfg.pdcch.search_space_present[ss.search_space_id] = true; - uecfg.phy_cfg.pdcch.search_space[ss.search_space_id] = - parent->cfg.cell_list[0].phy_cell.pdcch.search_space[ss.search_space_id]; + srsran::make_phy_search_space_cfg(ss, &uecfg.phy_cfg.pdcch.search_space[ss.search_space_id]); } for (auto& cs : pdcch.ctrl_res_set_to_add_mod_list) { uecfg.phy_cfg.pdcch.coreset_present[cs.ctrl_res_set_id] = true; - uecfg.phy_cfg.pdcch.coreset[cs.ctrl_res_set_id] = - parent->cfg.cell_list[0].phy_cell.pdcch.coreset[cs.ctrl_res_set_id]; + srsran::make_phy_coreset_cfg(cs, &uecfg.phy_cfg.pdcch.coreset[cs.ctrl_res_set_id]); } } diff --git a/test/phy/nr_phy_test.cc b/test/phy/nr_phy_test.cc index 2d163128e..9fb47b0cf 100644 --- a/test/phy/nr_phy_test.cc +++ b/test/phy/nr_phy_test.cc @@ -185,7 +185,6 @@ test_bench::args_t::args_t(int argc, char** argv) cell_list[0].carrier = phy_cfg.carrier; cell_list[0].rf_port = 0; cell_list[0].cell_id = 0; - cell_list[0].pdcch = phy_cfg.pdcch; ue_stack.rnti = rnti; From c0dda2958c4c3b27c0edc94129e74c13404be722 Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Mon, 7 Feb 2022 16:06:59 +0000 Subject: [PATCH 51/62] rrc,gnb: fix search space NSA config --- lib/src/asn1/rrc_nr_utils.cc | 2 +- srsgnb/hdr/stack/rrc/rrc_nr_du_manager.h | 1 + srsgnb/src/stack/rrc/cell_asn1_config.cc | 2 +- srsgnb/src/stack/rrc/rrc_nr_config_utils.cc | 151 +++++++++----------- srsgnb/src/stack/rrc/rrc_nr_du_manager.cc | 19 +-- 5 files changed, 82 insertions(+), 93 deletions(-) diff --git a/lib/src/asn1/rrc_nr_utils.cc b/lib/src/asn1/rrc_nr_utils.cc index 204b9a9b7..ac3ca653e 100644 --- a/lib/src/asn1/rrc_nr_utils.cc +++ b/lib/src/asn1/rrc_nr_utils.cc @@ -1792,7 +1792,7 @@ bool fill_phy_pdcch_cfg_common(const asn1::rrc_nr::pdcch_cfg_common_s& pdcch_cfg pdcch->ra_search_space = pdcch->search_space[ss.search_space_id]; pdcch->ra_search_space.type = srsran_search_space_type_common_1; pdcch->ra_search_space.nof_formats = 1; - pdcch->ra_search_space.formats[1] = srsran_dci_format_nr_1_0; + pdcch->ra_search_space.formats[0] = srsran_dci_format_nr_1_0; } } return true; diff --git a/srsgnb/hdr/stack/rrc/rrc_nr_du_manager.h b/srsgnb/hdr/stack/rrc/rrc_nr_du_manager.h index d0f930a8a..94f14d29e 100644 --- a/srsgnb/hdr/stack/rrc/rrc_nr_du_manager.h +++ b/srsgnb/hdr/stack/rrc/rrc_nr_du_manager.h @@ -35,6 +35,7 @@ public: srsran_ssb_patern_t ssb_pattern; double ssb_center_freq_hz; double dl_freq_hz; + bool is_standalone; const asn1::rrc_nr::serving_cell_cfg_common_sib_s& serv_cell_cfg_common() const { diff --git a/srsgnb/src/stack/rrc/cell_asn1_config.cc b/srsgnb/src/stack/rrc/cell_asn1_config.cc index 4080a5fd2..83b87920f 100644 --- a/srsgnb/src/stack/rrc/cell_asn1_config.cc +++ b/srsgnb/src/stack/rrc/cell_asn1_config.cc @@ -1054,7 +1054,7 @@ void fill_pdcch_cfg_common(const rrc_nr_cfg_t& cfg, uint32_t cc, pdcch_cfg_commo out.common_ctrl_res_set_present = cell_cfg.pdcch_cfg_common.common_ctrl_res_set_present; out.common_ctrl_res_set = cell_cfg.pdcch_cfg_common.common_ctrl_res_set; - out.common_search_space_list = cell_cfg.pdcch_cfg_ded.search_spaces_to_add_mod_list; + out.common_search_space_list = cell_cfg.pdcch_cfg_common.common_search_space_list; out.search_space_sib1_present = true; out.search_space_sib1 = 0; diff --git a/srsgnb/src/stack/rrc/rrc_nr_config_utils.cc b/srsgnb/src/stack/rrc/rrc_nr_config_utils.cc index fbf29d151..0c05133dc 100644 --- a/srsgnb/src/stack/rrc/rrc_nr_config_utils.cc +++ b/srsgnb/src/stack/rrc/rrc_nr_config_utils.cc @@ -28,6 +28,8 @@ } \ } while (0) +using namespace asn1::rrc_nr; + namespace srsenb { uint32_t coreset_get_bw(const asn1::rrc_nr::ctrl_res_set_s& coreset) @@ -57,6 +59,48 @@ int coreset_get_pdcch_nr_max_candidates(const asn1::rrc_nr::ctrl_res_set_s& core return SRSRAN_MIN(nof_candidates, SRSRAN_SEARCH_SPACE_MAX_NOF_CANDIDATES_NR); } +ctrl_res_set_s make_default_coreset(uint8_t coreset_id, uint32_t nof_prb) +{ + ctrl_res_set_s coreset; + coreset.ctrl_res_set_id = coreset_id; + // Generate frequency resources for the full BW + for (uint32_t i = 0; i < SRSRAN_CORESET_FREQ_DOMAIN_RES_SIZE; i++) { + coreset.freq_domain_res.set(coreset.freq_domain_res.length() - i - 1, i < SRSRAN_FLOOR(nof_prb, 6)); + } + coreset.dur = 1; + coreset.cce_reg_map_type.set_non_interleaved(); + coreset.precoder_granularity.value = ctrl_res_set_s::precoder_granularity_opts::same_as_reg_bundle; + return coreset; +} + +search_space_s make_default_common_search_space(uint8_t ss_id, const ctrl_res_set_s& cs) +{ + search_space_s ss; + ss.search_space_id = ss_id; + ss.ctrl_res_set_id_present = true; + ss.ctrl_res_set_id = cs.ctrl_res_set_id; + ss.dur_present = false; // false for duration=1 + ss.monitoring_slot_periodicity_and_offset_present = true; + ss.monitoring_slot_periodicity_and_offset.set_sl1(); + ss.monitoring_symbols_within_slot_present = true; + ss.monitoring_symbols_within_slot.from_number(0b10000000000000); + ss.search_space_type_present = true; + ss.search_space_type.set_common().dci_format0_minus0_and_format1_minus0_present = true; + ss.nrof_candidates_present = true; + uint32_t nof_cand = SRSRAN_MIN(coreset_get_pdcch_nr_max_candidates(cs, 0), 2); + asn1::number_to_enum(ss.nrof_candidates.aggregation_level1, nof_cand); + nof_cand = SRSRAN_MIN(coreset_get_pdcch_nr_max_candidates(cs, 1), 2); + asn1::number_to_enum(ss.nrof_candidates.aggregation_level2, nof_cand); + nof_cand = SRSRAN_MIN(coreset_get_pdcch_nr_max_candidates(cs, 2), 2); + asn1::number_to_enum(ss.nrof_candidates.aggregation_level4, nof_cand); + nof_cand = SRSRAN_MIN(coreset_get_pdcch_nr_max_candidates(cs, 3), 2); + asn1::number_to_enum(ss.nrof_candidates.aggregation_level8, nof_cand); + nof_cand = SRSRAN_MIN(coreset_get_pdcch_nr_max_candidates(cs, 4), 2); + asn1::number_to_enum(ss.nrof_candidates.aggregation_level16, nof_cand); + + return ss; +} + /// Generate default phy cell configuration void generate_default_nr_phy_cell(phy_cell_cfg_nr_t& phy_cell) { @@ -77,7 +121,7 @@ void generate_default_nr_phy_cell(phy_cell_cfg_nr_t& phy_cell) phy_cell.prach.freq_offset = 1; // msg1-FrequencyStart (zero not supported with current PRACH implementation) phy_cell.prach.zero_corr_zone = 0; phy_cell.prach.num_ra_preambles = phy_cell.num_ra_preambles; - phy_cell.prach.hs_flag = false; + phy_cell.prach.hs_flag = false; phy_cell.prach.tdd_config.configured = false; // PDSCH @@ -96,41 +140,15 @@ void generate_default_nr_cell(rrc_cell_cfg_nr_t& cell) // PDCCH // - Add CORESET#2 as UE-specific cell.pdcch_cfg_ded.ctrl_res_set_to_add_mod_list.resize(1); - auto& coreset2 = cell.pdcch_cfg_ded.ctrl_res_set_to_add_mod_list[0]; - coreset2.ctrl_res_set_id = 2; - // Generate frequency resources for the full BW - for (uint32_t i = 0; i < SRSRAN_CORESET_FREQ_DOMAIN_RES_SIZE; i++) { - coreset2.freq_domain_res.set(i, i < SRSRAN_FLOOR(cell.phy_cell.carrier.nof_prb, 6)); - } - coreset2.dur = 1; - coreset2.cce_reg_map_type.set_non_interleaved(); - coreset2.precoder_granularity.value = asn1::rrc_nr::ctrl_res_set_s::precoder_granularity_opts::same_as_reg_bundle; + auto& coreset2 = cell.pdcch_cfg_ded.ctrl_res_set_to_add_mod_list[0]; + coreset2 = make_default_coreset(2, cell.phy_cell.carrier.nof_prb); // - Add SearchSpace#2 as UE-specific -> CORESET#2 cell.pdcch_cfg_ded.search_spaces_to_add_mod_list.resize(1); - auto& ss2 = cell.pdcch_cfg_ded.search_spaces_to_add_mod_list[0]; - ss2.search_space_id = 2; - ss2.ctrl_res_set_id_present = true; - ss2.ctrl_res_set_id = coreset2.ctrl_res_set_id; - ss2.dur_present = false; // false for duration=1 - ss2.monitoring_slot_periodicity_and_offset_present = true; - ss2.monitoring_slot_periodicity_and_offset.set_sl1(); - ss2.monitoring_symbols_within_slot_present = true; - ss2.monitoring_symbols_within_slot.from_number(0b10000000000000); - ss2.search_space_type_present = true; + auto& ss2 = cell.pdcch_cfg_ded.search_spaces_to_add_mod_list[0]; + ss2 = make_default_common_search_space(2, coreset2); ss2.search_space_type.set_ue_specific().dci_formats.value = asn1::rrc_nr::search_space_s::search_space_type_c_:: ue_specific_s_::dci_formats_opts::formats0_minus0_and_minus1_minus0; - ss2.nrof_candidates_present = true; - uint32_t nof_cand = SRSRAN_MIN(coreset_get_pdcch_nr_max_candidates(coreset2, 0), 2); - asn1::number_to_enum(ss2.nrof_candidates.aggregation_level1, nof_cand); - nof_cand = SRSRAN_MIN(coreset_get_pdcch_nr_max_candidates(coreset2, 1), 2); - asn1::number_to_enum(ss2.nrof_candidates.aggregation_level2, nof_cand); - nof_cand = SRSRAN_MIN(coreset_get_pdcch_nr_max_candidates(coreset2, 2), 2); - asn1::number_to_enum(ss2.nrof_candidates.aggregation_level4, nof_cand); - nof_cand = SRSRAN_MIN(coreset_get_pdcch_nr_max_candidates(coreset2, 3), 2); - asn1::number_to_enum(ss2.nrof_candidates.aggregation_level8, nof_cand); - nof_cand = SRSRAN_MIN(coreset_get_pdcch_nr_max_candidates(coreset2, 4), 2); - asn1::number_to_enum(ss2.nrof_candidates.aggregation_level16, nof_cand); } int derive_ssb_params(bool is_sa, @@ -260,64 +278,31 @@ int set_derived_nr_cell_params(bool is_sa, rrc_cell_cfg_nr_t& cell) cell.ssb_absolute_freq_point = band_helper.freq_to_nr_arfcn(cell.ssb_freq_hz); // Derive remaining config params - cell.pdcch_cfg_common.common_search_space_list.resize(1); // SearchSpace#1 - auto& ss1 = cell.pdcch_cfg_common.common_search_space_list[0]; - ss1.search_space_id = 1; - ss1.dur_present = false; // false for duration=1 - ss1.monitoring_slot_periodicity_and_offset_present = true; - ss1.monitoring_slot_periodicity_and_offset.set_sl1(); - ss1.monitoring_symbols_within_slot_present = true; - ss1.monitoring_symbols_within_slot.from_number(0b10000000000000); - ss1.nrof_candidates_present = true; - ss1.search_space_type_present = true; - ss1.search_space_type.set_common().dci_format0_minus0_and_format1_minus0_present = true; - cell.pdcch_cfg_common.ra_search_space_present = true; - cell.pdcch_cfg_common.ra_search_space = cell.pdcch_cfg_common.common_search_space_list[0].search_space_id; - if (is_sa) { - // Configure SearchSpace#1 -> CORESET#0 - ss1.ctrl_res_set_id_present = true; - ss1.ctrl_res_set_id = 0; - ss1.nrof_candidates.aggregation_level1.value = - asn1::rrc_nr::search_space_s::nrof_candidates_s_::aggregation_level1_opts::n0; - ss1.nrof_candidates.aggregation_level2.value = - asn1::rrc_nr::search_space_s::nrof_candidates_s_::aggregation_level2_opts::n0; - ss1.nrof_candidates.aggregation_level4.value = - asn1::rrc_nr::search_space_s::nrof_candidates_s_::aggregation_level4_opts::n1; - ss1.nrof_candidates.aggregation_level8.value = - asn1::rrc_nr::search_space_s::nrof_candidates_s_::aggregation_level8_opts::n0; - ss1.nrof_candidates.aggregation_level16.value = - asn1::rrc_nr::search_space_s::nrof_candidates_s_::aggregation_level16_opts::n0; - } else { + if (not is_sa) { // Configure CORESET#1 - // Note: In NSA, Common CORESET is passed in RRC Reconfiguration cell.pdcch_cfg_common.common_ctrl_res_set_present = true; - auto& coreset1 = cell.pdcch_cfg_common.common_ctrl_res_set; - coreset1.ctrl_res_set_id = 1; - // Generate frequency resources for the full BW - for (uint32_t i = 0; i < SRSRAN_CORESET_FREQ_DOMAIN_RES_SIZE; ++i) { - coreset1.freq_domain_res.set(i, i < SRSRAN_FLOOR(cell.phy_cell.carrier.nof_prb, 6)); - } - coreset1.dur = 1; - coreset1.cce_reg_map_type.set_non_interleaved(); - coreset1.precoder_granularity.value = asn1::rrc_nr::ctrl_res_set_s::precoder_granularity_opts::same_as_reg_bundle; + cell.pdcch_cfg_common.common_ctrl_res_set = make_default_coreset(1, cell.phy_cell.carrier.nof_prb); + } + // Configure SearchSpace#1 + cell.pdcch_cfg_common.common_search_space_list.resize(1); + auto& ss1 = cell.pdcch_cfg_common.common_search_space_list[0]; + if (is_sa) { + // Configure SearchSpace#1 -> CORESET#0 + ctrl_res_set_s dummy_coreset = make_default_coreset(0, cell.phy_cell.carrier.nof_prb); + ss1 = make_default_common_search_space(1, dummy_coreset); + ss1.nrof_candidates.aggregation_level1.value = search_space_s::nrof_candidates_s_::aggregation_level1_opts::n0; + ss1.nrof_candidates.aggregation_level2.value = search_space_s::nrof_candidates_s_::aggregation_level2_opts::n0; + ss1.nrof_candidates.aggregation_level4.value = search_space_s::nrof_candidates_s_::aggregation_level4_opts::n1; + ss1.nrof_candidates.aggregation_level8.value = search_space_s::nrof_candidates_s_::aggregation_level8_opts::n0; + ss1.nrof_candidates.aggregation_level16.value = search_space_s::nrof_candidates_s_::aggregation_level16_opts::n0; + } else { // Configure SearchSpace#1 -> CORESET#1 - ss1.ctrl_res_set_id_present = true; - ss1.ctrl_res_set_id = coreset1.ctrl_res_set_id; - uint32_t nof_cand = SRSRAN_MIN(coreset_get_pdcch_nr_max_candidates(coreset1, 0), 2); - asn1::number_to_enum(ss1.nrof_candidates.aggregation_level1, nof_cand); - nof_cand = SRSRAN_MIN(coreset_get_pdcch_nr_max_candidates(coreset1, 1), 2); - asn1::number_to_enum(ss1.nrof_candidates.aggregation_level2, nof_cand); - nof_cand = SRSRAN_MIN(coreset_get_pdcch_nr_max_candidates(coreset1, 2), 2); - asn1::number_to_enum(ss1.nrof_candidates.aggregation_level4, nof_cand); - nof_cand = SRSRAN_MIN(coreset_get_pdcch_nr_max_candidates(coreset1, 3), 2); - asn1::number_to_enum(ss1.nrof_candidates.aggregation_level8, nof_cand); - nof_cand = SRSRAN_MIN(coreset_get_pdcch_nr_max_candidates(coreset1, 4), 2); - asn1::number_to_enum(ss1.nrof_candidates.aggregation_level16, nof_cand); - ss1.search_space_type_present = true; - ss1.search_space_type.set_common().dci_format0_minus0_and_format1_minus0_present = true; + ss1 = make_default_common_search_space(1, cell.pdcch_cfg_common.common_ctrl_res_set); // cell.phy_cell.pdcch.search_space[1].type = srsran_search_space_type_common_3; } + cell.pdcch_cfg_common.ra_search_space_present = true; + cell.pdcch_cfg_common.ra_search_space = ss1.search_space_id; // Derive remaining PHY cell params cell.phy_cell.prach.num_ra_preambles = cell.phy_cell.num_ra_preambles; diff --git a/srsgnb/src/stack/rrc/rrc_nr_du_manager.cc b/srsgnb/src/stack/rrc/rrc_nr_du_manager.cc index 0b8f2f4f0..5c9e01a56 100644 --- a/srsgnb/src/stack/rrc/rrc_nr_du_manager.cc +++ b/srsgnb/src/stack/rrc/rrc_nr_du_manager.cc @@ -83,12 +83,14 @@ int du_config_manager::add_cell() } cell.packed_sib1->N_bytes = bref.distance_bytes(); } - logger.info(cell.packed_sib1->data(), - cell.packed_sib1->size(), - "BCCH-DL-SCH-Message (with SIB1) (%d B)", - cell.packed_sib1->size()); - cell.sib1.to_json(js); - logger.info("SIB1 content: %s", js.to_string().c_str()); + if (cfg.is_standalone) { + logger.info(cell.packed_sib1->data(), + cell.packed_sib1->size(), + "BCCH-DL-SCH-Message (with SIB1) (%d B)", + cell.packed_sib1->size()); + cell.sib1.to_json(js); + logger.info("SIB1 content: %s", js.to_string().c_str()); + } // Generate SSB SCS srsran_subcarrier_spacing_t ssb_scs; @@ -98,6 +100,7 @@ int du_config_manager::add_cell() cell.ssb_scs.value = (subcarrier_spacing_e::options)ssb_scs; cell.ssb_center_freq_hz = cfg.cell_list[cell.cc].ssb_freq_hz; cell.dl_freq_hz = cfg.cell_list[cell.cc].phy_cell.carrier.dl_center_frequency_hz; + cell.is_standalone = cfg.is_standalone; cells.push_back(std::move(obj)); return SRSRAN_SUCCESS; @@ -108,8 +111,8 @@ void fill_phy_pdcch_cfg_common(const du_cell_config& cell, srsran_pdcch_cfg_nr_t const serving_cell_cfg_common_sib_s& serv_cell = cell.serv_cell_cfg_common(); const pdcch_cfg_common_s& pdcch_common = serv_cell.dl_cfg_common.init_dl_bwp.pdcch_cfg_common.setup(); - bool is_sa = pdcch_common.ctrl_res_set_zero_present; - uint8_t coreset0_idx = pdcch_common.ctrl_res_set_zero; + bool is_sa = cell.is_standalone; + uint8_t coreset0_idx = cell.mib.pdcch_cfg_sib1.ctrl_res_set_zero; auto scs = (srsran_subcarrier_spacing_t)serv_cell.dl_cfg_common.init_dl_bwp.generic_params.subcarrier_spacing.value; auto ssb_scs = (srsran_subcarrier_spacing_t)cell.ssb_scs.value; uint32_t nof_prb = serv_cell.dl_cfg_common.freq_info_dl.scs_specific_carrier_list[0].carrier_bw; From 21c3a448b7b76ae7c152dbf30aecbfe6b734e436 Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Mon, 7 Feb 2022 15:53:34 +0100 Subject: [PATCH 52/62] mac_sch_pdu_nr: fix UL-CCCH packing fix MAC PDU packing issue for UL-CCCH that uses only 6 B SDU. If the SDU fits inside 6 B, the LCID for Msg3 should be set to be CCCH48 instead of CCCH64. --- lib/src/mac/mac_sch_pdu_nr.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/src/mac/mac_sch_pdu_nr.cc b/lib/src/mac/mac_sch_pdu_nr.cc index b606e9d38..240752f49 100644 --- a/lib/src/mac/mac_sch_pdu_nr.cc +++ b/lib/src/mac/mac_sch_pdu_nr.cc @@ -98,7 +98,8 @@ int32_t mac_sch_subpdu_nr::read_subheader(const uint8_t* ptr) void mac_sch_subpdu_nr::set_sdu(const uint32_t lcid_, const uint8_t* payload_, const uint32_t len_) { - lcid = lcid_; + // Use CCCH_SIZE_48 when SDU len fits + lcid = (lcid_ == CCCH_SIZE_64 && len_ == sizeof_ce(CCCH_SIZE_48, true)) ? CCCH_SIZE_48 : lcid_; sdu.set_storage_to(const_cast(payload_)); header_length = is_ul_ccch() ? 1 : 2; sdu_length = len_; From 32885e24045c01803c892c740ef9856c3711a050 Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Mon, 7 Feb 2022 15:55:10 +0100 Subject: [PATCH 53/62] ue, rrc_nr: refactor PHY config statages for NSA/SA operation split the PHY config states into NSA and SA states. this should remove unwanted warnings when PHY returns from the configuration. --- srsue/hdr/stack/rrc_nr/rrc_nr.h | 6 ++++-- srsue/src/stack/rrc_nr/rrc_nr.cc | 24 ++++++++++++++------- srsue/src/stack/rrc_nr/rrc_nr_procedures.cc | 3 --- 3 files changed, 20 insertions(+), 13 deletions(-) diff --git a/srsue/hdr/stack/rrc_nr/rrc_nr.h b/srsue/hdr/stack/rrc_nr/rrc_nr.h index c9d8e9655..8696b87fa 100644 --- a/srsue/hdr/stack/rrc_nr/rrc_nr.h +++ b/srsue/hdr/stack/rrc_nr/rrc_nr.h @@ -197,8 +197,10 @@ private: // Stores the state of the PHY configuration setting enum { PHY_CFG_STATE_NONE = 0, - PHY_CFG_STATE_APPLY_SP_CELL, - PHY_CFG_STATE_RA_COMPLETED, + PHY_CFG_STATE_SA_SIB_CFG, + PHY_CFG_STATE_SA_FULL_CFG, + PHY_CFG_STATE_NSA_APPLY_SP_CELL, + PHY_CFG_STATE_NSA_RA_COMPLETED, } phy_cfg_state; rrc_nr_args_t args = {}; diff --git a/srsue/src/stack/rrc_nr/rrc_nr.cc b/srsue/src/stack/rrc_nr/rrc_nr.cc index fc788a206..7bb35d5f4 100644 --- a/srsue/src/stack/rrc_nr/rrc_nr.cc +++ b/srsue/src/stack/rrc_nr/rrc_nr.cc @@ -472,6 +472,7 @@ void rrc_nr::handle_sib1(const sib1_s& sib1) // Apply SSB Config fill_phy_ssb_cfg(sib1.serving_cell_cfg_common, &phy_cfg.ssb); + phy_cfg_state = PHY_CFG_STATE_SA_SIB_CFG; if (not phy->set_config(phy_cfg)) { logger.warning("Could not set phy config."); return; @@ -582,7 +583,10 @@ void rrc_nr::send_ul_ccch_msg(const asn1::rrc_nr::ul_ccch_msg_s& msg) } asn1::bit_ref bref(pdu->msg, pdu->get_tailroom()); - msg.pack(bref); + if (msg.pack(bref) != SRSASN_SUCCESS) { + logger.error("Coulnd't pack UL-CCCH message."); + return; + } bref.align_bytes_zero(); pdu->N_bytes = (uint32_t)bref.distance_bytes(pdu->msg); pdu->set_timestamp(); @@ -1589,8 +1593,6 @@ bool rrc_nr::apply_sp_cell_cfg(const sp_cell_cfg_s& sp_cell_cfg) { update_sp_cell_cfg(sp_cell_cfg); - phy_cfg_state = PHY_CFG_STATE_APPLY_SP_CELL; - return true; } @@ -1768,9 +1770,11 @@ bool rrc_nr::update_sp_cell_cfg(const sp_cell_cfg_s& sp_cell_cfg) // defer CSI config until after RA complete srsran::phy_cfg_nr_t current_phycfg = phy_cfg; current_phycfg.csi = prev_csi; + phy_cfg_state = PHY_CFG_STATE_NSA_APPLY_SP_CELL; phy->set_config(current_phycfg); } else { // apply full config immediately + phy_cfg_state = PHY_CFG_STATE_SA_FULL_CFG; phy->set_config(phy_cfg); } @@ -1793,8 +1797,6 @@ bool rrc_nr::apply_cell_group_cfg(const cell_group_cfg_s& cell_group_cfg) { update_cell_group_cfg(cell_group_cfg); - phy_cfg_state = PHY_CFG_STATE_APPLY_SP_CELL; - return true; } @@ -2102,8 +2104,8 @@ void rrc_nr::ra_completed() logger.info("RA completed."); if (rrc_eutra) { logger.debug("Applying remaining CSI configuration."); + phy_cfg_state = PHY_CFG_STATE_NSA_RA_COMPLETED; phy->set_config(phy_cfg); - phy_cfg_state = PHY_CFG_STATE_RA_COMPLETED; } else { phy_cfg_state = PHY_CFG_STATE_NONE; } @@ -2146,12 +2148,18 @@ void rrc_nr::set_phy_config_complete(bool status) case PHY_CFG_STATE_NONE: logger.warning("PHY configuration completed without a clear state."); break; - case PHY_CFG_STATE_APPLY_SP_CELL: + case PHY_CFG_STATE_SA_SIB_CFG: + logger.info("PHY configuration with SIB parameters completed."); + break; + case PHY_CFG_STATE_SA_FULL_CFG: + logger.info("PHY configuration completed."); + break; + case PHY_CFG_STATE_NSA_APPLY_SP_CELL: // Start RA procedure logger.info("PHY configuration completed. Starting RA procedure."); mac->start_ra_procedure(); break; - case PHY_CFG_STATE_RA_COMPLETED: + case PHY_CFG_STATE_NSA_RA_COMPLETED: logger.info("Remaining CSI configuration completed."); break; } diff --git a/srsue/src/stack/rrc_nr/rrc_nr_procedures.cc b/srsue/src/stack/rrc_nr/rrc_nr_procedures.cc index 864eb5fe0..8b90b007f 100644 --- a/srsue/src/stack/rrc_nr/rrc_nr_procedures.cc +++ b/srsue/src/stack/rrc_nr/rrc_nr_procedures.cc @@ -220,9 +220,6 @@ proc_outcome_t rrc_nr::setup_request_proc::step() if (state == state_t::config_serving_cell) { // TODO: start serving cell config and start T300 - rrc_handle.phy_cfg_state = PHY_CFG_STATE_APPLY_SP_CELL; - rrc_handle.phy->set_config(rrc_handle.phy_cfg); - // start T300 rrc_handle.t300.run(); From 2c2c1857e9e4a5f5a799beb9999fd890cf349da1 Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Tue, 8 Feb 2022 10:53:36 +0100 Subject: [PATCH 54/62] enb_phy_test: fix uninitialized memory --- srsenb/test/phy/enb_phy_test.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/srsenb/test/phy/enb_phy_test.cc b/srsenb/test/phy/enb_phy_test.cc index a18948d43..2a02834f0 100644 --- a/srsenb/test/phy/enb_phy_test.cc +++ b/srsenb/test/phy/enb_phy_test.cc @@ -1209,8 +1209,8 @@ private: srslog::basic_logger& logger; args_t args = {}; ///< Test arguments - srsenb::phy_args_t phy_args; ///< PHY arguments - srsenb::phy_cfg_t phy_cfg; ///< eNb Cell/Carrier configuration + srsenb::phy_args_t phy_args = {}; ///< PHY arguments + srsenb::phy_cfg_t phy_cfg = {}; ///< eNb Cell/Carrier configuration srsenb::phy_interface_rrc_lte::phy_rrc_cfg_list_t phy_rrc_cfg; ///< UE PHY configuration uint64_t tti_counter = 0; From c4cc94df1725d0f2d6608f66f06f10c355fe204d Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Fri, 4 Feb 2022 18:10:45 +0000 Subject: [PATCH 55/62] rrc,gnb: remove phy flat pdcch cfg struct from rrc nr cfg --- srsgnb/src/stack/rrc/rrc_nr_du_manager.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/srsgnb/src/stack/rrc/rrc_nr_du_manager.cc b/srsgnb/src/stack/rrc/rrc_nr_du_manager.cc index 5c9e01a56..8e8b965c7 100644 --- a/srsgnb/src/stack/rrc/rrc_nr_du_manager.cc +++ b/srsgnb/src/stack/rrc/rrc_nr_du_manager.cc @@ -149,4 +149,4 @@ void fill_phy_pdcch_cfg_common(const du_cell_config& cell, srsran_pdcch_cfg_nr_t srsran_assert(ret, "PDCCH Config Common"); } -} // namespace srsenb \ No newline at end of file +} // namespace srsenb From e8902c785fd2ffdb818781fbff57e6cfdbcced98 Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Mon, 7 Feb 2022 19:39:14 +0000 Subject: [PATCH 56/62] rrc,gnb: remove srsran_prach_cfg_t from gnb rrc config struct --- lib/include/srsran/asn1/rrc_nr_utils.h | 5 +- lib/src/asn1/rrc_nr_utils.cc | 53 ++++++++++-- srsenb/src/enb_cfg_parser.cc | 3 - srsgnb/hdr/stack/mac/sched_nr_interface.h | 1 - .../src/stack/mac/sched_nr_interface_utils.cc | 12 +-- .../stack/mac/test/sched_nr_cfg_generators.h | 3 +- srsgnb/src/stack/rrc/cell_asn1_config.cc | 84 ++++++++++++++----- srsgnb/src/stack/rrc/rrc_nr.cc | 4 +- srsgnb/src/stack/rrc/rrc_nr_config_utils.cc | 18 ---- srsue/src/stack/rrc_nr/rrc_nr.cc | 10 ++- 10 files changed, 132 insertions(+), 61 deletions(-) diff --git a/lib/include/srsran/asn1/rrc_nr_utils.h b/lib/include/srsran/asn1/rrc_nr_utils.h index d08dce7ae..a9815b262 100644 --- a/lib/include/srsran/asn1/rrc_nr_utils.h +++ b/lib/include/srsran/asn1/rrc_nr_utils.h @@ -81,7 +81,10 @@ void to_asn1(asn1::rrc_nr::plmn_id_s* asn1_type, const plmn_id_t& cfg); /*************************** * PHY Config **************************/ -bool make_phy_rach_cfg(const asn1::rrc_nr::rach_cfg_common_s& asn1_type, srsran_prach_cfg_t* prach_cfg); +bool make_phy_rach_cfg(const asn1::rrc_nr::rach_cfg_common_s& asn1_type, + srsran_duplex_mode_t duplex_mode, + srsran_prach_cfg_t* prach_cfg); +bool fill_rach_cfg_common(const srsran_prach_cfg_t& prach_cfg, asn1::rrc_nr::rach_cfg_common_s& asn1_type); bool make_phy_tdd_cfg(const asn1::rrc_nr::tdd_ul_dl_cfg_common_s& tdd_ul_dl_cfg_common, srsran_duplex_config_nr_t* srsran_duplex_config_nr); diff --git a/lib/src/asn1/rrc_nr_utils.cc b/lib/src/asn1/rrc_nr_utils.cc index ac3ca653e..056d7f4c4 100644 --- a/lib/src/asn1/rrc_nr_utils.cc +++ b/lib/src/asn1/rrc_nr_utils.cc @@ -272,14 +272,22 @@ srsran::pdcp_config_t make_drb_pdcp_config_t(const uint8_t bearer_id, bool is_ue return cfg; } -bool make_phy_rach_cfg(const rach_cfg_common_s& asn1_type, srsran_prach_cfg_t* prach_cfg) +bool make_phy_rach_cfg(const rach_cfg_common_s& asn1_type, + srsran_duplex_mode_t duplex_mode, + srsran_prach_cfg_t* prach_cfg) { prach_cfg->is_nr = true; prach_cfg->config_idx = asn1_type.rach_cfg_generic.prach_cfg_idx; prach_cfg->zero_corr_zone = (uint32_t)asn1_type.rach_cfg_generic.zero_correlation_zone_cfg; - prach_cfg->num_ra_preambles = 64; // Hard-coded - prach_cfg->hs_flag = false; // Hard-coded - prach_cfg->tdd_config = {}; // Hard-coded + prach_cfg->num_ra_preambles = 64; + if (asn1_type.total_nof_ra_preambs_present) { + prach_cfg->num_ra_preambles = asn1_type.total_nof_ra_preambs; + } + prach_cfg->hs_flag = false; // Hard-coded + prach_cfg->tdd_config = {}; + if (duplex_mode == SRSRAN_DUPLEX_MODE_TDD) { + prach_cfg->tdd_config.configured = true; + } // As the current PRACH is based on LTE, the freq-offset shall be subtracted 1 for aligning with NR bandwidth // For example. A 52 PRB cell with an freq_offset of 1 will match a LTE 50 PRB cell with freq_offset of 0 @@ -289,11 +297,12 @@ bool make_phy_rach_cfg(const rach_cfg_common_s& asn1_type, srsran_prach_cfg_t* p return false; } - switch (prach_cfg->root_seq_idx = asn1_type.prach_root_seq_idx.type()) { + switch (asn1_type.prach_root_seq_idx.type().value) { case rach_cfg_common_s::prach_root_seq_idx_c_::types_opts::l839: prach_cfg->root_seq_idx = (uint32_t)asn1_type.prach_root_seq_idx.l839(); break; case rach_cfg_common_s::prach_root_seq_idx_c_::types_opts::l139: + prach_cfg->root_seq_idx = (uint32_t)asn1_type.prach_root_seq_idx.l139(); default: asn1::log_error("Not-implemented option for prach_root_seq_idx type %s", asn1_type.prach_root_seq_idx.type().to_string()); @@ -303,6 +312,40 @@ bool make_phy_rach_cfg(const rach_cfg_common_s& asn1_type, srsran_prach_cfg_t* p return true; }; +bool fill_rach_cfg_common(const srsran_prach_cfg_t& prach_cfg, asn1::rrc_nr::rach_cfg_common_s& asn1_type) +{ + asn1_type = {}; + // rach-ConfigGeneric + asn1_type.rach_cfg_generic.prach_cfg_idx = prach_cfg.config_idx; + asn1_type.rach_cfg_generic.msg1_fdm.value = rach_cfg_generic_s::msg1_fdm_opts::one; + asn1_type.rach_cfg_generic.msg1_freq_start = prach_cfg.freq_offset; + asn1_type.rach_cfg_generic.zero_correlation_zone_cfg = prach_cfg.zero_corr_zone; + asn1_type.rach_cfg_generic.preamb_rx_target_pwr = -110; + asn1_type.rach_cfg_generic.preamb_trans_max.value = rach_cfg_generic_s::preamb_trans_max_opts::n7; + asn1_type.rach_cfg_generic.pwr_ramp_step.value = rach_cfg_generic_s::pwr_ramp_step_opts::db4; + asn1_type.rach_cfg_generic.ra_resp_win.value = rach_cfg_generic_s::ra_resp_win_opts::sl10; + + // totalNumberOfRA-Preambles + if (prach_cfg.num_ra_preambles != 64) { + asn1_type.total_nof_ra_preambs_present = true; + asn1_type.total_nof_ra_preambs = prach_cfg.num_ra_preambles; + } + + // ssb-perRACH-OccasionAndCB-PreamblesPerSSB + asn1_type.ssb_per_rach_occasion_and_cb_preambs_per_ssb_present = true; + if (not asn1::number_to_enum(asn1_type.ssb_per_rach_occasion_and_cb_preambs_per_ssb.set_one(), + prach_cfg.num_ra_preambles)) { + asn1::log_error("Invalid number of RA preambles=%d", prach_cfg.num_ra_preambles); + return false; + } + + asn1_type.ra_contention_resolution_timer.value = rach_cfg_common_s::ra_contention_resolution_timer_opts::sf64; + asn1_type.prach_root_seq_idx.set_l839() = prach_cfg.root_seq_idx; + asn1_type.restricted_set_cfg.value = rach_cfg_common_s::restricted_set_cfg_opts::unrestricted_set; + + return true; +} + bool make_phy_tdd_cfg(const tdd_ul_dl_cfg_common_s& tdd_ul_dl_cfg_common, srsran_duplex_config_nr_t* in_srsran_duplex_config_nr) { diff --git a/srsenb/src/enb_cfg_parser.cc b/srsenb/src/enb_cfg_parser.cc index 343376f34..ee3fc8db8 100644 --- a/srsenb/src/enb_cfg_parser.cc +++ b/srsenb/src/enb_cfg_parser.cc @@ -1593,9 +1593,6 @@ int set_derived_args_nr(all_args_t* args_, rrc_nr_cfg_t* rrc_nr_cfg_, phy_cfg_t* // phy_cell_cfg.root_seq_idx = cfg.root_seq_idx; - // PRACH - cfg.phy_cell.prach.hs_flag = phy_cfg_->prach_cnfg.prach_cfg_info.high_speed_flag; - // PDSCH cfg.phy_cell.pdsch.rs_power = phy_cfg_->pdsch_cnfg.ref_sig_pwr; cfg.phy_cell.pdsch.p_b = phy_cfg_->pdsch_cnfg.p_b; diff --git a/srsgnb/hdr/stack/mac/sched_nr_interface.h b/srsgnb/hdr/stack/mac/sched_nr_interface.h index edb14fdcd..d27808718 100644 --- a/srsgnb/hdr/stack/mac/sched_nr_interface.h +++ b/srsgnb/hdr/stack/mac/sched_nr_interface.h @@ -63,7 +63,6 @@ struct sched_nr_bwp_cfg_t { srsran_sch_hl_cfg_nr_t pdsch = {}; srsran_sch_hl_cfg_nr_t pusch = {}; srsran_pucch_nr_hl_cfg_t pucch = {}; - srsran_prach_cfg_t prach = {}; srsran_harq_ack_cfg_hl_t harq_ack = {}; uint32_t rar_window_size = 10; // See TS 38.331, ra-ResponseWindow: {1, 2, 4, 8, 10, 20, 40, 80} uint32_t numerology_idx = 0; diff --git a/srsgnb/src/stack/mac/sched_nr_interface_utils.cc b/srsgnb/src/stack/mac/sched_nr_interface_utils.cc index c50e572b2..39f57451c 100644 --- a/srsgnb/src/stack/mac/sched_nr_interface_utils.cc +++ b/srsgnb/src/stack/mac/sched_nr_interface_utils.cc @@ -71,11 +71,13 @@ srsran::phy_cfg_nr_t get_common_ue_phy_cfg(const sched_nr_cell_cfg_t& cfg) srsran_sanity_check(success, "Failed to convert Cell TDDConfig to UEPHYConfig"); } - ue_phy_cfg.pdcch = cfg.bwps[0].pdcch; - ue_phy_cfg.pdsch = cfg.bwps[0].pdsch; - ue_phy_cfg.pusch = cfg.bwps[0].pusch; - ue_phy_cfg.pucch = cfg.bwps[0].pucch; - ue_phy_cfg.prach = cfg.bwps[0].prach; + ue_phy_cfg.pdcch = cfg.bwps[0].pdcch; + ue_phy_cfg.pdsch = cfg.bwps[0].pdsch; + ue_phy_cfg.pusch = cfg.bwps[0].pusch; + ue_phy_cfg.pucch = cfg.bwps[0].pucch; + srsran::make_phy_rach_cfg(cfg.ul_cfg_common.init_ul_bwp.rach_cfg_common.setup(), + cfg.tdd_ul_dl_cfg_common.has_value() ? SRSRAN_DUPLEX_MODE_TDD : SRSRAN_DUPLEX_MODE_FDD, + &ue_phy_cfg.prach); ue_phy_cfg.harq_ack = cfg.bwps[0].harq_ack; ue_phy_cfg.csi = {}; // disable CSI until RA is complete ue_phy_cfg.carrier.pci = cfg.pci; diff --git a/srsgnb/src/stack/mac/test/sched_nr_cfg_generators.h b/srsgnb/src/stack/mac/test/sched_nr_cfg_generators.h index dc7744224..e48bf0619 100644 --- a/srsgnb/src/stack/mac/test/sched_nr_cfg_generators.h +++ b/srsgnb/src/stack/mac/test/sched_nr_cfg_generators.h @@ -60,6 +60,8 @@ inline sched_nr_cell_cfg_t get_default_cell_cfg(const srsran::phy_cfg_nr_t& phy_ phy_cfg.carrier.offset_to_carrier; cell_cfg.dl_cfg_common.init_dl_bwp.generic_params.subcarrier_spacing = (asn1::rrc_nr::subcarrier_spacing_opts::options)phy_cfg.carrier.scs; + cell_cfg.ul_cfg_common.init_ul_bwp.rach_cfg_common_present = true; + srsran::fill_rach_cfg_common(phy_cfg.prach, cell_cfg.ul_cfg_common.init_ul_bwp.rach_cfg_common.set_setup()); cell_cfg.dl_cell_nof_prb = phy_cfg.carrier.nof_prb; cell_cfg.nof_layers = phy_cfg.carrier.max_mimo_layers; cell_cfg.ssb_periodicity_ms = phy_cfg.ssb.periodicity_ms; @@ -77,7 +79,6 @@ inline sched_nr_cell_cfg_t get_default_cell_cfg(const srsran::phy_cfg_nr_t& phy_ cell_cfg.bwps[0].pdsch = phy_cfg.pdsch; cell_cfg.bwps[0].pusch = phy_cfg.pusch; cell_cfg.bwps[0].pucch = phy_cfg.pucch; - cell_cfg.bwps[0].prach = phy_cfg.prach; cell_cfg.bwps[0].harq_ack = phy_cfg.harq_ack; cell_cfg.bwps[0].rb_width = phy_cfg.carrier.nof_prb; diff --git a/srsgnb/src/stack/rrc/cell_asn1_config.cc b/srsgnb/src/stack/rrc/cell_asn1_config.cc index 83b87920f..d9558528f 100644 --- a/srsgnb/src/stack/rrc/cell_asn1_config.cc +++ b/srsgnb/src/stack/rrc/cell_asn1_config.cc @@ -796,11 +796,48 @@ int fill_freq_info_ul_from_enb_cfg(const rrc_nr_cfg_t& cfg, uint32_t cc, freq_in return SRSRAN_SUCCESS; } +int fill_rach_cfg_common(const rrc_nr_cfg_t& cfg, uint32_t cc, rach_cfg_common_s& rach) +{ + // rach-ConfigGeneric + rach.rach_cfg_generic.prach_cfg_idx = 0; + if (cfg.cell_list[cc].duplex_mode == SRSRAN_DUPLEX_MODE_TDD) { + // Note: Give more time margin to fit RAR + rach.rach_cfg_generic.prach_cfg_idx = 8; + } + rach.rach_cfg_generic.msg1_fdm.value = rach_cfg_generic_s::msg1_fdm_opts::one; + rach.rach_cfg_generic.msg1_freq_start = 1; // zero not supported with current PRACH implementation + rach.rach_cfg_generic.zero_correlation_zone_cfg = 0; + rach.rach_cfg_generic.preamb_rx_target_pwr = -110; + rach.rach_cfg_generic.preamb_trans_max.value = rach_cfg_generic_s::preamb_trans_max_opts::n7; + rach.rach_cfg_generic.pwr_ramp_step.value = rach_cfg_generic_s::pwr_ramp_step_opts::db4; + rach.rach_cfg_generic.ra_resp_win.value = rach_cfg_generic_s::ra_resp_win_opts::sl10; + + // totalNumberOfRA-Preambles + if (cfg.cell_list[cc].phy_cell.num_ra_preambles != 64) { + rach.total_nof_ra_preambs_present = true; + rach.total_nof_ra_preambs = cfg.cell_list[cc].phy_cell.num_ra_preambles; + } + + // ssb-perRACH-OccasionAndCB-PreamblesPerSSB + rach.ssb_per_rach_occasion_and_cb_preambs_per_ssb_present = true; + if (not asn1::number_to_enum(rach.ssb_per_rach_occasion_and_cb_preambs_per_ssb.set_one(), + cfg.cell_list[cc].phy_cell.num_ra_preambles)) { + get_logger(cfg).error("Invalid number of RA preambles=%d", cfg.cell_list[cc].phy_cell.num_ra_preambles); + return -1; + } + + rach.ra_contention_resolution_timer.value = rach_cfg_common_s::ra_contention_resolution_timer_opts::sf64; + rach.prach_root_seq_idx.set_l839() = cfg.cell_list[cc].phy_cell.root_seq_idx; + rach.restricted_set_cfg.value = rach_cfg_common_s::restricted_set_cfg_opts::unrestricted_set; + + return SRSRAN_SUCCESS; +} + /// Fill InitUlBwp with gNB config int fill_init_ul_bwp_from_enb_cfg(const rrc_nr_cfg_t& cfg, uint32_t cc, bwp_ul_common_s& init_ul_bwp) { init_ul_bwp.rach_cfg_common_present = true; - set_rach_cfg_common(cfg.cell_list[cc].phy_cell.prach, init_ul_bwp.rach_cfg_common.set_setup()); + HANDLE_ERROR(fill_rach_cfg_common(cfg, cc, init_ul_bwp.rach_cfg_common.set_setup())); // TODO: Add missing fields @@ -1120,36 +1157,37 @@ void fill_dl_cfg_common_sib(const rrc_nr_cfg_t& cfg, uint32_t cc, dl_cfg_common_ out.pcch_cfg.ns.value = pcch_cfg_s::ns_opts::one; } -void fill_ul_cfg_common_sib(const rrc_cell_cfg_nr_t& cell_cfg, ul_cfg_common_sib_s& cfg) +void fill_ul_cfg_common_sib(const rrc_nr_cfg_t& cfg, uint32_t cc, ul_cfg_common_sib_s& out) { + auto& cell_cfg = cfg.cell_list[cc]; srsran::srsran_band_helper band_helper; - cfg.freq_info_ul.freq_band_list.resize(1); - cfg.freq_info_ul.freq_band_list[0].freq_band_ind_nr_present = true; - cfg.freq_info_ul.freq_band_list[0].freq_band_ind_nr = cell_cfg.band; + out.freq_info_ul.freq_band_list.resize(1); + out.freq_info_ul.freq_band_list[0].freq_band_ind_nr_present = true; + out.freq_info_ul.freq_band_list[0].freq_band_ind_nr = cell_cfg.band; - cfg.freq_info_ul.absolute_freq_point_a_present = true; - cfg.freq_info_ul.absolute_freq_point_a = + out.freq_info_ul.absolute_freq_point_a_present = true; + out.freq_info_ul.absolute_freq_point_a = band_helper.get_abs_freq_point_a_arfcn(cell_cfg.phy_cell.carrier.nof_prb, cell_cfg.ul_arfcn); - cfg.freq_info_ul.scs_specific_carrier_list.resize(1); - cfg.freq_info_ul.scs_specific_carrier_list[0].offset_to_carrier = cell_cfg.phy_cell.carrier.offset_to_carrier; - cfg.freq_info_ul.scs_specific_carrier_list[0].subcarrier_spacing = + out.freq_info_ul.scs_specific_carrier_list.resize(1); + out.freq_info_ul.scs_specific_carrier_list[0].offset_to_carrier = cell_cfg.phy_cell.carrier.offset_to_carrier; + out.freq_info_ul.scs_specific_carrier_list[0].subcarrier_spacing = (subcarrier_spacing_opts::options)cell_cfg.phy_cell.carrier.scs; - cfg.freq_info_ul.scs_specific_carrier_list[0].carrier_bw = cell_cfg.phy_cell.carrier.nof_prb; + out.freq_info_ul.scs_specific_carrier_list[0].carrier_bw = cell_cfg.phy_cell.carrier.nof_prb; - cfg.freq_info_ul.p_max_present = true; - cfg.freq_info_ul.p_max = 10; + out.freq_info_ul.p_max_present = true; + out.freq_info_ul.p_max = 10; - cfg.init_ul_bwp.generic_params.location_and_bw = 14025; - cfg.init_ul_bwp.generic_params.subcarrier_spacing.value = + out.init_ul_bwp.generic_params.location_and_bw = 14025; + out.init_ul_bwp.generic_params.subcarrier_spacing.value = (subcarrier_spacing_opts::options)cell_cfg.phy_cell.carrier.scs; - cfg.init_ul_bwp.rach_cfg_common_present = true; - set_rach_cfg_common(cell_cfg.phy_cell.prach, cfg.init_ul_bwp.rach_cfg_common.set_setup()); + out.init_ul_bwp.rach_cfg_common_present = true; + fill_rach_cfg_common(cfg, cc, out.init_ul_bwp.rach_cfg_common.set_setup()); - cfg.init_ul_bwp.pusch_cfg_common_present = true; - pusch_cfg_common_s& pusch = cfg.init_ul_bwp.pusch_cfg_common.set_setup(); + out.init_ul_bwp.pusch_cfg_common_present = true; + pusch_cfg_common_s& pusch = out.init_ul_bwp.pusch_cfg_common.set_setup(); pusch.pusch_time_domain_alloc_list.resize(1); pusch.pusch_time_domain_alloc_list[0].k2_present = true; pusch.pusch_time_domain_alloc_list[0].k2 = 4; @@ -1158,15 +1196,15 @@ void fill_ul_cfg_common_sib(const rrc_cell_cfg_nr_t& cell_cfg, ul_cfg_common_sib pusch.p0_nominal_with_grant_present = true; pusch.p0_nominal_with_grant = -76; - cfg.init_ul_bwp.pucch_cfg_common_present = true; - pucch_cfg_common_s& pucch = cfg.init_ul_bwp.pucch_cfg_common.set_setup(); + out.init_ul_bwp.pucch_cfg_common_present = true; + pucch_cfg_common_s& pucch = out.init_ul_bwp.pucch_cfg_common.set_setup(); pucch.pucch_res_common_present = true; pucch.pucch_res_common = 11; pucch.pucch_group_hop.value = pucch_cfg_common_s::pucch_group_hop_opts::neither; pucch.p0_nominal_present = true; pucch.p0_nominal = -90; - cfg.time_align_timer_common.value = time_align_timer_opts::infinity; + out.time_align_timer_common.value = time_align_timer_opts::infinity; } int fill_serv_cell_cfg_common_sib(const rrc_nr_cfg_t& cfg, uint32_t cc, serving_cell_cfg_common_sib_s& out) @@ -1176,7 +1214,7 @@ int fill_serv_cell_cfg_common_sib(const rrc_nr_cfg_t& cfg, uint32_t cc, serving_ fill_dl_cfg_common_sib(cfg, cc, out.dl_cfg_common); out.ul_cfg_common_present = true; - fill_ul_cfg_common_sib(cell_cfg, out.ul_cfg_common); + fill_ul_cfg_common_sib(cfg, cc, out.ul_cfg_common); out.ssb_positions_in_burst.in_one_group.from_number(0x80); diff --git a/srsgnb/src/stack/rrc/rrc_nr.cc b/srsgnb/src/stack/rrc/rrc_nr.cc index 9ab5cc2a4..8b0c0129c 100644 --- a/srsgnb/src/stack/rrc/rrc_nr.cc +++ b/srsgnb/src/stack/rrc/rrc_nr.cc @@ -277,7 +277,9 @@ void rrc_nr::config_phy() bool ret = srsran::fill_phy_pdcch_cfg( cell_ctxt->master_cell_group->sp_cell_cfg.sp_cell_cfg_ded.init_dl_bwp.pdcch_cfg.setup(), &common_cfg.pdcch); srsran_assert(ret, "Failed to generate Dedicated PDCCH config"); - common_cfg.prach = cfg.cell_list[0].phy_cell.prach; + srsran::make_phy_rach_cfg(du_cfg->cell(0).serv_cell_cfg_common().ul_cfg_common.init_ul_bwp.rach_cfg_common.setup(), + cfg.cell_list[0].duplex_mode, + &common_cfg.prach); common_cfg.duplex_mode = cfg.cell_list[0].duplex_mode; ret = srsran::fill_phy_ssb_cfg( cfg.cell_list[0].phy_cell.carrier, du_cfg->cell(0).serv_cell_cfg_common(), &common_cfg.ssb); diff --git a/srsgnb/src/stack/rrc/rrc_nr_config_utils.cc b/srsgnb/src/stack/rrc/rrc_nr_config_utils.cc index 0c05133dc..04eb42ce4 100644 --- a/srsgnb/src/stack/rrc/rrc_nr_config_utils.cc +++ b/srsgnb/src/stack/rrc/rrc_nr_config_utils.cc @@ -114,16 +114,6 @@ void generate_default_nr_phy_cell(phy_cell_cfg_nr_t& phy_cell) phy_cell.ul_freq_hz = 0; phy_cell.num_ra_preambles = 8; - // PRACH - phy_cell.prach.is_nr = true; - phy_cell.prach.config_idx = 0; - phy_cell.prach.root_seq_idx = 1; - phy_cell.prach.freq_offset = 1; // msg1-FrequencyStart (zero not supported with current PRACH implementation) - phy_cell.prach.zero_corr_zone = 0; - phy_cell.prach.num_ra_preambles = phy_cell.num_ra_preambles; - phy_cell.prach.hs_flag = false; - phy_cell.prach.tdd_config.configured = false; - // PDSCH phy_cell.pdsch.rs_power = 0; phy_cell.pdsch.p_b = 0; @@ -304,14 +294,6 @@ int set_derived_nr_cell_params(bool is_sa, rrc_cell_cfg_nr_t& cell) cell.pdcch_cfg_common.ra_search_space_present = true; cell.pdcch_cfg_common.ra_search_space = ss1.search_space_id; - // Derive remaining PHY cell params - cell.phy_cell.prach.num_ra_preambles = cell.phy_cell.num_ra_preambles; - cell.phy_cell.prach.tdd_config.configured = (cell.duplex_mode == SRSRAN_DUPLEX_MODE_TDD); - if (cell.duplex_mode == SRSRAN_DUPLEX_MODE_TDD) { - // Note: Give more time margin to fit RAR - cell.phy_cell.prach.config_idx = 8; - } - return check_nr_cell_cfg_valid(cell, is_sa); } diff --git a/srsue/src/stack/rrc_nr/rrc_nr.cc b/srsue/src/stack/rrc_nr/rrc_nr.cc index 7bb35d5f4..107b68af8 100644 --- a/srsue/src/stack/rrc_nr/rrc_nr.cc +++ b/srsue/src/stack/rrc_nr/rrc_nr.cc @@ -457,6 +457,8 @@ void rrc_nr::handle_sib1(const sib1_s& sib1) // Apply RACH Config Common if (not make_phy_rach_cfg(sib1.serving_cell_cfg_common.ul_cfg_common.init_ul_bwp.rach_cfg_common.setup(), + sib1.serving_cell_cfg_common.tdd_ul_dl_cfg_common_present ? SRSRAN_DUPLEX_MODE_TDD + : SRSRAN_DUPLEX_MODE_FDD, &phy_cfg.prach)) { logger.warning("Could not set phy rach config."); return; @@ -1355,7 +1357,8 @@ bool rrc_nr::apply_ul_common_cfg(const asn1::rrc_nr::ul_cfg_common_s& ul_cfg_com mac->set_config(rach_cfg_nr); // Make the RACH configuration for PHY - if (not make_phy_rach_cfg(ul_cfg_common.init_ul_bwp.rach_cfg_common.setup(), &phy_cfg.prach)) { + if (not make_phy_rach_cfg( + ul_cfg_common.init_ul_bwp.rach_cfg_common.setup(), SRSRAN_DUPLEX_MODE_FDD, &phy_cfg.prach)) { logger.warning("Error parsing rach_cfg_common"); return false; } @@ -1640,8 +1643,9 @@ bool rrc_nr::update_sp_cell_cfg(const sp_cell_cfg_s& sp_cell_cfg) if (recfg_with_sync.sp_cell_cfg_common.tdd_ul_dl_cfg_common_present) { logger.debug("TDD UL DL config present, using TDD"); srsran_duplex_config_nr_t duplex; - if (make_phy_tdd_cfg(recfg_with_sync.sp_cell_cfg_common.tdd_ul_dl_cfg_common, &duplex) == true) { - phy_cfg.duplex = duplex; + if (make_phy_tdd_cfg(recfg_with_sync.sp_cell_cfg_common.tdd_ul_dl_cfg_common, &duplex)) { + phy_cfg.duplex = duplex; + phy_cfg.prach.tdd_config.configured = true; } else { logger.warning("Warning while building duplex structure"); return false; From e9760f110a4fe1e224a1d6dfdc509942ca9711ac Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Mon, 7 Feb 2022 19:45:38 +0000 Subject: [PATCH 57/62] rrc,gnb: remove obsolete methods to verify config correctness --- srsgnb/hdr/stack/rrc/rrc_nr_config_utils.h | 7 ++--- srsgnb/src/stack/rrc/rrc_nr.cc | 2 -- srsgnb/src/stack/rrc/rrc_nr_config_utils.cc | 26 +------------------ srsgnb/src/stack/rrc/test/rrc_nr_core_test.cc | 1 - srsgnb/src/stack/rrc/test/rrc_nr_test.cc | 3 --- 5 files changed, 5 insertions(+), 34 deletions(-) diff --git a/srsgnb/hdr/stack/rrc/rrc_nr_config_utils.h b/srsgnb/hdr/stack/rrc/rrc_nr_config_utils.h index 3dbb90a32..c83483f19 100644 --- a/srsgnb/hdr/stack/rrc/rrc_nr_config_utils.h +++ b/srsgnb/hdr/stack/rrc/rrc_nr_config_utils.h @@ -17,6 +17,10 @@ namespace srsenb { +// Helper methods +uint32_t coreset_get_bw(const asn1::rrc_nr::ctrl_res_set_s& coreset); +int coreset_get_pdcch_nr_max_candidates(const asn1::rrc_nr::ctrl_res_set_s& coreset, uint32_t aggregation_level); + void generate_default_nr_cell(rrc_cell_cfg_nr_t& cell); int set_derived_nr_cell_params(bool is_sa, rrc_cell_cfg_nr_t& cell); @@ -24,10 +28,7 @@ int set_derived_nr_rrc_params(rrc_nr_cfg_t& rrc_cfg); // Tests to ensure validity of config -int check_nr_cell_cfg_valid(const rrc_cell_cfg_nr_t& cell, bool is_sa); -int check_nr_phy_cell_cfg_valid(const phy_cell_cfg_nr_t& phy_cell); int check_nr_pdcch_cfg_valid(const srsran_pdcch_cfg_nr_t& pdcch); -int check_rrc_nr_cfg_valid(const rrc_nr_cfg_t& cfg); } // namespace srsenb diff --git a/srsgnb/src/stack/rrc/rrc_nr.cc b/srsgnb/src/stack/rrc/rrc_nr.cc index 8b0c0129c..9a2ee009a 100644 --- a/srsgnb/src/stack/rrc/rrc_nr.cc +++ b/srsgnb/src/stack/rrc/rrc_nr.cc @@ -90,8 +90,6 @@ int rrc_nr::init(const rrc_nr_cfg_t& cfg_, return SRSRAN_ERROR; } - srsran_assert(check_nr_phy_cell_cfg_valid(cfg.cell_list[0].phy_cell) == SRSRAN_SUCCESS, "Invalid PhyCell Config"); - config_phy(); // if PHY is not yet initialized, config will be stored and applied on initialization config_mac(); diff --git a/srsgnb/src/stack/rrc/rrc_nr_config_utils.cc b/srsgnb/src/stack/rrc/rrc_nr_config_utils.cc index 04eb42ce4..a5cf4ed07 100644 --- a/srsgnb/src/stack/rrc/rrc_nr_config_utils.cc +++ b/srsgnb/src/stack/rrc/rrc_nr_config_utils.cc @@ -294,7 +294,7 @@ int set_derived_nr_cell_params(bool is_sa, rrc_cell_cfg_nr_t& cell) cell.pdcch_cfg_common.ra_search_space_present = true; cell.pdcch_cfg_common.ra_search_space = ss1.search_space_id; - return check_nr_cell_cfg_valid(cell, is_sa); + return SRSRAN_SUCCESS; } int set_derived_nr_rrc_params(rrc_nr_cfg_t& rrc_cfg) @@ -305,19 +305,6 @@ int set_derived_nr_rrc_params(rrc_nr_cfg_t& rrc_cfg) return SRSRAN_SUCCESS; } -int check_nr_cell_cfg_valid(const rrc_cell_cfg_nr_t& cell, bool is_sa) -{ - // verify SSB params are consistent - HANDLE_ERROR(check_nr_phy_cell_cfg_valid(cell.phy_cell)); - - return SRSRAN_SUCCESS; -} - -int check_nr_phy_cell_cfg_valid(const phy_cell_cfg_nr_t& phy_cell) -{ - return SRSRAN_SUCCESS; -} - int check_nr_pdcch_cfg_valid(const srsran_pdcch_cfg_nr_t& pdcch) { // Verify Search Spaces @@ -340,15 +327,4 @@ int check_nr_pdcch_cfg_valid(const srsran_pdcch_cfg_nr_t& pdcch) return SRSRAN_SUCCESS; } -int check_rrc_nr_cfg_valid(const rrc_nr_cfg_t& cfg) -{ - ERROR_IF_NOT(cfg.cell_list.size() > 0, "The number of NR cells must be positive"); - - for (const rrc_cell_cfg_nr_t& cell : cfg.cell_list) { - HANDLE_ERROR(check_nr_cell_cfg_valid(cell, cfg.is_standalone)); - } - - return SRSRAN_SUCCESS; -} - } // namespace srsenb diff --git a/srsgnb/src/stack/rrc/test/rrc_nr_core_test.cc b/srsgnb/src/stack/rrc/test/rrc_nr_core_test.cc index 27680fbb7..ad2060328 100644 --- a/srsgnb/src/stack/rrc/test/rrc_nr_core_test.cc +++ b/srsgnb/src/stack/rrc/test/rrc_nr_core_test.cc @@ -158,7 +158,6 @@ void test_rrc_sa_ngap_integration(ngap_args_t ngap_args) rrc_cfg_nr.cell_list[0].duplex_mode = SRSRAN_DUPLEX_MODE_FDD; rrc_cfg_nr.is_standalone = true; set_derived_nr_cell_params(rrc_cfg_nr.is_standalone, rrc_cfg_nr.cell_list[0]); - srsran_assert(check_rrc_nr_cfg_valid(rrc_cfg_nr) == SRSRAN_SUCCESS, "Invalid RRC NR configuration"); TESTASSERT( rrc_obj.init(rrc_cfg_nr, &phy_obj, &mac_obj, &rlc_obj, &pdcp_obj, &ngap_obj, >pu_obj, bearer_mapper, nullptr) == diff --git a/srsgnb/src/stack/rrc/test/rrc_nr_test.cc b/srsgnb/src/stack/rrc/test/rrc_nr_test.cc index 89fb19ba9..3d70c1961 100644 --- a/srsgnb/src/stack/rrc/test/rrc_nr_test.cc +++ b/srsgnb/src/stack/rrc/test/rrc_nr_test.cc @@ -62,7 +62,6 @@ void test_sib_generation() srsran::string_to_mcc("001", &rrc_cfg_nr.mcc); srsran::string_to_mnc("01", &rrc_cfg_nr.mnc); set_derived_nr_cell_params(rrc_cfg_nr.is_standalone, rrc_cfg_nr.cell_list[0]); - srsran_assert(check_rrc_nr_cfg_valid(rrc_cfg_nr) == SRSRAN_SUCCESS, "Invalid RRC NR configuration"); TESTASSERT( rrc_obj.init(rrc_cfg_nr, &phy_obj, &mac_obj, &rlc_obj, &pdcp_obj, nullptr, nullptr, bearer_mapper, nullptr) == @@ -119,7 +118,6 @@ int test_rrc_setup() srsran::string_to_mcc("001", &rrc_cfg_nr.mcc); srsran::string_to_mnc("01", &rrc_cfg_nr.mnc); set_derived_nr_cell_params(rrc_cfg_nr.is_standalone, rrc_cfg_nr.cell_list[0]); - srsran_assert(check_rrc_nr_cfg_valid(rrc_cfg_nr) == SRSRAN_SUCCESS, "Invalid RRC NR configuration"); TESTASSERT( rrc_obj.init(rrc_cfg_nr, &phy_obj, &mac_obj, &rlc_obj, &pdcp_obj, nullptr, nullptr, bearer_mapper, nullptr) == SRSRAN_SUCCESS); @@ -163,7 +161,6 @@ void test_rrc_sa_connection() srsran::string_to_mcc("001", &rrc_cfg_nr.mcc); srsran::string_to_mnc("01", &rrc_cfg_nr.mnc); set_derived_nr_cell_params(rrc_cfg_nr.is_standalone, rrc_cfg_nr.cell_list[0]); - srsran_assert(check_rrc_nr_cfg_valid(rrc_cfg_nr) == SRSRAN_SUCCESS, "Invalid RRC NR configuration"); TESTASSERT( rrc_obj.init(rrc_cfg_nr, &phy_obj, &mac_obj, &rlc_obj, &pdcp_obj, &ngap_obj, nullptr, bearer_mapper, nullptr) == From e4a15c9c51e2c02f9447711b494a6bf12128dbea Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Mon, 7 Feb 2022 21:44:31 +0000 Subject: [PATCH 58/62] rrc,gnb: move non-phy fields out of phy_cell_nr_t --- lib/include/srsran/asn1/rrc_nr_utils.h | 2 +- lib/include/srsran/common/band_helper.h | 4 ++-- lib/include/srsran/common/phy_cfg_nr.h | 2 +- .../srsran/interfaces/ue_nr_interfaces.h | 2 +- lib/include/srsran/phy/common/phy_common_nr.h | 6 +++--- lib/include/srsran/phy/sync/ssb.h | 2 +- lib/src/asn1/rrc_nr_utils.cc | 2 +- lib/src/common/band_helper.cc | 2 +- lib/src/phy/common/phy_common_nr.c | 4 ++-- lib/src/phy/sync/test/ssb_decode_test.c | 2 +- lib/src/phy/sync/test/ssb_file_test.c | 2 +- lib/src/phy/sync/test/ssb_grid_test.c | 2 +- lib/src/phy/sync/test/ssb_measure_test.c | 2 +- lib/src/phy/ue/test/ue_sync_nr_test.c | 2 +- srsenb/hdr/phy/phy_common.h | 4 ++-- srsenb/src/enb_cfg_parser.cc | 5 ++--- srsgnb/hdr/phy/phy_nr_interfaces.h | 14 ++++--------- srsgnb/hdr/stack/rrc/rrc_nr_config.h | 9 +++++--- srsgnb/hdr/stack/rrc/rrc_nr_du_manager.h | 2 +- srsgnb/src/stack/rrc/cell_asn1_config.cc | 14 ++++++------- srsgnb/src/stack/rrc/rrc_nr_config_utils.cc | 21 +++++-------------- srsue/hdr/phy/nr/cell_search.h | 2 +- srsue/src/phy/test/gnb_emulator.h | 2 +- srsue/src/phy/test/gnb_rf_emulator.h | 2 +- srsue/src/phy/test/nr_cell_search_test.cc | 2 +- srsue/src/phy/test/nr_sa_cell_search_test.cc | 4 ++-- 26 files changed, 51 insertions(+), 66 deletions(-) diff --git a/lib/include/srsran/asn1/rrc_nr_utils.h b/lib/include/srsran/asn1/rrc_nr_utils.h index a9815b262..8c77e399d 100644 --- a/lib/include/srsran/asn1/rrc_nr_utils.h +++ b/lib/include/srsran/asn1/rrc_nr_utils.h @@ -133,7 +133,7 @@ bool fill_phy_ssb_cfg(const srsran_carrier_nr_t& carrier void fill_ssb_pos_in_burst(const asn1::rrc_nr::serving_cell_cfg_common_sib_s& ssb_pos, phy_cfg_nr_t::ssb_cfg_t* out_ssb); bool fill_ssb_pattern_scs(const srsran_carrier_nr_t& carrier, - srsran_ssb_patern_t* pattern, + srsran_ssb_pattern_t* pattern, srsran_subcarrier_spacing_t* ssb_scs); bool fill_phy_ssb_cfg(const srsran_carrier_nr_t& carrier, const asn1::rrc_nr::serving_cell_cfg_common_sib_s& serv_cell_cfg, diff --git a/lib/include/srsran/common/band_helper.h b/lib/include/srsran/common/band_helper.h index cf4ceef2b..44ff136c2 100644 --- a/lib/include/srsran/common/band_helper.h +++ b/lib/include/srsran/common/band_helper.h @@ -80,7 +80,7 @@ public: * @param scs SSB Subcarrier spacing * @return The SSB pattern case if band and subcarrier spacing match, SRSRAN_SSB_PATTERN_INVALID otherwise */ - static srsran_ssb_patern_t get_ssb_pattern(uint16_t band, srsran_subcarrier_spacing_t scs); + static srsran_ssb_pattern_t get_ssb_pattern(uint16_t band, srsran_subcarrier_spacing_t scs); /** * @brief Select the lower SSB subcarrier spacing valid for this band @@ -402,7 +402,7 @@ private: struct nr_band_ss_raster { uint16_t band; srsran_subcarrier_spacing_t scs; - srsran_ssb_patern_t pattern; + srsran_ssb_pattern_t pattern; uint32_t gscn_first; uint32_t gscn_step; uint32_t gscn_last; diff --git a/lib/include/srsran/common/phy_cfg_nr.h b/lib/include/srsran/common/phy_cfg_nr.h index d555b2e69..37c1ca499 100644 --- a/lib/include/srsran/common/phy_cfg_nr.h +++ b/lib/include/srsran/common/phy_cfg_nr.h @@ -33,7 +33,7 @@ struct phy_cfg_nr_t { uint32_t periodicity_ms = 0; std::array position_in_burst = {}; srsran_subcarrier_spacing_t scs = srsran_subcarrier_spacing_30kHz; - srsran_ssb_patern_t pattern = SRSRAN_SSB_PATTERN_A; + srsran_ssb_pattern_t pattern = SRSRAN_SSB_PATTERN_A; }; srsran_duplex_config_nr_t duplex = {}; diff --git a/lib/include/srsran/interfaces/ue_nr_interfaces.h b/lib/include/srsran/interfaces/ue_nr_interfaces.h index f2fe244a0..8668ce183 100644 --- a/lib/include/srsran/interfaces/ue_nr_interfaces.h +++ b/lib/include/srsran/interfaces/ue_nr_interfaces.h @@ -301,7 +301,7 @@ public: double center_freq_hz; double ssb_freq_hz; srsran_subcarrier_spacing_t ssb_scs; - srsran_ssb_patern_t ssb_pattern; + srsran_ssb_pattern_t ssb_pattern; srsran_duplex_mode_t duplex_mode; }; diff --git a/lib/include/srsran/phy/common/phy_common_nr.h b/lib/include/srsran/phy/common/phy_common_nr.h index c549e006f..595e36e31 100644 --- a/lib/include/srsran/phy/common/phy_common_nr.h +++ b/lib/include/srsran/phy/common/phy_common_nr.h @@ -349,7 +349,7 @@ typedef enum SRSRAN_API { SRSRAN_SSB_PATTERN_D, // FR2, 120 kHz SCS SRSRAN_SSB_PATTERN_E, // FR2, 240 kHz SCS SRSRAN_SSB_PATTERN_INVALID, -} srsran_ssb_patern_t; +} srsran_ssb_pattern_t; typedef enum SRSRAN_API { SRSRAN_DUPLEX_MODE_FDD = 0, // Paired @@ -732,14 +732,14 @@ SRSRAN_API int srsran_coreset_to_str(srsran_coreset_t* coreset, char* str, uint3 * @param pattern * @return a string describing the SSB pattern */ -SRSRAN_API const char* srsran_ssb_pattern_to_str(srsran_ssb_patern_t pattern); +SRSRAN_API const char* srsran_ssb_pattern_to_str(srsran_ssb_pattern_t pattern); /** * @brief Convert string to SSB pattern * @param str String to convert * @return The pattern, SRSRAN_SSB_PATTERN_INVALID if string is invalid */ -SRSRAN_API srsran_ssb_patern_t srsran_ssb_pattern_fom_str(const char* str); +SRSRAN_API srsran_ssb_pattern_t srsran_ssb_pattern_fom_str(const char* str); /** * @brief Compares if two NR carrier structures are equal diff --git a/lib/include/srsran/phy/sync/ssb.h b/lib/include/srsran/phy/sync/ssb.h index 4d1d4bd25..cb9b2aa99 100644 --- a/lib/include/srsran/phy/sync/ssb.h +++ b/lib/include/srsran/phy/sync/ssb.h @@ -61,7 +61,7 @@ typedef struct SRSRAN_API { double center_freq_hz; ///< Base-band center frequency in Hz double ssb_freq_hz; ///< SSB center frequency srsran_subcarrier_spacing_t scs; ///< SSB configured Subcarrier spacing - srsran_ssb_patern_t pattern; ///< SSB pattern as defined in TS 38.313 section 4.1 Cell search + srsran_ssb_pattern_t pattern; ///< SSB pattern as defined in TS 38.313 section 4.1 Cell search srsran_duplex_mode_t duplex_mode; ///< Set to true if the spectrum is paired (FDD) uint32_t periodicity_ms; ///< SSB periodicity in ms float beta_pss; ///< PSS power allocation diff --git a/lib/src/asn1/rrc_nr_utils.cc b/lib/src/asn1/rrc_nr_utils.cc index 056d7f4c4..f7affbe0e 100644 --- a/lib/src/asn1/rrc_nr_utils.cc +++ b/lib/src/asn1/rrc_nr_utils.cc @@ -1558,7 +1558,7 @@ void fill_ssb_pos_in_burst(const asn1::rrc_nr::serving_cell_cfg_common_sib_s& cf } bool fill_ssb_pattern_scs(const srsran_carrier_nr_t& carrier, - srsran_ssb_patern_t* pattern, + srsran_ssb_pattern_t* pattern, srsran_subcarrier_spacing_t* ssb_scs) { srsran::srsran_band_helper bands; diff --git a/lib/src/common/band_helper.cc b/lib/src/common/band_helper.cc index 8b8fd30a4..e1ff71237 100644 --- a/lib/src/common/band_helper.cc +++ b/lib/src/common/band_helper.cc @@ -166,7 +166,7 @@ uint32_t srsran_band_helper::get_abs_freq_ssb_arfcn(uint16_t return find_lower_bound_abs_freq_ssb(band, scs, freq_point_a_hz + coreset0_offset_hz); } -srsran_ssb_patern_t srsran_band_helper::get_ssb_pattern(uint16_t band, srsran_subcarrier_spacing_t scs) +srsran_ssb_pattern_t srsran_band_helper::get_ssb_pattern(uint16_t band, srsran_subcarrier_spacing_t scs) { // Look for the given band and SCS for (const nr_band_ss_raster& ss_raster : nr_band_ss_raster_table) { diff --git a/lib/src/phy/common/phy_common_nr.c b/lib/src/phy/common/phy_common_nr.c index 1d2c405f2..30f237b89 100644 --- a/lib/src/phy/common/phy_common_nr.c +++ b/lib/src/phy/common/phy_common_nr.c @@ -775,7 +775,7 @@ int srsran_coreset0_ssb_offset(uint32_t idx, srsran_subcarrier_spacing_t ssb_scs return entry->offset_rb; } -const char* srsran_ssb_pattern_to_str(srsran_ssb_patern_t pattern) +const char* srsran_ssb_pattern_to_str(srsran_ssb_pattern_t pattern) { switch (pattern) { case SRSRAN_SSB_PATTERN_A: @@ -795,7 +795,7 @@ const char* srsran_ssb_pattern_to_str(srsran_ssb_patern_t pattern) return "Invalid"; } -srsran_ssb_patern_t srsran_ssb_pattern_fom_str(const char* str) +srsran_ssb_pattern_t srsran_ssb_pattern_fom_str(const char* str) { if (str == NULL) { return SRSRAN_SSB_PATTERN_INVALID; diff --git a/lib/src/phy/sync/test/ssb_decode_test.c b/lib/src/phy/sync/test/ssb_decode_test.c index 0ffacaed5..4ecd957d0 100644 --- a/lib/src/phy/sync/test/ssb_decode_test.c +++ b/lib/src/phy/sync/test/ssb_decode_test.c @@ -29,7 +29,7 @@ static srsran_subcarrier_spacing_t carrier_scs = srsran_subcarrier_spacing_1 static double carrier_freq_hz = 3.5e9 + 960e3; static srsran_subcarrier_spacing_t ssb_scs = srsran_subcarrier_spacing_30kHz; static double ssb_freq_hz = 3.5e9; -static srsran_ssb_patern_t ssb_pattern = SRSRAN_SSB_PATTERN_A; +static srsran_ssb_pattern_t ssb_pattern = SRSRAN_SSB_PATTERN_A; // Channel parameters static cf_t wideband_gain = 1.0f + 0.5 * I; diff --git a/lib/src/phy/sync/test/ssb_file_test.c b/lib/src/phy/sync/test/ssb_file_test.c index 46baed8f3..583b8eba8 100644 --- a/lib/src/phy/sync/test/ssb_file_test.c +++ b/lib/src/phy/sync/test/ssb_file_test.c @@ -20,7 +20,7 @@ #include // NR parameters -static srsran_ssb_patern_t ssb_pattern = SRSRAN_SSB_PATTERN_C; +static srsran_ssb_pattern_t ssb_pattern = SRSRAN_SSB_PATTERN_C; static srsran_subcarrier_spacing_t ssb_scs = srsran_subcarrier_spacing_30kHz; static srsran_duplex_mode_t duplex_mode = SRSRAN_DUPLEX_MODE_TDD; diff --git a/lib/src/phy/sync/test/ssb_grid_test.c b/lib/src/phy/sync/test/ssb_grid_test.c index 2020f900e..d2bd4150d 100644 --- a/lib/src/phy/sync/test/ssb_grid_test.c +++ b/lib/src/phy/sync/test/ssb_grid_test.c @@ -25,7 +25,7 @@ static srsran_subcarrier_spacing_t carrier_scs = srsran_subcarrier_spacing_1 static double carrier_freq_hz = 3.5e9 + 960e3; static srsran_subcarrier_spacing_t ssb_scs = srsran_subcarrier_spacing_30kHz; static double ssb_freq_hz = 3.5e9; -static srsran_ssb_patern_t ssb_pattern = SRSRAN_SSB_PATTERN_A; +static srsran_ssb_pattern_t ssb_pattern = SRSRAN_SSB_PATTERN_A; static uint32_t ssb_idx = 0; // SSB candidate index to test static uint32_t pci = 123; // N_id diff --git a/lib/src/phy/sync/test/ssb_measure_test.c b/lib/src/phy/sync/test/ssb_measure_test.c index b8dbf9244..5ec152695 100644 --- a/lib/src/phy/sync/test/ssb_measure_test.c +++ b/lib/src/phy/sync/test/ssb_measure_test.c @@ -24,7 +24,7 @@ static srsran_subcarrier_spacing_t carrier_scs = srsran_subcarrier_spacing_1 static double carrier_freq_hz = 3.5e9 + 960e3; static srsran_subcarrier_spacing_t ssb_scs = srsran_subcarrier_spacing_30kHz; static double ssb_freq_hz = 3.5e9; -static srsran_ssb_patern_t ssb_pattern = SRSRAN_SSB_PATTERN_A; +static srsran_ssb_pattern_t ssb_pattern = SRSRAN_SSB_PATTERN_A; // Channel parameters static int32_t delay_n = 2; diff --git a/lib/src/phy/ue/test/ue_sync_nr_test.c b/lib/src/phy/ue/test/ue_sync_nr_test.c index 5eb2398fd..39f58f277 100644 --- a/lib/src/phy/ue/test/ue_sync_nr_test.c +++ b/lib/src/phy/ue/test/ue_sync_nr_test.c @@ -27,7 +27,7 @@ static srsran_subcarrier_spacing_t carrier_scs = srsran_subcarrier_spaci static double center_frequency_hz = 3.5e9; static srsran_subcarrier_spacing_t ssb_scs = srsran_subcarrier_spacing_15kHz; static double ssb_frequency_hz = 3.5e9 - 960e3; -static srsran_ssb_patern_t ssb_pattern = SRSRAN_SSB_PATTERN_C; +static srsran_ssb_pattern_t ssb_pattern = SRSRAN_SSB_PATTERN_C; static srsran_duplex_mode_t duplex_mode = SRSRAN_DUPLEX_MODE_TDD; // Test and channel parameters diff --git a/srsenb/hdr/phy/phy_common.h b/srsenb/hdr/phy/phy_common.h index 925567904..dfde7bf58 100644 --- a/srsenb/hdr/phy/phy_common.h +++ b/srsenb/hdr/phy/phy_common.h @@ -122,7 +122,7 @@ public: cc_idx -= cell_list_lte.size(); if (cc_idx < cell_list_nr.size()) { - ret = cell_list_nr[cc_idx].ul_freq_hz; + ret = cell_list_nr[cc_idx].carrier.ul_center_frequency_hz; } return ret; @@ -137,7 +137,7 @@ public: cc_idx -= cell_list_lte.size(); if (cc_idx < cell_list_nr.size()) { - ret = cell_list_nr[cc_idx].dl_freq_hz; + ret = cell_list_nr[cc_idx].carrier.dl_center_frequency_hz; } return ret; diff --git a/srsenb/src/enb_cfg_parser.cc b/srsenb/src/enb_cfg_parser.cc index ee3fc8db8..cefade786 100644 --- a/srsenb/src/enb_cfg_parser.cc +++ b/srsenb/src/enb_cfg_parser.cc @@ -1007,7 +1007,7 @@ static int parse_nr_cell_list(all_args_t* args, rrc_nr_cfg_t* rrc_cfg_nr, rrc_cf parse_opt_field(cell_cfg.phy_cell.rf_port, cellroot, "rf_port"); HANDLEPARSERCODE(parse_required_field(cell_cfg.phy_cell.carrier.pci, cellroot, "pci")); HANDLEPARSERCODE(parse_required_field(cell_cfg.phy_cell.cell_id, cellroot, "cell_id")); - HANDLEPARSERCODE(parse_required_field(cell_cfg.phy_cell.root_seq_idx, cellroot, "root_seq_idx")); + HANDLEPARSERCODE(parse_required_field(cell_cfg.prach_root_seq_idx, cellroot, "root_seq_idx")); HANDLEPARSERCODE(parse_required_field(cell_cfg.tac, cellroot, "tac")); cell_cfg.phy_cell.carrier.pci = cell_cfg.phy_cell.carrier.pci % SRSRAN_NOF_NID_NR; @@ -1594,8 +1594,7 @@ int set_derived_args_nr(all_args_t* args_, rrc_nr_cfg_t* rrc_nr_cfg_, phy_cfg_t* // phy_cell_cfg.root_seq_idx = cfg.root_seq_idx; // PDSCH - cfg.phy_cell.pdsch.rs_power = phy_cfg_->pdsch_cnfg.ref_sig_pwr; - cfg.phy_cell.pdsch.p_b = phy_cfg_->pdsch_cnfg.p_b; + cfg.pdsch_rs_power = phy_cfg_->pdsch_cnfg.ref_sig_pwr; } rrc_nr_cfg_->enb_id = args_->enb.enb_id; rrc_nr_cfg_->mcc = args_->stack.s1ap.mcc; diff --git a/srsgnb/hdr/phy/phy_nr_interfaces.h b/srsgnb/hdr/phy/phy_nr_interfaces.h index 4f91fb479..f9767b782 100644 --- a/srsgnb/hdr/phy/phy_nr_interfaces.h +++ b/srsgnb/hdr/phy/phy_nr_interfaces.h @@ -19,16 +19,10 @@ namespace srsenb { struct phy_cell_cfg_nr_t { - srsran_carrier_nr_t carrier; - uint32_t rf_port; - uint32_t cell_id; - double dl_freq_hz; - double ul_freq_hz; - uint32_t root_seq_idx; - uint32_t num_ra_preambles; - float gain_db; - srsran_pdsch_cfg_t pdsch = {}; - srsran_prach_cfg_t prach = {}; + srsran_carrier_nr_t carrier; + uint32_t rf_port; + uint32_t cell_id; + float gain_db; bool dl_measure; }; diff --git a/srsgnb/hdr/stack/rrc/rrc_nr_config.h b/srsgnb/hdr/stack/rrc/rrc_nr_config.h index 95cfe1dae..555f58941 100644 --- a/srsgnb/hdr/stack/rrc/rrc_nr_config.h +++ b/srsgnb/hdr/stack/rrc/rrc_nr_config.h @@ -25,19 +25,22 @@ namespace srsenb { struct rrc_cell_cfg_nr_t { phy_cell_cfg_nr_t phy_cell; // already contains all PHY-related parameters (i.e. RF port, PCI, etc.) uint32_t tac; // Tracking area code - uint32_t dl_arfcn; // DL freq already included in phy_cell - uint32_t ul_arfcn; // UL freq also in phy_cell + uint32_t dl_arfcn; // DL freq already included in carrier + uint32_t ul_arfcn; // UL freq also in carrier uint32_t dl_absolute_freq_point_a; // derived from DL ARFCN uint32_t ul_absolute_freq_point_a; // derived from UL ARFCN uint32_t band; + uint32_t prach_root_seq_idx; + uint32_t num_ra_preambles; uint32_t coreset0_idx; // Table 13-{1,...15} row index srsran_duplex_mode_t duplex_mode; double ssb_freq_hz; uint32_t ssb_absolute_freq_point; // derived from DL ARFCN (SSB arfcn) srsran_subcarrier_spacing_t ssb_scs; - srsran_ssb_patern_t ssb_pattern; + srsran_ssb_pattern_t ssb_pattern; asn1::rrc_nr::pdcch_cfg_common_s pdcch_cfg_common; asn1::rrc_nr::pdcch_cfg_s pdcch_cfg_ded; + int8_t pdsch_rs_power; }; typedef std::vector rrc_cell_list_nr_t; diff --git a/srsgnb/hdr/stack/rrc/rrc_nr_du_manager.h b/srsgnb/hdr/stack/rrc/rrc_nr_du_manager.h index 94f14d29e..ea4bbfa7d 100644 --- a/srsgnb/hdr/stack/rrc/rrc_nr_du_manager.h +++ b/srsgnb/hdr/stack/rrc/rrc_nr_du_manager.h @@ -32,7 +32,7 @@ public: srsran::unique_byte_buffer_t packed_sib1; asn1::rrc_nr::subcarrier_spacing_e ssb_scs; - srsran_ssb_patern_t ssb_pattern; + srsran_ssb_pattern_t ssb_pattern; double ssb_center_freq_hz; double dl_freq_hz; bool is_standalone; diff --git a/srsgnb/src/stack/rrc/cell_asn1_config.cc b/srsgnb/src/stack/rrc/cell_asn1_config.cc index d9558528f..af90efa99 100644 --- a/srsgnb/src/stack/rrc/cell_asn1_config.cc +++ b/srsgnb/src/stack/rrc/cell_asn1_config.cc @@ -813,21 +813,21 @@ int fill_rach_cfg_common(const rrc_nr_cfg_t& cfg, uint32_t cc, rach_cfg_common_s rach.rach_cfg_generic.ra_resp_win.value = rach_cfg_generic_s::ra_resp_win_opts::sl10; // totalNumberOfRA-Preambles - if (cfg.cell_list[cc].phy_cell.num_ra_preambles != 64) { + if (cfg.cell_list[cc].num_ra_preambles != 64) { rach.total_nof_ra_preambs_present = true; - rach.total_nof_ra_preambs = cfg.cell_list[cc].phy_cell.num_ra_preambles; + rach.total_nof_ra_preambs = cfg.cell_list[cc].num_ra_preambles; } // ssb-perRACH-OccasionAndCB-PreamblesPerSSB rach.ssb_per_rach_occasion_and_cb_preambs_per_ssb_present = true; if (not asn1::number_to_enum(rach.ssb_per_rach_occasion_and_cb_preambs_per_ssb.set_one(), - cfg.cell_list[cc].phy_cell.num_ra_preambles)) { - get_logger(cfg).error("Invalid number of RA preambles=%d", cfg.cell_list[cc].phy_cell.num_ra_preambles); + cfg.cell_list[cc].num_ra_preambles)) { + get_logger(cfg).error("Invalid number of RA preambles=%d", cfg.cell_list[cc].num_ra_preambles); return -1; } rach.ra_contention_resolution_timer.value = rach_cfg_common_s::ra_contention_resolution_timer_opts::sf64; - rach.prach_root_seq_idx.set_l839() = cfg.cell_list[cc].phy_cell.root_seq_idx; + rach.prach_root_seq_idx.set_l839() = cfg.cell_list[cc].prach_root_seq_idx; rach.restricted_set_cfg.value = rach_cfg_common_s::restricted_set_cfg_opts::unrestricted_set; return SRSRAN_SUCCESS; @@ -865,7 +865,7 @@ int fill_serv_cell_common_from_enb_cfg(const rrc_nr_cfg_t& cfg, uint32_t cc, ser { auto& cell_cfg = cfg.cell_list.at(cc); - serv_common.ss_pbch_block_pwr = cell_cfg.phy_cell.pdsch.rs_power; + serv_common.ss_pbch_block_pwr = cell_cfg.pdsch_rs_power; serv_common.n_timing_advance_offset_present = true; serv_common.n_timing_advance_offset = serving_cell_cfg_common_s::n_timing_advance_offset_opts::n0; serv_common.n_timing_advance_offset_present = true; @@ -1230,7 +1230,7 @@ int fill_serv_cell_cfg_common_sib(const rrc_nr_cfg_t& cfg, uint32_t cc, serving_ fill_tdd_ul_dl_config_common(cell_cfg, out.tdd_ul_dl_cfg_common); } - out.ss_pbch_block_pwr = cell_cfg.phy_cell.pdsch.rs_power; + out.ss_pbch_block_pwr = cell_cfg.pdsch_rs_power; return SRSRAN_SUCCESS; } diff --git a/srsgnb/src/stack/rrc/rrc_nr_config_utils.cc b/srsgnb/src/stack/rrc/rrc_nr_config_utils.cc index a5cf4ed07..c29caad9a 100644 --- a/srsgnb/src/stack/rrc/rrc_nr_config_utils.cc +++ b/srsgnb/src/stack/rrc/rrc_nr_config_utils.cc @@ -109,14 +109,6 @@ void generate_default_nr_phy_cell(phy_cell_cfg_nr_t& phy_cell) phy_cell.carrier.scs = srsran_subcarrier_spacing_15kHz; phy_cell.carrier.nof_prb = 52; phy_cell.carrier.max_mimo_layers = 1; - - phy_cell.dl_freq_hz = 0; // auto set - phy_cell.ul_freq_hz = 0; - phy_cell.num_ra_preambles = 8; - - // PDSCH - phy_cell.pdsch.rs_power = 0; - phy_cell.pdsch.p_b = 0; } /// Generate default rrc nr cell configuration @@ -125,6 +117,7 @@ void generate_default_nr_cell(rrc_cell_cfg_nr_t& cell) cell = {}; cell.coreset0_idx = 6; cell.ssb_absolute_freq_point = 0; // auto derived + cell.num_ra_preambles = 8; generate_default_nr_phy_cell(cell.phy_cell); // PDCCH @@ -208,25 +201,21 @@ int derive_phy_cell_freq_params(uint32_t dl_arfcn, uint32_t ul_arfcn, phy_cell_c srsran::srsran_band_helper band_helper; // derive DL freq from ARFCN - if (phy_cell.dl_freq_hz == 0) { - phy_cell.dl_freq_hz = band_helper.nr_arfcn_to_freq(dl_arfcn); + if (phy_cell.carrier.dl_center_frequency_hz == 0) { + phy_cell.carrier.dl_center_frequency_hz = band_helper.nr_arfcn_to_freq(dl_arfcn); } // derive UL freq from ARFCN - if (phy_cell.ul_freq_hz == 0) { + if (phy_cell.carrier.ul_center_frequency_hz == 0) { // auto-detect UL frequency if (ul_arfcn == 0) { // derive UL ARFCN from given DL ARFCN ul_arfcn = band_helper.get_ul_arfcn_from_dl_arfcn(dl_arfcn); ERROR_IF_NOT(ul_arfcn > 0, "Can't derive UL ARFCN from DL ARFCN %d", dl_arfcn); } - phy_cell.ul_freq_hz = band_helper.nr_arfcn_to_freq(ul_arfcn); + phy_cell.carrier.ul_center_frequency_hz = band_helper.nr_arfcn_to_freq(ul_arfcn); } - // copy center frequencies - phy_cell.carrier.dl_center_frequency_hz = phy_cell.dl_freq_hz; - phy_cell.carrier.ul_center_frequency_hz = phy_cell.ul_freq_hz; - return SRSRAN_SUCCESS; } diff --git a/srsue/hdr/phy/nr/cell_search.h b/srsue/hdr/phy/nr/cell_search.h index ec983ac14..63090e443 100644 --- a/srsue/hdr/phy/nr/cell_search.h +++ b/srsue/hdr/phy/nr/cell_search.h @@ -32,7 +32,7 @@ public: double center_freq_hz; double ssb_freq_hz; srsran_subcarrier_spacing_t ssb_scs; - srsran_ssb_patern_t ssb_pattern; + srsran_ssb_pattern_t ssb_pattern; srsran_duplex_mode_t duplex_mode; }; diff --git a/srsue/src/phy/test/gnb_emulator.h b/srsue/src/phy/test/gnb_emulator.h index 497f079ed..8573cfa8a 100644 --- a/srsue/src/phy/test/gnb_emulator.h +++ b/srsue/src/phy/test/gnb_emulator.h @@ -33,7 +33,7 @@ public: double srate_hz; srsran_carrier_nr_t carrier; srsran_subcarrier_spacing_t ssb_scs; - srsran_ssb_patern_t ssb_pattern; + srsran_ssb_pattern_t ssb_pattern; uint32_t ssb_periodicity_ms; srsran_duplex_mode_t duplex_mode; srsran::channel::args_t channel; diff --git a/srsue/src/phy/test/gnb_rf_emulator.h b/srsue/src/phy/test/gnb_rf_emulator.h index ab54efc88..e3083ddd4 100644 --- a/srsue/src/phy/test/gnb_rf_emulator.h +++ b/srsue/src/phy/test/gnb_rf_emulator.h @@ -60,7 +60,7 @@ public: double srate_hz; srsran_carrier_nr_t base_carrier; srsran_subcarrier_spacing_t ssb_scs; - srsran_ssb_patern_t ssb_pattern; + srsran_ssb_pattern_t ssb_pattern; uint32_t ssb_periodicity_ms; srsran_duplex_mode_t duplex_mode; std::set pci_list; diff --git a/srsue/src/phy/test/nr_cell_search_test.cc b/srsue/src/phy/test/nr_cell_search_test.cc index 08494e160..1dae520fe 100644 --- a/srsue/src/phy/test/nr_cell_search_test.cc +++ b/srsue/src/phy/test/nr_cell_search_test.cc @@ -48,7 +48,7 @@ public: srsran::channel::args_t channel; std::string log_level = "error"; - srsran_ssb_patern_t get_ssb_pattern() const { return srsran::srsran_band_helper().get_ssb_pattern(band, ssb_scs); } + srsran_ssb_pattern_t get_ssb_pattern() const { return srsran::srsran_band_helper().get_ssb_pattern(band, ssb_scs); } srsran_duplex_mode_t get_duplex_mode() const { return srsran::srsran_band_helper().get_duplex_mode(band); } }; diff --git a/srsue/src/phy/test/nr_sa_cell_search_test.cc b/srsue/src/phy/test/nr_sa_cell_search_test.cc index d80c526d0..36c9aebe7 100644 --- a/srsue/src/phy/test/nr_sa_cell_search_test.cc +++ b/srsue/src/phy/test/nr_sa_cell_search_test.cc @@ -24,7 +24,7 @@ struct args_t { // Generic parameters double srate_hz = 11.52e6; srsran_carrier_nr_t base_carrier = SRSRAN_DEFAULT_CARRIER_NR; - srsran_ssb_patern_t ssb_pattern = SRSRAN_SSB_PATTERN_A; + srsran_ssb_pattern_t ssb_pattern = SRSRAN_SSB_PATTERN_A; srsran_subcarrier_spacing_t ssb_scs = srsran_subcarrier_spacing_15kHz; srsran_duplex_mode_t duplex_mode = SRSRAN_DUPLEX_MODE_FDD; uint32_t duration_ms = 1000; @@ -216,7 +216,7 @@ struct cell_search_result_t { bool found = false; double ssb_abs_freq_hz = 0.0f; srsran_subcarrier_spacing_t ssb_scs = srsran_subcarrier_spacing_15kHz; - srsran_ssb_patern_t ssb_pattern = SRSRAN_SSB_PATTERN_A; + srsran_ssb_pattern_t ssb_pattern = SRSRAN_SSB_PATTERN_A; srsran_duplex_mode_t duplex_mode = SRSRAN_DUPLEX_MODE_FDD; srsran_mib_nr_t mib = {}; uint32_t pci = 0; From 01ef334a2480c9f906171b4e63b8163ff27b52b0 Mon Sep 17 00:00:00 2001 From: dvdgrgrtt Date: Tue, 8 Feb 2022 15:50:55 +0000 Subject: [PATCH 59/62] lib,phy: Fix thresholds in Viterbi test Under the NEON architecture, one of the BER thresholds was too tight. --- lib/src/phy/fec/convolutional/test/viterbi_test.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/phy/fec/convolutional/test/viterbi_test.h b/lib/src/phy/fec/convolutional/test/viterbi_test.h index db8da02fd..a10a47a88 100644 --- a/lib/src/phy/fec/convolutional/test/viterbi_test.h +++ b/lib/src/phy/fec/convolutional/test/viterbi_test.h @@ -53,7 +53,7 @@ static expected_errors_t expected_errors[] = {{1000, 1, 40, true, 0.0, 7282}, {1000, 1, 56, true, 3.0, 176}, {1000, 1, 56, true, 4.5, 24}, - {100, 1, 1000, true, 0.0, 13208}, + {100, 1, 1000, true, 0.0, 16000}, {100, 1, 1000, true, 2.0, 939}, {100, 1, 1000, true, 3.0, 110}, {100, 1, 1000, true, 4.5, 5}, From 83868fd2d2e5bd15439b71a8697f8f57f0bb9b71 Mon Sep 17 00:00:00 2001 From: Bedran Karakoc Date: Tue, 8 Feb 2022 04:35:54 +0100 Subject: [PATCH 60/62] lib,nas_5g: Implement to_string() for 5GSM Cause --- lib/include/srsran/asn1/nas_5g_ies.h | 2 +- lib/src/asn1/nas_5g_ies.cc | 94 ++++++++++++++++++++++++++++ 2 files changed, 95 insertions(+), 1 deletion(-) diff --git a/lib/include/srsran/asn1/nas_5g_ies.h b/lib/include/srsran/asn1/nas_5g_ies.h index 4f0ea4c42..9b7ad2dd1 100644 --- a/lib/include/srsran/asn1/nas_5g_ies.h +++ b/lib/include/srsran/asn1/nas_5g_ies.h @@ -2397,7 +2397,7 @@ public: protocol_error_unspecified = 0b01101111, } value; - const char* to_string(); + const char* to_string() const; }; typedef nas_enumerated cause_value_type; diff --git a/lib/src/asn1/nas_5g_ies.cc b/lib/src/asn1/nas_5g_ies.cc index 907f30a70..d5ee5a54c 100644 --- a/lib/src/asn1/nas_5g_ies.cc +++ b/lib/src/asn1/nas_5g_ies.cc @@ -4091,6 +4091,100 @@ SRSASN_CODE cause_5gsm_t::unpack(asn1::cbit_ref& bref) return SRSASN_SUCCESS; } +const char* cause_5gsm_t::cause_value_type_::to_string() const +{ + switch (value) { + case cause_value_type_::operator_determined_barring: + return "Operator determined barring"; + case cause_value_type_::insufficient_resources: + return "Insufficient resources"; + case cause_value_type_::missing_or_unknown_dnn: + return "Missing or unknown DNN"; + case cause_value_type_::unknown_pdu_session_type: + return "Unknown PDU session type"; + case cause_value_type_::user_authentication_or_authorization_failed: + return "User authentication or authorization failed"; + case cause_value_type_::request_rejected_unspecified: + return "Request rejected, unspecified"; + case cause_value_type_::service_option_not_supported: + return "Service option not supported"; + case cause_value_type_::requested_service_option_not_subscribed: + return "Requested service option not subscribed"; + case cause_value_type_::pti_already_in_use: + return "PTI already in use"; + case cause_value_type_::regular_deactivation: + return "Regular deactivation"; + case cause_value_type_::network_failure: + return "Network failure"; + case cause_value_type_::reactivation_requested: + return "Reactivation requested"; + case cause_value_type_::semantic_error_in_the_tft_operation: + return "Semantic error in the TFT operation"; + case cause_value_type_::syntactical_error_in_the_tft_operation: + return "Syntactical error in the TFT operation"; + case cause_value_type_::invalid_pdu_session_identity: + return "Invalid PDU session identity"; + case cause_value_type_::semantic_errors_in_packet_filter: + return "Semantic errors in packet filter"; + case cause_value_type_::syntactical_error_in_packet_filter: + return "Syntactical error in packet filter"; + case cause_value_type_::out_of_ladn_service_area: + return "Out of LADN service area"; + case cause_value_type_::pti_mismatch: + return "PTI mismatch"; + case cause_value_type_::pdu_session_type_i_pv4_only_allowed: + return "PDU session type IPv4 only allowed"; + case cause_value_type_::pdu_session_type_i_pv6_only_allowed: + return "PDU session type IPv6 only allowed"; + case cause_value_type_::pdu_session_does_not_exist: + return "PDU session does not exist"; + case cause_value_type_::pdu_session_type_i_pv4v6_only_allowed: + return "PDU session type IPv4v6 only allowed"; + case cause_value_type_::pdu_session_type_unstructured_only_allowed: + return "PDU session type Unstructured only allowed"; + case cause_value_type_::unsupported_5_qi_value: + return "Unsupported 5QI value"; + case cause_value_type_::pdu_session_type_ethernet_only_allowed: + return "PDU session type Ethernet only allowed"; + case cause_value_type_::insufficient_resources_for_specific_slice_and_dnn: + return "Insufficient resources for specific slice and DNN"; + case cause_value_type_::not_supported_ssc_mode: + return "Not supported SSC mode"; + case cause_value_type_::insufficient_resources_for_specific_slice: + return "Insufficient resources for specific slice"; + case cause_value_type_::missing_or_unknown_dnn_in_a_slice: + return "Missing or unknown DNN in a slice"; + case cause_value_type_::invalid_pti_value: + return "Invalid PTI value"; + case cause_value_type_::maximum_data_rate_per_ue_for_user_plane_integrity_protection_is_too_low: + return "Maximum data rate per UE for user-plane integrity protection is too low"; + case cause_value_type_::semantic_error_in_the_qo_s_operation: + return "Semantic error in the QoS operation"; + case cause_value_type_::syntactical_error_in_the_qo_s_operation: + return "Syntactical error in the QoS operation"; + case cause_value_type_::invalid_mapped_eps_bearer_identity: + return "Invalid mapped EPS bearer identity"; + case cause_value_type_::semantically_incorrect_message: + return "Semantically incorrect message"; + case cause_value_type_::invalid_mandatory_information: + return "Invalid mandatory information"; + case cause_value_type_::message_type_non_existent_or_not_implemented: + return "Message type non-existent or not implemented"; + case cause_value_type_::message_type_not_compatible_with_the_protocol_state: + return "Message type not compatible with the protocol state"; + case cause_value_type_::information_element_non_existent_or_not_implemented: + return "Information element non-existent or not implemented"; + case cause_value_type_::conditional_ie_error: + return "Conditional IE error"; + case cause_value_type_::message_not_compatible_with_the_protocol_state: + return "Message not compatible with the protocol state"; + case cause_value_type_::protocol_error_unspecified: + return "Protocol error, unspecified"; + default: + return "Invalid Choice"; + } +} + // IE: GPRS timer // Reference: 9.11.2.3 SRSASN_CODE gprs_timer_t::pack(asn1::bit_ref& bref) From 380280b4d08d0bd7e05064e92e3fff0fc8fb05fc Mon Sep 17 00:00:00 2001 From: Bedran Karakoc Date: Tue, 8 Feb 2022 04:36:49 +0100 Subject: [PATCH 61/62] lib,nas_5g: Log cause for pdu session establishment reject --- srsue/src/stack/upper/nas_5g_procedures.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/srsue/src/stack/upper/nas_5g_procedures.cc b/srsue/src/stack/upper/nas_5g_procedures.cc index 2ce2281af..f07e3ac38 100644 --- a/srsue/src/stack/upper/nas_5g_procedures.cc +++ b/srsue/src/stack/upper/nas_5g_procedures.cc @@ -77,7 +77,8 @@ srsran::proc_outcome_t nas_5g::pdu_session_establishment_procedure::react( srsran::proc_outcome_t nas_5g::pdu_session_establishment_procedure::react( const srsran::nas_5g::pdu_session_establishment_reject_t& session_est_reject) { - return srsran::proc_outcome_t::success; + logger.info("PDU Session Establishment Reject with cause: %s", session_est_reject.cause_5gsm.cause_value.to_string()); + return srsran::proc_outcome_t::error; } srsran::proc_outcome_t nas_5g::pdu_session_establishment_procedure::step() From c9c2d6982f1a58af87e6aab6c6416c79c95f3477 Mon Sep 17 00:00:00 2001 From: faluco Date: Wed, 2 Feb 2022 12:23:23 +0100 Subject: [PATCH 62/62] Implement a function to remove emergency handlers when a signal is raised. Make PCAP handlers deregister from this list when they are destructed. This avoid the signal handler calling destructed objects under very rare circumstances. --- lib/include/srsran/common/mac_pcap_base.h | 3 ++- lib/include/srsran/common/nas_pcap.h | 12 +++++++----- lib/include/srsran/common/ngap_pcap.h | 5 +++-- lib/include/srsran/common/s1ap_pcap.h | 4 +++- lib/include/srsran/support/emergency_handlers.h | 6 +++++- lib/src/common/mac_pcap_base.cc | 9 +++++++-- lib/src/common/nas_pcap.cc | 9 ++++++++- lib/src/common/ngap_pcap.cc | 9 ++++++++- lib/src/common/s1ap_pcap.cc | 9 ++++++++- lib/src/support/emergency_handlers.cc | 17 +++++++++++++++-- 10 files changed, 66 insertions(+), 17 deletions(-) diff --git a/lib/include/srsran/common/mac_pcap_base.h b/lib/include/srsran/common/mac_pcap_base.h index f9394bfbd..c446c747e 100644 --- a/lib/include/srsran/common/mac_pcap_base.h +++ b/lib/include/srsran/common/mac_pcap_base.h @@ -103,7 +103,8 @@ protected: srslog::basic_logger& logger; std::atomic running = {false}; static_blocking_queue queue; - uint16_t ue_id = 0; + uint16_t ue_id = 0; + int emergency_handler_id = -1; private: void pack_and_queue(uint8_t* payload, diff --git a/lib/include/srsran/common/nas_pcap.h b/lib/include/srsran/common/nas_pcap.h index f93c17a27..34a13bea9 100644 --- a/lib/include/srsran/common/nas_pcap.h +++ b/lib/include/srsran/common/nas_pcap.h @@ -23,16 +23,18 @@ class nas_pcap { public: nas_pcap(); - void enable(); + ~nas_pcap(); + void enable(); uint32_t open(std::string filename_, uint32_t ue_id = 0, srsran_rat_t rat_type = srsran_rat_t::lte); - void close(); - void write_nas(uint8_t* pdu, uint32_t pdu_len_bytes); + void close(); + void write_nas(uint8_t* pdu, uint32_t pdu_len_bytes); private: bool enable_write = false; std::string filename; - FILE* pcap_file = nullptr; - uint32_t ue_id = 0; + FILE* pcap_file = nullptr; + uint32_t ue_id = 0; + int emergency_handler_id = -1; void pack_and_write(uint8_t* pdu, uint32_t pdu_len_bytes); }; diff --git a/lib/include/srsran/common/ngap_pcap.h b/lib/include/srsran/common/ngap_pcap.h index e56c0ff6f..bbfc8f6df 100644 --- a/lib/include/srsran/common/ngap_pcap.h +++ b/lib/include/srsran/common/ngap_pcap.h @@ -22,7 +22,7 @@ class ngap_pcap { public: ngap_pcap(); - ~ngap_pcap() = default; + ~ngap_pcap(); ngap_pcap(const ngap_pcap& other) = delete; ngap_pcap& operator=(const ngap_pcap& other) = delete; ngap_pcap(ngap_pcap&& other) = delete; @@ -36,7 +36,8 @@ public: private: bool enable_write = false; std::string filename; - FILE* pcap_file = nullptr; + FILE* pcap_file = nullptr; + int emergency_handler_id = -1; }; } // namespace srsran diff --git a/lib/include/srsran/common/s1ap_pcap.h b/lib/include/srsran/common/s1ap_pcap.h index 0e9cae421..459790b8f 100644 --- a/lib/include/srsran/common/s1ap_pcap.h +++ b/lib/include/srsran/common/s1ap_pcap.h @@ -22,6 +22,7 @@ class s1ap_pcap { public: s1ap_pcap(); + ~s1ap_pcap(); s1ap_pcap(const s1ap_pcap& other) = delete; s1ap_pcap& operator=(const s1ap_pcap& other) = delete; s1ap_pcap(s1ap_pcap&& other) = delete; @@ -35,7 +36,8 @@ public: private: bool enable_write = false; std::string filename; - FILE* pcap_file = nullptr; + FILE* pcap_file = nullptr; + int emergency_handler_id = -1; }; } // namespace srsran diff --git a/lib/include/srsran/support/emergency_handlers.h b/lib/include/srsran/support/emergency_handlers.h index 818f1a211..6fe5c2fba 100644 --- a/lib/include/srsran/support/emergency_handlers.h +++ b/lib/include/srsran/support/emergency_handlers.h @@ -17,7 +17,11 @@ using emergency_cleanup_callback = void (*)(void*); // Add a cleanup function to be called when a kill signal is about to be delivered to the process. The handler may // optionally pass a pointer to identify what instance of the handler is being called. -void add_emergency_cleanup_handler(emergency_cleanup_callback callback, void* data); +// Returns the id of the handler as a positive value, otherwise returns -1 on error. +int add_emergency_cleanup_handler(emergency_cleanup_callback callback, void* data); + +// Removes the emergency handler with the specified id. +void remove_emergency_cleanup_handler(int id); // Executes all registered emergency cleanup handlers. void execute_emergency_cleanup_handlers(); diff --git a/lib/src/common/mac_pcap_base.cc b/lib/src/common/mac_pcap_base.cc index 2a12110d7..32c9902b5 100644 --- a/lib/src/common/mac_pcap_base.cc +++ b/lib/src/common/mac_pcap_base.cc @@ -26,10 +26,15 @@ static void emergency_cleanup_handler(void* data) mac_pcap_base::mac_pcap_base() : logger(srslog::fetch_basic_logger("MAC")), thread("PCAP_WRITER_MAC") { - add_emergency_cleanup_handler(emergency_cleanup_handler, this); + emergency_handler_id = add_emergency_cleanup_handler(emergency_cleanup_handler, this); } -mac_pcap_base::~mac_pcap_base() {} +mac_pcap_base::~mac_pcap_base() +{ + if (emergency_handler_id > 0) { + remove_emergency_cleanup_handler(emergency_handler_id); + } +} void mac_pcap_base::enable(bool enable_) { diff --git a/lib/src/common/nas_pcap.cc b/lib/src/common/nas_pcap.cc index 1011d0d12..7a6f482ae 100644 --- a/lib/src/common/nas_pcap.cc +++ b/lib/src/common/nas_pcap.cc @@ -26,7 +26,14 @@ static void emergency_cleanup_handler(void* data) nas_pcap::nas_pcap() { - add_emergency_cleanup_handler(emergency_cleanup_handler, this); + emergency_handler_id = add_emergency_cleanup_handler(emergency_cleanup_handler, this); +} + +nas_pcap::~nas_pcap() +{ + if (emergency_handler_id > 0) { + remove_emergency_cleanup_handler(emergency_handler_id); + } } void nas_pcap::enable() diff --git a/lib/src/common/ngap_pcap.cc b/lib/src/common/ngap_pcap.cc index 34ce35d2d..0174aeb1e 100644 --- a/lib/src/common/ngap_pcap.cc +++ b/lib/src/common/ngap_pcap.cc @@ -26,7 +26,14 @@ static void emergency_cleanup_handler(void* data) ngap_pcap::ngap_pcap() { - add_emergency_cleanup_handler(emergency_cleanup_handler, this); + emergency_handler_id = add_emergency_cleanup_handler(emergency_cleanup_handler, this); +} + +ngap_pcap::~ngap_pcap() +{ + if (emergency_handler_id > 0) { + remove_emergency_cleanup_handler(emergency_handler_id); + } } void ngap_pcap::enable() diff --git a/lib/src/common/s1ap_pcap.cc b/lib/src/common/s1ap_pcap.cc index 3909673d4..b52221419 100644 --- a/lib/src/common/s1ap_pcap.cc +++ b/lib/src/common/s1ap_pcap.cc @@ -26,7 +26,14 @@ static void emergency_cleanup_handler(void* data) s1ap_pcap::s1ap_pcap() { - add_emergency_cleanup_handler(emergency_cleanup_handler, this); + emergency_handler_id = add_emergency_cleanup_handler(emergency_cleanup_handler, this); +} + +s1ap_pcap::~s1ap_pcap() +{ + if (emergency_handler_id > 0) { + remove_emergency_cleanup_handler(emergency_handler_id); + } } void s1ap_pcap::enable() diff --git a/lib/src/support/emergency_handlers.cc b/lib/src/support/emergency_handlers.cc index b4e2cdc9a..fb170f848 100644 --- a/lib/src/support/emergency_handlers.cc +++ b/lib/src/support/emergency_handlers.cc @@ -11,6 +11,7 @@ */ #include "srsran/support/emergency_handlers.h" +#include "srsran/config.h" #include "srsran/support/srsran_assert.h" namespace { @@ -29,7 +30,7 @@ static constexpr unsigned max_handlers = 12; static handler_instance registered_handlers[max_handlers]; static std::atomic num_handlers; -void add_emergency_cleanup_handler(emergency_cleanup_callback callback, void* data) +int add_emergency_cleanup_handler(emergency_cleanup_callback callback, void* data) { // Reserve a slot in the array. auto pos = num_handlers.fetch_add(1); @@ -37,13 +38,25 @@ void add_emergency_cleanup_handler(emergency_cleanup_callback callback, void* da // Check if we have space in the array. if (pos >= max_handlers) { srsran_assert(0, "Exceeded the emergency cleanup handler registered limit"); - return; + return SRSRAN_ERROR; } // Order is important here: write last the callback member as it is used to signal that the handler is valid when // reading the array. registered_handlers[pos].data.store(data); registered_handlers[pos].callback.store(callback); + + return pos; +} + +void remove_emergency_cleanup_handler(int id) +{ + if (id < 0 || static_cast(id) >= num_handlers) { + srsran_assert(0, "Invalid emergency handler id"); + return; + } + + registered_handlers[id].callback.store(nullptr); } void execute_emergency_cleanup_handlers()