srsLTE/lib/src/phy/phch/pucch_proc.c

623 lines
22 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* Copyright 2013-2022 Software Radio Systems Limited
*
* This file is part of srsRAN.
*
* srsRAN 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.
*
* srsRAN 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 <srsran/phy/phch/pucch_proc.h>
#include <srsran/phy/utils/debug.h>
static bool pucch_proc_tx_sr(const srsran_uci_cfg_t* uci_cfg, const srsran_uci_value_t* uci_value)
{
// Check SR transmission
if (uci_value) {
// If UCI value is provided, ignore scheduling request TTI condition
return uci_value->scheduling_request;
}
return uci_cfg->is_scheduling_request_tti;
}
srsran_pucch_format_t srsran_pucch_proc_select_format(const srsran_cell_t* cell,
const srsran_pucch_cfg_t* cfg,
const srsran_uci_cfg_t* uci_cfg,
const srsran_uci_value_t* uci_value)
{
srsran_pucch_format_t format = SRSRAN_PUCCH_FORMAT_ERROR;
uint32_t total_ack = srsran_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 == SRSRAN_PUCCH_ACK_NACK_FEEDBACK_MODE_PUCCH3 &&
total_ack > uci_cfg->ack[0].nof_acks) {
format = SRSRAN_PUCCH_FORMAT_3;
}
// 1-bit ACK + optional SR
else if (total_ack == 1) {
format = SRSRAN_PUCCH_FORMAT_1A;
}
// 2-bit ACK + optional SR
else if (total_ack >= 2 && total_ack <= 4) {
format = SRSRAN_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 = SRSRAN_PUCCH_FORMAT_1;
} else {
ERROR("Error selecting PUCCH format: Unsupported number of ACK bits %d", total_ack);
}
}
// CQI data
else {
// CQI and no ack
if (total_ack == 0) {
format = SRSRAN_PUCCH_FORMAT_2;
}
// CQI + 1-bit ACK
else if (total_ack == 1 && SRSRAN_CP_ISNORM(cell->cp)) {
format = SRSRAN_PUCCH_FORMAT_2A;
}
// CQI + 2-bit ACK
else if (total_ack == 2) {
format = SRSRAN_PUCCH_FORMAT_2B;
}
// CQI + 1-bit ACK + extended cyclic prefix
else if (total_ack == 1 && SRSRAN_CP_ISEXT(cell->cp)) {
format = SRSRAN_PUCCH_FORMAT_2B;
}
}
if (format == SRSRAN_PUCCH_FORMAT_ERROR) {
ERROR("Returned Error while selecting PUCCH format");
}
return format;
}
static int pucch_cs_resources(const srsran_pucch_cfg_t* cfg,
const srsran_uci_cfg_t* uci_cfg,
uint32_t n_pucch_i[SRSRAN_PUCCH_MAX_ALLOC])
{
// Check inputs
if (!cfg || !uci_cfg || !n_pucch_i) {
return SRSRAN_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 < SRSRAN_PUCCH_CS_MAX_CARRIERS && k < SRSRAN_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 < SRSRAN_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 < SRSRAN_PUCCH_CS_MAX_ACK; j++) {
n_pucch_i[k++] = cfg->n1_pucch_an_cs[uci_cfg->ack[i].tpc_for_pucch % SRSRAN_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 < SRSRAN_PUCCH_CS_MAX_ACK; j++) {
n_pucch_i[k++] =
cfg->n1_pucch_an_cs[uci_cfg->ack[i].tpc_for_pucch % SRSRAN_PUCCH_SIZE_AN_CS][j % SRSRAN_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] < SRSRAN_PUCCH_CS_MAX_ACK; i++) { \
uci_value[pos[i]] = 1; \
} \
ret = SRSRAN_SUCCESS; \
} \
} while (false)
static int puccch_cs_get_ack_a2(uint32_t j, const uint8_t b[2], uint8_t uci_value[SRSRAN_UCI_MAX_ACK_BITS])
{
int ret = SRSRAN_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, SRSRAN_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[SRSRAN_UCI_MAX_ACK_BITS])
{
int ret = SRSRAN_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, SRSRAN_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[SRSRAN_UCI_MAX_ACK_BITS])
{
int ret = SRSRAN_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, SRSRAN_PUCCH_CS_MAX_ACK);
return ret;
}
int srsran_pucch_cs_get_ack(const srsran_pucch_cfg_t* cfg,
const srsran_uci_cfg_t* uci_cfg,
uint32_t j,
const uint8_t b[2],
srsran_uci_value_t* uci_value)
{
int ret = SRSRAN_ERROR_INVALID_INPUTS;
if (cfg && uci_cfg && uci_value) {
// Set bits to 0 by default
memset(uci_value->ack.ack_value, 0, SRSRAN_UCI_MAX_ACK_BITS);
uint32_t nof_ack = srsran_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)", nof_ack);
ret = SRSRAN_ERROR;
}
}
return ret;
}
static int pucch_f3_resources(const srsran_pucch_cfg_t* cfg, const srsran_uci_cfg_t* uci_cfg, uint32_t* n_pucch_3)
{
int ret = SRSRAN_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 % SRSRAN_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 * (SRSRAN_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", ncce);
return 0;
}
static int pucch_tdd_resources(const srsran_cell_t* cell,
const srsran_pucch_cfg_t* cfg,
const srsran_uci_cfg_t* uci_cfg,
uint32_t n_pucch_tdd[SRSRAN_PUCCH_MAX_ALLOC])
{
int ret = SRSRAN_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 srsran_pucch_proc_get_resources(const srsran_cell_t* cell,
const srsran_pucch_cfg_t* cfg,
const srsran_uci_cfg_t* uci_cfg,
const srsran_uci_value_t* uci_value,
uint32_t* n_pucch_i)
{
if (!cfg || !cell || !uci_cfg || !n_pucch_i) {
ERROR("pucch_resource_selection(): Invalid parameters");
return SRSRAN_ERROR_INVALID_INPUTS;
}
uint32_t total_nof_ack = srsran_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 != SRSRAN_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 < SRSRAN_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 == SRSRAN_TDD) {
return pucch_tdd_resources(cell, cfg, uci_cfg, n_pucch_i);
}
if (cfg->ack_nack_feedback_mode == SRSRAN_PUCCH_ACK_NACK_FEEDBACK_MODE_CS) {
return pucch_cs_resources(cfg, uci_cfg, n_pucch_i);
}
if (cfg->ack_nack_feedback_mode == SRSRAN_PUCCH_ACK_NACK_FEEDBACK_MODE_NORMAL ||
(cfg->ack_nack_feedback_mode == SRSRAN_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", srsran_ack_nack_feedback_mode_string(cfg->ack_nack_feedback_mode));
return SRSRAN_ERROR;
}
// PUCCH format 3
if (cfg->format == SRSRAN_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 srsran_pucch_cfg_t* cfg,
const srsran_uci_cfg_t* uci_cfg,
const uint32_t n_pucch_i[SRSRAN_PUCCH_MAX_ALLOC],
uint8_t b[SRSRAN_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 = srsran_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", srsran_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)", 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 srsran_uci_cfg_t* uci_cfg, uint8_t b[SRSRAN_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 srsran_pucch_proc_get_npucch(const srsran_cell_t* cell,
const srsran_pucch_cfg_t* cfg,
const srsran_uci_cfg_t* uci_cfg,
const srsran_uci_value_t* uci_value,
uint8_t b[SRSRAN_UCI_MAX_ACK_BITS])
{
uint32_t n_pucch_i[SRSRAN_PUCCH_MAX_ALLOC] = {};
int nof_resources = srsran_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, SRSRAN_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 == SRSRAN_TDD) {
return get_npucch_tdd(n_pucch_i, uci_cfg, b);
}
// Select Channel Selection resource
if (cfg->ack_nack_feedback_mode == SRSRAN_PUCCH_ACK_NACK_FEEDBACK_MODE_CS) {
return get_npucch_cs(cfg, uci_cfg, n_pucch_i, b);
}
return 0;
}