Changes in ACK procedure to support CA. Tested 1 cell in SISO/MIMO

master
Ismael Gomez 5 years ago committed by Xavier Arteaga
parent 7a672ca340
commit 1d83bb08e2

@ -64,7 +64,6 @@ typedef struct SRSLTE_API {
bool simul_cqi_ack;
bool tdd_ack_multiplex; // if false, bundle
bool sps_enabled;
uint32_t tpc_for_pucch;
// Release 10 CA specific
srslte_ack_nack_feedback_mode_t ack_nack_feedback_mode;

@ -127,6 +127,10 @@ SRSLTE_API int srslte_uci_decode_ack_ri(srslte_pusch_cfg_t* cfg,
uint32_t nof_bits,
bool is_ri);
SRSLTE_API uint32_t srslte_uci_cfg_total_ack(srslte_uci_cfg_t* uci_cfg);
SRSLTE_API void srslte_uci_data_reset(srslte_uci_data_t* uci_data);
SRSLTE_API int srslte_uci_data_info(srslte_uci_cfg_t* uci_cfg,
srslte_uci_value_t* uci_data,
char* str,

@ -40,11 +40,12 @@ typedef struct SRSLTE_API {
uint32_t tdd_ack_M;
uint32_t tdd_ack_m;
bool tdd_is_multiplex;
bool has_scell_ack;
uint32_t tpc_for_pucch;
uint32_t grant_cc_idx;
} srslte_uci_cfg_ack_t;
typedef struct SRSLTE_API {
srslte_uci_cfg_ack_t ack;
srslte_uci_cfg_ack_t ack[SRSLTE_MAX_CARRIERS];
srslte_cqi_cfg_t cqi;
bool is_scheduling_request_tti;
} srslte_uci_cfg_t;

@ -126,6 +126,8 @@ typedef struct SRSLTE_API {
typedef struct {
uint32_t v_dai_dl;
uint32_t n_cce;
uint32_t grant_cc_idx;
uint32_t tpc_for_pucch;
} srslte_pdsch_ack_resource_t;
typedef struct {

@ -580,14 +580,13 @@ void srslte_ofdm_set_normalize(srslte_ofdm_t *q, bool normalize_enable) {
void srslte_ofdm_tx_sf(srslte_ofdm_t *q)
{
uint32_t n;
if(!q->mbsfn_subframe){
if (!q->mbsfn_subframe) {
for (n=0;n<2;n++) {
srslte_ofdm_tx_slot(q, n);
}
}
else{
srslte_ofdm_tx_slot_mbsfn(q, &q->in_buffer[0*q->nof_re*q->nof_symbols], &q->out_buffer[0*q->slot_sz]);
srslte_ofdm_tx_slot(q, 1);
} else {
srslte_ofdm_tx_slot_mbsfn(q, &q->in_buffer[0 * q->nof_re * q->nof_symbols], &q->out_buffer[0 * q->slot_sz]);
srslte_ofdm_tx_slot(q, 1);
}
if (q->freq_shift) {
srslte_vec_prod_ccc(q->out_buffer, q->shift_buffer, q->out_buffer, 2*q->slot_sz);

@ -217,7 +217,7 @@ int srslte_enb_ul_get_pucch(srslte_enb_ul_t* q,
// If we are looking for SR and ACK at the same time and ret=0, means there is no SR.
// try again to decode ACK only
if (cfg->uci_cfg.is_scheduling_request_tti && cfg->uci_cfg.ack.nof_acks && !res->detected) {
if (cfg->uci_cfg.is_scheduling_request_tti && srslte_uci_cfg_total_ack(&cfg->uci_cfg) && !res->detected) {
cfg->uci_cfg.is_scheduling_request_tti = false;
if (get_pucch(q, ul_sf, cfg, res)) {
return -1;

@ -571,7 +571,7 @@ static int encode_bits(srslte_pucch_cfg_t* cfg,
uint8_t pucch2_bits[SRSLTE_PUCCH_MAX_BITS])
{
if (format < SRSLTE_PUCCH_FORMAT_2) {
memcpy(pucch_bits, uci_data->ack.ack_value, cfg->uci_cfg.ack.nof_acks * sizeof(uint8_t));
memcpy(pucch_bits, uci_data->ack.ack_value, srslte_uci_cfg_total_ack(&cfg->uci_cfg) * sizeof(uint8_t));
} else if (format >= SRSLTE_PUCCH_FORMAT_2 && format < SRSLTE_PUCCH_FORMAT_3) {
/* Put RI (goes alone) */
if (cfg->uci_cfg.cqi.ri_len) {
@ -594,7 +594,7 @@ static int encode_bits(srslte_pucch_cfg_t* cfg,
} else if (format == SRSLTE_PUCCH_FORMAT_3) {
uint8_t temp[SRSLTE_UCI_MAX_ACK_BITS + 1];
uint32_t k = 0;
for (; k < cfg->uci_cfg.ack.nof_acks; k++) {
for (; k < srslte_uci_cfg_total_ack(&cfg->uci_cfg); k++) {
temp[k] = (uint8_t)((uci_data->ack.ack_value[k] == 1) ? 1 : 0);
}
if (cfg->uci_cfg.is_scheduling_request_tti) {
@ -719,7 +719,7 @@ static void decode_bits(srslte_uci_cfg_t* uci_cfg,
}
// Save ACK bits
for (uint32_t a = 0; a < uci_cfg->ack.nof_acks; a++) {
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];
} else {

@ -938,7 +938,7 @@ static int uci_decode_ri_ack(
uint32_t cqi_len = srslte_cqi_size(&cfg->uci_cfg.cqi);
// Deinterleave and decode HARQ bits
if (cfg->uci_cfg.ack.nof_acks > 0) {
if (srslte_uci_cfg_total_ack(&cfg->uci_cfg) > 0) {
float beta = beta_harq_offset[cfg->uci_offset.I_offset_ack];
if (cfg->grant.tb.tbs == 0) {
beta /= beta_cqi_offset[cfg->uci_offset.I_offset_cqi];
@ -951,7 +951,7 @@ static int uci_decode_ri_ack(
cqi_len,
q->ack_ri_bits,
uci_data->ack.ack_value,
cfg->uci_cfg.ack.nof_acks,
srslte_uci_cfg_total_ack(&cfg->uci_cfg),
false);
if (ret < 0) {
return ret;
@ -1120,7 +1120,7 @@ int srslte_ulsch_encode(srslte_sch_t* q,
beta,
nb_q / Qm,
true,
cfg->uci_cfg.ack.N_bundle,
cfg->uci_cfg.ack[0].N_bundle,
q->ack_ri_bits);
if (ret < 0) {
return ret;
@ -1169,19 +1169,19 @@ int srslte_ulsch_encode(srslte_sch_t* q,
ulsch_interleave(g_bits, Qm, nb_q / Qm, cfg->grant.nof_symb, q_bits, q->ack_ri_bits, Q_prime_ri * Qm, q->temp_g_bits);
// Encode (and interleave) ACK
if (cfg->uci_cfg.ack.nof_acks > 0) {
if (srslte_uci_cfg_total_ack(&cfg->uci_cfg) > 0) {
float beta = beta_harq_offset[cfg->uci_offset.I_offset_ack];
if (cb_segm.tbs == 0) {
beta /= beta_cqi_offset[cfg->uci_offset.I_offset_cqi];
}
ret = srslte_uci_encode_ack_ri(cfg,
uci_data->ack.ack_value,
cfg->uci_cfg.ack.nof_acks,
srslte_uci_cfg_total_ack(&cfg->uci_cfg),
(uint32_t)uci_cqi_len,
beta,
nb_q / Qm,
false,
cfg->uci_cfg.ack.N_bundle,
cfg->uci_cfg.ack[0].N_bundle,
&q->ack_ri_bits[Q_prime_ri * Qm]);
if (ret < 0) {
return ret;

@ -204,13 +204,13 @@ int main(int argc, char **argv) {
case SRSLTE_PUCCH_FORMAT_1A:
case SRSLTE_PUCCH_FORMAT_2A:
uci_data.value.ack.ack_value[0] = 1;
uci_data.cfg.ack.nof_acks = 1;
uci_data.cfg.ack[0].nof_acks = 1;
break;
case SRSLTE_PUCCH_FORMAT_1B:
case SRSLTE_PUCCH_FORMAT_2B:
uci_data.value.ack.ack_value[0] = 1;
uci_data.value.ack.ack_value[1] = 1;
uci_data.cfg.ack.nof_acks = 2;
uci_data.cfg.ack[0].nof_acks = 2;
break;
default:
break;

@ -121,7 +121,7 @@ void parse_extensive_param(char *param, char *arg) {
uci_data_tx.cfg.cqi.ri_len = 1;
}
} else if (!strcmp(param, "uci_ack")) {
uci_data_tx.cfg.ack.nof_acks = SRSLTE_MIN(uci_data_tx.cfg.ack.nof_acks + 1, SRSLTE_UCI_MAX_ACK_BITS);
uci_data_tx.cfg.ack[0].nof_acks = SRSLTE_MIN(uci_data_tx.cfg.ack[0].nof_acks + 1, SRSLTE_UCI_MAX_ACK_BITS);
} else if (!strcmp(param, "enable_64qam")) {
enable_64_qam ^= true;
} else {
@ -295,7 +295,7 @@ int main(int argc, char** argv)
data[i] = (uint8_t)srslte_random_uniform_int_dist(random_h, 0, 255);
}
for (uint32_t a = 0; a < uci_data_tx.cfg.ack.nof_acks; a++) {
for (uint32_t a = 0; a < uci_data_tx.cfg.ack[0].nof_acks; a++) {
uci_data_tx.value.ack.ack_value[a] = (uint8_t)srslte_random_uniform_int_dist(random_h, 0, 1);
}
@ -338,17 +338,17 @@ int main(int argc, char** argv)
INFO("Rx Data is Ok\n");
}
if (uci_data_tx.cfg.ack.nof_acks) {
if (memcmp(uci_data_tx.value.ack.ack_value, pusch_res.uci.ack.ack_value, uci_data_tx.cfg.ack.nof_acks) != 0) {
if (uci_data_tx.cfg.ack[0].nof_acks) {
if (memcmp(uci_data_tx.value.ack.ack_value, pusch_res.uci.ack.ack_value, uci_data_tx.cfg.ack[0].nof_acks) != 0) {
printf("UCI ACK bit error:\n");
printf("\tTx: ");
srslte_vec_fprint_byte(stdout, uci_data_tx.value.ack.ack_value, uci_data_tx.cfg.ack.nof_acks);
srslte_vec_fprint_byte(stdout, uci_data_tx.value.ack.ack_value, uci_data_tx.cfg.ack[0].nof_acks);
printf("\tRx: ");
srslte_vec_fprint_byte(stdout, pusch_res.uci.ack.ack_value, cfg.uci_cfg.ack.nof_acks);
srslte_vec_fprint_byte(stdout, pusch_res.uci.ack.ack_value, cfg.uci_cfg.ack[0].nof_acks);
ret = SRSLTE_ERROR;
} else {
INFO("Rx ACK (%d bits) is Ok, %d%d\n",
uci_data_tx.cfg.ack.nof_acks,
uci_data_tx.cfg.ack[0].nof_acks,
uci_data_tx.value.ack.ack_value[0],
uci_data_tx.value.ack.ack_value[1]);
}

@ -787,6 +787,23 @@ int srslte_uci_decode_ack_ri(srslte_pusch_cfg_t* cfg,
return (int) Qprime;
}
uint32_t srslte_uci_cfg_total_ack(srslte_uci_cfg_t* uci_cfg)
{
uint32_t nof_ack = 0;
for (uint32_t i = 0; i < SRSLTE_MAX_CARRIERS; i++) {
nof_ack += uci_cfg->ack[i].nof_acks;
}
return nof_ack;
}
void srslte_uci_data_reset(srslte_uci_data_t* uci_data)
{
bzero(uci_data, sizeof(srslte_uci_data_t));
/* Set all ACKs to DTX */
memset(uci_data->value.ack.ack_value, 2, SRSLTE_UCI_MAX_ACK_BITS);
}
int srslte_uci_data_info(srslte_uci_cfg_t* uci_cfg, srslte_uci_value_t* uci_data, char* str, uint32_t str_len)
{
int n = 0;
@ -795,13 +812,13 @@ 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 (uci_cfg->ack.nof_acks) {
if (srslte_uci_cfg_total_ack(uci_cfg)) {
n = srslte_print_check(str, str_len, n, ", ack=");
for (uint32_t i = 0; i < uci_cfg->ack.nof_acks; i++) {
for (uint32_t i = 0; i < srslte_uci_cfg_total_ack(uci_cfg); i++) {
n = srslte_print_check(str, str_len, n, "%d", uci_data->ack.ack_value[i]);
}
if (uci_cfg->ack.N_bundle) {
n = srslte_print_check(str, str_len, n, ", n_bundle=%d", uci_cfg->ack.N_bundle);
if (uci_cfg->ack[0].N_bundle) {
n = srslte_print_check(str, str_len, n, ", n_bundle=%d", uci_cfg->ack[0].N_bundle);
}
}

@ -20,3 +20,5 @@
file(GLOB SOURCES "*.c")
add_library(srslte_ue OBJECT ${SOURCES})
add_subdirectory(test)

@ -0,0 +1,31 @@
#
# 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/.
#
########################################################################
# PROGRAM TO DEBUG PSS FROM USRP
########################################################################
add_executable(gen_ack_test gen_ack_test.c)
target_link_libraries(gen_ack_test srslte_phy)
add_test(gen_ack_test gen_ack_test)
add_executable(pucch_resource_test pucch_resource_test.c)
target_link_libraries(pucch_resource_test srslte_phy)
add_test(pucch_resource_test pucch_resource_test)

@ -0,0 +1,129 @@
/*
* 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 <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <time.h>
#include <unistd.h>
#include "srslte/srslte.h"
#define TESTASSERT(cond) \
{ \
if (!(cond)) { \
printf("[%s][Line %d]. Fail at %s\n", __FUNCTION__, __LINE__, #cond); \
return -1; \
} \
}
int fdd_tests(uint32_t max_cc)
{
srslte_ue_dl_t ue_dl;
srslte_dl_sf_cfg_t sf_cfg_dl;
srslte_pdsch_ack_t ack_info;
srslte_uci_data_t uci_data;
uint32_t test_cnt = 0;
ZERO_OBJECT(ue_dl);
ue_dl.cell.frame_type = SRSLTE_FDD;
// This is used for TDD only
ZERO_OBJECT(sf_cfg_dl);
for (uint32_t nof_cc = 1; nof_cc <= max_cc; nof_cc++) {
for (uint32_t nof_tb = 1; nof_tb <= SRSLTE_MAX_CODEWORDS; nof_tb++) {
for (uint32_t nof_active_cc = 1; nof_active_cc <= nof_cc; nof_active_cc++) {
for (uint32_t nof_active_tb = 1; nof_active_tb <= nof_tb; nof_active_tb++) {
ZERO_OBJECT(ack_info);
ack_info.nof_cc = nof_cc;
ack_info.transmission_mode = nof_tb == 1 ? SRSLTE_TM1 : SRSLTE_TM4;
// Check different modes?
ack_info.ack_nack_feedback_mode = SRSLTE_PUCCH_ACK_NACK_FEEDBACK_MODE_CS;
for (uint32_t cc_idx = 0; cc_idx < nof_cc; cc_idx++) {
ack_info.cc[cc_idx].M = 1; // always 1 in FDD
ack_info.cc[cc_idx].m[0].present = cc_idx <= nof_active_cc;
ack_info.cc[cc_idx].m[0].resource.n_cce = cc_idx + 1;
if (ack_info.cc[cc_idx].m[0].present) {
for (uint32_t j = 0; j < nof_tb; j++) {
ack_info.cc[cc_idx].m[0].value[j] = j < nof_active_tb ? 1 : 2;
}
}
}
for (uint32_t sr_enabled = 0; sr_enabled < 2; sr_enabled++) {
// Generate ACK/NACK bits
srslte_uci_data_reset(&uci_data);
uci_data.value.scheduling_request = (sr_enabled > 0);
printf("FDD Test %d: TM=%d, CC=%d, nof_active_tb=%d, nof_active_cc=%d, sr_request=%s\n",
test_cnt++,
ack_info.transmission_mode + 1,
nof_cc,
nof_active_tb,
nof_active_cc,
sr_enabled ? "yes" : "no");
srslte_ue_dl_gen_ack(&ue_dl, &sf_cfg_dl, &ack_info, &uci_data);
// Check output
if (nof_cc == 1) {
TESTASSERT(uci_data.cfg.ack[0].nof_acks == nof_active_tb);
} else {
if (uci_data.value.scheduling_request) {
TESTASSERT(uci_data.cfg.ack[0].nof_acks == 1);
} else {
for (int i = 0; i < nof_cc; i++) {
TESTASSERT(uci_data.cfg.ack[i].nof_acks == nof_tb);
}
}
}
uint32_t k = 0;
for (uint32_t i = 0; i < nof_cc; i++) {
TESTASSERT(uci_data.cfg.ack[i].ncce[0] == i + 1);
for (uint32_t j = 0; j < uci_data.cfg.ack[i].nof_acks; j++) {
TESTASSERT(uci_data.value.ack.ack_value[k++]);
}
}
TESTASSERT(k == srslte_uci_cfg_total_ack(&uci_data.cfg));
TESTASSERT(uci_data.value.ack.ack_value[k] == 2);
}
}
}
}
}
return 0;
}
int main(int argc, char** argv)
{
// Test only until Format1B - CS
TESTASSERT(fdd_tests(2) == 0);
printf("Ok\n");
exit(0);
}

@ -0,0 +1,165 @@
/*
* 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 <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <time.h>
#include <unistd.h>
#include "srslte/srslte.h"
#define TESTASSERT(cond) \
{ \
if (!(cond)) { \
printf("[%s][Line %d]. Fail at %s\n", __FUNCTION__, __LINE__, #cond); \
return -1; \
} \
}
int fdd_tests()
{
srslte_cell_t cell;
srslte_pucch_cfg_t pucch_cfg;
srslte_uci_cfg_t uci_cfg;
srslte_uci_value_t uci_value;
ZERO_OBJECT(cell);
cell.cp = SRSLTE_CP_NORM;
cell.frame_type = SRSLTE_FDD;
cell.nof_prb = 50;
ZERO_OBJECT(pucch_cfg);
pucch_cfg.n_pucch_sr = 3;
pucch_cfg.N_pucch_1 = 7;
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 2; j++) {
pucch_cfg.n1_pucch_an_cs[i][j] = j * 11 + i * 13;
}
}
ZERO_OBJECT(uci_value);
// Format 1
ZERO_OBJECT(uci_cfg);
uci_value.scheduling_request = true;
srslte_ue_ul_pucch_resource_selection(&cell, &pucch_cfg, &uci_cfg, &uci_value);
TESTASSERT(pucch_cfg.format == SRSLTE_PUCCH_FORMAT_1);
TESTASSERT(pucch_cfg.n_pucch == pucch_cfg.n_pucch_sr);
// Format 1A with and without SR
for (int i = 0; i < 2; i++) {
uci_value.scheduling_request = i == 0;
ZERO_OBJECT(uci_cfg);
uci_cfg.ack[0].nof_acks = 1;
uci_cfg.ack[0].ncce[0] = 13;
srslte_ue_ul_pucch_resource_selection(&cell, &pucch_cfg, &uci_cfg, &uci_value);
TESTASSERT(pucch_cfg.format == SRSLTE_PUCCH_FORMAT_1A);
if (i == 0) {
TESTASSERT(pucch_cfg.n_pucch == pucch_cfg.n_pucch_sr);
} else {
TESTASSERT(pucch_cfg.n_pucch == uci_cfg.ack[0].ncce[0] + pucch_cfg.N_pucch_1);
}
}
// Format 1B with and without SR, MIMO
pucch_cfg.ack_nack_feedback_mode = SRSLTE_PUCCH_ACK_NACK_FEEDBACK_MODE_NORMAL;
for (int i = 0; i < 2; i++) {
uci_value.scheduling_request = i == 0;
uci_value.ack.ack_value[0] = 1; // To force a different resource than n_pucch_0 in case of CS incorrectly selected
uci_value.ack.ack_value[1] = 1;
ZERO_OBJECT(uci_cfg);
uci_cfg.ack[0].nof_acks = 2;
uci_cfg.ack[0].ncce[0] = 13;
srslte_ue_ul_pucch_resource_selection(&cell, &pucch_cfg, &uci_cfg, &uci_value);
TESTASSERT(pucch_cfg.format == SRSLTE_PUCCH_FORMAT_1B);
if (i == 0) {
TESTASSERT(pucch_cfg.n_pucch == pucch_cfg.n_pucch_sr);
} else {
TESTASSERT(pucch_cfg.n_pucch == uci_cfg.ack[0].ncce[0] + pucch_cfg.N_pucch_1);
}
}
// Format 1B-CS, no SR, 2 CA SISO
uci_value.scheduling_request = 0;
ZERO_OBJECT(uci_cfg);
pucch_cfg.ack_nack_feedback_mode = SRSLTE_PUCCH_ACK_NACK_FEEDBACK_MODE_CS;
uci_cfg.ack[0].nof_acks = 1;
uci_cfg.ack[1].nof_acks = 1;
uci_cfg.ack[0].ncce[0] = 13;
uci_cfg.ack[1].ncce[0] = 4;
// Both on Pcell
// ACK/ACK, n_pucch = n_pucch_1
uci_value.ack.ack_value[0] = 1;
uci_value.ack.ack_value[1] = 1;
srslte_ue_ul_pucch_resource_selection(&cell, &pucch_cfg, &uci_cfg, &uci_value);
TESTASSERT(pucch_cfg.format == SRSLTE_PUCCH_FORMAT_1B);
TESTASSERT(pucch_cfg.n_pucch == uci_cfg.ack[1].ncce[0] + pucch_cfg.N_pucch_1);
// ACK/DTX, n_pucch = n_pucch_0
uci_value.ack.ack_value[0] = 1;
uci_value.ack.ack_value[1] = 2;
srslte_ue_ul_pucch_resource_selection(&cell, &pucch_cfg, &uci_cfg, &uci_value);
TESTASSERT(pucch_cfg.format == SRSLTE_PUCCH_FORMAT_1B);
TESTASSERT(pucch_cfg.n_pucch == uci_cfg.ack[0].ncce[0] + pucch_cfg.N_pucch_1);
// Each on its serving cell, n_pucch_1 is explicit
uci_cfg.ack[1].grant_cc_idx = 1;
uci_cfg.ack[1].tpc_for_pucch = 3;
uci_value.ack.ack_value[0] = 1;
uci_value.ack.ack_value[1] = 1;
srslte_ue_ul_pucch_resource_selection(&cell, &pucch_cfg, &uci_cfg, &uci_value);
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]);
// PCell scheduled on Scell
uci_cfg.ack[0].grant_cc_idx = 1;
uci_cfg.ack[0].tpc_for_pucch = 2;
uci_value.ack.ack_value[0] = 1;
uci_value.ack.ack_value[1] = 2;
srslte_ue_ul_pucch_resource_selection(&cell, &pucch_cfg, &uci_cfg, &uci_value);
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]);
// MIMO has the same logic of resource selection, no need to test for now
// Format 1B-CS with SR
ZERO_OBJECT(uci_cfg);
uci_value.scheduling_request = true;
uci_cfg.ack[0].nof_acks = 1;
uci_cfg.ack[1].nof_acks = 1;
srslte_ue_ul_pucch_resource_selection(&cell, &pucch_cfg, &uci_cfg, &uci_value);
TESTASSERT(pucch_cfg.format == SRSLTE_PUCCH_FORMAT_1B);
return 0;
}
int main(int argc, char** argv)
{
// Test only until Format1B - CS
TESTASSERT(fdd_tests() == 0);
printf("Ok\n");
exit(0);
}

@ -927,157 +927,136 @@ void srslte_ue_dl_gen_cqi_aperiodic(srslte_ue_dl_t* q,
}
}
// Table 7.3-1
static const uint32_t multiple_acknack[10][2] = {
{0, 0}, {1, 1}, {1, 0}, {0, 1}, {1, 1}, {1, 0}, {0, 1}, {1, 1}, {1, 0}, {0, 1}};
/* UE downlink procedure for reporting ACK/NACK, Section 7.3 36.213
/* UE downlink procedure for reporting HARQ-ACK bits in FDD, Section 7.3 36.213
*/
void srslte_ue_dl_gen_ack(srslte_ue_dl_t* q,
srslte_dl_sf_cfg_t* sf,
srslte_pdsch_ack_t* ack_info,
srslte_uci_data_t* uci_data)
static void gen_ack_fdd(srslte_pdsch_ack_t* ack_info, srslte_uci_data_t* uci_data)
{
uint32_t V_dai_dl = 0;
bool is_tdd_mode16 = sf->tdd_config.sf_config >= 1 && sf->tdd_config.sf_config <= 6;
uint32_t nof_tb = 1;
if (ack_info->transmission_mode > SRSLTE_TM2) {
nof_tb = SRSLTE_MAX_CODEWORDS;
}
// Implementation 3GPP 36.213 V10.13.0. Section 7.3. 2nd Clause.
if (q->cell.frame_type == SRSLTE_FDD) {
if (ack_info->ack_nack_feedback_mode == SRSLTE_PUCCH_ACK_NACK_FEEDBACK_MODE_CS &&
uci_data->value.scheduling_request && !ack_info->is_pusch_available) {
for (uint32_t cc_idx = 0; cc_idx < ack_info->nof_cc; cc_idx++) {
uint32_t dtx_count = 0;
bool bundle_spatial = true;
// Second clause: When 2 CC are configured with PUCCH CS mode and SR is also requested, bundle spatial codewords
if (ack_info->nof_cc == 2 && uci_data->value.scheduling_request == true &&
ack_info->ack_nack_feedback_mode == SRSLTE_PUCCH_ACK_NACK_FEEDBACK_MODE_CS) {
for (uint32_t cc_idx = 0; cc_idx < ack_info->nof_cc; cc_idx++) {
if (ack_info->cc[cc_idx].m[0].present) {
uci_data->value.ack.ack_value[cc_idx] = 1;
for (uint32_t tb = 0; tb < nof_tb; tb++) {
if (ack_info->cc[cc_idx].m[0].present && ack_info->cc[cc_idx].m[0].value[tb] != 2) {
if (ack_info->cc[cc_idx].m[0].value[tb] != 1) {
bundle_spatial = false;
}
if (cc_idx != 0) {
uci_data->cfg.ack.has_scell_ack = true;
}
} else {
dtx_count++;
if (ack_info->cc[cc_idx].m[0].value[tb] != 2) {
uci_data->value.ack.ack_value[cc_idx] &= ack_info->cc[cc_idx].m[0].value[tb];
}
}
uci_data->value.ack.ack_value[cc_idx] = (uint8_t)((bundle_spatial && dtx_count != nof_tb) ? 1 : 0);
} else {
uci_data->value.ack.ack_value[cc_idx] = 2;
}
uci_data->cfg.ack.nof_acks = ack_info->nof_cc;
uci_data->cfg.ack.tdd_ack_M = 1;
return;
} else if ((ack_info->ack_nack_feedback_mode == SRSLTE_PUCCH_ACK_NACK_FEEDBACK_MODE_CS &&
ack_info->is_pusch_available) ||
ack_info->ack_nack_feedback_mode == SRSLTE_PUCCH_ACK_NACK_FEEDBACK_MODE_PUCCH3) {
uint32_t tb_count = 0;
uint32_t n = 0;
for (uint32_t cc_idx = 0; cc_idx < ack_info->nof_cc; cc_idx++) {
for (uint32_t tb = 0; tb < nof_tb; tb++, n++) {
uci_data->value.ack.ack_value[n] = ack_info->cc[cc_idx].m[0].value[tb];
if (ack_info->cc[cc_idx].m[0].present && ack_info->cc[cc_idx].m[0].value[tb] != 2) {
tb_count++;
}
}
for (uint32_t i = 0; i < 2; i++) {
uci_data->cfg.ack[i].nof_acks = 1;
}
} else {
// By default, in FDD we just pass through all HARQ-ACK bits
uint32_t tb_count = 0;
uint32_t n = 0;
for (uint32_t cc_idx = 0; cc_idx < ack_info->nof_cc; cc_idx++) {
for (uint32_t tb = 0; tb < nof_tb; tb++, n++) {
uci_data->value.ack.ack_value[n] = ack_info->cc[cc_idx].m[0].value[tb];
if (ack_info->cc[cc_idx].m[0].present && ack_info->cc[cc_idx].m[0].value[tb] != 2) {
tb_count++;
}
}
uci_data->cfg.ack.nof_acks = (tb_count != 0) ? n : 0;
return;
}
}
// Calculate U_dai and count number of ACK for this subframe by spatial bundling across codewords
uint32_t nof_pos_acks = 0;
uint32_t nof_total_acks = 0;
uint32_t U_dai = 0;
for (uint32_t cc_idx = 0; cc_idx < ack_info->nof_cc; cc_idx++) {
for (uint32_t i = 0; i < ack_info->cc[cc_idx].M; i++) {
bool bundle_spatial = false;
bool first_bundle = true;
for (uint32_t j = 0; j < nof_tb; j++) {
if (ack_info->cc[cc_idx].m[i].present) {
if (first_bundle) {
bundle_spatial = ack_info->cc[cc_idx].m[i].value[j] == 1;
U_dai++;
first_bundle = false;
} else {
bundle_spatial &= ack_info->cc[cc_idx].m[i].value[j] == 1;
}
if (bundle_spatial) {
nof_pos_acks++;
}
if (ack_info->cc[cc_idx].m[i].value[j] != 2) {
nof_total_acks++;
}
}
if (ack_info->nof_cc == 1) {
// If only 1 configured cell, report 1 or 2 bits depending on number of detected TB
uci_data->cfg.ack[0].nof_acks = tb_count;
} else {
// For 2 or more configured cells, report nof_tb per carrier except if there are no HARQ-ACK bits to report, in
// which case we set to 0
for (int i = 0; i < 2; i++) {
uci_data->cfg.ack[i].nof_acks = (tb_count != 0) ? nof_tb : 0;
}
}
}
for (uint32_t cc_idx = 0; cc_idx < ack_info->nof_cc; cc_idx++) {
// n_cce values are just copied
for (uint32_t i = 0; i < ack_info->nof_cc; i++) {
uci_data->cfg.ack[i].ncce[0] = ack_info->cc[i].m[0].resource.n_cce;
uci_data->cfg.ack[i].grant_cc_idx = ack_info->cc[i].m[0].resource.grant_cc_idx;
uci_data->cfg.ack[i].tpc_for_pucch = ack_info->cc[i].m[0].resource.tpc_for_pucch;
}
}
// Table 7.3-1
static const uint32_t multiple_acknack[10][2] = {
{0, 0}, {1, 1}, {1, 0}, {0, 1}, {1, 1}, {1, 0}, {0, 1}, {1, 1}, {1, 0}, {0, 1}};
/* UE downlink procedure for reporting HARQ-ACK bits in TDD, Section 7.3 36.213
*/
static void gen_ack_tdd(bool is_tdd_mode16, srslte_pdsch_ack_t* ack_info, srslte_uci_data_t* uci_data)
{
uint32_t V_dai_dl = 0;
uint32_t nof_tb = 1;
if (ack_info->transmission_mode > SRSLTE_TM2) {
nof_tb = SRSLTE_MAX_CODEWORDS;
}
if (ack_info->nof_cc > 1) {
fprintf(stderr, "Error generating HARQ-ACK bits. Only 1 CC is supported in TDD\n");
}
// Arrange bits for FDD or TDD Bundling or Multiplexing
srslte_pdsch_ack_cc_t* ack_value = &ack_info->cc[cc_idx];
// Arrange bits for FDD or TDD Bundling or Multiplexing.
srslte_pdsch_ack_cc_t* ack_value = &ack_info->cc[0];
srslte_uci_cfg_ack_t* ack_cfg = &uci_data->cfg.ack[0];
uint32_t min_k = 10;
uint32_t min_k = 10;
if (ack_info->cc[cc_idx].M > 0) {
if (ack_value->M > 0) {
uci_data->cfg.ack.tdd_ack_M = ack_value->M;
ack_cfg->tdd_ack_M = ack_value->M;
// ACK/NACK bundling or multiplexing and M=1
if (!ack_info->tdd_ack_multiplex || ack_value->M == 1) {
for (uint32_t tb = 0; tb < nof_tb; tb++) {
bool first_in_bundle = true;
for (uint32_t k = 0; k < ack_value->M; k++) {
if (ack_value->m[k].present && ack_value->m[k].value[tb] != 2) {
uci_data->cfg.ack.has_scell_ack |= (cc_idx != 0); // If a grant is detected in an scell
// Bundle on time domain
if (first_in_bundle) {
uci_data->value.ack.ack_value[nof_tb * cc_idx + tb] = ack_value->m[k].value[tb];
first_in_bundle = false;
} else {
uci_data->value.ack.ack_value[nof_tb * cc_idx + tb] = (uint8_t)(
((uci_data->value.ack.ack_value[nof_tb * cc_idx + tb] == 1) & (ack_value->m[k].value[tb])) ? 1 : 0);
}
// V_dai_dl is for the one with lowest k value
if (ack_value->m[k].k < min_k || q->cell.frame_type == SRSLTE_FDD) {
min_k = ack_value->m[k].k;
V_dai_dl = ack_value->m[k].resource.v_dai_dl + 1; // Table 7.3-X
if (cc_idx == 0) {
uci_data->cfg.ack.ncce[0] = ack_info->cc[cc_idx].m[k].resource.n_cce;
uci_data->cfg.ack.tdd_ack_m = k;
}
}
// ACK/NACK bundling or multiplexing and M=1
if (!ack_info->tdd_ack_multiplex || ack_value->M == 1) {
for (uint32_t tb = 0; tb < nof_tb; tb++) {
bool first_in_bundle = true;
for (uint32_t k = 0; k < ack_value->M; k++) {
if (ack_value->m[k].present && ack_value->m[k].value[tb] != 2) {
// Bundle on time domain
if (first_in_bundle) {
uci_data->value.ack.ack_value[tb] = ack_value->m[k].value[tb];
first_in_bundle = false;
} else {
uci_data->value.ack.ack_value[tb] =
(uint8_t)(((uci_data->value.ack.ack_value[tb] == 1) & (ack_value->m[k].value[tb])) ? 1 : 0);
}
// V_dai_dl is for the one with lowest k value
if (ack_value->m[k].k < min_k) {
min_k = ack_value->m[k].k;
V_dai_dl = ack_value->m[k].resource.v_dai_dl + 1; // Table 7.3-X
ack_cfg->ncce[0] = ack_value->m[k].resource.n_cce;
ack_cfg->tdd_ack_m = k;
}
}
}
// ACK/NACK multiplexing and M > 1
} else {
for (uint32_t k = 0; k < ack_value->M; k++) {
// Bundle spatial domain
bool spatial_ack = true;
for (uint32_t i = 0; i < nof_tb; i++) {
if (ack_value->m[k].value[i] != 2) {
spatial_ack &= (ack_value->m[k].value[i] == 1);
}
}
// ACK/NACK multiplexing and M > 1
} else {
for (uint32_t k = 0; k < ack_value->M; k++) {
// Bundle spatial domain
bool spatial_ack = true;
for (uint32_t i = 0; i < nof_tb; i++) {
if (ack_value->m[k].value[i] != 2) {
spatial_ack &= (ack_value->m[k].value[i] == 1);
}
// In multiplexing for pusch, sort them accordingly
if (ack_value->m[k].present) {
uint32_t p = k;
if (q->cell.frame_type == SRSLTE_TDD && ack_info->is_pusch_available && ack_info->is_grant_available) {
p = ack_value->m[k].resource.v_dai_dl;
}
uci_data->value.ack.ack_value[ack_value->M * cc_idx + p] = (uint8_t)(spatial_ack ? 1 : 0);
uci_data->cfg.ack.ncce[ack_value->M * cc_idx + p] = ack_info->cc[cc_idx].m[k].resource.n_cce;
}
// In multiplexing for pusch, sort them accordingly
if (ack_value->m[k].present) {
uint32_t p = k;
if (ack_info->is_pusch_available && ack_info->is_grant_available) {
p = ack_value->m[k].resource.v_dai_dl;
}
uci_data->value.ack.ack_value[p] = (uint8_t)(spatial_ack ? 1 : 0);
ack_cfg->ncce[p] = ack_value->m[k].resource.n_cce;
}
}
}
@ -1085,17 +1064,43 @@ void srslte_ue_dl_gen_ack(srslte_ue_dl_t* q,
bool missing_ack = false;
// Calculate U_dai and count number of ACK for this subframe by spatial bundling across codewords
uint32_t nof_pos_acks = 0;
uint32_t U_dai = 0;
uint32_t nof_total_acks = 0;
for (uint32_t i = 0; i < ack_value->M; i++) {
bool bundle_spatial = false;
bool first_bundle = true;
for (uint32_t j = 0; j < nof_tb; j++) {
if (ack_value->m[i].present) {
if (first_bundle) {
bundle_spatial = ack_value->m[i].value[j] == 1;
U_dai++;
first_bundle = false;
} else {
bundle_spatial &= ack_value->m[i].value[j] == 1;
}
if (bundle_spatial) {
nof_pos_acks++;
}
if (ack_value->m[i].value[j] != 2) {
nof_total_acks++;
}
}
}
}
// For TDD PUSCH
if (q->cell.frame_type == SRSLTE_TDD && is_tdd_mode16) {
if (is_tdd_mode16) {
ack_info->V_dai_ul++; // Table 7.3-x
uci_data->cfg.ack.tdd_is_multiplex = ack_info->tdd_ack_multiplex;
ack_cfg->tdd_is_multiplex = ack_info->tdd_ack_multiplex;
// Bundling or multiplexing and M=1
if (!ack_info->tdd_ack_multiplex || ack_info->cc[0].M == 1) {
// 1 or 2 ACK/NACK bits
uci_data->cfg.ack.nof_acks = nof_tb;
ack_cfg->nof_acks = nof_tb;
// Determine if there is any missing ACK/NACK in the set and N_bundle value
@ -1103,7 +1108,7 @@ void srslte_ue_dl_gen_ack(srslte_ue_dl_t* q,
if (!ack_info->is_pusch_available) {
if ((V_dai_dl != (U_dai - 1) % 4 + 1 && U_dai > 0) || U_dai == 0) {
// In ul procedure 10.2, skip ACK/NACK in bundling PUCCH
uci_data->cfg.ack.nof_acks = 0;
ack_cfg->nof_acks = 0;
if (U_dai > 0) {
missing_ack = true;
}
@ -1112,30 +1117,30 @@ void srslte_ue_dl_gen_ack(srslte_ue_dl_t* q,
} else if (ack_info->is_grant_available) {
if (ack_info->V_dai_ul != (U_dai - 1) % 4 + 1) {
bzero(uci_data->value.ack.ack_value, nof_tb);
uci_data->cfg.ack.N_bundle = ack_info->V_dai_ul + 2;
ack_cfg->N_bundle = ack_info->V_dai_ul + 2;
} else {
uci_data->cfg.ack.N_bundle = ack_info->V_dai_ul;
ack_cfg->N_bundle = ack_info->V_dai_ul;
}
// do not transmit case
if (ack_info->V_dai_ul == 4 && U_dai == 0) {
uci_data->cfg.ack.nof_acks = 0;
ack_cfg->nof_acks = 0;
}
// Transmitting on PUSCH not based on grant
} else {
if (V_dai_dl != (U_dai - 1) % 4 + 1 && U_dai > 0) {
bzero(uci_data->value.ack.ack_value, nof_tb);
}
uci_data->cfg.ack.N_bundle = U_dai;
ack_cfg->N_bundle = U_dai;
// do not transmit case
if (U_dai == 0) {
uci_data->cfg.ack.nof_acks = 0;
ack_cfg->nof_acks = 0;
}
}
// In PUSCH and MIMO, nack 2nd codeword if not received, in PUCCH do not transmit
if (nof_tb == 2 && uci_data->value.ack.ack_value[1] == 2 && uci_data->cfg.ack.nof_acks == 2) {
if (nof_tb == 2 && uci_data->value.ack.ack_value[1] == 2 && ack_cfg->nof_acks == 2) {
if (!ack_info->is_pusch_available) {
uci_data->cfg.ack.nof_acks = 1;
ack_cfg->nof_acks = 1;
} else {
uci_data->value.ack.ack_value[1] = 0;
}
@ -1147,15 +1152,15 @@ void srslte_ue_dl_gen_ack(srslte_ue_dl_t* q,
if (ack_info->is_grant_available) {
// Do not transmit if...
if (!(ack_info->V_dai_ul == 4 && U_dai == 0)) {
uci_data->cfg.ack.nof_acks = ack_info->V_dai_ul;
ack_cfg->nof_acks = ack_info->V_dai_ul;
}
} else {
uci_data->cfg.ack.nof_acks = ack_info->cc[0].M;
ack_cfg->nof_acks = ack_info->cc[0].M;
}
// Set DTX bits to NACKs
uint32_t count_acks = 0;
for (uint32_t i = 0; i < uci_data->cfg.ack.nof_acks; i++) {
for (uint32_t i = 0; i < ack_cfg->nof_acks; i++) {
if (uci_data->value.ack.ack_value[i] == 2) {
uci_data->value.ack.ack_value[i] = 0;
} else {
@ -1163,26 +1168,19 @@ void srslte_ue_dl_gen_ack(srslte_ue_dl_t* q,
}
}
if (!count_acks) {
uci_data->cfg.ack.nof_acks = 0;
ack_cfg->nof_acks = 0;
}
} else {
uci_data->cfg.ack.nof_acks = ack_info->cc[0].M;
ack_cfg->nof_acks = ack_info->cc[0].M;
}
}
} else {
if (q->cell.frame_type == SRSLTE_TDD) { // And subframe config 0
uci_data->cfg.ack.N_bundle = 1;
}
uci_data->cfg.ack.nof_acks = nof_total_acks;
}
// If no pending ACK/NACK
if (uci_data->cfg.ack.nof_acks == 0) {
return;
ack_cfg->N_bundle = 1;
ack_cfg->nof_acks = nof_total_acks;
}
// Multiple ACK/NACK responses with SR and CQI
if (q->cell.frame_type == SRSLTE_TDD && uci_data->cfg.ack.nof_acks && !ack_info->is_pusch_available &&
if (ack_cfg->nof_acks && !ack_info->is_pusch_available &&
(uci_data->value.scheduling_request ||
((uci_data->cfg.cqi.data_enable || uci_data->cfg.cqi.ri_len) && ack_info->simul_cqi_ack))) {
if (missing_ack) {
@ -1193,7 +1191,23 @@ void srslte_ue_dl_gen_ack(srslte_ue_dl_t* q,
uci_data->value.ack.ack_value[0] = multiple_acknack[nof_pos_acks][0];
uci_data->value.ack.ack_value[1] = multiple_acknack[nof_pos_acks][1];
}
uci_data->cfg.ack.nof_acks = 2;
ack_cfg->nof_acks = 2;
}
}
/* UE downlink procedure for reporting ACK/NACK, Section 7.3 36.213
*/
void srslte_ue_dl_gen_ack(srslte_ue_dl_t* q,
srslte_dl_sf_cfg_t* sf,
srslte_pdsch_ack_t* ack_info,
srslte_uci_data_t* uci_data)
{
if (q->cell.frame_type == SRSLTE_FDD) {
gen_ack_fdd(ack_info, uci_data);
} else {
bool is_tdd_mode16 = sf->tdd_config.sf_config >= 1 && sf->tdd_config.sf_config <= 6;
gen_ack_tdd(is_tdd_mode16, ack_info, uci_data);
}
}

@ -385,7 +385,7 @@ float srslte_ue_ul_pucch_power(srslte_ue_ul_t* q, srslte_ue_ul_cfg_t* cfg, srslt
float h;
int n_cqi = srslte_cqi_size(&uci_cfg->cqi);
int n_harq = uci_cfg->ack.nof_acks;
int n_harq = srslte_uci_cfg_total_ack(uci_cfg);
if (format <= SRSLTE_PUCCH_FORMAT_1B) {
h = 0;
@ -487,15 +487,16 @@ get_format(srslte_pucch_cfg_t* cfg, srslte_uci_cfg_t* uci_cfg, srslte_uci_value_
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 && uci_cfg->ack.has_scell_ack) {
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 (uci_cfg->ack.nof_acks == 1) {
else if (srslte_uci_cfg_total_ack(uci_cfg) == 1) {
format = SRSLTE_PUCCH_FORMAT_1A;
}
// 2-bit ACK + optional SR
else if (uci_cfg->ack.nof_acks >= 2) {
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
@ -503,52 +504,79 @@ get_format(srslte_pucch_cfg_t* cfg, srslte_uci_cfg_t* uci_cfg, srslte_uci_value_
if (uci_value->scheduling_request) {
format = SRSLTE_PUCCH_FORMAT_1;
}
} else if (uci_cfg->is_scheduling_request_tti) {
format = SRSLTE_PUCCH_FORMAT_1;
} else {
if (uci_cfg->is_scheduling_request_tti) {
format = SRSLTE_PUCCH_FORMAT_1;
}
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 (uci_cfg->ack.nof_acks == 0) {
if (srslte_uci_cfg_total_ack(uci_cfg) == 0) {
format = SRSLTE_PUCCH_FORMAT_2;
}
// CQI + 1-bit ACK
else if (uci_cfg->ack.nof_acks == 1 && SRSLTE_CP_ISNORM(cp)) {
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 (uci_cfg->ack.nof_acks == 2) {
else if (srslte_uci_cfg_total_ack(uci_cfg) == 2) {
format = SRSLTE_PUCCH_FORMAT_2B;
}
// CQI + 2-bit ACK + cyclic prefix
else if (uci_cfg->ack.nof_acks == 1 && SRSLTE_CP_ISEXT(cp)) {
else if (srslte_uci_cfg_total_ack(uci_cfg) == 1 && SRSLTE_CP_ISEXT(cp)) {
format = SRSLTE_PUCCH_FORMAT_2B;
}
}
return format;
}
// n_pucch and b0b1 selection for CA, tables 10.1.2.2.1-3 to -5
static uint32_t
get_npucch_cs(srslte_pucch_cfg_t* cfg, uint32_t n_cce, srslte_uci_cfg_t* uci_cfg, srslte_uci_value_t* uci_value)
// 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 = 0;
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");
}
}
}
}
switch (uci_cfg->ack.nof_acks) {
// 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)) {
case 1:
n_pucch = n_cce + cfg->N_pucch_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_cce + cfg->N_pucch_1;
n_pucch = n_pucch_i[0];
} else {
/* n_pucch1_1 */
n_pucch = cfg->n1_pucch_an_cs[cfg->tpc_for_pucch % 4][0];
n_pucch = n_pucch_i[1];
}
if (b[0] == 1) {
b[0] = 1;
@ -561,13 +589,13 @@ get_npucch_cs(srslte_pucch_cfg_t* cfg, uint32_t n_cce, srslte_uci_cfg_t* uci_cfg
case 3:
if (b[0] != 1 && b[1] != 1) {
/* n_pucch1_2 */
n_pucch = cfg->n1_pucch_an_cs[cfg->tpc_for_pucch % 4][0];
n_pucch = n_pucch_i[2];
} else if (b[2] == 1) {
/* n_pucch1_1 */
n_pucch = cfg->n1_pucch_an_cs[cfg->tpc_for_pucch % 4][0];
n_pucch = n_pucch_i[1];
} else {
/* n_pucch1_0 */
n_pucch = n_cce + cfg->N_pucch_1;
n_pucch = n_pucch_i[0];
}
if (b[0] != 1 && b[1] != 1 && b[2] != 1) {
b[0] = 0;
@ -586,16 +614,16 @@ get_npucch_cs(srslte_pucch_cfg_t* cfg, uint32_t n_cce, srslte_uci_cfg_t* uci_cfg
case 4:
if (b[2] != 1 && b[3] != 1) {
/* n_pucch1_0 */
n_pucch = n_cce + cfg->N_pucch_1;
n_pucch = n_pucch_i[0];
} else if (b[1] == 1 && b[2] == 1) {
/* n_pucch1_1 */
n_pucch = n_cce + cfg->N_pucch_1 + 1;
n_pucch = n_pucch_i[1];
} else if (b[0] == 1) {
/* n_pucch1_2 */
n_pucch = cfg->n1_pucch_an_cs[cfg->tpc_for_pucch % 4][0];
n_pucch = n_pucch_i[2];
} else {
/* n_pucch1_3 */
n_pucch = cfg->n1_pucch_an_cs[cfg->tpc_for_pucch % 4][1];
n_pucch = n_pucch_i[3];
}
if (b[2] != 1 && b[3] != 1) {
/* n_pucch1_0 */
@ -651,7 +679,7 @@ static void set_b01(uint8_t* b, uint8_t x)
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.nof_acks) {
switch (uci_cfg->ack[0].nof_acks) {
case 1:
return n_pucch[0];
case 2:
@ -673,7 +701,7 @@ static uint32_t get_npucch_tdd(uint32_t n_pucch[4], srslte_uci_cfg_t* uci_cfg, s
}
break;
case 3:
uci_cfg->ack.nof_acks = 2;
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];
@ -707,7 +735,7 @@ static uint32_t get_npucch_tdd(uint32_t n_pucch[4], srslte_uci_cfg_t* uci_cfg, s
}
break;
case 4:
uci_cfg->ack.nof_acks = 2;
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];
@ -800,49 +828,55 @@ get_npucch(srslte_pucch_cfg_t* cfg, srslte_uci_cfg_t* uci_cfg, srslte_uci_value_
{
uint32_t n_pucch_res = 0;
if (uci_cfg->is_scheduling_request_tti) {
return cfg->n_pucch_sr;
}
if (uci_value) {
if (cfg->ack_nack_feedback_mode == SRSLTE_PUCCH_ACK_NACK_FEEDBACK_MODE_CS && cfg->format < SRSLTE_PUCCH_FORMAT_2 &&
!uci_value->scheduling_request && uci_cfg->ack.nof_acks > 0) {
n_pucch_res = get_npucch_cs(cfg, uci_cfg->ack.ncce[0], uci_cfg, uci_value);
return n_pucch_res;
} else if (cfg->ack_nack_feedback_mode == SRSLTE_PUCCH_ACK_NACK_FEEDBACK_MODE_PUCCH3 &&
cfg->format == SRSLTE_PUCCH_FORMAT_3) {
n_pucch_res = cfg->n3_pucch_an_list[cfg->tpc_for_pucch % SRSLTE_PUCCH_SIZE_AN_CS];
return n_pucch_res;
} else if (uci_value->scheduling_request) {
// If SR signal or SR opportunity, use n_pucch_sr for format 1, 1a, 1b
n_pucch_res = cfg->n_pucch_sr;
return n_pucch_res;
if (uci_value->scheduling_request) {
return cfg->n_pucch_sr;
}
} else if (uci_cfg->is_scheduling_request_tti) {
n_pucch_res = cfg->n_pucch_sr;
return n_pucch_res;
}
if (!uci_value || !cell || !uci_cfg) {
fprintf(stderr, "get_npucch(): Invalid parameters\n");
return 0;
}
if (cfg->format < SRSLTE_PUCCH_FORMAT_2) {
if (cfg->sps_enabled) {
n_pucch_res = cfg->n_pucch_1[cfg->tpc_for_pucch % 4];
n_pucch_res = cfg->n_pucch_1[uci_cfg->ack[0].tpc_for_pucch % 4];
} else {
if (cell->frame_type == SRSLTE_FDD) {
n_pucch_res = uci_cfg->ack.ncce[0] + cfg->N_pucch_1;
switch (cfg->ack_nack_feedback_mode) {
case SRSLTE_PUCCH_ACK_NACK_FEEDBACK_MODE_PUCCH3:
n_pucch_res = cfg->n3_pucch_an_list[uci_cfg->ack[0].tpc_for_pucch % SRSLTE_PUCCH_SIZE_AN_CS];
break;
case SRSLTE_PUCCH_ACK_NACK_FEEDBACK_MODE_CS:
n_pucch_res = get_npucch_cs(cfg, uci_cfg, uci_value);
break;
default:
n_pucch_res = uci_cfg->ack[0].ncce[0] + cfg->N_pucch_1;
break;
}
} else {
if (!uci_cfg->ack.tdd_is_multiplex || uci_cfg->ack.tdd_ack_M == 1) {
n_pucch_res = n_pucch_i_tdd(
uci_cfg->ack.ncce[0], cfg->N_pucch_1, cell->nof_prb, uci_cfg->ack.tdd_ack_M, uci_cfg->ack.tdd_ack_m);
// 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.tdd_ack_M <= 4) {
if (uci_cfg->ack[0].tdd_ack_M <= 4) {
uint32_t n_pucch[4] = {};
for (uint32_t i = 0; i < uci_cfg->ack.tdd_ack_M; i++) {
for (uint32_t i = 0; i < uci_cfg->ack[0].tdd_ack_M; i++) {
n_pucch[i] =
n_pucch_i_tdd(uci_cfg->ack.ncce[i], cfg->N_pucch_1, cell->nof_prb, uci_cfg->ack.tdd_ack_M, i);
}
if (uci_value) {
n_pucch_res = get_npucch_tdd(n_pucch, uci_cfg, uci_value);
} else {
ERROR("Error Not Implemented: TDD requires uci_value\n");
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.tdd_ack_M);
ERROR("Invalid M=%d in PUCCH TDD multiplexing\n", uci_cfg->ack[0].tdd_ack_M);
}
}
}
@ -861,7 +895,7 @@ void srslte_ue_ul_pucch_resource_selection(srslte_cell_t* cell,
srslte_uci_value_t* uci_value)
{
// Drop CQI if there is collision with ACK
if ((!cfg->simul_cqi_ack || uci_cfg->ack.has_scell_ack) && uci_cfg->ack.nof_acks > 0 && uci_cfg->cqi.data_enable) {
if (!cfg->simul_cqi_ack && srslte_uci_cfg_total_ack(uci_cfg) > 0 && uci_cfg->cqi.data_enable) {
uci_cfg->cqi.data_enable = false;
}
@ -870,16 +904,17 @@ void srslte_ue_ul_pucch_resource_selection(srslte_cell_t* cell,
if (uci_value) {
if (cfg->format == SRSLTE_PUCCH_FORMAT_3) {
fprintf(stderr, "Warning: PUCCH3 under development\n");
uint8_t* b = uci_value->ack.ack_value;
uint8_t temp[SRSLTE_UCI_MAX_ACK_BITS + 1];
uint32_t k = uci_cfg->ack.nof_acks;
for (; k < uci_cfg->ack.nof_acks; k++) {
uint32_t k = uci_cfg->ack[0].nof_acks;
for (; k < uci_cfg->ack[0].nof_acks; k++) {
temp[k] = (uint8_t)((b[k] == 1) ? 1 : 0);
}
memcpy(temp, uci_value->ack.ack_value, uci_cfg->ack.nof_acks);
memcpy(temp, uci_value->ack.ack_value, uci_cfg->ack[0].nof_acks);
if (uci_cfg->is_scheduling_request_tti) {
temp[uci_cfg->ack.nof_acks] = (uint8_t)(uci_value->scheduling_request ? 1 : 0);
temp[uci_cfg->ack[0].nof_acks] = (uint8_t)(uci_value->scheduling_request ? 1 : 0);
k++;
}
srslte_uci_encode_ack_sr_pucch3(temp, k, b);
@ -993,7 +1028,7 @@ bool srslte_ue_ul_gen_sr(srslte_ue_ul_cfg_t* cfg, srslte_ul_sf_cfg_t* sf, srslte
return false;
}
#define uci_pending(cfg) (cfg.ack.nof_acks > 0 || cfg.cqi.data_enable || cfg.cqi.ri_len > 0)
#define uci_pending(cfg) (srslte_uci_cfg_total_ack(&cfg) > 0 || cfg.cqi.data_enable || cfg.cqi.ri_len > 0)
int srslte_ue_ul_encode(srslte_ue_ul_t* q, srslte_ul_sf_cfg_t* sf, srslte_ue_ul_cfg_t* cfg, srslte_pusch_data_t* data)
{
@ -1002,7 +1037,7 @@ int srslte_ue_ul_encode(srslte_ue_ul_t* q, srslte_ul_sf_cfg_t* sf, srslte_ue_ul_
/* Convert DTX to NACK in channel-selection mode (Release 10 only)*/
if (cfg->ul_cfg.pucch.ack_nack_feedback_mode != SRSLTE_PUCCH_ACK_NACK_FEEDBACK_MODE_NORMAL) {
uint32_t dtx_count = 0;
for (uint32_t a = 0; a < cfg->ul_cfg.pusch.uci_cfg.ack.nof_acks; a++) {
for (uint32_t a = 0; a < srslte_uci_cfg_total_ack(&cfg->ul_cfg.pusch.uci_cfg); a++) {
if (data->uci.ack.ack_value[a] == 2) {
data->uci.ack.ack_value[a] = 0;
dtx_count++;
@ -1010,8 +1045,10 @@ int srslte_ue_ul_encode(srslte_ue_ul_t* q, srslte_ul_sf_cfg_t* sf, srslte_ue_ul_
}
/* If all bits are DTX, do not transmit HARQ */
if (dtx_count == cfg->ul_cfg.pusch.uci_cfg.ack.nof_acks) {
cfg->ul_cfg.pusch.uci_cfg.ack.nof_acks = 0;
if (dtx_count == srslte_uci_cfg_total_ack(&cfg->ul_cfg.pusch.uci_cfg)) {
for (int i = 0; i < 2; i++) { // Format 1b-CS only supports 2 CC
cfg->ul_cfg.pusch.uci_cfg.ack[i].nof_acks = 0;
}
}
}

@ -488,10 +488,10 @@ bool sf_worker::fill_uci_cfg(uint16_t rnti, bool aperiodic_cqi_request, srslte_u
// Get pending ACKs with an associated PUSCH transmission
// TODO: Use ue_dl procedures to compute uci_ack_cfg for TDD and CA
for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) {
uci_cfg->ack.pending_tb[tb] = phy->ue_db_is_ack_pending(tti_rx, rnti, tb, &uci_cfg->ack.ncce[0]);
Debug("ACK: is pending tti=%d, mod=%d, value=%d\n", tti_rx, TTIMOD(tti_rx), uci_cfg->ack.pending_tb[tb]);
if (uci_cfg->ack.pending_tb[tb]) {
uci_cfg->ack.nof_acks++;
uci_cfg->ack[0].pending_tb[tb] = phy->ue_db_is_ack_pending(tti_rx, rnti, tb, &uci_cfg->ack[0].ncce[0]);
Debug("ACK: is pending tti=%d, mod=%d, value=%d\n", tti_rx, TTIMOD(tti_rx), uci_cfg->ack[0].pending_tb[tb]);
if (uci_cfg->ack[0].pending_tb[tb]) {
uci_cfg->ack[0].nof_acks++;
uci_required = true;
}
}
@ -518,7 +518,7 @@ void sf_worker::send_uci_data(uint16_t rnti, srslte_uci_cfg_t* uci_cfg, srslte_u
/* If only one ACK is required, it can be for TB0 or TB1 */
uint32_t ack_idx = 0;
for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) {
if (uci_cfg->ack.pending_tb[tb]) {
if (uci_cfg->ack[0].pending_tb[tb]) {
bool ack = uci_value->ack.ack_value[ack_idx];
bool valid = uci_value->ack.valid;
phy->stack->ack_info(tti_rx, rnti, tb, ack && valid);

@ -278,8 +278,8 @@ bool sched_ue::get_pucch_sched(uint32_t current_tti, uint32_t prb_idx[2])
// Pending ACKs
for (int i = 0; i < SCHED_MAX_HARQ_PROC; i++) {
if (TTI_TX(dl_harq[i].get_tti()) == current_tti) {
cfg.pucch_cfg.uci_cfg.ack.ncce[0] = dl_harq[i].get_n_cce();
cfg.pucch_cfg.uci_cfg.ack.nof_acks = 1;
cfg.pucch_cfg.uci_cfg.ack[0].ncce[0] = dl_harq[i].get_n_cce();
cfg.pucch_cfg.uci_cfg.ack[0].nof_acks = 1;
ret = true;
}
}
@ -299,7 +299,7 @@ bool sched_ue::get_pucch_sched(uint32_t current_tti, uint32_t prb_idx[2])
prb_idx[0],
prb_idx[1],
cfg.pucch_cfg.n_pucch,
cfg.pucch_cfg.uci_cfg.ack.ncce[0],
cfg.pucch_cfg.uci_cfg.ack[0].ncce[0],
cfg.pucch_cfg.uci_cfg.is_scheduling_request_tti);
}
}
@ -896,9 +896,8 @@ uint32_t sched_ue::get_required_prb_dl(uint32_t req_bytes, uint32_t nof_ctrl_sym
uint32_t sched_ue::get_required_prb_ul(uint32_t req_bytes)
{
int mcs = 0;
int tbs = 0;
uint32_t nbytes = 0;
int mcs = 0;
uint32_t nbytes = 0;
uint32_t N_srs = 0;
uint32_t n = 0;

@ -100,8 +100,8 @@ public:
void set_rar_grant(uint8_t grant_payload[SRSLTE_RAR_GRANT_LEN], uint16_t rnti, srslte_tdd_config_t tdd_config);
void set_dl_pending_grant(uint32_t tti, uint32_t cc_idx, const srslte_dci_dl_t* dl_dci);
bool get_dl_pending_grant(uint32_t tti, uint32_t cc_idx, srslte_dci_dl_t* dl_dci);
void set_dl_pending_grant(uint32_t tti, uint32_t cc_idx, uint32_t grant_cc_idx, const srslte_dci_dl_t* dl_dci);
bool get_dl_pending_grant(uint32_t tti, uint32_t cc_idx, uint32_t* grant_cc_idx, srslte_dci_dl_t* dl_dci);
void set_ul_pending_ack(srslte_ul_sf_cfg_t* sf,
uint32_t cc_idx,
@ -215,6 +215,7 @@ private:
// Cross-carried grants scheduled from PCell
typedef struct {
bool enable;
uint32_t grant_cc_idx;
srslte_dci_dl_t dl_dci;
} pending_dl_grant_t;
pending_dl_grant_t pending_dl_grant[FDD_HARQ_DELAY_MS][SRSLTE_MAX_CARRIERS] = {};

@ -249,7 +249,8 @@ bool cc_worker::work_dl_regular()
}
srslte_dci_dl_t dci_dl = {};
bool has_dl_grant = phy->get_dl_pending_grant(CURRENT_TTI, cc_idx, &dci_dl);
uint32_t grant_cc_idx = 0;
bool has_dl_grant = phy->get_dl_pending_grant(CURRENT_TTI, cc_idx, &grant_cc_idx, &dci_dl);
// If found a dci for this carrier, generate a grant, pass it to MAC and decode the associated PDSCH
if (has_dl_grant) {
@ -277,7 +278,7 @@ bool cc_worker::work_dl_regular()
dl_phy_to_mac_grant(&ue_dl_cfg.cfg.pdsch.grant, &dci_dl, &mac_grant);
// Save ACK resource configuration
srslte_pdsch_ack_resource_t ack_resource = {dci_dl.dai, dci_dl.location.ncce};
srslte_pdsch_ack_resource_t ack_resource = {dci_dl.dai, dci_dl.location.ncce, grant_cc_idx, dci_dl.tpc_pucch};
// Send grant to MAC and get action for this TB, then call tb_decoded to unlock MAC
phy->stack->new_grant_dl(cc_idx, mac_grant, &dl_action);
@ -384,7 +385,7 @@ int cc_worker::decode_pdcch_dl()
for (int k = 0; k < nof_grants; k++) {
// Save dci to CC index
phy->set_dl_pending_grant(CURRENT_TTI, dci[k].cif_present ? dci[k].cif : cc_idx, &dci[k]);
phy->set_dl_pending_grant(CURRENT_TTI, dci[k].cif_present ? dci[k].cif : cc_idx, cc_idx, &dci[k]);
// Logging
char str[512] = {};
@ -863,17 +864,6 @@ void cc_worker::set_uci_ack(srslte_uci_data_t* uci_data,
}
}
// Set ACK length for CA (default value is set to DTX)
if (ue_ul_cfg.ul_cfg.pucch.ack_nack_feedback_mode != SRSLTE_PUCCH_ACK_NACK_FEEDBACK_MODE_NORMAL) {
if (ue_dl_cfg.cfg.tm > SRSLTE_TM2) {
/* TM3, TM4 */
uci_data->cfg.ack.nof_acks = nof_configured_carriers * SRSLTE_MAX_CODEWORDS;
} else {
/* TM1, TM2 */
uci_data->cfg.ack.nof_acks = nof_configured_carriers;
}
}
// Configure ACK parameters
ack_info.is_grant_available = is_grant_available;
ack_info.is_pusch_available = is_pusch_available;

@ -430,22 +430,30 @@ void phy_common::set_rar_grant_tti(uint32_t tti)
rar_grant_tti = tti;
}
void phy_common::set_dl_pending_grant(uint32_t tti, uint32_t cc_idx, const srslte_dci_dl_t* dl_dci)
void phy_common::set_dl_pending_grant(uint32_t tti,
uint32_t cc_idx,
uint32_t grant_cc_idx,
const srslte_dci_dl_t* dl_dci)
{
if (!pending_dl_grant[tti % FDD_HARQ_DELAY_MS][cc_idx].enable) {
pending_dl_grant[tti % FDD_HARQ_DELAY_MS][cc_idx].dl_dci = *dl_dci;
pending_dl_grant[tti % FDD_HARQ_DELAY_MS][cc_idx].enable = true;
pending_dl_grant[tti % FDD_HARQ_DELAY_MS][cc_idx].dl_dci = *dl_dci;
pending_dl_grant[tti % FDD_HARQ_DELAY_MS][cc_idx].grant_cc_idx = grant_cc_idx;
pending_dl_grant[tti % FDD_HARQ_DELAY_MS][cc_idx].enable = true;
} else {
Warning("set_dl_pending_grant: cc=%d already exists\n", cc_idx);
}
}
bool phy_common::get_dl_pending_grant(uint32_t tti, uint32_t cc_idx, srslte_dci_dl_t* dl_dci)
bool phy_common::get_dl_pending_grant(uint32_t tti, uint32_t cc_idx, uint32_t* grant_cc_idx, srslte_dci_dl_t* dl_dci)
{
if (pending_dl_grant[tti % FDD_HARQ_DELAY_MS][cc_idx].enable) {
// Read grant
*dl_dci = pending_dl_grant[tti % FDD_HARQ_DELAY_MS][cc_idx].dl_dci;
if (dl_dci) {
*dl_dci = pending_dl_grant[tti % FDD_HARQ_DELAY_MS][cc_idx].dl_dci;
}
if (grant_cc_idx) {
*grant_cc_idx = pending_dl_grant[tti % FDD_HARQ_DELAY_MS][cc_idx].grant_cc_idx;
}
// Reset read flag
pending_dl_grant[tti % FDD_HARQ_DELAY_MS][cc_idx].enable = false;
return true;

@ -283,10 +283,7 @@ void sf_worker::work_imp()
void sf_worker::reset_uci(srslte_uci_data_t* uci_data)
{
bzero(uci_data, sizeof(srslte_uci_data_t));
/* Set all ACKs to DTX */
memset(uci_data->value.ack.ack_value, 2, SRSLTE_UCI_MAX_ACK_BITS);
srslte_uci_data_reset(uci_data);
}
/**************************** Measurements **************************/

Loading…
Cancel
Save