Initial PUCCH 1B with channel selection

This commit is contained in:
Xavier Arteaga 2020-01-31 19:42:56 +01:00 committed by Xavier Arteaga
parent c76cdc6cea
commit 35f4e5d69a
11 changed files with 575 additions and 163 deletions

View File

@ -86,6 +86,4 @@ SRSLTE_API int srslte_enb_ul_get_pusch(srslte_enb_ul_t* q,
srslte_pusch_cfg_t* cfg,
srslte_pusch_res_t* res);
SRSLTE_API uint32_t srslte_enb_ul_get_pucch_prb_idx(srslte_cell_t* cell, srslte_pucch_cfg_t* cfg, uint32_t ns);
#endif // SRSLTE_ENB_UL_H

View File

@ -41,10 +41,16 @@
#define SRSLTE_PUCCH_N_SEQ 12
#define SRSLTE_PUCCH2_NOF_BITS SRSLTE_UCI_CQI_CODED_PUCCH_B
#define SRSLTE_PUCCH_1A_2A_NOF_ACK (1)
#define SRSLTE_PUCCH_1B_2B_NOF_ACK (2)
#define SRSLTE_PUCCH3_NOF_BITS (4 * SRSLTE_NRE)
#define SRSLTE_PUCCH_MAX_BITS SRSLTE_CQI_MAX_BITS
#define SRSLTE_PUCCH_MAX_SYMBOLS 128
// PUCCH Format 1B Channel selection
#define SRSLTE_PUCCH_CS_MAX_ACK 4
#define SRSLTE_PUCCH_CS_MAX_NOF_ALLOC 4
typedef struct {
srslte_sequence_t seq_f2[SRSLTE_NOF_SF_X_FRAME];
uint32_t cell_id;
@ -138,6 +144,13 @@ SRSLTE_API char* srslte_pucch_format_text(srslte_pucch_format_t format);
SRSLTE_API char* srslte_pucch_format_text_short(srslte_pucch_format_t format);
/**
* Returns the number of ACK bits supported by a given PUCCH format
* @param format PUCCH format
* @return Returns the number of bits supported by the format
*/
SRSLTE_API uint32_t srslte_pucch_nof_ack_format(srslte_pucch_format_t format);
SRSLTE_API void
srslte_pucch_tx_info(srslte_pucch_cfg_t* cfg, srslte_uci_value_t* uci_data, char* str, uint32_t str_len);
@ -146,4 +159,47 @@ 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);
/**
* Implements 3GPP 36.213 R10 10.1.2.2.1 PUCCH format 1b with channel selection HARQ-ACK procedure
* resource list
* @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]);
/**
* 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

View File

@ -27,6 +27,7 @@
#include "srslte/phy/phch/uci_cfg.h"
#define SRSLTE_PUCCH_SIZE_AN_CS 4
#define SRSLTE_PUCCH_SIZE_AN_N3 4
#define SRSLTE_PUCCH_NOF_AN_CS 2
#define SRSLTE_PUCCH2_MAX_DMRS_BITS 16
@ -68,7 +69,7 @@ typedef struct SRSLTE_API {
// Release 10 CA specific
srslte_ack_nack_feedback_mode_t ack_nack_feedback_mode;
uint32_t n1_pucch_an_cs[SRSLTE_PUCCH_SIZE_AN_CS][SRSLTE_PUCCH_NOF_AN_CS];
uint32_t n3_pucch_an_list[SRSLTE_PUCCH_SIZE_AN_CS];
uint32_t n3_pucch_an_list[SRSLTE_PUCCH_SIZE_AN_N3];
// Other configuration
float threshold_format1;

View File

@ -170,32 +170,108 @@ void srslte_enb_ul_fft(srslte_enb_ul_t* q)
srslte_ofdm_rx_sf(&q->fft);
}
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 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])
{
srslte_uci_value_t uci_value_default = {};
srslte_ue_ul_pucch_resource_selection(&q->cell, cfg, &cfg->uci_cfg, &uci_value_default);
int ret = 1;
// Prepare configuration
if (srslte_chest_ul_estimate_pucch(&q->chest, ul_sf, cfg, q->sf_symbols, &q->chest_res)) {
ERROR("Error estimating PUCCH DMRS\n");
return SRSLTE_ERROR;
if (!cfg || !cell || !uci_cfg || !n_pucch_i) {
ERROR("get_npucch(): Invalid parameters\n");
ret = SRSLTE_ERROR_INVALID_INPUTS;
} else if (uci_cfg->is_scheduling_request_tti) {
n_pucch_i[0] = cfg->n_pucch_sr;
} else 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];
} else {
if (cell->frame_type == SRSLTE_FDD) {
switch (cfg->ack_nack_feedback_mode) {
case SRSLTE_PUCCH_ACK_NACK_FEEDBACK_MODE_PUCCH3:
n_pucch_i[0] = cfg->n3_pucch_an_list[uci_cfg->ack[0].tpc_for_pucch % SRSLTE_PUCCH_SIZE_AN_N3];
break;
case SRSLTE_PUCCH_ACK_NACK_FEEDBACK_MODE_CS:
ret = srslte_pucch_cs_resources(cfg, uci_cfg, n_pucch_i);
break;
default:
n_pucch_i[0] = uci_cfg->ack[0].ncce[0] + cfg->N_pucch_1;
break;
}
} else {
ERROR("TDD not supported\n");
ret = SRSLTE_ERROR;
}
}
} else {
n_pucch_i[0] = cfg->n_pucch_2;
}
int ret_val = srslte_pucch_decode(&q->pucch, ul_sf, cfg, &q->chest_res, q->sf_symbols, res);
if (ret_val < 0) {
ERROR("Error decoding PUCCH\n");
return SRSLTE_ERROR;
}
return ret_val;
return ret;
}
uint32_t srslte_enb_ul_get_pucch_prb_idx(srslte_cell_t* cell, srslte_pucch_cfg_t* cfg, uint32_t ns)
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)
{
// compute Format and n_pucch
srslte_ue_ul_pucch_resource_selection(cell, cfg, &cfg->uci_cfg, NULL);
int ret = SRSLTE_SUCCESS;
uint32_t n_pucch_i[SRSLTE_PUCCH_CS_MAX_ACK];
srslte_pucch_res_t pucch_res;
// compute prb_idx
return srslte_pucch_n_prb(cell, cfg, ns);
// 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) {
cfg->uci_cfg.cqi.data_enable = false;
}
// Select format
cfg->format = srslte_pucch_select_format(cfg, &cfg->uci_cfg, q->cell.cp);
// Get possible resources
int nof_resources = pucch_resource_selection(cfg, &cfg->uci_cfg, &q->cell, 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;
}
// Initialise minimum correlation
res->correlation = -INFINITY;
// Iterate possible resources and select the one with higher correlation
for (int i = 0; i < nof_resources && ret == SRSLTE_SUCCESS; i++) {
// Configure resource
cfg->n_pucch = n_pucch_i[i];
// Prepare configuration
if (srslte_chest_ul_estimate_pucch(&q->chest, ul_sf, cfg, q->sf_symbols, &q->chest_res)) {
ERROR("Error estimating PUCCH DMRS\n");
return SRSLTE_ERROR;
}
ret = srslte_pucch_decode(&q->pucch, ul_sf, cfg, &q->chest_res, q->sf_symbols, &pucch_res);
if (ret < SRSLTE_SUCCESS) {
ERROR("Error decoding PUCCH\n");
} else {
// If channel selection enabled
if (cfg->ack_nack_feedback_mode == SRSLTE_PUCCH_ACK_NACK_FEEDBACK_MODE_CS) {
uint8_t b[2] = {pucch_res.uci_data.ack.ack_value[0], pucch_res.uci_data.ack.ack_value[1]};
srslte_pucch_cs_get_ack(cfg, &cfg->uci_cfg, i, b, &pucch_res.uci_data);
}
char txt[256];
srslte_pucch_rx_info(cfg, &pucch_res.uci_data, txt, sizeof(txt));
INFO("[ENB_UL/PUCCH] Decoded %s, corr=%.3f\n", txt, pucch_res.correlation);
// Check correlation value, keep maximum
if (pucch_res.correlation > res->correlation) {
*res = pucch_res;
}
}
}
return ret;
}
int srslte_enb_ul_get_pucch(srslte_enb_ul_t* q,

View File

@ -742,32 +742,32 @@ static bool decode_signal(srslte_pucch_t* q,
return detected;
}
static void decode_bits(srslte_uci_cfg_t* uci_cfg,
static void decode_bits(srslte_pucch_cfg_t* cfg,
bool pucch_found,
uint8_t pucch_bits[SRSLTE_PUCCH_MAX_BITS],
uint8_t pucch_dmrs_bits[SRSLTE_PUCCH2_MAX_DMRS_BITS],
uint8_t pucch2_bits[SRSLTE_PUCCH_MAX_BITS],
srslte_uci_value_t* uci_data)
{
// If was looking for scheduling request, update value
if (uci_cfg->is_scheduling_request_tti) {
if (cfg->uci_cfg.is_scheduling_request_tti) {
uci_data->scheduling_request = pucch_found;
}
// Save ACK bits
for (uint32_t a = 0; a < srslte_uci_cfg_total_ack(uci_cfg); a++) {
if (uci_cfg->cqi.data_enable || uci_cfg->cqi.ri_len) {
uci_data->ack.ack_value[a] = pucch_dmrs_bits[a];
for (uint32_t a = 0; a < srslte_pucch_nof_ack_format(cfg->format); a++) {
if (cfg->uci_cfg.cqi.data_enable || cfg->uci_cfg.cqi.ri_len) {
uci_data->ack.ack_value[a] = pucch2_bits[a];
} else {
uci_data->ack.ack_value[a] = pucch_bits[a];
}
}
// PUCCH2 CQI bits are already decoded
if (uci_cfg->cqi.data_enable) {
srslte_cqi_value_unpack(&uci_cfg->cqi, pucch_bits, &uci_data->cqi);
if (cfg->uci_cfg.cqi.data_enable) {
srslte_cqi_value_unpack(&cfg->uci_cfg.cqi, pucch_bits, &uci_data->cqi);
}
if (uci_cfg->cqi.ri_len) {
if (cfg->uci_cfg.cqi.ri_len) {
uci_data->ri = pucch_bits[0]; /* Assume only one bit of RI */
}
}
@ -837,7 +837,7 @@ int srslte_pucch_decode(srslte_pucch_t* q,
bool pucch_found = decode_signal(q, sf, cfg, pucch_bits, nof_re, nof_uci_bits, &data->correlation);
// Convert bits to UCI data
decode_bits(&cfg->uci_cfg, pucch_found, pucch_bits, cfg->pucch2_drs_bits, &data->uci_data);
decode_bits(cfg, pucch_found, pucch_bits, cfg->pucch2_drs_bits, &data->uci_data);
data->detected = pucch_found;
@ -893,8 +893,8 @@ char* srslte_pucch_format_text(srslte_pucch_format_t format)
ret = "Format 3";
break;
case SRSLTE_PUCCH_FORMAT_ERROR:
default:
ret = "Format Error";
break;
}
return ret;
@ -928,6 +928,7 @@ char* srslte_pucch_format_text_short(srslte_pucch_format_t format)
ret = "3";
break;
case SRSLTE_PUCCH_FORMAT_ERROR:
default:
ret = "Err";
break;
}
@ -935,6 +936,28 @@ char* srslte_pucch_format_text_short(srslte_pucch_format_t format)
return ret;
}
uint32_t srslte_pucch_nof_ack_format(srslte_pucch_format_t format)
{
uint32_t ret = 0;
switch (format) {
case SRSLTE_PUCCH_FORMAT_1A:
case SRSLTE_PUCCH_FORMAT_2A:
ret = 1;
break;
case SRSLTE_PUCCH_FORMAT_1B:
case SRSLTE_PUCCH_FORMAT_2B:
ret = 2;
break;
default:
// Keep default
break;
}
return ret;
}
/* Verify PUCCH configuration as given in Section 5.4 36.211 */
bool srslte_pucch_cfg_isvalid(srslte_pucch_cfg_t* cfg, uint32_t nof_prb)
{
@ -1154,3 +1177,195 @@ void srslte_pucch_rx_info(srslte_pucch_cfg_t* cfg, srslte_uci_value_t* uci_data,
srslte_uci_data_info(&cfg->uci_cfg, uci_data, &str[n], str_len - n);
}
}
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;
// No CQI data
if (!uci_cfg->cqi.data_enable && uci_cfg->cqi.ri_len == 0) {
// PUCCH Format 3 condition specified in:
// 3GPP 36.213 10.1.2.2.2 PUCCH format 3 HARQ-ACK procedure
if (cfg->ack_nack_feedback_mode == SRSLTE_PUCCH_ACK_NACK_FEEDBACK_MODE_PUCCH3 &&
srslte_uci_cfg_total_ack(uci_cfg) > 1) {
format = SRSLTE_PUCCH_FORMAT_3;
}
// 1-bit ACK + optional SR
else if (srslte_uci_cfg_total_ack(uci_cfg) == 1) {
format = SRSLTE_PUCCH_FORMAT_1A;
}
// 2-bit ACK + optional SR
else if (srslte_uci_cfg_total_ack(uci_cfg) >= 2 && srslte_uci_cfg_total_ack(uci_cfg) <= 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", srslte_uci_cfg_total_ack(uci_cfg));
}
}
// CQI data
else {
// CQI and no ack
if (srslte_uci_cfg_total_ack(uci_cfg) == 0) {
format = SRSLTE_PUCCH_FORMAT_2;
}
// CQI + 1-bit ACK
else if (srslte_uci_cfg_total_ack(uci_cfg) == 1 && SRSLTE_CP_ISNORM(cp)) {
format = SRSLTE_PUCCH_FORMAT_2A;
}
// CQI + 2-bit ACK
else if (srslte_uci_cfg_total_ack(uci_cfg) == 2) {
format = SRSLTE_PUCCH_FORMAT_2B;
}
// CQI + 2-bit ACK + cyclic prefix
else if (srslte_uci_cfg_total_ack(uci_cfg) == 1 && SRSLTE_CP_ISEXT(cp)) {
format = SRSLTE_PUCCH_FORMAT_2B;
}
}
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 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++) {
n_pucch_i[k++] = uci_cfg->ack[i].ncce[0] + cfg->N_pucch_1 + j;
}
} 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;
}
return ret;
}
#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;
}

