Moved UL/DL PUCCH procedures into pucch_proc

master
Xavier Arteaga 5 years ago committed by Xavier Arteaga
parent bf4ecc8064
commit 67c07dfb56

@ -51,7 +51,6 @@
#define SRSLTE_PUCCH_CS_MAX_ACK 4 #define SRSLTE_PUCCH_CS_MAX_ACK 4
#define SRSLTE_PUCCH_CS_MAX_CARRIERS 2 #define SRSLTE_PUCCH_CS_MAX_CARRIERS 2
#define SRSLTE_PUCCH_FORMAT3_MAX_CARRIERS 5 #define SRSLTE_PUCCH_FORMAT3_MAX_CARRIERS 5
#define SRSLTE_PUCCH_CS_MAX_NOF_ALLOC 4
#define SRSLTE_PUCCH_DEFAULT_THRESHOLD_FORMAT1 (0.1f) #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); 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 #endif // SRSLTE_PUCCH_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_

@ -128,7 +128,14 @@ SRSLTE_API int srslte_uci_decode_ack_ri(srslte_pusch_cfg_t* cfg,
uint32_t nof_bits, uint32_t nof_bits,
bool is_ri); 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); SRSLTE_API void srslte_uci_data_reset(srslte_uci_data_t* uci_data);

