Multiple fixes HARQ ACK/NACK feedback and CSI reporting for MIMO and CA

This commit is contained in:
Xavier Arteaga 2020-04-07 17:26:32 +02:00 committed by Xavier Arteaga
parent cb6a8444df
commit 784bf81a1a
11 changed files with 572 additions and 250 deletions

View File

@ -151,10 +151,13 @@ SRSLTE_API void srslte_enb_dl_gen_ack(const srslte_cell_t* cell,
* info itself. Note that it expects that the HARQ-ACK info has been set prior the UCI Data decoding.
*
* @param cell points to the physical layer cell parameters
* @param uci_cfg points to the UCI configration
* @param uci_value points to the received UCI values
* @param ack_info is the HARQ-ACK information
*/
SRSLTE_API void
srslte_enb_dl_get_ack(const srslte_cell_t* cell, const srslte_uci_value_t* uci_value, srslte_pdsch_ack_t* pdsch_ack);
SRSLTE_API void srslte_enb_dl_get_ack(const srslte_cell_t* cell,
const srslte_uci_cfg_t* uci_cfg,
const srslte_uci_value_t* uci_value,
srslte_pdsch_ack_t* pdsch_ack);
#endif // SRSLTE_ENB_DL_H

View File

@ -120,7 +120,6 @@ typedef enum {
typedef struct SRSLTE_API {
bool data_enable;
bool ri_present;
bool pmi_present;
bool four_antenna_ports; ///< If cell has 4 antenna ports then true otherwise false
bool rank_is_not_one; ///< If rank > 1 then true otherwise false

View File

@ -421,7 +421,7 @@ bool srslte_enb_dl_gen_cqi_periodic(const srslte_cell_t* cell,
{
bool cqi_enabled = false;
if (srslte_cqi_periodic_ri_send(&dl_cfg->cqi_report, tti, cell->frame_type)) {
cqi_cfg->ri_len = 1; /* Asumes only 1 bit for RI */
cqi_cfg->ri_len = srslte_ri_nof_bits(cell);
cqi_enabled = true;
} else if (srslte_cqi_periodic_send(&dl_cfg->cqi_report, tti, cell->frame_type)) {
cqi_cfg->type = SRSLTE_CQI_TYPE_WIDEBAND;
@ -445,7 +445,7 @@ bool srslte_enb_dl_gen_cqi_aperiodic(const srslte_cell_t* cell,
cqi_cfg->type = SRSLTE_CQI_TYPE_SUBBAND_HL;
if (dl_cfg->tm == SRSLTE_TM3 || dl_cfg->tm == SRSLTE_TM4) {
cqi_cfg->ri_present = true;
cqi_cfg->ri_len = srslte_ri_nof_bits(cell);
}
cqi_cfg->N = (cell->nof_prb > 7) ? srslte_cqi_hl_get_no_subbands(cell->nof_prb) : 0;
cqi_cfg->four_antenna_ports = (cell->nof_ports == 4);
@ -493,45 +493,135 @@ void srslte_enb_dl_gen_ack(const srslte_cell_t* cell,
*uci_cfg = uci_data.cfg;
}
static void get_ack_fdd(const srslte_uci_value_t* uci_value, srslte_pdsch_ack_t* pdsch_ack)
static void enb_dl_get_ack_fdd_all_spatial_bundling(const srslte_uci_value_t* uci_value,
srslte_pdsch_ack_t* pdsch_ack,
uint32_t nof_tb)
{
uint32_t nof_tb = 1;
if (pdsch_ack->transmission_mode > SRSLTE_TM2) {
nof_tb = SRSLTE_MAX_CODEWORDS;
}
// Second clause: When 2 CC are configured with PUCCH CS mode and SR is also requested, bundle spatial codewords
if (pdsch_ack->nof_cc == SRSLTE_PUCCH_CS_MAX_CARRIERS && uci_value->scheduling_request == true &&
pdsch_ack->ack_nack_feedback_mode == SRSLTE_PUCCH_ACK_NACK_FEEDBACK_MODE_CS) {
for (uint32_t cc_idx = 0; cc_idx < pdsch_ack->nof_cc; cc_idx++) {
if (pdsch_ack->cc[cc_idx].m[0].present) {
if (uci_value->ack.ack_value[cc_idx] == 1) {
for (uint32_t tb = 0; tb < nof_tb; tb++) {
for (uint32_t cc_idx = 0; cc_idx < pdsch_ack->nof_cc; cc_idx++) {
if (pdsch_ack->cc[cc_idx].m[0].present) {
if (uci_value->ack.ack_value[cc_idx] == 1) {
for (uint32_t tb = 0; tb < nof_tb; tb++) {
// Check that TB was transmitted
if (pdsch_ack->cc[cc_idx].m[0].value[tb] != 2) {
pdsch_ack->cc[cc_idx].m[0].value[tb] = uci_value->ack.ack_value[cc_idx];
}
}
}
}
} else {
// By default, in FDD we just pass through all HARQ-ACK bits
uint32_t n = 0;
for (uint32_t cc_idx = 0; cc_idx < pdsch_ack->nof_cc; cc_idx++) {
for (uint32_t tb = 0; tb < nof_tb; tb++, n++) {
if (pdsch_ack->cc[cc_idx].m[0].present) {
pdsch_ack->cc[cc_idx].m[0].value[tb] = uci_value->ack.ack_value[n];
}
}
}
}
}
static void
enb_dl_get_ack_fdd_pcell_skip_drx(const srslte_uci_value_t* uci_value, srslte_pdsch_ack_t* pdsch_ack, uint32_t nof_tb)
{
if (pdsch_ack->cc[0].m[0].present) {
if (uci_value->ack.ack_value[0] == 1) {
for (uint32_t tb = 0; tb < nof_tb; tb++) {
// Check that TB was transmitted
if (pdsch_ack->cc[0].m[0].value[tb] != 2) {
pdsch_ack->cc[0].m[0].value[tb] = uci_value->ack.ack_value[0];
}
}
}
}
}
static void
enb_dl_get_ack_fdd_all_keep_drx(const srslte_uci_value_t* uci_value, srslte_pdsch_ack_t* pdsch_ack, uint32_t nof_tb)
{
for (uint32_t cc_idx = 0; cc_idx < pdsch_ack->nof_cc; cc_idx++) {
if (pdsch_ack->cc[cc_idx].m[0].present) {
if (uci_value->ack.ack_value[cc_idx] == 1) {
for (uint32_t tb = 0; tb < nof_tb; tb++) {
// Check that TB was transmitted
if (pdsch_ack->cc[cc_idx].m[0].value[tb] != 2) {
pdsch_ack->cc[cc_idx].m[0].value[tb] = uci_value->ack.ack_value[cc_idx * nof_tb + tb];
}
}
}
}
}
}
static void
get_ack_fdd(const srslte_uci_cfg_t* uci_cfg, const srslte_uci_value_t* uci_value, srslte_pdsch_ack_t* pdsch_ack)
{
// Number of transport blocks for the current Transmission Mode
uint32_t nof_tb = 1;
if (pdsch_ack->transmission_mode > SRSLTE_TM2) {
nof_tb = SRSLTE_MAX_CODEWORDS;
}
// Count number of transmissions
uint32_t tb_count = 0; // All transmissions
uint32_t tb_count_cc0 = 0; // Transmissions on PCell
for (uint32_t cc_idx = 0; cc_idx < pdsch_ack->nof_cc; cc_idx++) {
for (uint32_t tb = 0; tb < nof_tb; tb++) {
if (pdsch_ack->cc[cc_idx].m[0].present && pdsch_ack->cc[cc_idx].m[0].value[tb] != 2) {
tb_count++;
}
// Save primary cell number of TB
if (cc_idx == 0) {
tb_count_cc0 = tb_count;
}
}
}
// Does CSI report need to be transmitted?
bool csi_report = uci_cfg->cqi.data_enable || uci_cfg->cqi.ri_len;
switch (pdsch_ack->ack_nack_feedback_mode) {
case SRSLTE_PUCCH_ACK_NACK_FEEDBACK_MODE_NORMAL:
// Get ACK from PCell only, skipping DRX
enb_dl_get_ack_fdd_pcell_skip_drx(uci_value, pdsch_ack, nof_tb);
break;
case SRSLTE_PUCCH_ACK_NACK_FEEDBACK_MODE_CS:
if (pdsch_ack->nof_cc == 1) {
enb_dl_get_ack_fdd_pcell_skip_drx(uci_value, pdsch_ack, nof_tb);
} else if (pdsch_ack->is_pusch_available) {
enb_dl_get_ack_fdd_all_keep_drx(uci_value, pdsch_ack, nof_tb);
} else if (uci_value->scheduling_request) {
// For FDD with PUCCH format 1b with channel selection, when both HARQ-ACK and SR are transmitted in the same
// sub-frame a UE shall transmit the HARQ-ACK on its assigned HARQ-ACK PUCCH resource with channel selection as
// defined in subclause 10.1.2.2.1 for a negative SR transmission and transmit one HARQ-ACK bit per serving cell
// on its assigned SR PUCCH resource for a positive SR transmission according to the following:
// if only one transport block or a PDCCH indicating downlink SPS release is detected on a serving cell, the
// HARQ-ACK bit for the serving cell is the HARQ-ACK bit corresponding to the transport block or the PDCCH
// indicating downlink SPS release;
// if two transport blocks are received on a serving cell, the HARQ-ACK bit for the serving cell is generated
// by spatially bundling the HARQ-ACK bits corresponding to the transport blocks;
// if neither PDSCH transmission for which HARQ-ACK response shall be provided nor PDCCH indicating
// downlink SPS release is detected for a serving cell, the HARQ-ACK bit for the serving cell is set to NACK;
enb_dl_get_ack_fdd_all_spatial_bundling(uci_value, pdsch_ack, nof_tb);
} else if (csi_report) {
enb_dl_get_ack_fdd_pcell_skip_drx(uci_value, pdsch_ack, nof_tb);
} else {
enb_dl_get_ack_fdd_all_keep_drx(uci_value, pdsch_ack, nof_tb);
}
break;
case SRSLTE_PUCCH_ACK_NACK_FEEDBACK_MODE_PUCCH3:
if (tb_count == tb_count_cc0) {
enb_dl_get_ack_fdd_pcell_skip_drx(uci_value, pdsch_ack, nof_tb);
} else {
enb_dl_get_ack_fdd_all_keep_drx(uci_value, pdsch_ack, nof_tb);
}
break;
case SRSLTE_PUCCH_ACK_NACK_FEEDBACK_MODE_ERROR:
default:; // Do nothing
break;
}
}
void srslte_enb_dl_get_ack(const srslte_cell_t* cell,
const srslte_uci_cfg_t* uci_cfg,
const srslte_uci_value_t* uci_value,
srslte_pdsch_ack_t* pdsch_ack)
{
if (cell->frame_type == SRSLTE_FDD) {
get_ack_fdd(uci_value, pdsch_ack);
get_ack_fdd(uci_cfg, uci_value, pdsch_ack);
} else {
ERROR("Not implemented for TDD\n");
}
}
}

View File

@ -322,7 +322,7 @@ int srslte_cqi_size(srslte_cqi_cfg_t* cfg)
int size = 0;
if (!cfg->data_enable) {
return 0;
return cfg->ri_len;
}
switch (cfg->type) {

View File

@ -1205,7 +1205,7 @@ static int dci_format2AB_unpack(srslte_cell_t* cell,
dci->pinfo = srslte_bit_pack(&y, precoding_bits_f2a(cell->nof_ports));
}
// Apply TB swap table
// Apply TB swap table according to 3GPP 36.212 R8, section 5.3.3.1.5
if (nof_tb == 2) {
// Table 5.3.3.1.5-1
for (uint32_t i = 0; i < SRSLTE_MAX_CODEWORDS; i++) {
@ -1213,10 +1213,6 @@ static int dci_format2AB_unpack(srslte_cell_t* cell,
}
} else {
// Table 5.3.3.1.5-2
if (!SRSLTE_DCI_IS_TB_EN(dci->tb[0])) {
dci->tb[0] = dci->tb[1];
}
SRSLTE_DCI_TB_DISABLE(dci->tb[1]);
for (uint32_t i = 0; i < SRSLTE_MAX_CODEWORDS; i++) {
dci->tb[i].cw_idx = 0;
}

View File

@ -1025,7 +1025,7 @@ static int uci_decode_ri_ack(srslte_sch_t* q,
// If there is RI and CQI, assume RI = 1 for the purpose of RI/ACK decoding (3GPP 36.212 Clause 5.2.4.1. )
if (cfg->uci_cfg.cqi.data_enable) {
if (cfg->uci_cfg.cqi.type == SRSLTE_CQI_TYPE_SUBBAND_HL && cfg->uci_cfg.cqi.ri_present) {
if (cfg->uci_cfg.cqi.type == SRSLTE_CQI_TYPE_SUBBAND_HL && cfg->uci_cfg.cqi.ri_len) {
cfg->uci_cfg.cqi.rank_is_not_one = false;
}
}
@ -1075,7 +1075,7 @@ static int uci_decode_ri_ack(srslte_sch_t* q,
// Now set correct RI
if (cfg->uci_cfg.cqi.data_enable) {
if (cfg->uci_cfg.cqi.type == SRSLTE_CQI_TYPE_SUBBAND_HL && cfg->uci_cfg.cqi.ri_present) {
if (cfg->uci_cfg.cqi.type == SRSLTE_CQI_TYPE_SUBBAND_HL && cfg->uci_cfg.cqi.ri_len) {
cfg->uci_cfg.cqi.rank_is_not_one = uci_data->ri > 0;
}
}

View File

@ -945,70 +945,186 @@ void srslte_ue_dl_gen_cqi_aperiodic(srslte_ue_dl_t* q,
}
}
static void ue_dl_gen_ack_fdd_none(const srslte_pdsch_ack_t* ack_info, srslte_uci_data_t* uci_data)
{
// Set all carriers number of ACKs to 0
for (uint32_t i = 0; i < ack_info->nof_cc; i++) {
uci_data->cfg.ack[i].nof_acks = 0;
}
}
static void
ue_dl_gen_ack_fdd_pcell_skip_drx(const srslte_pdsch_ack_t* ack_info, srslte_uci_data_t* uci_data, uint32_t nof_tb)
{
uint32_t ack_idx = 0;
// Find ACK/NACK
if (ack_info->cc[0].m[0].present) {
for (uint32_t tb = 0; tb < nof_tb; tb++) {
if (ack_info->cc[0].m[0].value[tb] != 2) {
uci_data->value.ack.ack_value[ack_idx] = ack_info->cc[0].m[0].value[tb];
ack_idx++;
}
}
}
// Set number of ACKs for PCell
uci_data->cfg.ack[0].nof_acks = ack_idx;
// Set rest of carriers to 0 ACKs
for (uint32_t i = 1; i < ack_info->nof_cc; i++) {
uci_data->cfg.ack[i].nof_acks = 0;
}
}
static void
ue_dl_gen_ack_fdd_all_keep_drx(const srslte_pdsch_ack_t* ack_info, srslte_uci_data_t* uci_data, uint32_t nof_tb)
{
for (uint32_t cc_idx = 0; cc_idx < ack_info->nof_cc; cc_idx++) {
// Find ACK/NACK
if (ack_info->cc[cc_idx].m[0].present) {
for (uint32_t tb = 0; tb < nof_tb; tb++) {
if (ack_info->cc[cc_idx].m[0].value[tb] != 2) {
uci_data->value.ack.ack_value[cc_idx * nof_tb + tb] = ack_info->cc[cc_idx].m[0].value[tb];
}
}
}
// Set all carriers to maximum number of TBs
uci_data->cfg.ack[cc_idx].nof_acks = nof_tb;
}
}
static void
ue_dl_gen_ack_fdd_all_spatial_bundling(const srslte_pdsch_ack_t* ack_info, srslte_uci_data_t* uci_data, uint32_t nof_tb)
{
uint32_t nof_ack = 0;
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].value[tb] != 2) {
uci_data->value.ack.ack_value[cc_idx] &= ack_info->cc[cc_idx].m[0].value[tb];
nof_ack++;
}
}
} else {
uci_data->value.ack.ack_value[cc_idx] = 2;
}
}
// If no ACK is counted, set all zero, bundle otherwise
for (uint32_t i = 0; i < SRSLTE_PUCCH_CS_MAX_CARRIERS; i++) {
uci_data->cfg.ack[i].nof_acks = (nof_ack == 0) ? 0 : 1;
}
}
/* UE downlink procedure for reporting HARQ-ACK bits in FDD, Section 7.3 36.213
*/
static void gen_ack_fdd(const srslte_pdsch_ack_t* ack_info, srslte_uci_data_t* uci_data)
{
// Number of transport blocks for the current Transmission Mode
uint32_t nof_tb = 1;
if (ack_info->transmission_mode > SRSLTE_TM2) {
nof_tb = SRSLTE_MAX_CODEWORDS;
}
// Second clause: When 2 CC are configured with PUCCH CS mode and SR is also requested, bundle spatial codewords
if (!ack_info->is_pusch_available && ack_info->nof_cc == SRSLTE_PUCCH_CS_MAX_CARRIERS &&
uci_data->value.scheduling_request == true &&
ack_info->ack_nack_feedback_mode == SRSLTE_PUCCH_ACK_NACK_FEEDBACK_MODE_CS) {
uint32_t nof_ack = 0;
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].value[tb] != 2) {
uci_data->value.ack.ack_value[cc_idx] &= ack_info->cc[cc_idx].m[0].value[tb];
nof_ack++;
}
}
// Count number of transmissions
uint32_t tb_count = 0; // All transmissions
uint32_t tb_count_cc0 = 0; // Transmissions on PCell
for (uint32_t cc_idx = 0; cc_idx < ack_info->nof_cc; cc_idx++) {
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) {
tb_count++;
}
// Save primary cell number of TB
if (cc_idx == 0) {
tb_count_cc0 = tb_count;
}
}
}
// if no transmission counted return without reporting any ACK/NACK
if (tb_count == 0) {
ue_dl_gen_ack_fdd_none(ack_info, uci_data);
return;
}
// Count total of Uplink Control Bits
uint32_t total_uci_bits =
tb_count + srslte_cqi_size(&uci_data->cfg.cqi) + (uci_data->value.scheduling_request ? 1 : 0);
// Does CSI report need to be transmitted?
bool csi_report = uci_data->cfg.cqi.data_enable || uci_data->cfg.cqi.ri_len;
// Logic for dropping CSI report if required
if (csi_report && !ack_info->is_pusch_available) {
bool drop_csi_report = true; ///< CSI report shall be dropped by default
// 3GPP 36.213 R.15 Section 10.1.1:
// For FDD or for FDD-TDD and primary cell frame structure type 1 and for a UE that is configured with more than
// one serving cell, in case of collision between a periodic CSI report and an HARQ-ACK in a same subframe without
// PUSCH,
// - if the parameter simultaneousAckNackAndCQI provided by higher layers is set TRUE and if the HARQ-ACK
// corresponds to a PDSCH transmission or PDCCH/EPDCCH indicating downlink SPS release only on the
// primary cell, then the periodic CSI report is multiplexed with HARQ-ACK on PUCCH using PUCCH format 2/2a/2b
drop_csi_report &= !(tb_count_cc0 == tb_count && ack_info->simul_cqi_ack);
// - else if the UE is configured with PUCCH format 3 and if the parameter simultaneousAckNackAndCQI-Format3-
// r11 provided by higher layers is set TRUE, and if PUCCH resource is determined according to subclause
// 10.1.2.2.2, and
// - if the total number of bits in the subframe corresponding to HARQ-ACKs, SR (if any), and the CSI is not
// larger than 22 or
// - if the total number of bits in the subframe corresponding to spatially bundled HARQ-ACKs, SR (if any),
// and the CSI is not larger than 22 then the periodic CSI report is multiplexed with HARQ-ACK on PUCCH
// using the determined PUCCH format 3 resource according to [4]
drop_csi_report &= !(ack_info->simul_cqi_ack_pucch3 && total_uci_bits <= 22);
// - otherwise, CSI is dropped
if (drop_csi_report) {
uci_data->cfg.cqi.data_enable = false;
uci_data->cfg.cqi.ri_len = 0;
csi_report = false;
}
}
// For each HARQ ACK/NACK feedback mode
switch (ack_info->ack_nack_feedback_mode) {
case SRSLTE_PUCCH_ACK_NACK_FEEDBACK_MODE_NORMAL:
// Get ACK from PCell only, skipping DRX
ue_dl_gen_ack_fdd_pcell_skip_drx(ack_info, uci_data, nof_tb);
break;
case SRSLTE_PUCCH_ACK_NACK_FEEDBACK_MODE_CS:
// Configured with more than serving cell and PUCCH Format 1b with channel selection
if (ack_info->nof_cc == 1) {
ue_dl_gen_ack_fdd_pcell_skip_drx(ack_info, uci_data, nof_tb);
} else if (ack_info->is_pusch_available) {
ue_dl_gen_ack_fdd_all_keep_drx(ack_info, uci_data, nof_tb);
} else if (uci_data->value.scheduling_request) {
// For FDD with PUCCH format 1b with channel selection, when both HARQ-ACK and SR are transmitted in the same
// sub-frame a UE shall transmit the HARQ-ACK on its assigned HARQ-ACK PUCCH resource with channel selection as
// defined in subclause 10.1.2.2.1 for a negative SR transmission and transmit one HARQ-ACK bit per serving cell
// on its assigned SR PUCCH resource for a positive SR transmission according to the following:
// if only one transport block or a PDCCH indicating downlink SPS release is detected on a serving cell, the
// HARQ-ACK bit for the serving cell is the HARQ-ACK bit corresponding to the transport block or the PDCCH
// indicating downlink SPS release;
// if two transport blocks are received on a serving cell, the HARQ-ACK bit for the serving cell is generated
// by spatially bundling the HARQ-ACK bits corresponding to the transport blocks;
// if neither PDSCH transmission for which HARQ-ACK response shall be provided nor PDCCH indicating
// downlink SPS release is detected for a serving cell, the HARQ-ACK bit for the serving cell is set to NACK;
ue_dl_gen_ack_fdd_all_spatial_bundling(ack_info, uci_data, nof_tb);
} else if (csi_report) {
ue_dl_gen_ack_fdd_pcell_skip_drx(ack_info, uci_data, nof_tb);
} else {
uci_data->value.ack.ack_value[cc_idx] = 2;
ue_dl_gen_ack_fdd_all_keep_drx(ack_info, uci_data, nof_tb);
}
}
// If no ACK is counted, set all zero, bundle otherwise
for (uint32_t i = 0; i < SRSLTE_PUCCH_CS_MAX_CARRIERS; i++) {
uci_data->cfg.ack[i].nof_acks = (nof_ack == 0) ? 0 : 1;
}
} else {
// By default, in FDD we just pass through all HARQ-ACK bits
uint32_t tb_count = 0;
uint32_t tb_count_cc0 = 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++;
}
// Save primary cell number of TB
if (cc_idx == 0) {
tb_count_cc0 = tb_count;
}
}
}
uint32_t total_uci_bits =
tb_count + srslte_cqi_size(&uci_data->cfg.cqi) + (uci_data->value.scheduling_request ? 1 : 0);
if (tb_count == 0) {
// If no PDSCH TB detected, set all to zeros and do not modify the UCI configuration
for (int i = 0; i < ack_info->nof_cc; i++) {
uci_data->cfg.ack[i].nof_acks = 0;
}
} else 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 if (ack_info->ack_nack_feedback_mode == SRSLTE_PUCCH_ACK_NACK_FEEDBACK_MODE_PUCCH3 &&
tb_count_cc0 == tb_count) {
break;
case SRSLTE_PUCCH_ACK_NACK_FEEDBACK_MODE_PUCCH3:
// According to 3GPP 36.213 Section 10.1.2.2.2 PUCCH format 3 HARQ-ACK procedure
// For FDD with PUCCH format 3, the UE shall use PUCCH resource n_pucch_3 or n_pucch_1 for transmission of
// HARQ-ACK in subframe n where
@ -1021,56 +1137,15 @@ static void gen_ack_fdd(const srslte_pdsch_ack_t* ack_info, srslte_uci_data_t* u
// - for a PDSCH transmission on the secondary cell indicated by the detection of a corresponding PDCCH in
// subframe n 4 , the UE shall use PUCCH format 3 and PUCCH resource n_pucch_3 where the value of n PUCCH
// is determined according to higher layer configuration and Table 10.1.2.2.2-1.
uci_data->cfg.ack[0].nof_acks = tb_count_cc0; // So, set only PCell
for (int i = 1; i < ack_info->nof_cc; i++) {
uci_data->cfg.ack[i].nof_acks = 0;
if (tb_count == tb_count_cc0) {
ue_dl_gen_ack_fdd_pcell_skip_drx(ack_info, uci_data, nof_tb);
} else {
ue_dl_gen_ack_fdd_all_keep_drx(ack_info, uci_data, nof_tb);
}
} 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 < ack_info->nof_cc; i++) {
uci_data->cfg.ack[i].nof_acks = nof_tb;
}
}
if (tb_count && uci_data->cfg.cqi.data_enable && !ack_info->is_pusch_available) {
bool drop_csi_report = true; ///< CSI report shall be dropped by default
// 3GPP 36.213 R.15 Section 10.1.1:
// For FDD or for FDD-TDD and primary cell frame structure type 1 and for a UE that is configured with more than
// one serving cell, in case of collision between a periodic CSI report and an HARQ-ACK in a same subframe without
// PUSCH,
// - if the parameter simultaneousAckNackAndCQI provided by higher layers is set TRUE and if the HARQ-ACK
// corresponds to a PDSCH transmission or PDCCH/EPDCCH indicating downlink SPS release only on the
// primary cell, then the periodic CSI report is multiplexed with HARQ-ACK on PUCCH using PUCCH format 2/2a/2b
if ((tb_count_cc0 == tb_count && ack_info->simul_cqi_ack)) {
// Do not drop CSI report
drop_csi_report = false;
// Set number of active only ACKs
uci_data->cfg.ack[0].nof_acks = tb_count_cc0;
// Set all SCell number of ACKs to 0
for (int i = 1; i < ack_info->nof_cc; i++) {
uci_data->cfg.ack[i].nof_acks = 0;
}
}
// - else if the UE is configured with PUCCH format 3 and if the parameter simultaneousAckNackAndCQI-Format3-
// r11 provided by higher layers is set TRUE, and if PUCCH resource is determined according to subclause
// 10.1.2.2.2, and
// - if the total number of bits in the subframe corresponding to HARQ-ACKs, SR (if any), and the CSI is not
// larger than 22 or
// - if the total number of bits in the subframe corresponding to spatially bundled HARQ-ACKs, SR (if any),
// and the CSI is not larger than 22 then the periodic CSI report is multiplexed with HARQ-ACK on PUCCH
// using the determined PUCCH format 3 resource according to [4]
drop_csi_report &= !(ack_info->simul_cqi_ack_pucch3 && total_uci_bits <= 22);
// - otherwise, CSI is dropped
uci_data->cfg.cqi.data_enable = !drop_csi_report;
}
break;
case SRSLTE_PUCCH_ACK_NACK_FEEDBACK_MODE_ERROR:
default:; // Do nothing
break;
}
// n_cce values are just copied
@ -1297,7 +1372,6 @@ void srslte_ue_dl_gen_ack(const srslte_cell_t* cell,
const srslte_pdsch_ack_t* ack_info,
srslte_uci_data_t* uci_data)
{
if (cell->frame_type == SRSLTE_FDD) {
gen_ack_fdd(ack_info, uci_data);
} else {

View File

@ -266,7 +266,7 @@ public:
uint16_t rnti,
bool aperiodic_cqi_request,
bool is_pusch_available,
srslte_uci_cfg_t& uci_cfg) const;
srslte_uci_cfg_t& uci_cfg);
/**
* Sends the decoded Uplink Control Information by PUCCH or PUSCH to MAC

View File

@ -361,10 +361,13 @@ void phy_ue_db::set_ack_pending(uint32_t tti, uint32_t enb_cc_idx, const srslte_
pdsch_ack_m.resource.tpc_for_pucch = dci.tpc_pucch;
// Set TB info
for (uint32_t i = 0; i < srslte_dci_format_max_tb(dci.format); i++) {
if (SRSLTE_DCI_IS_TB_EN(dci.tb[i])) {
pdsch_ack_m.value[i] = 1;
for (uint32_t tb_idx = 0; tb_idx < SRSLTE_MAX_CODEWORDS; tb_idx++) {
// Count only if the TB is enabled and the TB index is valid for the DCI format
if (SRSLTE_DCI_IS_TB_EN(dci.tb[tb_idx]) and tb_idx < srslte_dci_format_max_tb(dci.format)) {
pdsch_ack_m.value[tb_idx] = 1;
pdsch_ack_m.k++;
} else {
pdsch_ack_m.value[tb_idx] = 2;
}
}
}
@ -374,7 +377,7 @@ bool phy_ue_db::fill_uci_cfg(uint32_t tti,
uint16_t rnti,
bool aperiodic_cqi_request,
bool is_pusch_available,
srslte_uci_cfg_t& uci_cfg) const
srslte_uci_cfg_t& uci_cfg)
{
std::lock_guard<std::mutex> lock(mutex);
@ -391,9 +394,12 @@ bool phy_ue_db::fill_uci_cfg(uint32_t tti,
return false;
}
const auto& ue = ue_db.at(rnti);
const auto& pcell_cfg = ue.cell_info[0].phy_cfg;
bool uci_required = false;
common_ue& ue = ue_db.at(rnti);
const srslte::phy_cfg_t& pcell_cfg = ue.cell_info[0].phy_cfg;
bool uci_required = false;
const cell_info_t& pcell_info = ue.cell_info[0];
const srslte_cell_t& pcell = cell_cfg_list->at(pcell_info.enb_cc_idx).cell;
// Check if SR opportunity (will only be used in PUCCH)
uci_cfg.is_scheduling_request_tti = (srslte_ue_ul_sr_send_tti(&pcell_cfg.ul_cfg.pucch, tti) == 1);
@ -420,20 +426,17 @@ bool phy_ue_db::fill_uci_cfg(uint32_t tti,
// If no periodic CQI report required, check aperiodic reporting
if ((not periodic_cqi_required) and aperiodic_cqi_request) {
// Aperiodic only supported for PCell
const cell_info_t& pcell_info = ue.cell_info[0];
const srslte_cell_t& cell = cell_cfg_list->at(pcell_info.enb_cc_idx).cell;
const srslte_dl_cfg_t& dl_cfg = pcell_info.phy_cfg.dl_cfg;
const srslte_dl_cfg_t& dl_cfg = pcell_info.phy_cfg.dl_cfg;
uci_required = srslte_enb_dl_gen_cqi_aperiodic(&cell, &dl_cfg, pcell_info.last_ri, &uci_cfg.cqi);
uci_required = srslte_enb_dl_gen_cqi_aperiodic(&pcell, &dl_cfg, pcell_info.last_ri, &uci_cfg.cqi);
}
// Get pending ACKs from PDSCH
srslte_dl_sf_cfg_t dl_sf_cfg = {};
dl_sf_cfg.tti = tti;
const srslte_cell_t& cell = cell_cfg_list->at(ue.cell_info[0].enb_cc_idx).cell;
srslte_pdsch_ack_t ack_info = ue.pdsch_ack[TTIMOD(tti)];
ack_info.is_pusch_available = is_pusch_available;
srslte_enb_dl_gen_ack(&cell, &dl_sf_cfg, &ack_info, &uci_cfg);
srslte_dl_sf_cfg_t dl_sf_cfg = {};
dl_sf_cfg.tti = tti;
srslte_pdsch_ack_t& pdsch_ack = ue.pdsch_ack[TTIMOD(tti)];
pdsch_ack.is_pusch_available = is_pusch_available;
srslte_enb_dl_gen_ack(&pcell, &dl_sf_cfg, &pdsch_ack, &uci_cfg);
uci_required |= (srslte_uci_cfg_total_ack(&uci_cfg) > 0);
// Return whether UCI needs to be decoded
@ -468,15 +471,17 @@ void phy_ue_db::send_uci_data(uint32_t tti,
// Get ACK info
srslte_pdsch_ack_t& pdsch_ack = ue.pdsch_ack[TTIMOD(tti)];
srslte_enb_dl_get_ack(&cell_cfg_list->at(ue.cell_info[0].enb_cc_idx).cell, &uci_value, &pdsch_ack);
srslte_enb_dl_get_ack(&cell_cfg_list->at(ue.cell_info[0].enb_cc_idx).cell, &uci_cfg, &uci_value, &pdsch_ack);
// Iterate over the ACK information
for (uint32_t scell_idx = 0; scell_idx < SRSLTE_MAX_CARRIERS; scell_idx++) {
const srslte_pdsch_ack_cc_t& pdsch_ack_cc = pdsch_ack.cc[scell_idx];
for (uint32_t m = 0; m < pdsch_ack_cc.M; m++) {
if (pdsch_ack_cc.m[m].present) {
for (uint32_t tb = 0; tb < pdsch_ack_cc.m[m].k; tb++) {
stack->ack_info(tti, rnti, ue.cell_info[scell_idx].enb_cc_idx, tb, pdsch_ack_cc.m[m].value[tb] == 1);
for (uint32_t tb = 0; tb < SRSLTE_MAX_CODEWORDS; tb++) {
if (pdsch_ack_cc.m[m].value[tb] != 2) {
stack->ack_info(tti, rnti, ue.cell_info[scell_idx].enb_cc_idx, tb, pdsch_ack_cc.m[m].value[tb] == 1);
}
}
}
}
@ -511,12 +516,6 @@ void phy_ue_db::send_uci_data(uint32_t tti,
stack->cqi_info(tti, rnti, cqi_cc_idx, cqi_value);
}
// Rank indicator (TM3 and TM4)
if (uci_cfg.cqi.ri_len) {
stack->ri_info(tti, rnti, cqi_cc_idx, uci_value.ri);
cqi_scell_info.last_ri = uci_value.ri;
}
// Precoding Matrix indicator (TM4)
if (uci_cfg.cqi.pmi_present) {
uint8_t pmi_value = 0;
@ -534,6 +533,12 @@ void phy_ue_db::send_uci_data(uint32_t tti,
stack->pmi_info(tti, rnti, cqi_cc_idx, pmi_value);
}
}
// Rank indicator (TM3 and TM4)
if (uci_cfg.cqi.ri_len) {
stack->ri_info(tti, rnti, cqi_cc_idx, uci_value.ri);
cqi_scell_info.last_ri = uci_value.ri;
}
}
void phy_ue_db::set_last_ul_tb(uint16_t rnti, uint32_t enb_cc_idx, uint32_t pid, srslte_ra_tb_t tb)

View File

@ -35,19 +35,62 @@ target_link_libraries(enb_phy_test
set(ENB_PHY_TEST_DURATION 128)
# Basic eNb PHY test:
# eNb PHY test:
# - Single carrier
# - Transmission Mode 1
# - 1 eNb cell/carrier (no carrier aggregation)
# - maximum bandwidth 100
add_test(enb_phy_test_base enb_phy_test --duration=${ENB_PHY_TEST_DURATION} --cell.nof_prb=100 )
# - 100 PRB
add_test(enb_phy_test_tm1 enb_phy_test --duration=${ENB_PHY_TEST_DURATION} --cell.nof_prb=100 --tm=1)
# Five carrier aggregation using PUCCH3
# - 6 eNb cell/carrier (only using 5 aggregated)
# Single carrier TM2 eNb PHY test:
# - Single carrier
# - Transmission Mode 2
# - 1 eNb cell/carrier (no carrier aggregation)
# - 6 PRB
add_test(enb_phy_test_tm2 enb_phy_test --duration=${ENB_PHY_TEST_DURATION} --cell.nof_prb=100 --tm=2)
# Single carrier TM3 eNb PHY test:
# - Single carrier
# - Transmission Mode 3
# - 1 eNb cell/carrier (no carrier aggregation)
# - 6 PRB
add_test(enb_phy_test_tm3 enb_phy_test --duration=${ENB_PHY_TEST_DURATION} --cell.nof_prb=100 --tm=3)
# Single carrier eNb PHY test:
# - Single carrier
# - Transmission Mode 4
# - 1 eNb cell/carrier (no carrier aggregation)
# - 6 PRB
add_test(enb_phy_test_tm4 enb_phy_test --duration=${ENB_PHY_TEST_DURATION} --cell.nof_prb=100 --tm=4)
# Five carrier aggregation using PUCCH3:
# - 6 eNb cell/carrier
# - Transmission Mode 1
# - 5 Aggregated carriers
# - 6 PRB
# - PUCCH format 3 ACK/NACK feedback mode and more than 2 ACK/NACK bits in PUSCH
add_test(enb_phy_test_ca_pucch3 enb_phy_test --duration=${ENB_PHY_TEST_DURATION} --nof_enb_cells=6 --ue_cell_list=3,4,0,1,2 --ack_mode=pucch3 --cell.nof_prb=6 )
add_test(enb_phy_test_tm1_ca_pucch3 enb_phy_test --duration=${ENB_PHY_TEST_DURATION} --nof_enb_cells=6 --ue_cell_list=3,4,0,1,2 --ack_mode=pucch3 --cell.nof_prb=6 --tm=1)
# Two carrier aggregation using Channel Selection
# - 6 eNb cell/carrier (only using 2 aggregated)
# Five carrier aggregation using PUCCH3:
# - 6 eNb cell/carrier
# - Transmission Mode 4
# - 5 Aggregated carriers
# - 6 PRB
# - PUCCH format 3 ACK/NACK feedback mode and more than 2 ACK/NACK bits in PUSCH
add_test(enb_phy_test_tm4_ca_pucch3 enb_phy_test --duration=${ENB_PHY_TEST_DURATION} --nof_enb_cells=6 --ue_cell_list=0,4,3,1,2 --ack_mode=pucch3 --cell.nof_prb=6 --tm=4)
# Two carrier aggregation using Channel Selection:
# - 6 eNb cell/carrier
# - Transmission Mode 1
# - 2 Aggregated carriers
# - 6 PRB
# - PUCCH format 1b with Channel selection ACK/NACK feedback mode
add_test(enb_phy_test_cs enb_phy_test --duration=${ENB_PHY_TEST_DURATION} --nof_enb_cells=6 --ue_cell_list=5,4 --ack_mode=cs --cell.nof_prb=6 )
add_test(enb_phy_test_tm1_ca_cs enb_phy_test --duration=${ENB_PHY_TEST_DURATION} --nof_enb_cells=6 --ue_cell_list=5,4 --ack_mode=cs --cell.nof_prb=6 --tm=1)
# Two carrier aggregation using Channel Selection:
# - 6 eNb cell/carrier
# - Transmission Mode 4
# - 2 Aggregated carriers
# - 6 PRB
# - PUCCH format 1b with Channel selection ACK/NACK feedback mode
add_test(enb_phy_test_tm4_ca_cs enb_phy_test --duration=${ENB_PHY_TEST_DURATION} --nof_enb_cells=6 --ue_cell_list=1,5 --ack_mode=cs --cell.nof_prb=6 --tm=4)

View File

@ -255,19 +255,20 @@ typedef std::unique_ptr<dummy_radio> unique_dummy_radio_t;
class dummy_stack : public srsenb::stack_interface_phy_lte
{
private:
static constexpr float prob_dl_grant = 0.50f;
static constexpr float prob_ul_grant = 0.10f;
static constexpr uint32_t cfi = 2;
static constexpr float prob_dl_grant = 0.50f;
static constexpr float prob_ul_grant = 0.10f;
static constexpr uint32_t cfi = 2;
srsenb::phy_cell_cfg_list_t phy_cell_cfg;
std::mutex mutex;
std::condition_variable cvar;
srslte::log_filter log_h;
srslte_softbuffer_tx_t softbuffer_tx = {};
srslte_softbuffer_rx_t softbuffer_rx[SRSLTE_MAX_CARRIERS][SRSLTE_FDD_NOF_HARQ] = {};
uint8_t* data = nullptr;
uint16_t ue_rnti = 0;
srslte_random_t random_gen = nullptr;
srsenb::phy_cell_cfg_list_t phy_cell_cfg;
srsenb::phy_interface_rrc_lte::phy_rrc_dedicated_list_t phy_rrc;
std::mutex mutex;
std::condition_variable cvar;
srslte::log_filter log_h;
srslte_softbuffer_tx_t softbuffer_tx = {};
srslte_softbuffer_rx_t softbuffer_rx[SRSLTE_MAX_CARRIERS][SRSLTE_FDD_NOF_HARQ] = {};
uint8_t* data = nullptr;
uint16_t ue_rnti = 0;
srslte_random_t random_gen = nullptr;
CALLBACK(sr_detected);
CALLBACK(rach_detected);
@ -290,7 +291,7 @@ private:
uint32_t tti;
uint32_t cc_idx;
uint32_t tb_idx;
uint32_t ack;
bool ack;
} tti_dl_info_t;
typedef struct {
@ -322,14 +323,16 @@ private:
uint32_t ul_riv = 0;
public:
explicit dummy_stack(srsenb::phy_cfg_t& phy_cfg_,
const std::string& log_level,
uint16_t rnti_,
std::vector<uint32_t>& active_cell_list_) :
explicit dummy_stack(const srsenb::phy_cfg_t& phy_cfg_,
const srsenb::phy_interface_rrc_lte::phy_rrc_dedicated_list_t& phy_rrc_,
const std::string& log_level,
uint16_t rnti_,
std::vector<uint32_t>& active_cell_list_) :
log_h("STACK"),
ue_rnti(rnti_),
random_gen(srslte_random_init(rnti_)),
phy_cell_cfg(phy_cfg_.phy_cell_cfg),
phy_rrc(phy_rrc_),
active_cell_list(active_cell_list_)
{
log_h.set_level(log_level);
@ -415,11 +418,17 @@ public:
int ri_info(uint32_t tti, uint16_t rnti, uint32_t cc_idx, uint32_t ri_value) override
{
notify_ri_info();
log_h.info("Received RI tti=%d; rnti=0x%x; cc_idx=%d; ri=%d;\n", tti, rnti, cc_idx, ri_value);
return 0;
}
int pmi_info(uint32_t tti, uint16_t rnti, uint32_t cc_idx, uint32_t pmi_value) override
{
notify_pmi_info();
log_h.info("Received PMI tti=%d; rnti=0x%x; cc_idx=%d; pmi=%d;\n", tti, rnti, cc_idx, pmi_value);
return 0;
}
int cqi_info(uint32_t tti, uint16_t rnti, uint32_t cc_idx, uint32_t cqi_value) override
@ -453,7 +462,7 @@ public:
tti_dl_info_t tti_dl_info = {};
tti_dl_info.tti = tti;
tti_dl_info.cc_idx = cc_idx;
tti_dl_info.tb_idx = 0;
tti_dl_info.tb_idx = tb_idx;
tti_dl_info.ack = ack;
tti_dl_info_ack_queue.push(tti_dl_info);
@ -484,14 +493,25 @@ public:
dl_sched_res[0].cfi = cfi;
// Iterate for each carrier
uint32_t scell_idx = 0;
for (uint32_t& cc_idx : active_cell_list) {
auto& dl_sched = dl_sched_res[cc_idx];
// Required
dl_sched.cfi = cfi;
// Default TB scheduling
bool sched_tb[SRSLTE_MAX_TB] = {};
sched_tb[0] = srslte_random_bool(random_gen, prob_dl_grant);
// Schedule second TB for TM3 or TM4
if (phy_rrc[scell_idx].phy_cfg.dl_cfg.tm == SRSLTE_TM3 or phy_rrc[scell_idx].phy_cfg.dl_cfg.tm == SRSLTE_TM4) {
sched_tb[1] = srslte_random_bool(random_gen, prob_dl_grant);
}
// Random decision on whether transmit or not
bool sched = srslte_random_bool(random_gen, prob_dl_grant);
bool sched = sched_tb[0] | sched_tb[1];
// RNTI needs to be valid
sched &= (ue_rnti != 0);
@ -511,18 +531,24 @@ public:
dl_sched.pdsch[0].dci.type0_alloc.rbg_bitmask = 0xffffffff;
dl_sched.pdsch[0].dci.rnti = ue_rnti;
dl_sched.pdsch[0].dci.alloc_type = SRSLTE_RA_ALLOC_TYPE0;
dl_sched.pdsch[0].dci.tb[0].cw_idx = 0;
dl_sched.pdsch[0].dci.tb[0].mcs_idx = 27;
dl_sched.pdsch[0].dci.tb[0].rv = 0;
dl_sched.pdsch[0].dci.tb[0].ndi = false;
dl_sched.pdsch[0].dci.tb[1].cw_idx = 1;
dl_sched.pdsch[0].dci.tb[1].mcs_idx = 0;
dl_sched.pdsch[0].dci.tb[1].rv = 1;
dl_sched.pdsch[0].dci.tb[1].ndi = false;
dl_sched.pdsch[0].data[0] = data;
dl_sched.pdsch[0].data[1] = data;
dl_sched.pdsch[0].dci.format = SRSLTE_DCI_FORMAT1;
dl_sched.pdsch[0].dci.tpc_pucch = (location.ncce + 1) % SRSLTE_PUCCH_SIZE_AN_CS;
dl_sched.pdsch[0].dci.tpc_pucch = (location.ncce) % SRSLTE_PUCCH_SIZE_AN_CS;
// Set DCI format depending on the transmission mode
switch (phy_rrc[0].phy_cfg.dl_cfg.tm) {
default:
case SRSLTE_TM1:
case SRSLTE_TM2:
dl_sched.pdsch[0].dci.format = SRSLTE_DCI_FORMAT1;
break;
case SRSLTE_TM3:
dl_sched.pdsch[0].dci.format = SRSLTE_DCI_FORMAT2A;
break;
case SRSLTE_TM4:
dl_sched.pdsch[0].dci.format = SRSLTE_DCI_FORMAT2;
break;
}
// Push grant info in queue
tti_dl_info_t tti_dl_info = {};
@ -531,11 +557,34 @@ public:
tti_dl_info.tb_idx = 0;
tti_dl_info.ack = true;
// Push to queue
tti_dl_info_sched_queue.push(tti_dl_info);
// Schedule TB
uint32_t cw_count = 0;
for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) {
if (sched_tb[tb]) {
log_h.debug("Transmitted DL grant tti=%d; rnti=0x%x; cc=%d; tb=%d;\n", tti, ue_rnti, cc_idx, tb);
// Create Grant with maximum safe MCS
dl_sched.pdsch[0].dci.tb[tb].cw_idx = cw_count++;
dl_sched.pdsch[0].dci.tb[tb].mcs_idx = 27;
dl_sched.pdsch[0].dci.tb[tb].rv = 0;
dl_sched.pdsch[0].dci.tb[tb].ndi = false;
// Push to queue
tti_dl_info.tb_idx = tb;
tti_dl_info_sched_queue.push(tti_dl_info);
} else {
// Create Grant with no TB
dl_sched.pdsch[0].dci.tb[tb].cw_idx = 0;
dl_sched.pdsch[0].dci.tb[tb].mcs_idx = 0;
dl_sched.pdsch[0].dci.tb[tb].rv = 1;
dl_sched.pdsch[0].dci.tb[tb].ndi = false;
}
}
} else {
dl_sched.nof_grants = 0;
}
scell_idx++;
}
return 0;
@ -624,11 +673,8 @@ public:
void set_sched_dl_tti_mask(uint8_t* tti_mask, uint32_t nof_sfs) override { notify_set_sched_dl_tti_mask(); }
void rl_failure(uint16_t rnti) override { notify_rl_failure(); }
void rl_ok(uint16_t rnti) override { notify_rl_ok(); }
void tti_clock() override
{
notify_tti_clock();
}
int run_tti()
void tti_clock() override { notify_tti_clock(); }
int run_tti()
{
// Check DL ACKs match with grants
while (not tti_dl_info_ack_queue.empty()) {
@ -700,6 +746,7 @@ private:
std::vector<cf_t*> buffers = {};
dummy_radio* radio = nullptr;
uint32_t sf_len = 0;
uint32_t nof_ports = 0;
uint16_t rnti = 0;
srslte_dl_sf_cfg_t sf_dl_cfg = {};
srslte_ul_sf_cfg_t sf_ul_cfg = {};
@ -707,6 +754,7 @@ private:
uint8_t* tx_data = nullptr;
srsenb::phy_interface_rrc_lte::phy_rrc_dedicated_list_t phy_rrc_cfg = {};
srslte::log_filter log_h;
std::map<uint32_t, uint32_t> last_ri = {};
public:
dummy_ue(dummy_radio* _radio,
@ -714,16 +762,19 @@ public:
std::string log_level,
uint16_t rnti_,
const srsenb::phy_interface_rrc_lte::phy_rrc_dedicated_list_t& phy_rrc_cfg_) :
radio(_radio), log_h("UE PHY", nullptr, true), phy_rrc_cfg(phy_rrc_cfg_)
radio(_radio),
log_h("UE PHY", nullptr, true),
phy_rrc_cfg(phy_rrc_cfg_)
{
// Calculate subframe length
sf_len = static_cast<uint32_t>(SRSLTE_SF_LEN_PRB(cell_list[0].cell.nof_prb));
rnti = rnti_;
nof_ports = cell_list[0].cell.nof_ports;
sf_len = static_cast<uint32_t>(SRSLTE_SF_LEN_PRB(cell_list[0].cell.nof_prb));
rnti = rnti_;
log_h.set_level(std::move(log_level));
// Initialise one buffer per eNb
for (uint32_t i = 0; i < cell_list.size(); i++) {
for (uint32_t i = 0; i < cell_list.size() * nof_ports; i++) {
// Allocate buffers
cf_t* buffer = srslte_vec_cf_malloc(sf_len);
if (not buffer) {
@ -747,7 +798,7 @@ public:
// Initialise UE DL
if (srslte_ue_dl_init(
ue_dl, &buffers[cc_idx], cell_list[cc_idx].cell.nof_prb, cell_list[cc_idx].cell.nof_ports)) {
ue_dl, &buffers[cc_idx * nof_ports], cell_list[cc_idx].cell.nof_prb, cell_list[cc_idx].cell.nof_ports)) {
ERROR("Initiating UE DL\n");
}
@ -767,7 +818,7 @@ public:
ue_ul_v.push_back(ue_ul);
// Initialise UE UL
if (srslte_ue_ul_init(ue_ul, buffers[cc_idx], cell_list[cc_idx].cell.nof_prb)) {
if (srslte_ue_ul_init(ue_ul, buffers[cc_idx * nof_ports], cell_list[cc_idx].cell.nof_prb)) {
ERROR("Setting UE UL cell\n");
}
@ -856,6 +907,11 @@ public:
ue_dl_cfg.cfg.cqi_report.periodic_mode = SRSLTE_CQI_MODE_12;
ue_dl_cfg.cfg.pdsch.rnti = rnti;
int report_ri_cc_idx = -1;
if (last_ri.count(i)) {
ue_dl_cfg.last_ri = last_ri[i];
}
srslte_ue_dl_decode_fft_estimate(ue_dl_v[i], &sf_dl_cfg, &ue_dl_cfg);
// Get DL Grants
@ -883,8 +939,14 @@ public:
pdsch_ack.cc[i].m[0].resource.n_cce = dci_dl->location.ncce;
pdsch_ack.cc[i].m[0].resource.grant_cc_idx = i;
pdsch_ack.cc[i].m[0].resource.tpc_for_pucch = dci_dl->tpc_pucch;
pdsch_ack.cc[i].m[0].value[0] = 1;
pdsch_ack.cc[i].m[0].value[1] = 1;
for (uint32_t tb_idx = 0; tb_idx < SRSLTE_MAX_TB; tb_idx++) {
if (ue_dl_cfg.cfg.pdsch.grant.tb[tb_idx].enabled) {
pdsch_ack.cc[i].m[0].value[tb_idx] = 1;
} else {
pdsch_ack.cc[i].m[0].value[tb_idx] = 2;
}
}
} else {
pdsch_ack.cc[i].M = 1;
pdsch_ack.cc[i].m[0].present = false;
@ -892,6 +954,11 @@ public:
// Generate CQI periodic if required
srslte_ue_dl_gen_cqi_periodic(ue_dl_v[i], &ue_dl_cfg, 0x0f, sf_ul_cfg.tti, &uci_data);
if (srslte_cqi_periodic_ri_send(&ue_dl_cfg.cfg.cqi_report, sf_ul_cfg.tti, ue_dl_v[i]->cell.frame_type) &&
uci_data.cfg.cqi.ri_len) {
uci_data.cfg.cqi.scell_index = i;
}
}
return SRSLTE_SUCCESS;
@ -945,6 +1012,10 @@ public:
// Generate Acknowledgements
srslte_ue_dl_gen_ack(&ue_dl_v[i]->cell, &sf_dl_cfg, &pdsch_ack, &uci_data);
if (uci_data.cfg.cqi.ri_len) {
last_ri[uci_data.cfg.cqi.scell_index] = uci_data.value.ri;
}
}
// Set UCI only for PCel
@ -1000,20 +1071,44 @@ class phy_test_bench
{
public:
struct args_t {
uint16_t rnti = 0x1234;
uint32_t duration = 10240;
uint32_t nof_enb_cells = 1;
srslte_cell_t cell = {};
uint16_t rnti = 0x1234;
uint32_t duration = 10240;
uint32_t nof_enb_cells = 1;
srslte_cell_t cell = {};
std::string ue_cell_list_str = "0"; ///< First indicates PCell
std::vector<uint32_t> ue_cell_list = {0};
std::string ack_mode = "normal";
std::string log_level = "none";
std::string ack_mode = "normal";
std::string log_level = "none";
uint32_t tm_u32 = 1;
srslte_tm_t tm = SRSLTE_TM1;
args_t()
{
cell.nof_prb = 6;
cell.nof_ports = 1;
}
// Initialises secondary parameters
void init()
{
switch (tm_u32) {
case 2:
cell.nof_ports = 2;
tm = SRSLTE_TM2;
break;
case 3:
cell.nof_ports = 2;
tm = SRSLTE_TM3;
break;
case 4:
cell.nof_ports = 2;
tm = SRSLTE_TM4;
break;
case 1:
default:
cell.nof_ports = 1;
tm = SRSLTE_TM1;
}
}
};
private:
@ -1068,29 +1163,41 @@ public:
phy_cfg.prach_cnfg.prach_cfg_info.zero_correlation_zone_cfg = 5;
// Create base UE dedicated configuration
srslte::phy_cfg_t dedicated = {};
dedicated.ul_cfg.pucch.ack_nack_feedback_mode = srslte_string_ack_nack_feedback_mode(args.ack_mode.c_str());
dedicated.ul_cfg.pucch.delta_pucch_shift = delta_pucch;
dedicated.ul_cfg.pucch.n_rb_2 = 2;
dedicated.ul_cfg.pucch.N_cs = 0;
dedicated.ul_cfg.pucch.n_pucch_sr = 0;
dedicated.ul_cfg.pucch.N_pucch_1 = N_pucch_1;
dedicated.ul_cfg.pucch.n_pucch_2 = 5;
dedicated.ul_cfg.pucch.simul_cqi_ack = true;
dedicated.ul_cfg.pucch.sr_configured = true;
dedicated.ul_cfg.pucch.I_sr = 5;
dedicated.ul_cfg.pucch.n1_pucch_an_cs[0][0] = N_pucch_1 + delta_pucch * 1;
dedicated.ul_cfg.pucch.n1_pucch_an_cs[1][0] = N_pucch_1 + delta_pucch * 2;
dedicated.ul_cfg.pucch.n1_pucch_an_cs[2][0] = N_pucch_1 + delta_pucch * 3;
dedicated.ul_cfg.pucch.n1_pucch_an_cs[3][0] = N_pucch_1 + delta_pucch * 4;
dedicated.ul_cfg.pucch.n1_pucch_an_cs[0][1] = N_pucch_1 + delta_pucch * 2;
dedicated.ul_cfg.pucch.n1_pucch_an_cs[1][1] = N_pucch_1 + delta_pucch * 3;
dedicated.ul_cfg.pucch.n1_pucch_an_cs[2][1] = N_pucch_1 + delta_pucch * 4;
dedicated.ul_cfg.pucch.n1_pucch_an_cs[3][1] = N_pucch_1 + delta_pucch * 1;
srslte::phy_cfg_t dedicated = {};
// Configure DL
dedicated.dl_cfg.tm = args.tm;
// Configure reporting
dedicated.dl_cfg.cqi_report.periodic_configured = true;
dedicated.dl_cfg.cqi_report.pmi_idx = 25;
dedicated.dl_cfg.cqi_report.periodic_mode = SRSLTE_CQI_MODE_20;
dedicated.ul_cfg.pusch.uci_offset.I_offset_ack = 7;
if (args.tm == SRSLTE_TM3 or args.tm == SRSLTE_TM4) {
dedicated.dl_cfg.cqi_report.ri_idx_present = true;
dedicated.dl_cfg.cqi_report.ri_idx = 483; // Every 8 CQI/PMI report, schedule an RI report
}
// Configure UL Resources
dedicated.ul_cfg.pucch.ack_nack_feedback_mode = srslte_string_ack_nack_feedback_mode(args.ack_mode.c_str());
dedicated.ul_cfg.pucch.delta_pucch_shift = delta_pucch;
dedicated.ul_cfg.pucch.n_rb_2 = 2;
dedicated.ul_cfg.pucch.N_cs = 0;
dedicated.ul_cfg.pucch.n_pucch_sr = 0;
dedicated.ul_cfg.pucch.N_pucch_1 = N_pucch_1;
dedicated.ul_cfg.pucch.n_pucch_2 = 5;
dedicated.ul_cfg.pucch.simul_cqi_ack = true;
dedicated.ul_cfg.pucch.sr_configured = true;
dedicated.ul_cfg.pucch.I_sr = 5;
dedicated.ul_cfg.pucch.n1_pucch_an_cs[0][0] = N_pucch_1 + 2;
dedicated.ul_cfg.pucch.n1_pucch_an_cs[1][0] = N_pucch_1 + 3;
dedicated.ul_cfg.pucch.n1_pucch_an_cs[2][0] = N_pucch_1 + 4;
dedicated.ul_cfg.pucch.n1_pucch_an_cs[3][0] = N_pucch_1 + 5;
dedicated.ul_cfg.pucch.n1_pucch_an_cs[0][1] = N_pucch_1 + 3;
dedicated.ul_cfg.pucch.n1_pucch_an_cs[1][1] = N_pucch_1 + 4;
dedicated.ul_cfg.pucch.n1_pucch_an_cs[2][1] = N_pucch_1 + 5;
dedicated.ul_cfg.pucch.n1_pucch_an_cs[3][1] = N_pucch_1 + 6;
dedicated.ul_cfg.pusch.uci_offset.I_offset_ack = 7;
// Configure UE PHY
std::array<bool, SRSLTE_MAX_CARRIERS> activation = {}; ///< Activation/Deactivation vector
@ -1111,10 +1218,11 @@ public:
}
/// Create Radio instance
radio = unique_dummy_radio_t(new dummy_radio(args.nof_enb_cells, args.cell.nof_prb, args.log_level));
radio = unique_dummy_radio_t(
new dummy_radio(args.nof_enb_cells * args.cell.nof_ports, args.cell.nof_prb, args.log_level));
/// Create Dummy Stack isntance
stack = unique_dummy_stack_t(new dummy_stack(phy_cfg, args.log_level, args.rnti, args.ue_cell_list));
stack = unique_dummy_stack_t(new dummy_stack(phy_cfg, phy_rrc_cfg, args.log_level, args.rnti, args.ue_cell_list));
/// eNb PHY initialisation instance
enb_phy = unique_srsenb_phy_t(new srsenb::phy(&logger_stdout));
@ -1171,6 +1279,7 @@ int parse_args(int argc, char** argv, phy_test_bench::args_t& args)
("ack_mode", bpo::value<std::string>(&args.ack_mode), "HARQ ACK/NACK mode: normal, pucch3, cs")
("cell.nof_prb", bpo::value<uint32_t>(&args.cell.nof_prb)->default_value(args.cell.nof_prb), "eNb Cell/Carrier bandwidth")
("cell.nof_ports", bpo::value<uint32_t>(&args.cell.nof_ports)->default_value(args.cell.nof_ports), "eNb Cell/Carrier number of ports")
("tm", bpo::value<uint32_t>(&args.tm_u32)->default_value(args.tm_u32), "Transmission mode")
;
options.add(common).add_options()("help", "Show this message");
@ -1216,6 +1325,9 @@ int main(int argc, char** argv)
// Parse arguments
TESTASSERT(parse_args(argc, argv, test_args) == SRSLTE_SUCCESS);
// Initialize secondary parameters
test_args.init();
// Create Test Bench
unique_phy_test_bench test_bench = unique_phy_test_bench(new phy_test_bench(test_args));