diff --git a/lib/include/srsran/phy/phch/prach.h b/lib/include/srsran/phy/phch/prach.h index a0755f835..c5188a3e6 100644 --- a/lib/include/srsran/phy/phch/prach.h +++ b/lib/include/srsran/phy/phch/prach.h @@ -116,6 +116,21 @@ typedef struct SRSRAN_API { uint32_t sf[5]; } srsran_prach_sf_config_t; +///@brief Maximum number of subframe number candidates for PRACH NR configuration +#define PRACH_NR_CFG_MAX_NOF_SF 5 + +/** + * @brief PRACH configuration for NR as described in TS 38.211 Tables 6.3.3.2-2, 6.3.3.2-3 and 6.3.3.2-4 + */ +typedef struct { + uint32_t preamble_format; + uint32_t x; + uint32_t y; + uint32_t subframe_number[PRACH_NR_CFG_MAX_NOF_SF]; + uint32_t nof_subframe_number; + uint32_t starting_symbol; // subframe number +} prach_nr_config_t; + typedef enum SRSRAN_API { SRSRAN_PRACH_SFN_EVEN = 0, SRSRAN_PRACH_SFN_ANY, @@ -160,6 +175,12 @@ SRSRAN_API bool srsran_prach_tti_opportunity_config_tdd(uint32_t config_idx, uint32_t current_tti, uint32_t* prach_idx); +SRSRAN_API const prach_nr_config_t* srsran_prach_nr_get_cfg_fr1_unpaired(uint32_t config_idx); + +SRSRAN_API bool srsran_prach_nr_tti_opportunity_fr1_unpaired(uint32_t config_idx, uint32_t current_tti); + +SRSRAN_API uint32_t srsran_prach_nr_start_symbol_fr1_unpaired(uint32_t config_idx); + SRSRAN_API uint32_t srsran_prach_f_ra_tdd(uint32_t config_idx, uint32_t tdd_ul_dl_config, uint32_t current_tti, diff --git a/lib/src/phy/phch/prach.c b/lib/src/phy/phch/prach.c index 744ed57a7..210561f55 100644 --- a/lib/src/phy/phch/prach.c +++ b/lib/src/phy/phch/prach.c @@ -114,6 +114,14 @@ srsran_prach_sfn_t srsran_prach_get_sfn(uint32_t config_idx) */ bool srsran_prach_tti_opportunity(srsran_prach_t* p, uint32_t current_tti, int allowed_subframe) { + if (p == NULL) { + return false; + } + + if (p->is_nr) { + return srsran_prach_nr_tti_opportunity_fr1_unpaired(p->config_idx, current_tti); + } + uint32_t config_idx = p->config_idx; if (!p->tdd_config.configured) { return srsran_prach_tti_opportunity_config_fdd(config_idx, current_tti, allowed_subframe); @@ -256,6 +264,66 @@ void srsran_prach_sf_config(uint32_t config_idx, srsran_prach_sf_config_t* sf_co memcpy(sf_config, &prach_sf_config[config_idx % 16], sizeof(srsran_prach_sf_config_t)); } +const prach_nr_config_t* srsran_prach_nr_get_cfg_fr1_unpaired(uint32_t config_idx) +{ + if (config_idx < PRACH_NR_CFG_FR1_UNPAIRED_NOF_CFG) { + return &prach_nr_cfg_fr1_unpaired[config_idx]; + } + + ERROR("Invalid configuration index %d", config_idx); + return NULL; +} + +bool srsran_prach_nr_tti_opportunity_fr1_unpaired(uint32_t config_idx, uint32_t current_tti) +{ + uint32_t sfn = current_tti / SRSRAN_NOF_SF_X_FRAME; + uint32_t sf_idx = current_tti % SRSRAN_NOF_SF_X_FRAME; + + // Get configuration + const prach_nr_config_t* cfg = srsran_prach_nr_get_cfg_fr1_unpaired(config_idx); + if (cfg == NULL) { + return false; + } + + // Protect zero division + if (cfg->x == 0) { + ERROR("Invalid Zero value"); + return false; + } + + // Check for System Frame Number match + if (sfn % cfg->x != cfg->y) { + return false; + } + + // Protect subframe number vector access + if (cfg->nof_subframe_number > PRACH_NR_CFG_MAX_NOF_SF) { + ERROR("Invalid number of subframes (%d)", cfg->nof_subframe_number); + return false; + } + + // Check for subframe number match + for (uint32_t i = 0; i < cfg->nof_subframe_number; i++) { + if (cfg->subframe_number[i] == sf_idx) { + return true; + } + } + + // If reached here, no opportunity + return false; +} + +uint32_t srsran_prach_nr_start_symbol_fr1_unpaired(uint32_t config_idx) +{ + // Get configuration + const prach_nr_config_t* cfg = srsran_prach_nr_get_cfg_fr1_unpaired(config_idx); + if (cfg == NULL) { + return false; + } + + return cfg->starting_symbol; +} + // For debug use only void print(void* d, uint32_t size, uint32_t len, char* file_str) { diff --git a/lib/src/phy/phch/prach_tables.h b/lib/src/phy/phch/prach_tables.h index 334910ea5..902be2599 100644 --- a/lib/src/phy/phch/prach_tables.h +++ b/lib/src/phy/phch/prach_tables.h @@ -433,4 +433,23 @@ srsran_prach_tdd_loc_table_t prach_tdd_loc_table[64][7] = { {4, {{0, 0, 0, 0}, {1, 0, 0, 0}, {2, 0, 0, 0}, {3, 0, 0, 0}}}, {0, {{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}}}, {0, {{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}}}, - {4, {{0, 0, 0, 0}, {1, 0, 0, 0}, {2, 0, 0, 0}, {3, 0, 0, 0}}}}}; \ No newline at end of file + {4, {{0, 0, 0, 0}, {1, 0, 0, 0}, {2, 0, 0, 0}, {3, 0, 0, 0}}}}}; + +#define PRACH_NR_CFG_FR1_UNPAIRED_NOF_CFG 28 + +// Table 6.3.3.2-3: Random access configurations for FR1 and unpaired spectrum. +static const prach_nr_config_t prach_nr_cfg_fr1_unpaired[PRACH_NR_CFG_FR1_UNPAIRED_NOF_CFG] = { + {0, 16, 1, {9}, 1, 0}, {0, 8, 1, {9}, 1, 0}, + {0, 4, 1, {9}, 1, 0}, {0, 2, 0, {9}, 1, 0}, + {0, 2, 1, {9}, 1, 0}, {0, 2, 0, {4}, 1, 0}, + {0, 2, 1, {4}, 1, 0}, {0, 1, 0, {9}, 1, 0}, + {0, 1, 0, {8}, 1, 0}, {0, 1, 0, {7}, 1, 0}, + {0, 1, 0, {6}, 1, 0}, {0, 1, 0, {5}, 1, 0}, + {0, 1, 0, {4}, 1, 0}, {0, 1, 0, {3}, 1, 0}, + {0, 1, 0, {2}, 1, 0}, {0, 1, 0, {1, 6}, 1, 0}, + {0, 1, 0, {1, 6}, 1, 7}, {0, 1, 0, {4, 9}, 1, 0}, + {0, 1, 0, {3, 8}, 1, 0}, {0, 1, 0, {2, 7}, 1, 0}, + {0, 1, 0, {8, 9}, 1, 0}, {0, 1, 0, {4, 8, 9}, 1, 0}, + {0, 1, 0, {3, 4, 9}, 1, 0}, {0, 1, 0, {7, 8, 9}, 1, 0}, + {0, 1, 0, {3, 4, 8, 9}, 1, 0}, {0, 1, 0, {6, 7, 8, 9}, 1, 0}, + {0, 1, 0, {1, 4, 6, 9}, 1, 0}, {0, 1, 0, {1, 3, 5, 7, 9}, 1, 0}};