@ -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_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_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, /**
* 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, srslte_pucch_cfg_t* cfg,
srslte_uci_cfg_t* uci_cfg, const srslte_uci_cfg_t* uci_cfg,
srslte_uci_value_t* uci_data); 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_API bool srslte_ue_ul_info(srslte_ue_ul_cfg_t* cfg,
srslte_ul_sf_cfg_t* sf, srslte_ul_sf_cfg_t* sf,

@ -95,6 +95,7 @@ extern "C" {
#include "srslte/phy/phch/phich.h" #include "srslte/phy/phch/phich.h"
#include "srslte/phy/phch/prach.h" #include "srslte/phy/phch/prach.h"
#include "srslte/phy/phch/pucch.h" #include "srslte/phy/phch/pucch.h"
#include "srslte/phy/phch/pucch_proc.h"
#include "srslte/phy/phch/pusch.h" #include "srslte/phy/phch/pusch.h"
#include "srslte/phy/phch/ra.h" #include "srslte/phy/phch/ra.h"
#include "srslte/phy/phch/ra_dl.h" #include "srslte/phy/phch/ra_dl.h"

@ -26,12 +26,6 @@
#include <math.h> #include <math.h>
#include <string.h> #include <string.h>
#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 srslte_enb_ul_init(srslte_enb_ul_t* q, cf_t* in_buffer, uint32_t max_prb)
{ {
int ret = SRSLTE_ERROR_INVALID_INPUTS; int ret = SRSLTE_ERROR_INVALID_INPUTS;
@ -170,68 +164,10 @@ void srslte_enb_ul_fft(srslte_enb_ul_t* q)
srslte_ofdm_rx_sf(&q->fft); 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) 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; int ret = SRSLTE_SUCCESS;
uint32_t n_pucch_i[SRSLTE_PUCCH_CS_MAX_ACK] = {}; uint32_t n_pucch_i[SRSLTE_PUCCH_MAX_ALLOC] = {};
srslte_pucch_res_t pucch_res = {}; srslte_pucch_res_t pucch_res = {};
// Drop CQI if there is collision with ACK // Drop CQI if there is collision with ACK
@ -240,10 +176,10 @@ static int get_pucch(srslte_enb_ul_t* q, srslte_ul_sf_cfg_t* ul_sf, srslte_pucch
} }
// Select format // 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 // 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) { if (nof_resources < SRSLTE_SUCCESS || nof_resources > SRSLTE_PUCCH_CS_MAX_ACK) {
ERROR("No PUCCH resource could be calculated\n"); ERROR("No PUCCH resource could be calculated\n");
return SRSLTE_ERROR; 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)) { if (!srslte_pucch_cfg_isvalid(cfg, q->cell.nof_prb)) {
ERROR("Invalid PUCCH configuration\n"); ERROR("Invalid PUCCH configuration\n");
return -1; return SRSLTE_ERROR_INVALID_INPUTS;
} }
if (get_pucch(q, ul_sf, cfg, res)) { 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. // If we are looking for SR and ACK at the same time and ret=0, means there is no SR.

@ -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;
}

@ -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 <srslte/phy/phch/pucch_proc.h>
#include <srslte/phy/utils/debug.h>
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;
}

@ -785,7 +785,7 @@ int srslte_uci_decode_ack_ri(srslte_pusch_cfg_t* cfg,
return (int)Qprime; 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; uint32_t nof_ack = 0;
for (uint32_t i = 0; i < SRSLTE_MAX_CARRIERS; i++) { for (uint32_t i = 0; i < SRSLTE_MAX_CARRIERS; i++) {

@ -42,6 +42,7 @@ int fdd_tests()
srslte_pucch_cfg_t pucch_cfg; srslte_pucch_cfg_t pucch_cfg;
srslte_uci_cfg_t uci_cfg; srslte_uci_cfg_t uci_cfg;
srslte_uci_value_t uci_value; srslte_uci_value_t uci_value;
uint8_t b[SRSLTE_UCI_MAX_ACK_BITS] = {};
ZERO_OBJECT(cell); ZERO_OBJECT(cell);
cell.cp = SRSLTE_CP_NORM; cell.cp = SRSLTE_CP_NORM;
@ -61,7 +62,7 @@ int fdd_tests()
// Format 1 // Format 1
ZERO_OBJECT(uci_cfg); ZERO_OBJECT(uci_cfg);
uci_value.scheduling_request = true; 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.format == SRSLTE_PUCCH_FORMAT_1);
TESTASSERT(pucch_cfg.n_pucch == pucch_cfg.n_pucch_sr); TESTASSERT(pucch_cfg.n_pucch == pucch_cfg.n_pucch_sr);
@ -71,7 +72,7 @@ int fdd_tests()
ZERO_OBJECT(uci_cfg); ZERO_OBJECT(uci_cfg);
uci_cfg.ack[0].nof_acks = 1; uci_cfg.ack[0].nof_acks = 1;
uci_cfg.ack[0].ncce[0] = 13; 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); TESTASSERT(pucch_cfg.format == SRSLTE_PUCCH_FORMAT_1A);
if (i == 0) { if (i == 0) {
TESTASSERT(pucch_cfg.n_pucch == pucch_cfg.n_pucch_sr); TESTASSERT(pucch_cfg.n_pucch == pucch_cfg.n_pucch_sr);
@ -89,7 +90,7 @@ int fdd_tests()
ZERO_OBJECT(uci_cfg); ZERO_OBJECT(uci_cfg);
uci_cfg.ack[0].nof_acks = 2; uci_cfg.ack[0].nof_acks = 2;
uci_cfg.ack[0].ncce[0] = 13; 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); TESTASSERT(pucch_cfg.format == SRSLTE_PUCCH_FORMAT_1B);
if (i == 0) { if (i == 0) {
TESTASSERT(pucch_cfg.n_pucch == pucch_cfg.n_pucch_sr); TESTASSERT(pucch_cfg.n_pucch == pucch_cfg.n_pucch_sr);
@ -112,14 +113,14 @@ int fdd_tests()
// ACK/ACK, n_pucch = n_pucch_1 // ACK/ACK, n_pucch = n_pucch_1
uci_value.ack.ack_value[0] = 1; uci_value.ack.ack_value[0] = 1;
uci_value.ack.ack_value[1] = 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.format == SRSLTE_PUCCH_FORMAT_1B);
TESTASSERT(pucch_cfg.n_pucch == uci_cfg.ack[1].ncce[0] + pucch_cfg.N_pucch_1); TESTASSERT(pucch_cfg.n_pucch == uci_cfg.ack[1].ncce[0] + pucch_cfg.N_pucch_1);
// ACK/DTX, n_pucch = n_pucch_0 // ACK/DTX, n_pucch = n_pucch_0
uci_value.ack.ack_value[0] = 1; uci_value.ack.ack_value[0] = 1;
uci_value.ack.ack_value[1] = 2; 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.format == SRSLTE_PUCCH_FORMAT_1B);
TESTASSERT(pucch_cfg.n_pucch == uci_cfg.ack[0].ncce[0] + pucch_cfg.N_pucch_1); 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_cfg.ack[1].tpc_for_pucch = 3;
uci_value.ack.ack_value[0] = 1; uci_value.ack.ack_value[0] = 1;
uci_value.ack.ack_value[1] = 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.format == SRSLTE_PUCCH_FORMAT_1B);
TESTASSERT(pucch_cfg.n_pucch == pucch_cfg.n1_pucch_an_cs[uci_cfg.ack[1].tpc_for_pucch][0]); 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_cfg.ack[0].tpc_for_pucch = 2;
uci_value.ack.ack_value[0] = 1; uci_value.ack.ack_value[0] = 1;
uci_value.ack.ack_value[1] = 2; 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.format == SRSLTE_PUCCH_FORMAT_1B);
TESTASSERT(pucch_cfg.n_pucch == pucch_cfg.n1_pucch_an_cs[uci_cfg.ack[0].tpc_for_pucch][0]); 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_value.scheduling_request = true;
uci_cfg.ack[0].nof_acks = 1; uci_cfg.ack[0].nof_acks = 1;
uci_cfg.ack[1].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); TESTASSERT(pucch_cfg.format == SRSLTE_PUCCH_FORMAT_1B);
return 0; return 0;

@ -474,370 +474,16 @@ float srs_power(srslte_ue_ul_t* q, srslte_ue_ul_cfg_t* cfg, float PL)
return p_srs; 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 */ /* Procedure for determining PUCCH assignment 10.1 36.213 */
void srslte_ue_ul_pucch_resource_selection(srslte_cell_t* cell, void srslte_ue_ul_pucch_resource_selection(const srslte_cell_t* cell,
srslte_pucch_cfg_t* cfg, srslte_pucch_cfg_t* cfg,
srslte_uci_cfg_t* uci_cfg, const srslte_uci_cfg_t* uci_cfg,
srslte_uci_value_t* uci_value) 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 // Get PUCCH Resources
cfg->format = srslte_pucch_select_format(cfg, uci_cfg, cell->cp); cfg->format = srslte_pucch_proc_select_format(cell, cfg, uci_cfg, uci_value);
cfg->n_pucch = get_npucch(cfg, uci_cfg, uci_value, cell); 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 /* 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; int ret = SRSLTE_ERROR_INVALID_INPUTS;
if (q != NULL && cfg != NULL) { 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; ret = SRSLTE_ERROR;
if (!srslte_pucch_cfg_isvalid(&cfg->ul_cfg.pucch, q->cell.nof_prb)) { 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)); bzero(q->sf_symbols, sizeof(cf_t) * SRSLTE_NOF_RE(q->cell));
// Prepare configuration // 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); srslte_refsignal_srs_pucch_shortened(&q->signals, sf, &cfg->ul_cfg.srs, &cfg->ul_cfg.pucch);

Loading…
Cancel
Save