diff --git a/lib/include/srslte/phy/phch/pucch.h b/lib/include/srslte/phy/phch/pucch.h index 47b6608d2..46f0894c3 100644 --- a/lib/include/srslte/phy/phch/pucch.h +++ b/lib/include/srslte/phy/phch/pucch.h @@ -51,7 +51,6 @@ #define SRSLTE_PUCCH_CS_MAX_ACK 4 #define SRSLTE_PUCCH_CS_MAX_CARRIERS 2 #define SRSLTE_PUCCH_FORMAT3_MAX_CARRIERS 5 -#define SRSLTE_PUCCH_CS_MAX_NOF_ALLOC 4 #define SRSLTE_PUCCH_DEFAULT_THRESHOLD_FORMAT1 (0.1f) @@ -164,48 +163,4 @@ srslte_pucch_rx_info(srslte_pucch_cfg_t* cfg, srslte_uci_value_t* uci_data, char SRSLTE_API bool srslte_pucch_cfg_isvalid(srslte_pucch_cfg_t* cfg, uint32_t nof_prb); -/** - * Implements 3GPP 36.213 R10 10.1 PUCCH format selection - * @param cfg PUCCH configuration struct - * @param uci_cfg uplink control information configuration - * @param uci_value uplink control information, set NULL for eNb - * @param cp Cyclic prefix - * @return Returns the number of entries in the table or negative value indicating error - */ -SRSLTE_API srslte_pucch_format_t srslte_pucch_select_format(srslte_pucch_cfg_t* cfg, - srslte_uci_cfg_t* uci_cfg, - srslte_cp_t cp); - -/** - * 3GPP 36.213 R10 10.1.2.2.1 PUCCH format 1b with channel selection HARQ-ACK procedure. Determines the A - * PUCCH resources, n_pucch_i associated with HARQ-ACK(j) where 0 ≤ j ≤ A − 1 in Table 10.1.2.2.1-1 - * - * @param cfg PUCCH configuration struct - * @param uci_cfg uplink control information configuration - * @param n_pucch_i table with the PUCCH format 1b possible resources - * @return Returns the number of entries in the table or negative value indicating error - */ -SRSLTE_API int srslte_pucch_cs_resources(const srslte_pucch_cfg_t* cfg, - const srslte_uci_cfg_t* uci_cfg, - uint32_t n_pucch_i[SRSLTE_PUCCH_CS_MAX_NOF_ALLOC]); - -/** - * Decodes the HARQ ACK bits from a selected resource (j) and received bits (b) - * 3GPP 36.213 R10 10.1.2.2.1 PUCCH format 1b with channel selection HARQ-ACK procedure - * tables: - * - Table 10.1.2.2.1-3: Transmission of Format 1b HARQ-ACK channel selection for A = 2 - * - Table 10.1.2.2.1-4: Transmission of Format 1b HARQ-ACK channel selection for A = 3 - * - Table 10.1.2.2.1-5: Transmission of Format 1b HARQ-ACK channel selection for A = 4 - * @param cfg PUCCH configuration struct - * @param uci_cfg uplink control information configuration - * @param j selected channel - * @param b received bits - * @return Returns SRSLTE_SUCCESS if it can decode it succesfully, SRSLTE_ERROR code otherwise - */ -SRSLTE_API int srslte_pucch_cs_get_ack(srslte_pucch_cfg_t* cfg, - srslte_uci_cfg_t* uci_cfg, - uint32_t j, - uint8_t b[SRSLTE_PUCCH_1B_2B_NOF_ACK], - srslte_uci_value_t* uci_value); - #endif // SRSLTE_PUCCH_H diff --git a/lib/include/srslte/phy/phch/pucch_proc.h b/lib/include/srslte/phy/phch/pucch_proc.h new file mode 100644 index 000000000..2323b4a0b --- /dev/null +++ b/lib/include/srslte/phy/phch/pucch_proc.h @@ -0,0 +1,98 @@ +/* + * Copyright 2013-2019 Software Radio Systems Limited + * + * This file is part of srsLTE. + * + * srsLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#ifndef SRSLTE_PUCCH_PROC_H_ +#define SRSLTE_PUCCH_PROC_H_ + +#include "srslte/config.h" +#include "srslte/phy/ch_estimation/chest_ul.h" +#include "srslte/phy/common/phy_common.h" +#include "srslte/phy/common/sequence.h" +#include "srslte/phy/modem/mod.h" +#include "srslte/phy/phch/pucch.h" +#include "srslte/phy/phch/uci.h" + +#define SRSLTE_PUCCH_MAX_ALLOC 4 + +/** + * Implements 3GPP 36.213 R10 10.1 PUCCH format selection + * @param cell cell configuration + * @param cfg PUCCH configuration struct + * @param uci_cfg uplink control information configuration + * @param uci_value uplink control information data, use NULL if unavailable + * @return + */ +SRSLTE_API srslte_pucch_format_t srslte_pucch_proc_select_format(const srslte_cell_t* cell, + const srslte_pucch_cfg_t* cfg, + const srslte_uci_cfg_t* uci_cfg, + const srslte_uci_value_t* uci_value); + +/** + * Determines the possible n_pucch_i resources/locations for PUCCH. It follows 3GPP 36.213 R10 10.1 UE procedure for + * determining physical uplink control channel assignment. + * + * @param cell cell configuration + * @param cfg PUCCH configuration struct + * @param uci_cfg uplink control information configuration + * @param uci_value uplink control information value + * @param n_pucch_i table with the PUCCH format 1b possible resources + * @return Returns the number of entries in the table or negative value indicating error + */ +SRSLTE_API int srslte_pucch_proc_get_resources(const srslte_cell_t* cell, + const srslte_pucch_cfg_t* cfg, + const srslte_uci_cfg_t* uci_cfg, + const srslte_uci_value_t* uci_value, + uint32_t* n_pucch_i); +/** + * Determines the n_pucch resource for PUCCH. + * @param cell Cell setup + * @param cfg PUCCH configuration + * @param uci_cfg UCI configuration (CS and TDD HARQ-ACK modes may modify this value) + * @param uci_value UCI Value (CS and TDD HARQ-ACK modes may modify this value) + * @param b Selected ACK-NACK bits after HARQ-ACK feedback mode "encoding" + * @return the selected resource + */ +SRSLTE_API uint32_t srslte_pucch_proc_get_npucch(const srslte_cell_t* cell, + const srslte_pucch_cfg_t* cfg, + const srslte_uci_cfg_t* uci_cfg, + const srslte_uci_value_t* uci_value, + uint8_t b[SRSLTE_UCI_MAX_ACK_BITS]); + +/** + * Decodes the HARQ ACK bits from a selected resource (j) and received bits (b) + * 3GPP 36.213 R10 10.1.2.2.1 PUCCH format 1b with channel selection HARQ-ACK procedure + * tables: + * - Table 10.1.2.2.1-3: Transmission of Format 1b HARQ-ACK channel selection for A = 2 + * - Table 10.1.2.2.1-4: Transmission of Format 1b HARQ-ACK channel selection for A = 3 + * - Table 10.1.2.2.1-5: Transmission of Format 1b HARQ-ACK channel selection for A = 4 + * @param cfg PUCCH configuration struct + * @param uci_cfg uplink control information configuration + * @param j selected channel + * @param b received bits + * @return Returns SRSLTE_SUCCESS if it can decode it succesfully, SRSLTE_ERROR code otherwise + */ +SRSLTE_API int srslte_pucch_cs_get_ack(const srslte_pucch_cfg_t* cfg, + const srslte_uci_cfg_t* uci_cfg, + uint32_t j, + const uint8_t b[SRSLTE_PUCCH_1B_2B_NOF_ACK], + srslte_uci_value_t* uci_value); + +#endif // SRSLTE_PUCCH_PROC_H_ diff --git a/lib/include/srslte/phy/phch/uci.h b/lib/include/srslte/phy/phch/uci.h index df953cfd3..8b4fa8d99 100644 --- a/lib/include/srslte/phy/phch/uci.h +++ b/lib/include/srslte/phy/phch/uci.h @@ -128,7 +128,14 @@ SRSLTE_API int srslte_uci_decode_ack_ri(srslte_pusch_cfg_t* cfg, uint32_t nof_bits, bool is_ri); -SRSLTE_API uint32_t srslte_uci_cfg_total_ack(srslte_uci_cfg_t* uci_cfg); +/** + * Calculates the number of acknowledgements carried by the Uplink Control Information (UCI) deduced from the number of + * transport blocks indicated in the UCI's configuration. + * + * @param uci_cfg is the UCI configuration + * @return the number of acknowledgements + */ +SRSLTE_API uint32_t srslte_uci_cfg_total_ack(const srslte_uci_cfg_t* uci_cfg); SRSLTE_API void srslte_uci_data_reset(srslte_uci_data_t* uci_data); diff --git a/lib/include/srslte/phy/ue/ue_ul.h b/lib/include/srslte/phy/ue/ue_ul.h index 875ec74f0..7703febe1 100644 --- a/lib/include/srslte/phy/ue/ue_ul.h +++ b/lib/include/srslte/phy/ue/ue_ul.h @@ -146,10 +146,21 @@ SRSLTE_API int srslte_ue_ul_sr_send_tti(srslte_pucch_cfg_t* cfg, uint32_t curren SRSLTE_API bool srslte_ue_ul_gen_sr(srslte_ue_ul_cfg_t* cfg, srslte_ul_sf_cfg_t* sf, srslte_uci_data_t* uci_data, bool sr_request); -SRSLTE_API void srslte_ue_ul_pucch_resource_selection(srslte_cell_t* cell, - srslte_pucch_cfg_t* cfg, - srslte_uci_cfg_t* uci_cfg, - srslte_uci_value_t* uci_data); +/** + * Determines the PUCCH resource selection according to 3GPP 36.213 R10 Section 10.1. The PUCCH format and resource are + * saved in cfg->format and cfg->n_pucch. Also, HARQ-ACK + * + * @param cell Cell parameter, non-modifiable + * @param cfg PUCCH configuration and contains function results + * @param uci_cfg UCI configuration + * @param uci_data UCI data + * @param b Modified bits after applying HARQ-ACK feedback mode "encoding" + */ +SRSLTE_API void srslte_ue_ul_pucch_resource_selection(const srslte_cell_t* cell, + srslte_pucch_cfg_t* cfg, + const srslte_uci_cfg_t* uci_cfg, + const srslte_uci_value_t* uci_value, + uint8_t b[SRSLTE_UCI_MAX_ACK_BITS]); SRSLTE_API bool srslte_ue_ul_info(srslte_ue_ul_cfg_t* cfg, srslte_ul_sf_cfg_t* sf, diff --git a/lib/include/srslte/srslte.h b/lib/include/srslte/srslte.h index d50cd50a9..3a1fac98f 100644 --- a/lib/include/srslte/srslte.h +++ b/lib/include/srslte/srslte.h @@ -95,6 +95,7 @@ extern "C" { #include "srslte/phy/phch/phich.h" #include "srslte/phy/phch/prach.h" #include "srslte/phy/phch/pucch.h" +#include "srslte/phy/phch/pucch_proc.h" #include "srslte/phy/phch/pusch.h" #include "srslte/phy/phch/ra.h" #include "srslte/phy/phch/ra_dl.h" diff --git a/lib/src/phy/enb/enb_ul.c b/lib/src/phy/enb/enb_ul.c index c68e74c6a..2885b5f9c 100644 --- a/lib/src/phy/enb/enb_ul.c +++ b/lib/src/phy/enb/enb_ul.c @@ -26,12 +26,6 @@ #include #include -#define CURRENT_FFTSIZE srslte_symbol_sz(q->cell.nof_prb) -#define CURRENT_SFLEN SRSLTE_SF_LEN(CURRENT_FFTSIZE) - -#define CURRENT_SLOTLEN_RE SRSLTE_SLOT_LEN_RE(q->cell.nof_prb, q->cell.cp) -#define CURRENT_SFLEN_RE SRSLTE_NOF_RE(q->cell) - int srslte_enb_ul_init(srslte_enb_ul_t* q, cf_t* in_buffer, uint32_t max_prb) { int ret = SRSLTE_ERROR_INVALID_INPUTS; @@ -170,69 +164,11 @@ void srslte_enb_ul_fft(srslte_enb_ul_t* q) srslte_ofdm_rx_sf(&q->fft); } -static int pucch_resource_selection(srslte_pucch_cfg_t* cfg, - srslte_uci_cfg_t* uci_cfg, - srslte_cell_t* cell, - uint32_t n_pucch_i[SRSLTE_PUCCH_CS_MAX_ACK]) -{ - if (!cfg || !cell || !uci_cfg || !n_pucch_i) { - ERROR("pucch_resource_selection(): Invalid parameters\n"); - return SRSLTE_ERROR_INVALID_INPUTS; - } - - uint32_t total_nof_ack = srslte_uci_cfg_total_ack(uci_cfg); - - // Available scheduling request and PUCCH format is not PUCCH3 - if (uci_cfg->is_scheduling_request_tti && cfg->format != SRSLTE_PUCCH_FORMAT_3) { - n_pucch_i[0] = cfg->n_pucch_sr; - return 1; - } - - // PUCCH formats 1, 1A and 1B (normal anb channel selection modes) - if (cfg->format < SRSLTE_PUCCH_FORMAT_2) { - if (cfg->sps_enabled) { - n_pucch_i[0] = cfg->n_pucch_1[uci_cfg->ack[0].tpc_for_pucch % 4]; - return 1; - } - - if (cell->frame_type == SRSLTE_TDD) { - ERROR("TDD not supported\n"); - return SRSLTE_ERROR; - } - - if (cfg->ack_nack_feedback_mode == SRSLTE_PUCCH_ACK_NACK_FEEDBACK_MODE_CS) { - return srslte_pucch_cs_resources(cfg, uci_cfg, n_pucch_i); - } - - if (cfg->ack_nack_feedback_mode == SRSLTE_PUCCH_ACK_NACK_FEEDBACK_MODE_NORMAL || - (cfg->ack_nack_feedback_mode == SRSLTE_PUCCH_ACK_NACK_FEEDBACK_MODE_PUCCH3 && - total_nof_ack == uci_cfg->ack[0].nof_acks)) { - // If normal or feedback mode PUCCH3 with only data in PCell - n_pucch_i[0] = uci_cfg->ack[0].ncce[0] + cfg->N_pucch_1; - return 1; - } - - // Otherwise an error shall be prompt - ERROR("Unhandled PUCCH format mode %s\n", srslte_ack_nack_feedback_mode_string(cfg->ack_nack_feedback_mode)); - return SRSLTE_ERROR; - } - - // PUCCH format 3 - if (cfg->format == SRSLTE_PUCCH_FORMAT_3) { - n_pucch_i[0] = cfg->n3_pucch_an_list[uci_cfg->ack[0].tpc_for_pucch % SRSLTE_PUCCH_SIZE_AN_N3]; - return 1; - } - - // PUCCH format 1 - n_pucch_i[0] = cfg->n_pucch_2; - return 1; -} - static int get_pucch(srslte_enb_ul_t* q, srslte_ul_sf_cfg_t* ul_sf, srslte_pucch_cfg_t* cfg, srslte_pucch_res_t* res) { - int ret = SRSLTE_SUCCESS; - uint32_t n_pucch_i[SRSLTE_PUCCH_CS_MAX_ACK] = {}; - srslte_pucch_res_t pucch_res = {}; + int ret = SRSLTE_SUCCESS; + uint32_t n_pucch_i[SRSLTE_PUCCH_MAX_ALLOC] = {}; + srslte_pucch_res_t pucch_res = {}; // Drop CQI if there is collision with ACK if (!cfg->simul_cqi_ack && srslte_uci_cfg_total_ack(&cfg->uci_cfg) > 0 && cfg->uci_cfg.cqi.data_enable) { @@ -240,10 +176,10 @@ static int get_pucch(srslte_enb_ul_t* q, srslte_ul_sf_cfg_t* ul_sf, srslte_pucch } // Select format - cfg->format = srslte_pucch_select_format(cfg, &cfg->uci_cfg, q->cell.cp); + cfg->format = srslte_pucch_proc_select_format(&q->cell, cfg, &cfg->uci_cfg, NULL); // Get possible resources - int nof_resources = pucch_resource_selection(cfg, &cfg->uci_cfg, &q->cell, n_pucch_i); + int nof_resources = srslte_pucch_proc_get_resources(&q->cell, cfg, &cfg->uci_cfg, NULL, n_pucch_i); if (nof_resources < SRSLTE_SUCCESS || nof_resources > SRSLTE_PUCCH_CS_MAX_ACK) { ERROR("No PUCCH resource could be calculated\n"); return SRSLTE_ERROR; @@ -296,11 +232,11 @@ int srslte_enb_ul_get_pucch(srslte_enb_ul_t* q, if (!srslte_pucch_cfg_isvalid(cfg, q->cell.nof_prb)) { ERROR("Invalid PUCCH configuration\n"); - return -1; + return SRSLTE_ERROR_INVALID_INPUTS; } if (get_pucch(q, ul_sf, cfg, res)) { - return -1; + return SRSLTE_ERROR; } // If we are looking for SR and ACK at the same time and ret=0, means there is no SR. diff --git a/lib/src/phy/phch/pucch.c b/lib/src/phy/phch/pucch.c index 7558bc8d7..866112e2d 100644 --- a/lib/src/phy/phch/pucch.c +++ b/lib/src/phy/phch/pucch.c @@ -1252,206 +1252,3 @@ void srslte_pucch_rx_info(srslte_pucch_cfg_t* cfg, srslte_uci_value_t* uci_data, } } -srslte_pucch_format_t srslte_pucch_select_format(srslte_pucch_cfg_t* cfg, srslte_uci_cfg_t* uci_cfg, srslte_cp_t cp) -{ - srslte_pucch_format_t format = SRSLTE_PUCCH_FORMAT_ERROR; - uint32_t total_ack = srslte_uci_cfg_total_ack(uci_cfg); - - // No CQI data - if (!uci_cfg->cqi.data_enable && uci_cfg->cqi.ri_len == 0) { - if (cfg->ack_nack_feedback_mode == SRSLTE_PUCCH_ACK_NACK_FEEDBACK_MODE_PUCCH3 && - total_ack > uci_cfg->ack[0].nof_acks) { - format = SRSLTE_PUCCH_FORMAT_3; - } - // 1-bit ACK + optional SR - else if (total_ack == 1) { - format = SRSLTE_PUCCH_FORMAT_1A; - } - // 2-bit ACK + optional SR - else if (total_ack >= 2 && total_ack <= 4) { - format = SRSLTE_PUCCH_FORMAT_1B; // with channel selection if > 2 - } - // If UCI value is provided, use SR signal only, otherwise SR request opportunity - else if (uci_cfg->is_scheduling_request_tti) { - format = SRSLTE_PUCCH_FORMAT_1; - } else { - ERROR("Error selecting PUCCH format: Unsupported number of ACK bits %d\n", total_ack); - } - } - // CQI data - else { - // CQI and no ack - if (total_ack == 0) { - format = SRSLTE_PUCCH_FORMAT_2; - } - // CQI + 1-bit ACK - else if (total_ack == 1 && SRSLTE_CP_ISNORM(cp)) { - format = SRSLTE_PUCCH_FORMAT_2A; - } - // CQI + 2-bit ACK - else if (total_ack == 2) { - format = SRSLTE_PUCCH_FORMAT_2B; - } - // CQI + 2-bit ACK + cyclic prefix - else if (total_ack == 1 && SRSLTE_CP_ISEXT(cp)) { - format = SRSLTE_PUCCH_FORMAT_2B; - } - } - return format; -} - -int srslte_pucch_cs_resources(const srslte_pucch_cfg_t* cfg, const srslte_uci_cfg_t* uci_cfg, uint32_t n_pucch_i[4]) -{ - // Check inputs - if (!cfg || !uci_cfg || !n_pucch_i) { - return SRSLTE_ERROR_INVALID_INPUTS; - } - - // Determine up to 4 PUCCH resources n_pucch_j associated with HARQ-ACK(j) - int k = 0; - for (int i = 0; i < SRSLTE_PUCCH_CS_MAX_CARRIERS && k < SRSLTE_PUCCH_CS_MAX_ACK; i++) { - if (uci_cfg->ack[i].grant_cc_idx == 0) { - // - for a PDSCH transmission indicated by the detection of a corresponding PDCCH in subframe n − 4 on the primary - // cell, or for a PDCCH indicating downlink SPS release (defined in subclause 9.2) in subframe n − 4 on the - // primary cell, the PUCCH resource is n_pucch_i = n_cce + N_pucch_1, and for transmission mode that supports up - // to two transport blocks, the PUCCH resource n_pucch_i+1 = n_cce + N_pucch_1 + 1 - for (uint32_t j = 0; j < uci_cfg->ack[i].nof_acks && k < SRSLTE_PUCCH_CS_MAX_ACK; j++) { - n_pucch_i[k++] = uci_cfg->ack[i].ncce[0] + cfg->N_pucch_1 + j; - } - } else if (i == 0) { - // - for a PDSCH transmission on the primary cell where there is not a corresponding PDCCH detected in subframe - // n − 4 , the value of n_pucch_i is determined according to higher layer configuration and Table 9.2-2. For - // transmission mode that supports up to two transport blocks, the PUCCH resource n_pucch_i+1 = n_pucch_i + 1 - for (uint32_t j = 0; j < uci_cfg->ack[i].nof_acks && k < SRSLTE_PUCCH_CS_MAX_ACK; j++) { - n_pucch_i[k++] = cfg->n1_pucch_an_cs[uci_cfg->ack[i].tpc_for_pucch % SRSLTE_PUCCH_SIZE_AN_CS][0] + j; - } - } else { - // - for a PDSCH transmission indicated by the detection of a corresponding PDCCH in subframe n − 4 on the - // secondary cell, the value of n_pucch_i, and the value of n_pucch_i+1 for the transmission mode that supports - // up to two transport blocks is determined according to higher layer configuration and Table 10.1.2.2.1-2. The - // TPC field in the DCI format of the corresponding PDCCH shall be used to determine the PUCCH resource values - // from one of the four resource values configured by higher layers, with the mapping defined in Table - // 10.1.2.2.1-2. For a UE configured for a transmission mode that supports up to two transport blocks a PUCCH - // resource value in Table 10.1.2.2.1-2 maps to two PUCCH resources (n_pucch_i, n_pucch_i + 1), otherwise the - // PUCCH resource value maps to a single PUCCH resource n_pucch_i. - for (uint32_t j = 0; j < uci_cfg->ack[i].nof_acks && k < SRSLTE_PUCCH_CS_MAX_ACK; j++) { - n_pucch_i[k++] = - cfg->n1_pucch_an_cs[uci_cfg->ack[i].tpc_for_pucch % SRSLTE_PUCCH_SIZE_AN_CS][j % SRSLTE_PUCCH_NOF_AN_CS]; - } - } - } - - return k; -} - -#define PUCCH_CS_SET_ACK(J, B0, B1, ...) \ - do { \ - if (j == J && b[0] == B0 && b[1] == B1) { \ - uint8_t pos[] = {__VA_ARGS__}; \ - for (uint32_t i = 0; i < sizeof(pos) && pos[i] < SRSLTE_PUCCH_CS_MAX_ACK; i++) { \ - uci_value[pos[i]] = 1; \ - } \ - ret = SRSLTE_SUCCESS; \ - } \ - } while (false) - -static int puccch_cs_get_ack_a2(uint32_t j, const uint8_t b[2], uint8_t uci_value[SRSLTE_UCI_MAX_ACK_BITS]) -{ - int ret = SRSLTE_ERROR; - - PUCCH_CS_SET_ACK(1, 1, 1, 0, 1); - PUCCH_CS_SET_ACK(0, 1, 1, 0); - PUCCH_CS_SET_ACK(1, 0, 0, 1); - PUCCH_CS_SET_ACK(1, 0, 0, SRSLTE_PUCCH_CS_MAX_ACK); - - return ret; -} - -static int puccch_cs_get_ack_a3(uint32_t j, const uint8_t b[2], uint8_t uci_value[SRSLTE_UCI_MAX_ACK_BITS]) -{ - int ret = SRSLTE_ERROR; - - PUCCH_CS_SET_ACK(1, 1, 1, 0, 1, 2); - PUCCH_CS_SET_ACK(1, 1, 0, 0, 2); - PUCCH_CS_SET_ACK(1, 0, 1, 1, 2); - PUCCH_CS_SET_ACK(2, 1, 1, 2); - PUCCH_CS_SET_ACK(0, 1, 1, 0, 1); - PUCCH_CS_SET_ACK(0, 1, 0, 0); - PUCCH_CS_SET_ACK(0, 0, 1, 1); - PUCCH_CS_SET_ACK(1, 0, 0, SRSLTE_PUCCH_CS_MAX_ACK); - - return ret; -} - -static int puccch_cs_get_ack_a4(uint32_t j, const uint8_t b[2], uint8_t uci_value[SRSLTE_UCI_MAX_ACK_BITS]) -{ - int ret = SRSLTE_ERROR; - - PUCCH_CS_SET_ACK(1, 1, 1, 0, 1, 2, 3); - PUCCH_CS_SET_ACK(2, 0, 1, 0, 2, 3); - PUCCH_CS_SET_ACK(1, 0, 1, 1, 2, 3); - PUCCH_CS_SET_ACK(3, 1, 1, 2, 3); - PUCCH_CS_SET_ACK(1, 1, 0, 0, 1, 2); - PUCCH_CS_SET_ACK(2, 0, 0, 0, 2); - PUCCH_CS_SET_ACK(1, 0, 0, 1, 2); - PUCCH_CS_SET_ACK(3, 1, 0, 2); - PUCCH_CS_SET_ACK(2, 1, 1, 0, 1, 3); - PUCCH_CS_SET_ACK(2, 1, 0, 0, 3); - PUCCH_CS_SET_ACK(3, 0, 1, 1, 3); - PUCCH_CS_SET_ACK(3, 0, 0, 3); - PUCCH_CS_SET_ACK(0, 1, 1, 0, 1); - PUCCH_CS_SET_ACK(0, 1, 0, 0); - PUCCH_CS_SET_ACK(0, 0, 1, 1); - PUCCH_CS_SET_ACK(0, 0, 0, SRSLTE_PUCCH_CS_MAX_ACK); - - return ret; -} - -int srslte_pucch_cs_get_ack(srslte_pucch_cfg_t* cfg, - srslte_uci_cfg_t* uci_cfg, - uint32_t j, - uint8_t b[2], - srslte_uci_value_t* uci_value) -{ - int ret = SRSLTE_ERROR_INVALID_INPUTS; - - if (cfg && uci_cfg && uci_value) { - // Set bits to 0 by default - memset(uci_value->ack.ack_value, 0, SRSLTE_UCI_MAX_ACK_BITS); - uci_value->ack.valid = true; - - uint32_t nof_ack = srslte_uci_cfg_total_ack(uci_cfg); - switch (nof_ack) { - case 2: - // A = 2 - ret = puccch_cs_get_ack_a2(j, b, uci_value->ack.ack_value); - break; - case 3: - // A = 3 - ret = puccch_cs_get_ack_a3(j, b, uci_value->ack.ack_value); - break; - case 4: - // A = 4 - ret = puccch_cs_get_ack_a4(j, b, uci_value->ack.ack_value); - break; - default: - // Unhandled case - ERROR("Unexpected number of ACK (%d)\n", nof_ack); - ret = SRSLTE_ERROR; - } - } - - return ret; -} - -int srslte_pucch_pucch3_resources(const srslte_pucch_cfg_t* cfg, const srslte_uci_cfg_t* uci_cfg, uint32_t n_pucch_i[4]) -{ - int ret = SRSLTE_ERROR_INVALID_INPUTS; - - if (cfg && uci_cfg && n_pucch_i) { - n_pucch_i[0] = cfg->n3_pucch_an_list[uci_cfg->ack[0].tpc_for_pucch % SRSLTE_PUCCH_SIZE_AN_CS]; - ret = 1; - } - - return ret; -} diff --git a/lib/src/phy/phch/pucch_proc.c b/lib/src/phy/phch/pucch_proc.c new file mode 100644 index 000000000..e293c5458 --- /dev/null +++ b/lib/src/phy/phch/pucch_proc.c @@ -0,0 +1,618 @@ +/* + * Copyright 2013-2019 Software Radio Systems Limited + * + * This file is part of srsLTE. + * + * srsLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#include +#include + +static bool pucch_proc_tx_sr(const srslte_uci_cfg_t* uci_cfg, const srslte_uci_value_t* uci_value) +{ + // Check SR transmission + bool tx_sr = uci_cfg->is_scheduling_request_tti; + if (uci_value) { + tx_sr |= uci_value->scheduling_request; + } + return tx_sr; +} + +srslte_pucch_format_t srslte_pucch_proc_select_format(const srslte_cell_t* cell, + const srslte_pucch_cfg_t* cfg, + const srslte_uci_cfg_t* uci_cfg, + const srslte_uci_value_t* uci_value) +{ + srslte_pucch_format_t format = SRSLTE_PUCCH_FORMAT_ERROR; + uint32_t total_ack = srslte_uci_cfg_total_ack(uci_cfg); + + // No CQI data + if (!uci_cfg->cqi.data_enable && uci_cfg->cqi.ri_len == 0) { + if (cfg->ack_nack_feedback_mode == SRSLTE_PUCCH_ACK_NACK_FEEDBACK_MODE_PUCCH3 && + total_ack > uci_cfg->ack[0].nof_acks) { + format = SRSLTE_PUCCH_FORMAT_3; + } + // 1-bit ACK + optional SR + else if (total_ack == 1) { + format = SRSLTE_PUCCH_FORMAT_1A; + } + // 2-bit ACK + optional SR + else if (total_ack >= 2 && total_ack <= 4) { + format = SRSLTE_PUCCH_FORMAT_1B; // with channel selection if > 2 + } + // If UCI value is provided, use SR signal only, otherwise SR request opportunity + else if (pucch_proc_tx_sr(uci_cfg, uci_value)) { + format = SRSLTE_PUCCH_FORMAT_1; + } else { + ERROR("Error selecting PUCCH format: Unsupported number of ACK bits %d\n", total_ack); + } + } + // CQI data + else { + // CQI and no ack + if (total_ack == 0) { + format = SRSLTE_PUCCH_FORMAT_2; + } + // CQI + 1-bit ACK + else if (total_ack == 1 && SRSLTE_CP_ISNORM(cell->cp)) { + format = SRSLTE_PUCCH_FORMAT_2A; + } + // CQI + 2-bit ACK + else if (total_ack == 2) { + format = SRSLTE_PUCCH_FORMAT_2B; + } + // CQI + 2-bit ACK + cyclic prefix + else if (total_ack == 1 && SRSLTE_CP_ISEXT(cell->cp)) { + format = SRSLTE_PUCCH_FORMAT_2B; + } + } + return format; +} + +static int pucch_cs_resources(const srslte_pucch_cfg_t* cfg, + const srslte_uci_cfg_t* uci_cfg, + uint32_t n_pucch_i[SRSLTE_PUCCH_MAX_ALLOC]) +{ + // Check inputs + if (!cfg || !uci_cfg || !n_pucch_i) { + return SRSLTE_ERROR_INVALID_INPUTS; + } + + // Determine up to 4 PUCCH resources n_pucch_j associated with HARQ-ACK(j) + int k = 0; + for (int i = 0; i < SRSLTE_PUCCH_CS_MAX_CARRIERS && k < SRSLTE_PUCCH_CS_MAX_ACK; i++) { + if (uci_cfg->ack[i].grant_cc_idx == 0) { + // - for a PDSCH transmission indicated by the detection of a corresponding PDCCH in subframe n − 4 on the primary + // cell, or for a PDCCH indicating downlink SPS release (defined in subclause 9.2) in subframe n − 4 on the + // primary cell, the PUCCH resource is n_pucch_i = n_cce + N_pucch_1, and for transmission mode that supports up + // to two transport blocks, the PUCCH resource n_pucch_i+1 = n_cce + N_pucch_1 + 1 + for (uint32_t j = 0; j < uci_cfg->ack[i].nof_acks && k < SRSLTE_PUCCH_CS_MAX_ACK; j++) { + n_pucch_i[k++] = uci_cfg->ack[i].ncce[0] + cfg->N_pucch_1 + j; + } + } else if (i == 0) { + // - for a PDSCH transmission on the primary cell where there is not a corresponding PDCCH detected in subframe + // n − 4 , the value of n_pucch_i is determined according to higher layer configuration and Table 9.2-2. For + // transmission mode that supports up to two transport blocks, the PUCCH resource n_pucch_i+1 = n_pucch_i + 1 + for (uint32_t j = 0; j < uci_cfg->ack[i].nof_acks && k < SRSLTE_PUCCH_CS_MAX_ACK; j++) { + n_pucch_i[k++] = cfg->n1_pucch_an_cs[uci_cfg->ack[i].tpc_for_pucch % SRSLTE_PUCCH_SIZE_AN_CS][0] + j; + } + } else { + // - for a PDSCH transmission indicated by the detection of a corresponding PDCCH in subframe n − 4 on the + // secondary cell, the value of n_pucch_i, and the value of n_pucch_i+1 for the transmission mode that supports + // up to two transport blocks is determined according to higher layer configuration and Table 10.1.2.2.1-2. The + // TPC field in the DCI format of the corresponding PDCCH shall be used to determine the PUCCH resource values + // from one of the four resource values configured by higher layers, with the mapping defined in Table + // 10.1.2.2.1-2. For a UE configured for a transmission mode that supports up to two transport blocks a PUCCH + // resource value in Table 10.1.2.2.1-2 maps to two PUCCH resources (n_pucch_i, n_pucch_i + 1), otherwise the + // PUCCH resource value maps to a single PUCCH resource n_pucch_i. + for (uint32_t j = 0; j < uci_cfg->ack[i].nof_acks && k < SRSLTE_PUCCH_CS_MAX_ACK; j++) { + n_pucch_i[k++] = + cfg->n1_pucch_an_cs[uci_cfg->ack[i].tpc_for_pucch % SRSLTE_PUCCH_SIZE_AN_CS][j % SRSLTE_PUCCH_NOF_AN_CS]; + } + } + } + + return k; +} + +#define PUCCH_CS_SET_ACK(J, B0, B1, ...) \ + do { \ + if (j == J && b[0] == B0 && b[1] == B1) { \ + uint8_t pos[] = {__VA_ARGS__}; \ + for (uint32_t i = 0; i < sizeof(pos) && pos[i] < SRSLTE_PUCCH_CS_MAX_ACK; i++) { \ + uci_value[pos[i]] = 1; \ + } \ + ret = SRSLTE_SUCCESS; \ + } \ + } while (false) + +static int puccch_cs_get_ack_a2(uint32_t j, const uint8_t b[2], uint8_t uci_value[SRSLTE_UCI_MAX_ACK_BITS]) +{ + int ret = SRSLTE_ERROR; + + PUCCH_CS_SET_ACK(1, 1, 1, 0, 1); + PUCCH_CS_SET_ACK(0, 1, 1, 0); + PUCCH_CS_SET_ACK(1, 0, 0, 1); + PUCCH_CS_SET_ACK(1, 0, 0, SRSLTE_PUCCH_CS_MAX_ACK); + + return ret; +} + +static int puccch_cs_get_ack_a3(uint32_t j, const uint8_t b[2], uint8_t uci_value[SRSLTE_UCI_MAX_ACK_BITS]) +{ + int ret = SRSLTE_ERROR; + + PUCCH_CS_SET_ACK(1, 1, 1, 0, 1, 2); + PUCCH_CS_SET_ACK(1, 1, 0, 0, 2); + PUCCH_CS_SET_ACK(1, 0, 1, 1, 2); + PUCCH_CS_SET_ACK(2, 1, 1, 2); + PUCCH_CS_SET_ACK(0, 1, 1, 0, 1); + PUCCH_CS_SET_ACK(0, 1, 0, 0); + PUCCH_CS_SET_ACK(0, 0, 1, 1); + PUCCH_CS_SET_ACK(1, 0, 0, SRSLTE_PUCCH_CS_MAX_ACK); + + return ret; +} + +static int puccch_cs_get_ack_a4(uint32_t j, const uint8_t b[2], uint8_t uci_value[SRSLTE_UCI_MAX_ACK_BITS]) +{ + int ret = SRSLTE_ERROR; + + PUCCH_CS_SET_ACK(1, 1, 1, 0, 1, 2, 3); + PUCCH_CS_SET_ACK(2, 0, 1, 0, 2, 3); + PUCCH_CS_SET_ACK(1, 0, 1, 1, 2, 3); + PUCCH_CS_SET_ACK(3, 1, 1, 2, 3); + PUCCH_CS_SET_ACK(1, 1, 0, 0, 1, 2); + PUCCH_CS_SET_ACK(2, 0, 0, 0, 2); + PUCCH_CS_SET_ACK(1, 0, 0, 1, 2); + PUCCH_CS_SET_ACK(3, 1, 0, 2); + PUCCH_CS_SET_ACK(2, 1, 1, 0, 1, 3); + PUCCH_CS_SET_ACK(2, 1, 0, 0, 3); + PUCCH_CS_SET_ACK(3, 0, 1, 1, 3); + PUCCH_CS_SET_ACK(3, 0, 0, 3); + PUCCH_CS_SET_ACK(0, 1, 1, 0, 1); + PUCCH_CS_SET_ACK(0, 1, 0, 0); + PUCCH_CS_SET_ACK(0, 0, 1, 1); + PUCCH_CS_SET_ACK(0, 0, 0, SRSLTE_PUCCH_CS_MAX_ACK); + + return ret; +} + +int srslte_pucch_cs_get_ack(const srslte_pucch_cfg_t* cfg, + const srslte_uci_cfg_t* uci_cfg, + uint32_t j, + const uint8_t b[2], + srslte_uci_value_t* uci_value) +{ + int ret = SRSLTE_ERROR_INVALID_INPUTS; + + if (cfg && uci_cfg && uci_value) { + // Set bits to 0 by default + memset(uci_value->ack.ack_value, 0, SRSLTE_UCI_MAX_ACK_BITS); + uci_value->ack.valid = true; + + uint32_t nof_ack = srslte_uci_cfg_total_ack(uci_cfg); + switch (nof_ack) { + case 2: + // A = 2 + ret = puccch_cs_get_ack_a2(j, b, uci_value->ack.ack_value); + break; + case 3: + // A = 3 + ret = puccch_cs_get_ack_a3(j, b, uci_value->ack.ack_value); + break; + case 4: + // A = 4 + ret = puccch_cs_get_ack_a4(j, b, uci_value->ack.ack_value); + break; + default: + // Unhandled case + ERROR("Unexpected number of ACK (%d)\n", nof_ack); + ret = SRSLTE_ERROR; + } + } + + return ret; +} + +static int pucch_f3_resources(const srslte_pucch_cfg_t* cfg, const srslte_uci_cfg_t* uci_cfg, uint32_t* n_pucch_3) +{ + int ret = SRSLTE_ERROR_INVALID_INPUTS; + + if (cfg && uci_cfg && n_pucch_3) { + n_pucch_3[0] = cfg->n3_pucch_an_list[uci_cfg->ack[0].tpc_for_pucch % SRSLTE_PUCCH_SIZE_AN_CS]; + ret = 1; + } + + return ret; +} + +static uint32_t get_Np(uint32_t p, uint32_t nof_prb) +{ + if (p == 0) { + return 0; + } else { + return nof_prb * (SRSLTE_NRE * p - 4) / 36; + } +} + +static uint32_t n_pucch_i_tdd(uint32_t ncce, uint32_t N_pucch_1, uint32_t nof_prb, uint32_t M, uint32_t m) +{ + uint32_t Np = 0, Np_1 = 0; + for (uint32_t p = 0; p < 4; p++) { + Np = get_Np(p, nof_prb); + Np_1 = get_Np(p + 1, nof_prb); + if (ncce >= Np && ncce < Np_1) { + uint32_t npucch = (M - m - 1) * Np + m * Np_1 + ncce + N_pucch_1; + return npucch; + } + } + ERROR("Could not find Np value for ncce=%d\n", ncce); + return 0; +} + +static int pucch_tdd_resources(const srslte_cell_t* cell, + const srslte_pucch_cfg_t* cfg, + const srslte_uci_cfg_t* uci_cfg, + uint32_t n_pucch_tdd[SRSLTE_PUCCH_MAX_ALLOC]) +{ + int ret = SRSLTE_ERROR_INVALID_INPUTS; + + for (uint32_t i = 0; i < uci_cfg->ack[0].tdd_ack_M; i++) { + n_pucch_tdd[i] = + n_pucch_i_tdd(uci_cfg->ack[0].ncce[i], cfg->N_pucch_1, cell->nof_prb, uci_cfg->ack[0].tdd_ack_M, i); + } + + return ret; +} + +int srslte_pucch_proc_get_resources(const srslte_cell_t* cell, + const srslte_pucch_cfg_t* cfg, + const srslte_uci_cfg_t* uci_cfg, + const srslte_uci_value_t* uci_value, + uint32_t* n_pucch_i) +{ + if (!cfg || !cell || !uci_cfg || !n_pucch_i) { + ERROR("pucch_resource_selection(): Invalid parameters\n"); + return SRSLTE_ERROR_INVALID_INPUTS; + } + + uint32_t total_nof_ack = srslte_uci_cfg_total_ack(uci_cfg); + + // Available scheduling request and PUCCH format is not PUCCH3 + if (pucch_proc_tx_sr(uci_cfg, uci_value) && cfg->format != SRSLTE_PUCCH_FORMAT_3) { + n_pucch_i[0] = cfg->n_pucch_sr; + return 1; + } + + // PUCCH formats 1, 1A and 1B (normal anb channel selection modes) + if (cfg->format < SRSLTE_PUCCH_FORMAT_2) { + if (cfg->sps_enabled) { + n_pucch_i[0] = cfg->n_pucch_1[uci_cfg->ack[0].tpc_for_pucch % 4]; + return 1; + } + + if (cell->frame_type == SRSLTE_TDD) { + return pucch_tdd_resources(cell, cfg, uci_cfg, n_pucch_i); + } + + if (cfg->ack_nack_feedback_mode == SRSLTE_PUCCH_ACK_NACK_FEEDBACK_MODE_CS) { + return pucch_cs_resources(cfg, uci_cfg, n_pucch_i); + } + + if (cfg->ack_nack_feedback_mode == SRSLTE_PUCCH_ACK_NACK_FEEDBACK_MODE_NORMAL || + (cfg->ack_nack_feedback_mode == SRSLTE_PUCCH_ACK_NACK_FEEDBACK_MODE_PUCCH3 && + total_nof_ack == uci_cfg->ack[0].nof_acks)) { + // If normal or feedback mode PUCCH3 with only data in PCell + n_pucch_i[0] = uci_cfg->ack[0].ncce[0] + cfg->N_pucch_1; + return 1; + } + + // Otherwise an error shall be prompt + ERROR("Unhandled PUCCH format mode %s\n", srslte_ack_nack_feedback_mode_string(cfg->ack_nack_feedback_mode)); + return SRSLTE_ERROR; + } + + // PUCCH format 3 + if (cfg->format == SRSLTE_PUCCH_FORMAT_3) { + return pucch_f3_resources(cfg, uci_cfg, n_pucch_i); + } + + // PUCCH format 2 + n_pucch_i[0] = cfg->n_pucch_2; + return 1; +} + +// Selection of n_pucch for PUCCH Format 1a and 1b with channel selection for 1 and 2 CC +static uint32_t get_npucch_cs(const srslte_pucch_cfg_t* cfg, + const srslte_uci_cfg_t* uci_cfg, + const uint32_t n_pucch_i[SRSLTE_PUCCH_MAX_ALLOC], + uint8_t b[SRSLTE_UCI_MAX_ACK_BITS]) +{ + uint32_t n_pucch = 0; + + // Do resource selection and bit mapping according to tables 10.1.2.2.1-3, 10.1.2.2.1-4 and 10.1.2.2.1-5 + uint32_t nof_ack = srslte_uci_cfg_total_ack(uci_cfg); + switch (nof_ack) { + case 1: + // 1-bit is Format1A always + n_pucch = n_pucch_i[0]; + break; + case 2: + if (b[1] != 1) { + /* n_pucch1_0 */ + n_pucch = n_pucch_i[0]; + } else { + /* n_pucch1_1 */ + n_pucch = n_pucch_i[1]; + } + if (b[0] == 1) { + b[0] = 1; + b[1] = 1; + } else { + b[0] = 0; + b[1] = 0; + } + break; + case 3: + if (b[0] != 1 && b[1] != 1) { + /* n_pucch1_2 */ + n_pucch = n_pucch_i[2]; + } else if (b[2] == 1) { + /* n_pucch1_1 */ + n_pucch = n_pucch_i[1]; + } else { + /* n_pucch1_0 */ + n_pucch = n_pucch_i[0]; + } + if (b[0] != 1 && b[1] != 1 && b[2] != 1) { + b[0] = 0; + b[1] = 0; + } else if (b[0] != 1 && b[1] == 1) { + b[0] = 0; + b[1] = 1; + } else if (b[0] == 1 && b[1] != 1) { + b[0] = 1; + b[1] = 0; + } else { + b[0] = 1; + b[1] = 1; + } + break; + case 4: + if (b[2] != 1 && b[3] != 1) { + /* n_pucch1_0 */ + n_pucch = n_pucch_i[0]; + } else if (b[1] == 1 && b[2] == 1) { + /* n_pucch1_1 */ + n_pucch = n_pucch_i[1]; + } else if (b[0] == 1) { + /* n_pucch1_2 */ + n_pucch = n_pucch_i[2]; + } else { + /* n_pucch1_3 */ + n_pucch = n_pucch_i[3]; + } + if (b[2] != 1 && b[3] != 1) { + /* n_pucch1_0 */ + b[0] = (uint8_t)(b[0] != 1 ? 0 : 1); + b[1] = (uint8_t)(b[1] != 1 ? 0 : 1); + } else if (b[1] == 1 && b[2] == 1) { + /* n_pucch1_1 */ + b[0] = (uint8_t)(b[0] != 1 ? 0 : 1); + b[1] = (uint8_t)(b[3] != 1 ? 0 : 1); + } else if (b[0] == 1) { + /* n_pucch1_2 */ + b[0] = (uint8_t)((b[3] != 1 ? 0 : 1) & (b[2] != 1 ? 1 : 0)); + b[1] = (uint8_t)((b[3] != 1 ? 0 : 1) & ((b[1] != 1 ? 0 : 1) ^ (b[2] != 1 ? 0 : 1))); + } else { + /* n_pucch1_3 */ + b[0] = (uint8_t)(b[2] != 1 ? 0 : 1); + b[1] = (uint8_t)(((b[3] == 1) && ((b[1] == 1) != (b[2] == 1))) ? 1 : 0); + } + break; + default: + ERROR("Too many (%d) ACK for this CS mode\n", srslte_uci_cfg_total_ack(uci_cfg)); + } + + return n_pucch; +} + +static void set_b01(uint8_t* b, uint8_t x) +{ + switch (x) { + case 0: + b[0] = 0; + b[1] = 0; + break; + case 1: + b[0] = 0; + b[1] = 1; + break; + case 2: + b[0] = 1; + b[1] = 0; + break; + case 3: + b[0] = 1; + b[1] = 1; + break; + default: + ERROR("Unhandled case (%d)\n", x); + } +} + +#define is_ack(h) (h == 1) +#define is_nack(h) (h == 0) +#define is_nackdtx(h) ((h & 1) == 0) +#define is_dtx(h) (h == 2) + +// n_pucch and b0b1 selection for TDD, tables 10.1-2, 10.1-3 and 10.1-4 +static uint32_t +get_npucch_tdd(const uint32_t n_pucch[4], const srslte_uci_cfg_t* uci_cfg, uint8_t b[SRSLTE_UCI_MAX_ACK_BITS]) +{ + switch (uci_cfg->ack[0].nof_acks) { + case 1: + return n_pucch[0]; + case 2: + if (is_ack(b[0]) && is_ack(b[1])) { + set_b01(b, 3); + return n_pucch[1]; + } else if (is_ack(b[0]) && is_nackdtx(b[1])) { + set_b01(b, 1); + return n_pucch[0]; + } else if (is_nackdtx(b[0]) && is_ack(b[1])) { + set_b01(b, 0); + return n_pucch[1]; + } else if (is_nackdtx(b[0]) && is_nack(b[1])) { + set_b01(b, 2); + return n_pucch[1]; + } else if (is_nack(b[0]) && is_dtx(b[1])) { + set_b01(b, 2); + return n_pucch[0]; + } + break; + case 3: + if (is_ack(b[0]) && is_ack(b[1]) && is_ack(b[2])) { + set_b01(b, 3); + return n_pucch[2]; + } else if (is_ack(b[0]) && is_ack(b[1]) && is_nackdtx(b[2])) { + set_b01(b, 3); + return n_pucch[1]; + } else if (is_ack(b[0]) && is_nackdtx(b[1]) && is_ack(b[2])) { + set_b01(b, 3); + return n_pucch[0]; + } else if (is_ack(b[0]) && is_nackdtx(b[1]) && is_nackdtx(b[2])) { + set_b01(b, 1); + return n_pucch[0]; + } else if (is_nackdtx(b[0]) && is_ack(b[1]) && is_ack(b[2])) { + set_b01(b, 2); + return n_pucch[2]; + } else if (is_nackdtx(b[0]) && is_ack(b[1]) && is_nackdtx(b[2])) { + set_b01(b, 0); + return n_pucch[1]; + } else if (is_nackdtx(b[0]) && is_nackdtx(b[1]) && is_ack(b[2])) { + set_b01(b, 0); + return n_pucch[2]; + } else if (is_dtx(b[0]) && is_dtx(b[1]) && is_nack(b[2])) { + set_b01(b, 1); + return n_pucch[2]; + } else if (is_dtx(b[0]) && is_nack(b[1]) && is_nackdtx(b[2])) { + set_b01(b, 2); + return n_pucch[1]; + } else if (is_nack(b[0]) && is_nackdtx(b[1]) && is_nackdtx(b[2])) { + set_b01(b, 2); + return n_pucch[0]; + } + break; + case 4: + if (is_ack(b[0]) && is_ack(b[1]) && is_ack(b[2]) && is_ack(b[3])) { + set_b01(b, 3); + return n_pucch[1]; + } else if (is_ack(b[0]) && is_ack(b[1]) && is_ack(b[2]) && is_nackdtx(b[3])) { + set_b01(b, 2); + return n_pucch[1]; + } else if (is_nackdtx(b[0]) && is_nackdtx(b[1]) && is_nack(b[2]) && is_dtx(b[3])) { + set_b01(b, 3); + return n_pucch[2]; + } else if (is_ack(b[0]) && is_ack(b[1]) && is_nackdtx(b[2]) && is_ack(b[3])) { + set_b01(b, 2); + return n_pucch[1]; + } else if (is_nack(b[0]) && is_dtx(b[1]) && is_dtx(b[2]) && is_dtx(b[3])) { + set_b01(b, 2); + return n_pucch[0]; + } else if (is_ack(b[0]) && is_ack(b[1]) && is_nackdtx(b[2]) && is_nackdtx(b[3])) { + set_b01(b, 2); + return n_pucch[1]; + } else if (is_ack(b[0]) && is_nackdtx(b[1]) && is_ack(b[2]) && is_ack(b[3])) { + set_b01(b, 1); + return n_pucch[3]; + } else if (is_nackdtx(b[0]) && is_nackdtx(b[1]) && is_nackdtx(b[2]) && is_nack(b[3])) { + set_b01(b, 3); + return n_pucch[3]; + } else if (is_ack(b[0]) && is_nackdtx(b[1]) && is_ack(b[2]) && is_nack(b[3])) { + set_b01(b, 2); + return n_pucch[1]; + } else if (is_ack(b[0]) && is_nackdtx(b[1]) && is_nackdtx(b[2]) && is_ack(b[3])) { + set_b01(b, 1); + return n_pucch[0]; + } else if (is_ack(b[0]) && is_nackdtx(b[1]) && is_nackdtx(b[2]) && is_nackdtx(b[3])) { + set_b01(b, 3); + return n_pucch[0]; + } else if (is_nackdtx(b[0]) && is_ack(b[1]) && is_ack(b[2]) && is_ack(b[3])) { + set_b01(b, 1); + return n_pucch[3]; + } else if (is_nackdtx(b[0]) && is_nack(b[1]) && is_dtx(b[2]) && is_dtx(b[3])) { + set_b01(b, 0); + return n_pucch[1]; + } else if (is_nackdtx(b[0]) && is_ack(b[1]) && is_ack(b[2]) && is_nackdtx(b[3])) { + set_b01(b, 2); + return n_pucch[2]; + } else if (is_nackdtx(b[0]) && is_ack(b[1]) && is_nackdtx(b[2]) && is_ack(b[3])) { + set_b01(b, 2); + return n_pucch[3]; + } else if (is_nackdtx(b[0]) && is_ack(b[1]) && is_nackdtx(b[2]) && is_nackdtx(b[3])) { + set_b01(b, 1); + return n_pucch[1]; + } else if (is_nackdtx(b[0]) && is_nackdtx(b[1]) && is_ack(b[2]) && is_ack(b[3])) { + set_b01(b, 1); + return n_pucch[3]; + } else if (is_nackdtx(b[0]) && is_nackdtx(b[1]) && is_ack(b[2]) && is_nackdtx(b[3])) { + set_b01(b, 0); + return n_pucch[2]; + } else if (is_nackdtx(b[0]) && is_nackdtx(b[1]) && is_nackdtx(b[2]) && is_ack(b[3])) { + set_b01(b, 0); + return n_pucch[3]; + } + } + return 0; +} + +uint32_t srslte_pucch_proc_get_npucch(const srslte_cell_t* cell, + const srslte_pucch_cfg_t* cfg, + const srslte_uci_cfg_t* uci_cfg, + const srslte_uci_value_t* uci_value, + uint8_t b[SRSLTE_UCI_MAX_ACK_BITS]) +{ + uint32_t n_pucch_i[SRSLTE_PUCCH_MAX_ALLOC] = {}; + int nof_resources = srslte_pucch_proc_get_resources(cell, cfg, uci_cfg, uci_value, n_pucch_i); + + // Copy original bits in b + memcpy(b, uci_value->ack.ack_value, SRSLTE_UCI_MAX_ACK_BITS); + + // If error occurred, return 0 + if (nof_resources < 1) { + return 0; + } + + // Return immediately if only one possible resource + if (nof_resources == 1) { + return n_pucch_i[0]; + } + + // Select TDD resource + if (cell->frame_type == SRSLTE_TDD) { + return get_npucch_tdd(n_pucch_i, uci_cfg, b); + } + + // Select Channel Selection resource + if (cfg->ack_nack_feedback_mode == SRSLTE_PUCCH_ACK_NACK_FEEDBACK_MODE_CS) { + return get_npucch_cs(cfg, uci_cfg, n_pucch_i, b); + } + + return 0; +} diff --git a/lib/src/phy/phch/uci.c b/lib/src/phy/phch/uci.c index 9cd8849a0..43b95a38e 100644 --- a/lib/src/phy/phch/uci.c +++ b/lib/src/phy/phch/uci.c @@ -785,7 +785,7 @@ int srslte_uci_decode_ack_ri(srslte_pusch_cfg_t* cfg, return (int)Qprime; } -uint32_t srslte_uci_cfg_total_ack(srslte_uci_cfg_t* uci_cfg) +uint32_t srslte_uci_cfg_total_ack(const srslte_uci_cfg_t* uci_cfg) { uint32_t nof_ack = 0; for (uint32_t i = 0; i < SRSLTE_MAX_CARRIERS; i++) { diff --git a/lib/src/phy/ue/test/pucch_resource_test.c b/lib/src/phy/ue/test/pucch_resource_test.c index 324cc2d5d..23a5eaa00 100644 --- a/lib/src/phy/ue/test/pucch_resource_test.c +++ b/lib/src/phy/ue/test/pucch_resource_test.c @@ -42,6 +42,7 @@ int fdd_tests() srslte_pucch_cfg_t pucch_cfg; srslte_uci_cfg_t uci_cfg; srslte_uci_value_t uci_value; + uint8_t b[SRSLTE_UCI_MAX_ACK_BITS] = {}; ZERO_OBJECT(cell); cell.cp = SRSLTE_CP_NORM; @@ -61,7 +62,7 @@ int fdd_tests() // Format 1 ZERO_OBJECT(uci_cfg); uci_value.scheduling_request = true; - srslte_ue_ul_pucch_resource_selection(&cell, &pucch_cfg, &uci_cfg, &uci_value); + srslte_ue_ul_pucch_resource_selection(&cell, &pucch_cfg, &uci_cfg, &uci_value, b); TESTASSERT(pucch_cfg.format == SRSLTE_PUCCH_FORMAT_1); TESTASSERT(pucch_cfg.n_pucch == pucch_cfg.n_pucch_sr); @@ -71,7 +72,7 @@ int fdd_tests() ZERO_OBJECT(uci_cfg); uci_cfg.ack[0].nof_acks = 1; uci_cfg.ack[0].ncce[0] = 13; - srslte_ue_ul_pucch_resource_selection(&cell, &pucch_cfg, &uci_cfg, &uci_value); + srslte_ue_ul_pucch_resource_selection(&cell, &pucch_cfg, &uci_cfg, &uci_value, b); TESTASSERT(pucch_cfg.format == SRSLTE_PUCCH_FORMAT_1A); if (i == 0) { TESTASSERT(pucch_cfg.n_pucch == pucch_cfg.n_pucch_sr); @@ -89,7 +90,7 @@ int fdd_tests() ZERO_OBJECT(uci_cfg); uci_cfg.ack[0].nof_acks = 2; uci_cfg.ack[0].ncce[0] = 13; - srslte_ue_ul_pucch_resource_selection(&cell, &pucch_cfg, &uci_cfg, &uci_value); + srslte_ue_ul_pucch_resource_selection(&cell, &pucch_cfg, &uci_cfg, &uci_value, b); TESTASSERT(pucch_cfg.format == SRSLTE_PUCCH_FORMAT_1B); if (i == 0) { TESTASSERT(pucch_cfg.n_pucch == pucch_cfg.n_pucch_sr); @@ -112,14 +113,14 @@ int fdd_tests() // ACK/ACK, n_pucch = n_pucch_1 uci_value.ack.ack_value[0] = 1; uci_value.ack.ack_value[1] = 1; - srslte_ue_ul_pucch_resource_selection(&cell, &pucch_cfg, &uci_cfg, &uci_value); + srslte_ue_ul_pucch_resource_selection(&cell, &pucch_cfg, &uci_cfg, &uci_value, b); TESTASSERT(pucch_cfg.format == SRSLTE_PUCCH_FORMAT_1B); TESTASSERT(pucch_cfg.n_pucch == uci_cfg.ack[1].ncce[0] + pucch_cfg.N_pucch_1); // ACK/DTX, n_pucch = n_pucch_0 uci_value.ack.ack_value[0] = 1; uci_value.ack.ack_value[1] = 2; - srslte_ue_ul_pucch_resource_selection(&cell, &pucch_cfg, &uci_cfg, &uci_value); + srslte_ue_ul_pucch_resource_selection(&cell, &pucch_cfg, &uci_cfg, &uci_value, b); TESTASSERT(pucch_cfg.format == SRSLTE_PUCCH_FORMAT_1B); TESTASSERT(pucch_cfg.n_pucch == uci_cfg.ack[0].ncce[0] + pucch_cfg.N_pucch_1); @@ -128,7 +129,7 @@ int fdd_tests() uci_cfg.ack[1].tpc_for_pucch = 3; uci_value.ack.ack_value[0] = 1; uci_value.ack.ack_value[1] = 1; - srslte_ue_ul_pucch_resource_selection(&cell, &pucch_cfg, &uci_cfg, &uci_value); + srslte_ue_ul_pucch_resource_selection(&cell, &pucch_cfg, &uci_cfg, &uci_value, b); TESTASSERT(pucch_cfg.format == SRSLTE_PUCCH_FORMAT_1B); TESTASSERT(pucch_cfg.n_pucch == pucch_cfg.n1_pucch_an_cs[uci_cfg.ack[1].tpc_for_pucch][0]); @@ -137,7 +138,7 @@ int fdd_tests() uci_cfg.ack[0].tpc_for_pucch = 2; uci_value.ack.ack_value[0] = 1; uci_value.ack.ack_value[1] = 2; - srslte_ue_ul_pucch_resource_selection(&cell, &pucch_cfg, &uci_cfg, &uci_value); + srslte_ue_ul_pucch_resource_selection(&cell, &pucch_cfg, &uci_cfg, &uci_value, b); TESTASSERT(pucch_cfg.format == SRSLTE_PUCCH_FORMAT_1B); TESTASSERT(pucch_cfg.n_pucch == pucch_cfg.n1_pucch_an_cs[uci_cfg.ack[0].tpc_for_pucch][0]); @@ -148,7 +149,7 @@ int fdd_tests() uci_value.scheduling_request = true; uci_cfg.ack[0].nof_acks = 1; uci_cfg.ack[1].nof_acks = 1; - srslte_ue_ul_pucch_resource_selection(&cell, &pucch_cfg, &uci_cfg, &uci_value); + srslte_ue_ul_pucch_resource_selection(&cell, &pucch_cfg, &uci_cfg, &uci_value, b); TESTASSERT(pucch_cfg.format == SRSLTE_PUCCH_FORMAT_1B); return 0; diff --git a/lib/src/phy/ue/ue_ul.c b/lib/src/phy/ue/ue_ul.c index ca0085486..56eb948f9 100644 --- a/lib/src/phy/ue/ue_ul.c +++ b/lib/src/phy/ue/ue_ul.c @@ -474,370 +474,16 @@ float srs_power(srslte_ue_ul_t* q, srslte_ue_ul_cfg_t* cfg, float PL) return p_srs; } -// Selection of n_pucch for PUCCH Format 1a and 1b with channel selection for 1 and 2 CC -static uint32_t get_npucch_cs(srslte_pucch_cfg_t* cfg, srslte_uci_cfg_t* uci_cfg, srslte_uci_value_t* uci_value) -{ - uint32_t n_pucch = 0; - uint8_t* b = uci_value->ack.ack_value; - uint32_t n_pucch_i[4] = {}; - - if (srslte_pucch_cs_resources(cfg, uci_cfg, n_pucch_i) < SRSLTE_SUCCESS) { - ERROR("Selecting n_pucch_i resources\n"); - return 0; - } - - // Do resource selection and bit mapping according to tables 10.1.2.2.1-3, 10.1.2.2.1-4 and 10.1.2.2.1-5 - uint32_t nof_ack = srslte_uci_cfg_total_ack(uci_cfg); - switch (nof_ack) { - case 1: - // 1-bit is Format1A always - n_pucch = n_pucch_i[0]; - break; - case 2: - if (b[1] != 1) { - /* n_pucch1_0 */ - n_pucch = n_pucch_i[0]; - } else { - /* n_pucch1_1 */ - n_pucch = n_pucch_i[1]; - } - if (b[0] == 1) { - b[0] = 1; - b[1] = 1; - } else { - b[0] = 0; - b[1] = 0; - } - break; - case 3: - if (b[0] != 1 && b[1] != 1) { - /* n_pucch1_2 */ - n_pucch = n_pucch_i[2]; - } else if (b[2] == 1) { - /* n_pucch1_1 */ - n_pucch = n_pucch_i[1]; - } else { - /* n_pucch1_0 */ - n_pucch = n_pucch_i[0]; - } - if (b[0] != 1 && b[1] != 1 && b[2] != 1) { - b[0] = 0; - b[1] = 0; - } else if (b[0] != 1 && b[1] == 1) { - b[0] = 0; - b[1] = 1; - } else if (b[0] == 1 && b[1] != 1) { - b[0] = 1; - b[1] = 0; - } else { - b[0] = 1; - b[1] = 1; - } - break; - case 4: - if (b[2] != 1 && b[3] != 1) { - /* n_pucch1_0 */ - n_pucch = n_pucch_i[0]; - } else if (b[1] == 1 && b[2] == 1) { - /* n_pucch1_1 */ - n_pucch = n_pucch_i[1]; - } else if (b[0] == 1) { - /* n_pucch1_2 */ - n_pucch = n_pucch_i[2]; - } else { - /* n_pucch1_3 */ - n_pucch = n_pucch_i[3]; - } - if (b[2] != 1 && b[3] != 1) { - /* n_pucch1_0 */ - b[0] = (uint8_t)(b[0] != 1 ? 0 : 1); - b[1] = (uint8_t)(b[1] != 1 ? 0 : 1); - } else if (b[1] == 1 && b[2] == 1) { - /* n_pucch1_1 */ - b[0] = (uint8_t)(b[0] != 1 ? 0 : 1); - b[1] = (uint8_t)(b[3] != 1 ? 0 : 1); - } else if (b[0] == 1) { - /* n_pucch1_2 */ - b[0] = (uint8_t)((b[3] != 1 ? 0 : 1) & (b[2] != 1 ? 1 : 0)); - b[1] = (uint8_t)((b[3] != 1 ? 0 : 1) & ((b[1] != 1 ? 0 : 1) ^ (b[2] != 1 ? 0 : 1))); - } else { - /* n_pucch1_3 */ - b[0] = (uint8_t)(b[2] != 1 ? 0 : 1); - b[1] = (uint8_t)(((b[3] == 1) && ((b[1] == 1) != (b[2] == 1))) ? 1 : 0); - } - break; - default: - ERROR("Too many (%d) ACK for this CS mode\n", srslte_uci_cfg_total_ack(uci_cfg)); - } - - return n_pucch; -} - -static void set_b01(uint8_t* b, uint8_t x) -{ - switch (x) { - case 0: - b[0] = 0; - b[1] = 0; - break; - case 1: - b[0] = 0; - b[1] = 1; - break; - case 2: - b[0] = 1; - b[1] = 0; - break; - case 3: - b[0] = 1; - b[1] = 1; - break; - } -} - -#define is_ack(h) (h == 1) -#define is_nack(h) (h == 0) -#define is_nackdtx(h) ((h & 1) == 0) -#define is_dtx(h) (h == 2) - -// n_pucch and b0b1 selection for TDD, tables 10.1-2, 10.1-3 and 10.1-4 -static uint32_t get_npucch_tdd(uint32_t n_pucch[4], srslte_uci_cfg_t* uci_cfg, srslte_uci_value_t* uci_value) -{ - uint8_t* b = uci_value->ack.ack_value; - switch (uci_cfg->ack[0].nof_acks) { - case 1: - return n_pucch[0]; - case 2: - if (is_ack(b[0]) && is_ack(b[1])) { - set_b01(b, 3); - return n_pucch[1]; - } else if (is_ack(b[0]) && is_nackdtx(b[1])) { - set_b01(b, 1); - return n_pucch[0]; - } else if (is_nackdtx(b[0]) && is_ack(b[1])) { - set_b01(b, 0); - return n_pucch[1]; - } else if (is_nackdtx(b[0]) && is_nack(b[1])) { - set_b01(b, 2); - return n_pucch[1]; - } else if (is_nack(b[0]) && is_dtx(b[1])) { - set_b01(b, 2); - return n_pucch[0]; - } - break; - case 3: - uci_cfg->ack[0].nof_acks = 2; - if (is_ack(b[0]) && is_ack(b[1]) && is_ack(b[2])) { - set_b01(b, 3); - return n_pucch[2]; - } else if (is_ack(b[0]) && is_ack(b[1]) && is_nackdtx(b[2])) { - set_b01(b, 3); - return n_pucch[1]; - } else if (is_ack(b[0]) && is_nackdtx(b[1]) && is_ack(b[2])) { - set_b01(b, 3); - return n_pucch[0]; - } else if (is_ack(b[0]) && is_nackdtx(b[1]) && is_nackdtx(b[2])) { - set_b01(b, 1); - return n_pucch[0]; - } else if (is_nackdtx(b[0]) && is_ack(b[1]) && is_ack(b[2])) { - set_b01(b, 2); - return n_pucch[2]; - } else if (is_nackdtx(b[0]) && is_ack(b[1]) && is_nackdtx(b[2])) { - set_b01(b, 0); - return n_pucch[1]; - } else if (is_nackdtx(b[0]) && is_nackdtx(b[1]) && is_ack(b[2])) { - set_b01(b, 0); - return n_pucch[2]; - } else if (is_dtx(b[0]) && is_dtx(b[1]) && is_nack(b[2])) { - set_b01(b, 1); - return n_pucch[2]; - } else if (is_dtx(b[0]) && is_nack(b[1]) && is_nackdtx(b[2])) { - set_b01(b, 2); - return n_pucch[1]; - } else if (is_nack(b[0]) && is_nackdtx(b[1]) && is_nackdtx(b[2])) { - set_b01(b, 2); - return n_pucch[0]; - } - break; - case 4: - uci_cfg->ack[0].nof_acks = 2; - if (is_ack(b[0]) && is_ack(b[1]) && is_ack(b[2]) && is_ack(b[3])) { - set_b01(b, 3); - return n_pucch[1]; - } else if (is_ack(b[0]) && is_ack(b[1]) && is_ack(b[2]) && is_nackdtx(b[3])) { - set_b01(b, 2); - return n_pucch[1]; - } else if (is_nackdtx(b[0]) && is_nackdtx(b[1]) && is_nack(b[2]) && is_dtx(b[3])) { - set_b01(b, 3); - return n_pucch[2]; - } else if (is_ack(b[0]) && is_ack(b[1]) && is_nackdtx(b[2]) && is_ack(b[3])) { - set_b01(b, 2); - return n_pucch[1]; - } else if (is_nack(b[0]) && is_dtx(b[1]) && is_dtx(b[2]) && is_dtx(b[3])) { - set_b01(b, 2); - return n_pucch[0]; - } else if (is_ack(b[0]) && is_ack(b[1]) && is_nackdtx(b[2]) && is_nackdtx(b[3])) { - set_b01(b, 2); - return n_pucch[1]; - } else if (is_ack(b[0]) && is_nackdtx(b[1]) && is_ack(b[2]) && is_ack(b[3])) { - set_b01(b, 1); - return n_pucch[3]; - } else if (is_nackdtx(b[0]) && is_nackdtx(b[1]) && is_nackdtx(b[2]) && is_nack(b[3])) { - set_b01(b, 3); - return n_pucch[3]; - } else if (is_ack(b[0]) && is_nackdtx(b[1]) && is_ack(b[2]) && is_nack(b[3])) { - set_b01(b, 2); - return n_pucch[1]; - } else if (is_ack(b[0]) && is_nackdtx(b[1]) && is_nackdtx(b[2]) && is_ack(b[3])) { - set_b01(b, 1); - return n_pucch[0]; - } else if (is_ack(b[0]) && is_nackdtx(b[1]) && is_nackdtx(b[2]) && is_nackdtx(b[3])) { - set_b01(b, 3); - return n_pucch[0]; - } else if (is_nackdtx(b[0]) && is_ack(b[1]) && is_ack(b[2]) && is_ack(b[3])) { - set_b01(b, 1); - return n_pucch[3]; - } else if (is_nackdtx(b[0]) && is_nack(b[1]) && is_dtx(b[2]) && is_dtx(b[3])) { - set_b01(b, 0); - return n_pucch[1]; - } else if (is_nackdtx(b[0]) && is_ack(b[1]) && is_ack(b[2]) && is_nackdtx(b[3])) { - set_b01(b, 2); - return n_pucch[2]; - } else if (is_nackdtx(b[0]) && is_ack(b[1]) && is_nackdtx(b[2]) && is_ack(b[3])) { - set_b01(b, 2); - return n_pucch[3]; - } else if (is_nackdtx(b[0]) && is_ack(b[1]) && is_nackdtx(b[2]) && is_nackdtx(b[3])) { - set_b01(b, 1); - return n_pucch[1]; - } else if (is_nackdtx(b[0]) && is_nackdtx(b[1]) && is_ack(b[2]) && is_ack(b[3])) { - set_b01(b, 1); - return n_pucch[3]; - } else if (is_nackdtx(b[0]) && is_nackdtx(b[1]) && is_ack(b[2]) && is_nackdtx(b[3])) { - set_b01(b, 0); - return n_pucch[2]; - } else if (is_nackdtx(b[0]) && is_nackdtx(b[1]) && is_nackdtx(b[2]) && is_ack(b[3])) { - set_b01(b, 0); - return n_pucch[3]; - } - } - return 0; -} - -static uint32_t get_Np(uint32_t p, uint32_t nof_prb) -{ - if (p == 0) { - return 0; - } else { - return nof_prb * (SRSLTE_NRE * p - 4) / 36; - } -} - -static uint32_t n_pucch_i_tdd(uint32_t ncce, uint32_t N_pucch_1, uint32_t nof_prb, uint32_t M, uint32_t m) -{ - uint32_t Np = 0, Np_1 = 0; - for (uint32_t p = 0; p < 4; p++) { - Np = get_Np(p, nof_prb); - Np_1 = get_Np(p + 1, nof_prb); - if (ncce >= Np && ncce < Np_1) { - uint32_t npucch = (M - m - 1) * Np + m * Np_1 + ncce + N_pucch_1; - return npucch; - } - } - ERROR("Could not find Np value for ncce=%d\n", ncce); - return 0; -} - -/** Choose PUCCH resource as described in 3GPP 36.213 version 10.13.0 section 10.1.2.2 */ -static uint32_t -get_npucch(srslte_pucch_cfg_t* cfg, srslte_uci_cfg_t* uci_cfg, srslte_uci_value_t* uci_value, srslte_cell_t* cell) -{ - uint32_t n_pucch_res = 0; - - if (cfg->format != SRSLTE_PUCCH_FORMAT_3) { - if (uci_value) { - if (uci_value->scheduling_request) { - return cfg->n_pucch_sr; - } - } else if (uci_cfg->is_scheduling_request_tti) { - return cfg->n_pucch_sr; - } - } - - if (!uci_value || !cell || !uci_cfg) { - fprintf(stderr, "get_npucch(): Invalid parameters\n"); - return 0; - } - - switch (cfg->format) { - - case SRSLTE_PUCCH_FORMAT_1: - case SRSLTE_PUCCH_FORMAT_1A: - case SRSLTE_PUCCH_FORMAT_1B: - if (cfg->sps_enabled) { - n_pucch_res = cfg->n_pucch_1[uci_cfg->ack[0].tpc_for_pucch % 4]; - } else if (cell->frame_type == SRSLTE_TDD) { - // only 1 CC supported in TDD - if (!uci_cfg->ack[0].tdd_is_multiplex || uci_cfg->ack[0].tdd_ack_M == 1) { - n_pucch_res = n_pucch_i_tdd(uci_cfg->ack[0].ncce[0], - cfg->N_pucch_1, - cell->nof_prb, - uci_cfg->ack[0].tdd_ack_M, - uci_cfg->ack[0].tdd_ack_m); - } else { - if (uci_cfg->ack[0].tdd_ack_M <= 4) { - uint32_t n_pucch[4] = {}; - for (uint32_t i = 0; i < uci_cfg->ack[0].tdd_ack_M; i++) { - n_pucch[i] = - n_pucch_i_tdd(uci_cfg->ack[0].ncce[i], cfg->N_pucch_1, cell->nof_prb, uci_cfg->ack[0].tdd_ack_M, i); - } - n_pucch_res = get_npucch_tdd(n_pucch, uci_cfg, uci_value); - } else { - ERROR("Invalid M=%d in PUCCH TDD multiplexing\n", uci_cfg->ack[0].tdd_ack_M); - } - } - } else if (cfg->ack_nack_feedback_mode == SRSLTE_PUCCH_ACK_NACK_FEEDBACK_MODE_CS) { - // Channel selection enabled - n_pucch_res = get_npucch_cs(cfg, uci_cfg, uci_value); - } else { - // Normal case - n_pucch_res = uci_cfg->ack[0].ncce[0] + cfg->N_pucch_1; - } - break; - case SRSLTE_PUCCH_FORMAT_2: - case SRSLTE_PUCCH_FORMAT_2A: - case SRSLTE_PUCCH_FORMAT_2B: - n_pucch_res = cfg->n_pucch_2; - break; - case SRSLTE_PUCCH_FORMAT_3: - n_pucch_res = cfg->n3_pucch_an_list[uci_cfg->ack[0].tpc_for_pucch % SRSLTE_PUCCH_SIZE_AN_CS]; - break; - case SRSLTE_PUCCH_FORMAT_ERROR: - default: - ERROR("Wrong PUCCH format %s\n", srslte_pucch_format_text_short(cfg->format)); - } - - return n_pucch_res; -} - /* Procedure for determining PUCCH assignment 10.1 36.213 */ -void srslte_ue_ul_pucch_resource_selection(srslte_cell_t* cell, - srslte_pucch_cfg_t* cfg, - srslte_uci_cfg_t* uci_cfg, - srslte_uci_value_t* uci_value) +void srslte_ue_ul_pucch_resource_selection(const srslte_cell_t* cell, + srslte_pucch_cfg_t* cfg, + const srslte_uci_cfg_t* uci_cfg, + const srslte_uci_value_t* uci_value, + uint8_t b[SRSLTE_UCI_MAX_ACK_BITS]) { - // Drop CQI if there is collision with ACK - if (!cfg->simul_cqi_ack && srslte_uci_cfg_total_ack(uci_cfg) > 0 && uci_cfg->cqi.data_enable) { - uci_cfg->cqi.data_enable = false; - } - - // Set Scheduling request to true in UCI config if SR - if (uci_value && uci_value->scheduling_request) { - uci_cfg->is_scheduling_request_tti = true; - } - // Get PUCCH Resources - cfg->format = srslte_pucch_select_format(cfg, uci_cfg, cell->cp); - cfg->n_pucch = get_npucch(cfg, uci_cfg, uci_value, cell); + cfg->format = srslte_pucch_proc_select_format(cell, cfg, uci_cfg, uci_value); + cfg->n_pucch = srslte_pucch_proc_get_npucch(cell, cfg, uci_cfg, uci_value, b); } /* Choose PUCCH format as in Sec 10.1 of 36.213 and generate PUCCH signal @@ -848,7 +494,7 @@ pucch_encode(srslte_ue_ul_t* q, srslte_ul_sf_cfg_t* sf, srslte_ue_ul_cfg_t* cfg, int ret = SRSLTE_ERROR_INVALID_INPUTS; if (q != NULL && cfg != NULL) { - srslte_uci_value_t uci_value2 = *uci_data; + srslte_uci_value_t uci_value2 = *uci_data; ///< Make copy of UCI Data, so the original input does not get altered ret = SRSLTE_ERROR; if (!srslte_pucch_cfg_isvalid(&cfg->ul_cfg.pucch, q->cell.nof_prb)) { @@ -859,7 +505,8 @@ pucch_encode(srslte_ue_ul_t* q, srslte_ul_sf_cfg_t* sf, srslte_ue_ul_cfg_t* cfg, bzero(q->sf_symbols, sizeof(cf_t) * SRSLTE_NOF_RE(q->cell)); // Prepare configuration - srslte_ue_ul_pucch_resource_selection(&q->cell, &cfg->ul_cfg.pucch, &cfg->ul_cfg.pucch.uci_cfg, &uci_value2); + srslte_ue_ul_pucch_resource_selection( + &q->cell, &cfg->ul_cfg.pucch, &cfg->ul_cfg.pucch.uci_cfg, uci_data, uci_value2.ack.ack_value); srslte_refsignal_srs_pucch_shortened(&q->signals, sf, &cfg->ul_cfg.srs, &cfg->ul_cfg.pucch);