diff --git a/lib/include/srslte/phy/common/phy_common.h b/lib/include/srslte/phy/common/phy_common.h index 03200e479..cb76fe219 100644 --- a/lib/include/srslte/phy/common/phy_common.h +++ b/lib/include/srslte/phy/common/phy_common.h @@ -471,4 +471,12 @@ SRSLTE_API char* srslte_nbiot_mode_string(srslte_nbiot_mode_t mode); bool srslte_psbch_is_symbol(srslte_sl_symbol_t type, srslte_sl_tm_t tm, uint32_t i); +/** + * Returns a constant string pointer with the ACK/NACK feedback mode + * + * @param ack_nack_feedback_mode Mode + * @return Returns constant pointer with the text of the mode if succesful, `error` otherwise + */ +SRSLTE_API const char* srslte_ack_nack_feedback_mode_string(srslte_ack_nack_feedback_mode_t ack_nack_feedback_mode); + #endif // SRSLTE_PHY_COMMON_H diff --git a/lib/include/srslte/phy/phch/pucch.h b/lib/include/srslte/phy/phch/pucch.h index db0ec2647..d5cd871ee 100644 --- a/lib/include/srslte/phy/phch/pucch.h +++ b/lib/include/srslte/phy/phch/pucch.h @@ -49,6 +49,8 @@ // PUCCH Format 1B Channel selection #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 typedef struct { @@ -173,16 +175,17 @@ SRSLTE_API srslte_pucch_format_t srslte_pucch_select_format(srslte_pucch_cfg_t* srslte_cp_t cp); /** - * Implements 3GPP 36.213 R10 10.1.2.2.1 PUCCH format 1b with channel selection HARQ-ACK procedure - * resource list + * 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(srslte_pucch_cfg_t* cfg, - srslte_uci_cfg_t* uci_cfg, - uint32_t n_pucch_i[SRSLTE_PUCCH_CS_MAX_NOF_ALLOC]); +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) diff --git a/lib/src/phy/common/phy_common.c b/lib/src/phy/common/phy_common.c index 94d08b55c..2b55fd711 100644 --- a/lib/src/phy/common/phy_common.c +++ b/lib/src/phy/common/phy_common.c @@ -854,3 +854,18 @@ bool srslte_psbch_is_symbol(srslte_sl_symbol_t type, srslte_sl_tm_t tm, uint32_t return srslte_psbch_symbol_map_tm34[i] == type; } } + +const char* srslte_ack_nack_feedback_mode_string(srslte_ack_nack_feedback_mode_t ack_nack_feedback_mode) +{ + switch (ack_nack_feedback_mode) { + case SRSLTE_PUCCH_ACK_NACK_FEEDBACK_MODE_NORMAL: + return "normal"; + case SRSLTE_PUCCH_ACK_NACK_FEEDBACK_MODE_CS: + return "cs"; + case SRSLTE_PUCCH_ACK_NACK_FEEDBACK_MODE_PUCCH3: + return "pucch3"; + case SRSLTE_PUCCH_ACK_NACK_FEEDBACK_MODE_ERROR: + default: + return "error"; + } +} diff --git a/lib/src/phy/phch/pucch.c b/lib/src/phy/phch/pucch.c index 7866b1022..98821cd63 100644 --- a/lib/src/phy/phch/pucch.c +++ b/lib/src/phy/phch/pucch.c @@ -1299,41 +1299,48 @@ srslte_pucch_format_t srslte_pucch_select_format(srslte_pucch_cfg_t* cfg, srslte return format; } -int srslte_pucch_cs_resources(srslte_pucch_cfg_t* cfg, srslte_uci_cfg_t* uci_cfg, uint32_t n_pucch_i[4]) +int srslte_pucch_cs_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) { - // Determine the 4 PUCCH resources n_pucch_j associated with HARQ-ACK(j) - uint32_t k = 0; - for (int i = 0; i < SRSLTE_MAX_CARRIERS && k < SRSLTE_PUCCH_CS_MAX_ACK; i++) { - // If grant has been scheduled in PCell - if (uci_cfg->ack[i].grant_cc_idx == 0) { - for (uint32_t j = 0; j < uci_cfg->ack[i].nof_acks && k < SRSLTE_PUCCH_CS_MAX_ACK; j++) { - if (k % 2 == 1) { - n_pucch_i[k] = cfg->n1_pucch_an_cs[uci_cfg->ack[i].tpc_for_pucch][k / 2]; - } else { - n_pucch_i[k] = uci_cfg->ack[i].ncce[0] + cfg->N_pucch_1 + j; - } - k++; - } - } else { - for (uint32_t j = 0; j < uci_cfg->ack[i].nof_acks; j++) { - if (k < 4) { - 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]; - } else { - fprintf(stderr, "get_npucch_cs(): Too many ack bits\n"); - return SRSLTE_ERROR; - } - } - } - } - - ret = (int)k; + // Check inputs + if (!cfg || !uci_cfg || !n_pucch_i) { + return SRSLTE_ERROR_INVALID_INPUTS; } - return ret; + // 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, ...) \ diff --git a/lib/test/phy/pucch_ca_test.c b/lib/test/phy/pucch_ca_test.c index 2cfc9c848..0b96cad71 100644 --- a/lib/test/phy/pucch_ca_test.c +++ b/lib/test/phy/pucch_ca_test.c @@ -30,9 +30,9 @@ #include "srslte/srslte.h" -static int test_pucch_cs(srslte_ack_nack_feedback_mode_t ack_nack_feedback_mode, +static int test_pucch_ca(srslte_ack_nack_feedback_mode_t ack_nack_feedback_mode, uint32_t nof_prb, - const uint32_t nof_tb[SRSLTE_MAX_CARRIERS], + const uint32_t* nof_tb, uint16_t nof_carriers) { srslte_pucch_cfg_t pucch_cfg = {}; @@ -145,28 +145,26 @@ int main(int argc, char** argv) // Set PHY lib verbose to INFO srslte_verbose = SRSLTE_VERBOSE_INFO; - uint32_t nof_tb_1[SRSLTE_MAX_CARRIERS] = {1, 1, 1, 1, 0}; - uint32_t nof_tb_2[SRSLTE_MAX_CARRIERS] = {2, 1, 1, 0, 0}; + uint32_t nof_tb_1[SRSLTE_MAX_CARRIERS] = {1, 1, 1, 1, 1}; + uint32_t nof_tb_2[SRSLTE_MAX_CARRIERS] = {2, 1, 1, 1, 1}; uint32_t nof_tb_3[SRSLTE_MAX_CARRIERS] = {2, 2, 2, 2, 2}; - for (srslte_ack_nack_feedback_mode_t ack_nack_feedback_mode = SRSLTE_PUCCH_ACK_NACK_FEEDBACK_MODE_CS; - ack_nack_feedback_mode < SRSLTE_PUCCH_ACK_NACK_FEEDBACK_MODE_ERROR; - ack_nack_feedback_mode++) { - TESTASSERT(!test_pucch_cs(ack_nack_feedback_mode, 6, nof_tb_1, 2)); - TESTASSERT(!test_pucch_cs(ack_nack_feedback_mode, 6, nof_tb_1, 3)); - TESTASSERT(!test_pucch_cs(ack_nack_feedback_mode, 6, nof_tb_1, 4)); - TESTASSERT(!test_pucch_cs(ack_nack_feedback_mode, 6, nof_tb_2, 3)); - TESTASSERT(!test_pucch_cs(ack_nack_feedback_mode, 6, nof_tb_2, 3)); - TESTASSERT(!test_pucch_cs(ack_nack_feedback_mode, 6, nof_tb_3, 2)); - TESTASSERT(!test_pucch_cs(ack_nack_feedback_mode, 100, nof_tb_1, 2)); - TESTASSERT(!test_pucch_cs(ack_nack_feedback_mode, 100, nof_tb_1, 3)); - TESTASSERT(!test_pucch_cs(ack_nack_feedback_mode, 100, nof_tb_1, 4)); - TESTASSERT(!test_pucch_cs(ack_nack_feedback_mode, 100, nof_tb_2, 3)); - TESTASSERT(!test_pucch_cs(ack_nack_feedback_mode, 100, nof_tb_2, 3)); - TESTASSERT(!test_pucch_cs(ack_nack_feedback_mode, 100, nof_tb_3, 2)); - if (ack_nack_feedback_mode == SRSLTE_PUCCH_ACK_NACK_FEEDBACK_MODE_PUCCH3) { - TESTASSERT(!test_pucch_cs(ack_nack_feedback_mode, 6, nof_tb_3, 5)); - } + TESTASSERT(!test_pucch_ca(SRSLTE_PUCCH_ACK_NACK_FEEDBACK_MODE_CS, 6, nof_tb_1, 2)); + TESTASSERT(!test_pucch_ca(SRSLTE_PUCCH_ACK_NACK_FEEDBACK_MODE_CS, 6, nof_tb_2, 2)); + TESTASSERT(!test_pucch_ca(SRSLTE_PUCCH_ACK_NACK_FEEDBACK_MODE_CS, 6, nof_tb_3, 2)); + + TESTASSERT(!test_pucch_ca(SRSLTE_PUCCH_ACK_NACK_FEEDBACK_MODE_CS, 100, nof_tb_1, 2)); + TESTASSERT(!test_pucch_ca(SRSLTE_PUCCH_ACK_NACK_FEEDBACK_MODE_CS, 100, nof_tb_2, 2)); + TESTASSERT(!test_pucch_ca(SRSLTE_PUCCH_ACK_NACK_FEEDBACK_MODE_CS, 100, nof_tb_3, 2)); + + for (uint32_t i = 2; i < SRSLTE_PUCCH_FORMAT3_MAX_CARRIERS; i++) { + TESTASSERT(!test_pucch_ca(SRSLTE_PUCCH_ACK_NACK_FEEDBACK_MODE_PUCCH3, 6, nof_tb_1, i)); + TESTASSERT(!test_pucch_ca(SRSLTE_PUCCH_ACK_NACK_FEEDBACK_MODE_PUCCH3, 6, nof_tb_2, i)); + TESTASSERT(!test_pucch_ca(SRSLTE_PUCCH_ACK_NACK_FEEDBACK_MODE_PUCCH3, 6, nof_tb_3, i)); + + TESTASSERT(!test_pucch_ca(SRSLTE_PUCCH_ACK_NACK_FEEDBACK_MODE_PUCCH3, 100, nof_tb_1, i)); + TESTASSERT(!test_pucch_ca(SRSLTE_PUCCH_ACK_NACK_FEEDBACK_MODE_PUCCH3, 100, nof_tb_2, i)); + TESTASSERT(!test_pucch_ca(SRSLTE_PUCCH_ACK_NACK_FEEDBACK_MODE_PUCCH3, 100, nof_tb_3, i)); } printf("Ok\n");