View File

@ -771,9 +771,10 @@ int srslte_uci_data_info(srslte_uci_cfg_t* uci_cfg, srslte_uci_value_t* uci_data
n = srslte_print_check(str, str_len, n, ", sr=%s", uci_data->scheduling_request ? "yes" : "no");
}
if (srslte_uci_cfg_total_ack(uci_cfg)) {
uint32_t nof_acks = srslte_uci_cfg_total_ack(uci_cfg);
if (nof_acks) {
n = srslte_print_check(str, str_len, n, ", ack=");
for (uint32_t i = 0; i < srslte_uci_cfg_total_ack(uci_cfg); i++) {
for (uint32_t i = 0; i < nof_acks; i++) {
n = srslte_print_check(str, str_len, n, "%d", uci_data->ack.ack_value[i]);
}
if (uci_cfg->ack[0].N_bundle) {

View File

@ -474,58 +474,6 @@ float srs_power(srslte_ue_ul_t* q, srslte_ue_ul_cfg_t* cfg, float PL)
return p_srs;
}
/* Choose PUCCH format based on pending transmission as described in 10.1 of 36.213 */
static srslte_pucch_format_t
get_format(srslte_pucch_cfg_t* cfg, srslte_uci_cfg_t* uci_cfg, srslte_uci_value_t* uci_value, srslte_cp_t cp)
{
srslte_pucch_format_t format = SRSLTE_PUCCH_FORMAT_ERROR;
// No CQI data
if (!uci_cfg->cqi.data_enable && uci_cfg->cqi.ri_len == 0) {
// PUCCH Format 3 condition specified in:
// 3GPP 36.213 10.1.2.2.2 PUCCH format 3 HARQ-ACK procedure
if (cfg->ack_nack_feedback_mode == SRSLTE_PUCCH_ACK_NACK_FEEDBACK_MODE_PUCCH3 &&
srslte_uci_cfg_total_ack(uci_cfg) > 1) {
format = SRSLTE_PUCCH_FORMAT_3;
}
// 1-bit ACK + optional SR
else if (srslte_uci_cfg_total_ack(uci_cfg) == 1) {
format = SRSLTE_PUCCH_FORMAT_1A;
}
// 2-bit ACK + optional SR
else if (srslte_uci_cfg_total_ack(uci_cfg) >= 2 && srslte_uci_cfg_total_ack(uci_cfg) <= 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 || (uci_value && uci_value->scheduling_request)) {
format = SRSLTE_PUCCH_FORMAT_1;
} else {
fprintf(stderr,
"Error selecting PUCCH format: Unsupported number of ACK bits %d\n",
srslte_uci_cfg_total_ack(uci_cfg));
}
}
// CQI data
else {
// CQI and no ack
if (srslte_uci_cfg_total_ack(uci_cfg) == 0) {
format = SRSLTE_PUCCH_FORMAT_2;
}
// CQI + 1-bit ACK
else if (srslte_uci_cfg_total_ack(uci_cfg) == 1 && SRSLTE_CP_ISNORM(cp)) {
format = SRSLTE_PUCCH_FORMAT_2A;
}
// CQI + 2-bit ACK
else if (srslte_uci_cfg_total_ack(uci_cfg) == 2) {
format = SRSLTE_PUCCH_FORMAT_2B;
}
// CQI + 2-bit ACK + cyclic prefix
else if (srslte_uci_cfg_total_ack(uci_cfg) == 1 && SRSLTE_CP_ISEXT(cp)) {
format = SRSLTE_PUCCH_FORMAT_2B;
}
}
return format;
}
// 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)
{
@ -533,31 +481,14 @@ static uint32_t get_npucch_cs(srslte_pucch_cfg_t* cfg, srslte_uci_cfg_t* uci_cfg
uint8_t* b = uci_value->ack.ack_value;
uint32_t n_pucch_i[4] = {};
// Determine the 4 PUCCH resources n_pucch_j associated with HARQ-ACK(j)
uint32_t k = 0;
for (int i = 0; i < 2; 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; j++) {
if (k < 4) {
n_pucch_i[k++] = uci_cfg->ack[i].ncce[0] + cfg->N_pucch_1 + j;
} else {
fprintf(stderr, "get_npucch_cs(): Too many ack bits\n");
}
}
} 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 % 4][j];
} else {
fprintf(stderr, "get_npucch_cs(): Too many ack bits\n");
}
}
}
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
switch (srslte_uci_cfg_total_ack(uci_cfg)) {
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];
@ -631,10 +562,12 @@ static uint32_t get_npucch_cs(srslte_pucch_cfg_t* cfg, srslte_uci_cfg_t* uci_cfg
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[1] != 1 ? 0 : 1) & (b[0] != 1 ? 1 : 0));
b[1] = (uint8_t)((b[3] != 1 ? 0 : 1) & ((b[1] != 1 ? 0 : 1) ^ (b[2] != 1 ? 0 : 1)));
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;
@ -891,7 +824,13 @@ void srslte_ue_ul_pucch_resource_selection(srslte_cell_t* cell,
uci_cfg->cqi.data_enable = false;
}
cfg->format = get_format(cfg, uci_cfg, uci_value, cell->cp);
// Assume that if a scheduling request is carried, it is the right TTI
if (uci_value) {
uci_cfg->is_scheduling_request_tti |= uci_value->scheduling_request;
}
// 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);
if (uci_value) {
@ -925,7 +864,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;
ret = SRSLTE_ERROR;
if (!srslte_pucch_cfg_isvalid(&cfg->ul_cfg.pucch, q->cell.nof_prb)) {
@ -936,11 +875,11 @@ 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_data);
srslte_ue_ul_pucch_resource_selection(&q->cell, &cfg->ul_cfg.pucch, &cfg->ul_cfg.pucch.uci_cfg, &uci_value2);
srslte_refsignal_srs_pucch_shortened(&q->signals, sf, &cfg->ul_cfg.srs, &cfg->ul_cfg.pucch);
if (srslte_pucch_encode(&q->pucch, sf, &cfg->ul_cfg.pucch, uci_data, q->sf_symbols)) {
if (srslte_pucch_encode(&q->pucch, sf, &cfg->ul_cfg.pucch, &uci_value2, q->sf_symbols)) {
ERROR("Error encoding TB\n");
return ret;
}
@ -958,6 +897,10 @@ pucch_encode(srslte_ue_ul_t* q, srslte_ul_sf_cfg_t* sf, srslte_ue_ul_cfg_t* cfg,
apply_cfo(q, cfg);
apply_norm(q, cfg, (float)q->cell.nof_prb / 15 / 10);
char txt[256];
srslte_pucch_tx_info(&cfg->ul_cfg.pucch, uci_data, txt, sizeof(txt));
INFO("[PUCCH] Encoded %s\n", txt);
ret = SRSLTE_SUCCESS;
}

View File

@ -65,3 +65,8 @@ foreach (cell_n_prb 6 15 25 50 75 100)
endforeach (ue_dl_tm)
endforeach (allow_256 0 1)
endforeach (cell_n_prb)
add_executable(pucch_cs_test pucch_cs_test.c)
target_link_libraries(pucch_cs_test srslte_phy srslte_common srslte_phy ${SEC_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT})
add_test(pucch_cs_test pucch_cs_test)

View File

@ -0,0 +1,166 @@
/*
* 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/common/test_common.h>
#include <srslte/phy/utils/random.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <sys/time.h>
#include <unistd.h>
#include "srslte/srslte.h"
static int test_pucch_cs(uint32_t nof_prb, uint32_t nof_tb[SRSLTE_MAX_CARRIERS], uint16_t nof_carriers)
{
srslte_pucch_cfg_t pucch_cfg = {};
uint16_t rnti = 0x1234;
srslte_cell_t cell = {
nof_prb, // nof_prb
1, // nof_ports
1, // cell_id
SRSLTE_CP_NORM, // cyclic prefix
SRSLTE_PHICH_NORM, // PHICH length
SRSLTE_PHICH_R_1_6, // PHICH resources
SRSLTE_FDD,
};
cf_t* buffer = NULL;
srslte_refsignal_dmrs_pusch_cfg_t dmrs_pusch_cfg = {}; // Use default
srslte_ue_ul_t ue_ul = {};
srslte_ue_ul_cfg_t ue_ul_cfg = {};
srslte_enb_ul_t enb_ul = {};
srslte_ul_sf_cfg_t ul_sf = {};
srslte_pucch_res_t pucch_res = {};
srslte_pusch_data_t pusch_data = {};
// Basic default args
pucch_cfg.delta_pucch_shift = 1; // 1, 2, 3
pucch_cfg.n_rb_2 = 1; // 0, 1, ..., 98
pucch_cfg.N_cs = 1; // 0, 1, ..., 7
pucch_cfg.N_pucch_1 = 1; // 0, 1, ..., 2047
pucch_cfg.ack_nack_feedback_mode = SRSLTE_PUCCH_ACK_NACK_FEEDBACK_MODE_CS; // Normal, CS, PUCCH3
// Set Channel Selection resources
for (uint32_t i = 0, k = 6; i < SRSLTE_PUCCH_SIZE_AN_CS; i++) {
for (uint32_t j = 0; j < SRSLTE_PUCCH_NOF_AN_CS; j++, k++) {
pucch_cfg.n1_pucch_an_cs[i][j] = k;
}
}
uint32_t base_ncce = 1;
for (uint32_t i = 0; i < nof_carriers; base_ncce += nof_tb[i++]) {
pucch_cfg.uci_cfg.ack[i].grant_cc_idx = 0; // 0: PCell Scheduling; 1: SCell Scheduling
pucch_cfg.uci_cfg.ack[i].ncce[0] = base_ncce; // PDCCH Location, 0 is always fine
pucch_cfg.uci_cfg.ack[i].nof_acks = nof_tb[i]; // Number of transport blocks, 1 or 2
}
// Set derived parameters
pucch_cfg.rnti = rnti;
// Init buffers
buffer = srslte_vec_cf_malloc(SRSLTE_SF_LEN_PRB(cell.nof_prb));
TESTASSERT(buffer);
// Init UE
TESTASSERT(!srslte_ue_ul_init(&ue_ul, buffer, cell.nof_prb));
TESTASSERT(!srslte_ue_ul_set_cell(&ue_ul, cell));
srslte_ue_ul_set_rnti(&ue_ul, rnti);
// Init eNb
TESTASSERT(!srslte_enb_ul_init(&enb_ul, buffer, cell.nof_prb));
TESTASSERT(!srslte_enb_ul_set_cell(&enb_ul, cell, &dmrs_pusch_cfg));
TESTASSERT(!srslte_enb_ul_add_rnti(&enb_ul, rnti));
// The test itself starts here
for (ul_sf.tti = 0; ul_sf.tti < (1U << (nof_carriers * 2)); ul_sf.tti++) {
// Generate new data
pusch_data.uci.ack.valid = true;
for (uint32_t i = 0, k = 0; i < nof_carriers; i++) {
for (uint32_t j = 0; j < nof_tb[i]; j++, k++) {
pusch_data.uci.ack.ack_value[k] = (ul_sf.tti >> k) & 0x01;
}
}
// Copy UL configuration
ue_ul_cfg.ul_cfg.pucch = pucch_cfg;
// Generate UL Signal
TESTASSERT(srslte_ue_ul_encode(&ue_ul, &ul_sf, &ue_ul_cfg, &pusch_data) >= SRSLTE_SUCCESS);
// Process UL signal
srslte_enb_ul_fft(&enb_ul);
TESTASSERT(!srslte_enb_ul_get_pucch(&enb_ul, &ul_sf, &pucch_cfg, &pucch_res));
TESTASSERT(pucch_res.detected);
TESTASSERT(pucch_res.uci_data.ack.valid);
// Check results
for (int i = 0, k = 0; i < nof_carriers; i++) {
for (int j = 0; j < nof_tb[i]; j++, k++) {
INFO("cc=%d; tb=%d; tx_ack=%d; rx_ack=%d;\n",
i,
j,
pusch_data.uci.ack.ack_value[k],
pucch_res.uci_data.ack.ack_value[k]);
TESTASSERT(pusch_data.uci.ack.ack_value[k] == pucch_res.uci_data.ack.ack_value[k]);
}
}
}
// Free all
srslte_ue_ul_free(&ue_ul);
srslte_enb_ul_free(&enb_ul);
free(buffer);
return SRSLTE_SUCCESS;
}
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_3[SRSLTE_MAX_CARRIERS] = {2, 2, 0, 0, 0};
TESTASSERT(!test_pucch_cs(6, nof_tb_1, 2));
TESTASSERT(!test_pucch_cs(6, nof_tb_1, 3));
TESTASSERT(!test_pucch_cs(6, nof_tb_1, 4));
TESTASSERT(!test_pucch_cs(6, nof_tb_2, 3));
TESTASSERT(!test_pucch_cs(6, nof_tb_2, 3));
TESTASSERT(!test_pucch_cs(6, nof_tb_3, 2));
TESTASSERT(!test_pucch_cs(100, nof_tb_1, 2));
TESTASSERT(!test_pucch_cs(100, nof_tb_1, 3));
TESTASSERT(!test_pucch_cs(100, nof_tb_1, 4));
TESTASSERT(!test_pucch_cs(100, nof_tb_2, 3));
TESTASSERT(!test_pucch_cs(100, nof_tb_2, 3));
TESTASSERT(!test_pucch_cs(100, nof_tb_3, 2));
printf("Ok\n");
return SRSLTE_SUCCESS;
}

View File

@ -200,7 +200,6 @@ public:
bool needs_cqi(uint32_t tti, uint32_t cc_idx, bool will_send = false);
uint32_t get_max_retx();
bool get_pucch_sched(uint32_t current_tti, uint32_t cc_idx, uint32_t prb_idx[2]);
bool pucch_sr_collision(uint32_t current_tti, uint32_t n_cce);
static int cqi_to_tbs(uint32_t cqi,

View File

@ -229,54 +229,6 @@ bool sched_ue::pucch_sr_collision(uint32_t current_tti, uint32_t n_cce)
return false;
}
bool sched_ue::get_pucch_sched(uint32_t current_tti, uint32_t cc_idx, uint32_t prb_idx[2])
{
bool ret = false;
std::lock_guard<std::mutex> lock(mutex);
if (phy_config_dedicated_enabled) {
// Configure expected UCI for this TTI
ZERO_OBJECT(cfg.pucch_cfg.uci_cfg);
// SR
cfg.pucch_cfg.uci_cfg.is_scheduling_request_tti = srslte_ue_ul_sr_send_tti(&cfg.pucch_cfg, current_tti);
ret |= cfg.pucch_cfg.uci_cfg.is_scheduling_request_tti;
// Pending ACKs
for (auto& h : carriers[cc_idx].dl_harq) {
if (TTI_TX(h.get_tti()) == current_tti) {
cfg.pucch_cfg.uci_cfg.ack[0].ncce[0] = h.get_n_cce();
cfg.pucch_cfg.uci_cfg.ack[0].nof_acks = 1;
ret = true;
}
}
// Periodic CQI
if (srslte_enb_dl_gen_cqi_periodic(&cell, &cfg.dl_cfg, current_tti, 1, &cfg.pucch_cfg.uci_cfg.cqi)) {
ret = true;
}
// Compute PRB index
if (prb_idx) {
for (int j = 0; j < 2; j++) {
prb_idx[j] = srslte_enb_ul_get_pucch_prb_idx(&cell, &cfg.pucch_cfg, j);
}
Debug("SCHED: Reserved %s PUCCH for rnti=0x%x, n_prb=%d,%d, n_pucch=%d, ncce=%d, has_sr=%d\n",
srslte_pucch_format_text(cfg.pucch_cfg.format),
rnti,
prb_idx[0],
prb_idx[1],
cfg.pucch_cfg.n_pucch,
cfg.pucch_cfg.uci_cfg.ack[0].ncce[0],
cfg.pucch_cfg.uci_cfg.is_scheduling_request_tti);
}
}
return ret;
}
int sched_ue::set_ack_info(uint32_t tti, uint32_t cc_idx, uint32_t tb_idx, bool ack)
{
std::lock_guard<std::mutex> lock(mutex);