From cdfbe28b6927269744b9c11e78e2e70cb5940cdf Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Wed, 25 Aug 2021 08:48:47 +0200 Subject: [PATCH] Initial NR-MIB packing/unpacking --- lib/include/srsran/phy/common/phy_common_nr.h | 8 + lib/include/srsran/phy/phch/pbch_msg_nr.h | 62 ++++++ lib/include/srsran/phy/phch/pbch_nr.h | 20 +- lib/include/srsran/phy/phch/phch_cfg_nr.h | 8 - lib/src/phy/phch/pbch_msg_nr.c | 179 ++++++++++++++++++ lib/src/phy/phch/pbch_nr.c | 30 +-- lib/src/phy/phch/test/CMakeLists.txt | 4 + lib/src/phy/phch/test/mib_nr_test.c | 109 +++++++++++ lib/src/phy/sync/test/ssb_decode_test.c | 2 +- 9 files changed, 367 insertions(+), 55 deletions(-) create mode 100644 lib/include/srsran/phy/phch/pbch_msg_nr.h create mode 100644 lib/src/phy/phch/pbch_msg_nr.c create mode 100644 lib/src/phy/phch/test/mib_nr_test.c diff --git a/lib/include/srsran/phy/common/phy_common_nr.h b/lib/include/srsran/phy/common/phy_common_nr.h index 87a679fbd..b5da5ada1 100644 --- a/lib/include/srsran/phy/common/phy_common_nr.h +++ b/lib/include/srsran/phy/common/phy_common_nr.h @@ -357,6 +357,14 @@ typedef enum SRSRAN_API { SRSRAN_DUPLEX_MODE_INVALID } srsran_duplex_mode_t; +/** + * @brief Determines whether the first DMRS goes into symbol index 2 or 3 + */ +typedef enum { + srsran_dmrs_sch_typeA_pos_2 = 0, // Start in slot symbol index 2 (default) + srsran_dmrs_sch_typeA_pos_3 // Start in slot symbol index 3 +} srsran_dmrs_sch_typeA_pos_t; + /** * @brief NR carrier parameters. It is a combination of fixed cell and bandwidth-part (BWP) */ diff --git a/lib/include/srsran/phy/phch/pbch_msg_nr.h b/lib/include/srsran/phy/phch/pbch_msg_nr.h new file mode 100644 index 000000000..8d1e09c09 --- /dev/null +++ b/lib/include/srsran/phy/phch/pbch_msg_nr.h @@ -0,0 +1,62 @@ +/** + * + * \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_PBCH_MSG_NR_H +#define SRSRAN_PBCH_MSG_NR_H + +#include "srsran/config.h" +#include "srsran/phy/common/phy_common_nr.h" +#include +#include + +/** + * @brief NR PBCH payload size generated by higher layers, deduced from TS 38.331 MIB description + */ +#define SRSRAN_PBCH_MSG_NR_SZ 24 + +/** + * @brief Describes the NR PBCH message + */ +typedef struct SRSRAN_API { + uint8_t payload[SRSRAN_PBCH_MSG_NR_SZ]; ///< Actual PBCH payload provided by higher layers + uint8_t sfn_4lsb; ///< SFN 4 LSB + uint8_t ssb_idx; ///< SS/PBCH blocks index described in TS 38.213 4.1 + uint8_t k_ssb_msb; ///< Subcarrier offset MSB described in TS 38.211 7.4.3.1 + bool hrf; ///< Half Radio Frame bit + bool crc; ///< Decoder only, it is true only if the received CRC matches +} srsran_pbch_msg_nr_t; + +typedef struct SRSRAN_API { + uint32_t sfn; ///< System frame number + uint8_t ssb_idx; ///< SS/PBCH blocks index described in TS 38.213 4.1 + bool hrf; ///< Half Radio Frame bit + srsran_subcarrier_spacing_t scs_common; ///< Subcarrier spacing common + uint32_t ssb_offset; ///< SSB subcarrier offset + srsran_dmrs_sch_typeA_pos_t dmrs_typeA_pos; ///< DMRS typeA position + uint32_t coreset0_idx; ///< CORESET Zero configuration index (0-15) + uint32_t ss0_idx; ///< SearchSpace Zero configuration index (0-15) + bool cell_barred; ///< Set to true if the cell is barred + bool intra_freq_reselection; ///< Set to true if allowed + uint32_t spare; ///< Unused bits +} srsran_mib_nr_t; + +SRSRAN_API bool srsran_pbch_msg_nr_is_mib(const srsran_pbch_msg_nr_t* msg); + +SRSRAN_API int srsran_pbch_msg_nr_mib_pack(const srsran_mib_nr_t* mib, srsran_pbch_msg_nr_t* msg); + +SRSRAN_API int srsran_pbch_msg_nr_mib_unpack(const srsran_pbch_msg_nr_t* pbch_msg, srsran_mib_nr_t* mib); + +SRSRAN_API uint32_t srsran_pbch_msg_info(const srsran_pbch_msg_nr_t* msg, char* str, uint32_t str_len); + +SRSRAN_API uint32_t srsran_pbch_msg_nr_mib_info(const srsran_mib_nr_t* mib, char* str, uint32_t str_len); + +#endif // SRSRAN_PBCH_MSG_NR_H diff --git a/lib/include/srsran/phy/phch/pbch_nr.h b/lib/include/srsran/phy/phch/pbch_nr.h index c91f68bdf..0ce10f0d8 100644 --- a/lib/include/srsran/phy/phch/pbch_nr.h +++ b/lib/include/srsran/phy/phch/pbch_nr.h @@ -20,11 +20,7 @@ #include "srsran/phy/fec/polar/polar_encoder.h" #include "srsran/phy/fec/polar/polar_rm.h" #include "srsran/phy/modem/modem_table.h" - -/** - * @brief NR PBCH payload size generated by higher layers, deduced from TS 38.331 MIB description - */ -#define SRSRAN_PBCH_NR_PAYLOAD_SZ 24 +#include "srsran/phy/phch/pbch_msg_nr.h" /** * @brief Describes the NR PBCH object initialisation arguments @@ -59,18 +55,6 @@ typedef struct SRSRAN_API { srsran_modem_table_t qpsk; } srsran_pbch_nr_t; -/** - * @brief Describes the PBCH message - */ -typedef struct SRSRAN_API { - uint8_t payload[SRSRAN_PBCH_NR_PAYLOAD_SZ]; ///< Actual PBCH payload provided by higher layers - uint8_t sfn_4lsb; ///< SFN 4 LSB - uint8_t ssb_idx; ///< SS/PBCH blocks index described in TS 38.213 4.1 - uint8_t k_ssb_msb; ///< Subcarrier offset MSB described in TS 38.211 7.4.3.1 - bool hrf; ///< Half Radio Frame bit - bool crc; ///< Decoder only, it is true only if the received CRC matches -} srsran_pbch_msg_nr_t; - /** * @brief Initialises an NR PBCH object with the provided arguments * @param q NR PBCH object @@ -112,6 +96,4 @@ SRSRAN_API int srsran_pbch_nr_decode(srsran_pbch_nr_t* q, const cf_t ce[SRSRAN_SSB_NOF_RE], srsran_pbch_msg_nr_t* msg); -SRSRAN_API uint32_t srsran_pbch_msg_info(const srsran_pbch_msg_nr_t* msg, char* str, uint32_t str_len); - #endif // SRSRAN_PBCH_NR_H diff --git a/lib/include/srsran/phy/phch/phch_cfg_nr.h b/lib/include/srsran/phy/phch/phch_cfg_nr.h index a8e8d337c..cd76ecc0b 100644 --- a/lib/include/srsran/phy/phch/phch_cfg_nr.h +++ b/lib/include/srsran/phy/phch/phch_cfg_nr.h @@ -49,14 +49,6 @@ typedef enum { srsran_dmrs_sch_len_2 // double, 2 symbol long } srsran_dmrs_sch_len_t; -/** - * @brief Determines whether the first pilot goes into symbol index 2 or 3 - */ -typedef enum { - srsran_dmrs_sch_typeA_pos_2 = 0, // Start in slot symbol index 2 (default) - srsran_dmrs_sch_typeA_pos_3 // Start in slot symbol index 3 -} srsran_dmrs_sch_typeA_pos_t; - /** * @brief Determines additional symbols if possible to be added */ diff --git a/lib/src/phy/phch/pbch_msg_nr.c b/lib/src/phy/phch/pbch_msg_nr.c new file mode 100644 index 000000000..9f223be24 --- /dev/null +++ b/lib/src/phy/phch/pbch_msg_nr.c @@ -0,0 +1,179 @@ +/** + * + * \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/phch/pbch_msg_nr.h" +#include "srsran/phy/utils/bit.h" +#include "srsran/phy/utils/vector.h" + +static bool pbch_msg_nr_is_mib(const srsran_pbch_msg_nr_t* msg) +{ + return msg->payload[0] == 0; +} + +bool srsran_pbch_msg_nr_is_mib(const srsran_pbch_msg_nr_t* msg) +{ + if (msg == NULL) { + return false; + } + + return pbch_msg_nr_is_mib(msg); +} + +int srsran_pbch_msg_nr_mib_pack(const srsran_mib_nr_t* mib, srsran_pbch_msg_nr_t* pbch_msg) +{ + if (mib == NULL || pbch_msg == NULL) { + return SRSRAN_ERROR_INVALID_INPUTS; + } + + // Copy PBCH message context + pbch_msg->sfn_4lsb = mib->sfn & 0b1111; + pbch_msg->ssb_idx = mib->ssb_idx; + pbch_msg->k_ssb_msb = mib->ssb_offset >> 4U; + pbch_msg->hrf = mib->hrf; + + // Pack MIB payload + uint8_t* y = pbch_msg->payload; + + // MIB - 1 bit + *(y++) = 0; + + // systemFrameNumber - 6 bits MSB + srsran_bit_unpack(mib->sfn >> 4U, &y, 6); + + // subCarrierSpacingCommon - 1 bit + *(y++) = (mib->scs_common == srsran_subcarrier_spacing_15kHz || mib->scs_common == srsran_subcarrier_spacing_60kHz) + ? 0 + : 1; + + // ssb-SubcarrierOffset - 4 bits + srsran_bit_unpack(mib->ssb_offset, &y, 4); + + // dmrs-TypeA-Position - 1 bit + *(y++) = (mib->dmrs_typeA_pos == srsran_dmrs_sch_typeA_pos_2) ? 0 : 1; + + // pdcch-ConfigSIB1 + // controlResourceSetZero - 4 bits + srsran_bit_unpack(mib->coreset0_idx, &y, 4); + + // searchSpaceZero - 4 bits + srsran_bit_unpack(mib->ss0_idx, &y, 4); + + // Barred - 1 bit + *(y++) = (mib->cell_barred) ? 0 : 1; + + // intraFreqReselection - 1 bit + *(y++) = (mib->intra_freq_reselection) ? 0 : 1; + + // Spare - 1 bit + srsran_bit_unpack(mib->spare, &y, 1); + + return SRSRAN_SUCCESS; +} + +int srsran_pbch_msg_nr_mib_unpack(const srsran_pbch_msg_nr_t* pbch_msg, srsran_mib_nr_t* mib) +{ + if (mib == NULL || pbch_msg == NULL) { + return SRSRAN_ERROR_INVALID_INPUTS; + } + + // Copy PBCH message context + mib->sfn = pbch_msg->sfn_4lsb; + mib->ssb_idx = pbch_msg->ssb_idx; + mib->hrf = pbch_msg->hrf; + mib->ssb_offset = pbch_msg->k_ssb_msb << 4U; + + // Pack MIB payload + uint8_t* y = (uint8_t*)pbch_msg->payload; + + // MIB - 1 bit + if (!pbch_msg_nr_is_mib(pbch_msg)) { + return SRSRAN_ERROR; + } + y++; + + // systemFrameNumber - 6 bits MSB + mib->sfn |= srsran_bit_pack(&y, 6) << 4U; + + // subCarrierSpacingCommon - 1 bit + mib->scs_common = *(y++) == 0 ? srsran_subcarrier_spacing_15kHz : srsran_subcarrier_spacing_30kHz; + + // ssb-SubcarrierOffset - 4 bits + mib->ssb_offset |= srsran_bit_pack(&y, 4); + + // dmrs-TypeA-Position - 1 bit + mib->dmrs_typeA_pos = *(y++) == 0 ? srsran_dmrs_sch_typeA_pos_2 : srsran_dmrs_sch_typeA_pos_3; + + // pdcch-ConfigSIB1 + // controlResourceSetZero - 4 bits + mib->coreset0_idx = srsran_bit_pack(&y, 4); + + // searchSpaceZero - 4 bits + mib->ss0_idx = srsran_bit_pack(&y, 4); + + // Barred - 1 bit + mib->cell_barred = (*(y++) == 0); + + // intraFreqReselection - 1 bit + mib->intra_freq_reselection = (*(y++) == 0); + + // Spare - 1 bit + mib->spare = srsran_bit_pack(&y, 1); + + return SRSRAN_SUCCESS; +} + +uint32_t srsran_pbch_msg_info(const srsran_pbch_msg_nr_t* msg, char* str, uint32_t str_len) +{ + if (msg == NULL || str == NULL || str_len == 0) { + return 0; + } + + uint32_t len = 0; + + len = srsran_print_check(str, str_len, len, "payload="); + + len += srsran_vec_sprint_hex(&str[len], str_len - len, (uint8_t*)msg->payload, SRSRAN_PBCH_MSG_NR_SZ); + + len = srsran_print_check(str, + str_len, + len, + " sfn_lsb=%d ssb_idx=%d k_ssb_msb=%d hrf=%d ", + msg->sfn_4lsb, + msg->ssb_idx, + msg->k_ssb_msb, + msg->hrf); + + return len; +} + +uint32_t srsran_pbch_msg_nr_mib_info(const srsran_mib_nr_t* mib, char* str, uint32_t str_len) +{ + uint32_t len = 0; + + len = srsran_print_check(str, + str_len, + len, + "sfn=%d ssb_idx=%d hrf=%c scs=%d ssb_offset=%d dmrs_typeA_pos=%s coreset0=%d ss0=%d " + "barred=%c intra_freq_reselection=%c spare=%d", + mib->sfn, + mib->ssb_idx, + mib->hrf ? 'y' : 'n', + SRSRAN_SUBC_SPACING_NR(mib->scs_common) / 1000, + mib->ssb_offset, + mib->dmrs_typeA_pos == srsran_dmrs_sch_typeA_pos_2 ? "pos2" : "pos3", + mib->coreset0_idx, + mib->ss0_idx, + mib->cell_barred ? 'y' : 'n', + mib->intra_freq_reselection ? 'y' : 'n', + mib->spare); + + return len; +} diff --git a/lib/src/phy/phch/pbch_nr.c b/lib/src/phy/phch/pbch_nr.c index bc4e28c9a..e91145ac8 100644 --- a/lib/src/phy/phch/pbch_nr.c +++ b/lib/src/phy/phch/pbch_nr.c @@ -43,7 +43,7 @@ /* * Number of generated payload bits, called A */ -#define PBCH_NR_A (SRSRAN_PBCH_NR_PAYLOAD_SZ + 8) +#define PBCH_NR_A (SRSRAN_PBCH_MSG_NR_SZ + 8) /* * Number of payload bits plus CRC @@ -184,7 +184,7 @@ static void pbch_nr_pbch_msg_pack(const srsran_pbch_nr_cfg_t* cfg, const srsran_pbch_msg_nr_t* msg, uint8_t a[PBCH_NR_A]) { // Extract actual payload size - uint32_t A_hat = SRSRAN_PBCH_NR_PAYLOAD_SZ; + uint32_t A_hat = SRSRAN_PBCH_MSG_NR_SZ; // Put SFN in a_hat[A_hat] to a_hat[A_hat + 3] uint32_t j_sfn = 0; @@ -231,7 +231,7 @@ pbch_nr_pbch_msg_unpack(const srsran_pbch_nr_cfg_t* cfg, const uint8_t a[PBCH_NR } // Extract actual payload size - uint32_t A_hat = SRSRAN_PBCH_NR_PAYLOAD_SZ; + uint32_t A_hat = SRSRAN_PBCH_MSG_NR_SZ; // Put SFN in a_hat[A_hat] to a_hat[A_hat + 3] uint32_t j_sfn = 0; @@ -651,27 +651,3 @@ int srsran_pbch_nr_decode(srsran_pbch_nr_t* q, return SRSRAN_SUCCESS; } - -uint32_t srsran_pbch_msg_info(const srsran_pbch_msg_nr_t* msg, char* str, uint32_t str_len) -{ - if (msg == NULL || str == NULL || str_len == 0) { - return 0; - } - - uint32_t len = 0; - - len = srsran_print_check(str, str_len, len, "payload="); - - len += srsran_vec_sprint_hex(&str[len], str_len - len, (uint8_t*)msg->payload, SRSRAN_PBCH_NR_PAYLOAD_SZ); - - len = srsran_print_check(str, - str_len, - len, - " sfn_lsb=%d ssb_idx=%d k_ssb_msb=%d hrf=%d ", - msg->sfn_4lsb, - msg->ssb_idx, - msg->k_ssb_msb, - msg->hrf); - - return len; -} diff --git a/lib/src/phy/phch/test/CMakeLists.txt b/lib/src/phy/phch/test/CMakeLists.txt index 965651324..7a93a4de9 100644 --- a/lib/src/phy/phch/test/CMakeLists.txt +++ b/lib/src/phy/phch/test/CMakeLists.txt @@ -627,6 +627,10 @@ add_executable(dci_nr_test dci_nr_test.c) target_link_libraries(dci_nr_test srsran_phy) add_nr_test(dci_nr_test dci_nr_test) +add_executable(mib_nr_test mib_nr_test.c) +target_link_libraries(mib_nr_test srsran_phy) +add_nr_test(mib_nr_test mib_nr_test) + add_executable(pucch_nr_test pucch_nr_test.c) target_link_libraries(pucch_nr_test srsran_phy) add_nr_test(pucch_nr_test pucch_nr_test) diff --git a/lib/src/phy/phch/test/mib_nr_test.c b/lib/src/phy/phch/test/mib_nr_test.c new file mode 100644 index 000000000..4ea88fbc7 --- /dev/null +++ b/lib/src/phy/phch/test/mib_nr_test.c @@ -0,0 +1,109 @@ +/** + * + * \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/phch/pbch_msg_nr.h" +#include "srsran/phy/utils/debug.h" +#include "srsran/phy/utils/random.h" +#include "srsran/support/srsran_test.h" +#include +#include + +static uint32_t nof_repetitions = 16; +static srsran_random_t random_gen = NULL; + +static int test_packing_unpacking() +{ + for (uint32_t r = 0; r < nof_repetitions; r++) { + srsran_mib_nr_t mib = {}; + mib.sfn = srsran_random_uniform_int_dist(random_gen, 0, 1023); + mib.ssb_idx = srsran_random_uniform_int_dist(random_gen, 0, 127); + mib.hrf = srsran_random_bool(random_gen, 0.5f); + mib.scs_common = + srsran_random_bool(random_gen, 0.5f) ? srsran_subcarrier_spacing_15kHz : srsran_subcarrier_spacing_30kHz; + mib.ssb_offset = srsran_random_uniform_int_dist(random_gen, 0, 31); + mib.dmrs_typeA_pos = + srsran_random_bool(random_gen, 0.5f) ? srsran_dmrs_sch_typeA_pos_2 : srsran_dmrs_sch_typeA_pos_3; + mib.coreset0_idx = srsran_random_uniform_int_dist(random_gen, 0, 15); + mib.ss0_idx = srsran_random_uniform_int_dist(random_gen, 0, 15); + mib.cell_barred = srsran_random_bool(random_gen, 0.5f); + mib.intra_freq_reselection = srsran_random_bool(random_gen, 0.5f); + mib.spare = srsran_random_uniform_int_dist(random_gen, 0, 1); + + srsran_pbch_msg_nr_t pbch_msg = {}; + TESTASSERT(srsran_pbch_msg_nr_mib_pack(&mib, &pbch_msg) == SRSRAN_SUCCESS); + + TESTASSERT(srsran_pbch_msg_nr_is_mib(&pbch_msg)); + + srsran_mib_nr_t mib2 = {}; + TESTASSERT(srsran_pbch_msg_nr_mib_unpack(&pbch_msg, &mib2) == SRSRAN_SUCCESS); + + char str1[256]; + char str2[256]; + char strp[256]; + srsran_pbch_msg_nr_mib_info(&mib, str1, (uint32_t)sizeof(str1)); + srsran_pbch_msg_nr_mib_info(&mib2, str2, (uint32_t)sizeof(str2)); + srsran_pbch_msg_info(&pbch_msg, strp, (uint32_t)sizeof(strp)); + + if (memcmp(&mib, &mib2, sizeof(srsran_mib_nr_t)) != 0) { + ERROR("Failed packing/unpacking MIB"); + printf(" Source: %s\n", str1); + printf("Unpacked: %s\n", str2); + printf(" Packed: %s\n", strp); + return SRSRAN_ERROR; + } + } + + return SRSRAN_SUCCESS; +} + +static void usage(char* prog) +{ + printf("Usage: %s [cpndv]\n", prog); + printf("\t-v Increase verbose [default none]\n"); + printf("\t-R Set number of Packing/Unpacking [default %d]\n", nof_repetitions); +} + +static void parse_args(int argc, char** argv) +{ + int opt; + while ((opt = getopt(argc, argv, "vR")) != -1) { + switch (opt) { + case 'v': + srsran_verbose++; + break; + case 'R': + nof_repetitions = (uint32_t)strtol(argv[optind], NULL, 10); + break; + default: + usage(argv[0]); + exit(-1); + } + } +} + +int main(int argc, char** argv) +{ + parse_args(argc, argv); + + int ret = SRSRAN_ERROR; + random_gen = srsran_random_init(1234); + + if (test_packing_unpacking() < SRSRAN_SUCCESS) { + goto clean_exit; + } + + ret = SRSRAN_SUCCESS; + +clean_exit: + srsran_random_free(random_gen); + return ret; +} diff --git a/lib/src/phy/sync/test/ssb_decode_test.c b/lib/src/phy/sync/test/ssb_decode_test.c index 5374b3571..ac7510c93 100644 --- a/lib/src/phy/sync/test/ssb_decode_test.c +++ b/lib/src/phy/sync/test/ssb_decode_test.c @@ -82,7 +82,7 @@ static void gen_pbch_msg(srsran_pbch_msg_nr_t* pbch_msg, uint32_t ssb_idx) SRSRAN_MEM_ZERO(pbch_msg, srsran_pbch_msg_nr_t, 1); // Generate payload - srsran_random_bit_vector(random_gen, pbch_msg->payload, SRSRAN_PBCH_NR_PAYLOAD_SZ); + srsran_random_bit_vector(random_gen, pbch_msg->payload, SRSRAN_PBCH_MSG_NR_SZ); pbch_msg->ssb_idx = ssb_idx; pbch_msg->crc = true;