Added Aperiodic mode 3-1 in enb and some more optimizations

This commit is contained in:
Xavier Arteaga 2017-11-16 14:48:03 +01:00 committed by Ismael Gomez
parent 0bd683b3c4
commit 8ab196901f
13 changed files with 491 additions and 300 deletions

View File

@ -141,6 +141,7 @@ SRSLTE_API int srslte_enb_ul_get_pusch(srslte_enb_ul_t *q,
uint32_t rv_idx,
uint32_t current_tx_nb,
uint8_t *data,
srslte_cqi_value_t *cqi_value,
srslte_uci_data_t *uci_data,
uint32_t tti);

View File

@ -142,6 +142,7 @@ SRSLTE_API int srslte_pusch_decode(srslte_pusch_t *q,
float noise_estimate,
uint16_t rnti,
uint8_t *data,
srslte_cqi_value_t *cqi_value,
srslte_uci_data_t *uci_data);
SRSLTE_API float srslte_pusch_average_noi(srslte_pusch_t *q);

View File

@ -131,31 +131,25 @@ SRSLTE_API int srslte_uci_encode_ack(srslte_pusch_cfg_t *cfg,
uint32_t H_prime_total,
srslte_uci_bit_t *ri_bits);
SRSLTE_API int srslte_uci_decode_ack(srslte_pusch_cfg_t *cfg,
int16_t *q_bits,
uint8_t *c_seq,
float beta,
uint32_t H_prime_total,
uint32_t O_cqi,
srslte_uci_bit_t *ack_bits,
uint8_t acks[2],
uint32_t nof_acks);
SRSLTE_API int srslte_uci_encode_ri(srslte_pusch_cfg_t *cfg,
uint8_t data,
SRSLTE_API int srslte_uci_encode_ack_ri(srslte_pusch_cfg_t *cfg,
uint8_t *data,
uint32_t data_len,
uint32_t O_cqi,
float beta,
uint32_t H_prime_total,
srslte_uci_bit_t *ri_bits);
SRSLTE_API int srslte_uci_decode_ri(srslte_pusch_cfg_t *cfg,
int16_t *q_bits,
uint8_t *c_seq,
float beta,
uint32_t H_prime_total,
uint32_t O_cqi,
srslte_uci_bit_t *ri_bits,
uint8_t *data);
bool is_ri);
SRSLTE_API int srslte_uci_decode_ack_ri(srslte_pusch_cfg_t *cfg,
int16_t *q_bits,
uint8_t *c_seq,
float beta,
uint32_t H_prime_total,
uint32_t O_cqi,
srslte_uci_bit_t *ack_ri_bits,
uint8_t data[2],
uint32_t nof_bits,
bool is_ri);
#endif

View File

@ -253,18 +253,22 @@ int srslte_enb_ul_cfg_ue(srslte_enb_ul_t *q, uint16_t rnti,
}
}
void srslte_enb_ul_fft(srslte_enb_ul_t *q, cf_t *signal_buffer)
void srslte_enb_ul_fft(srslte_enb_ul_t *q)
{
srslte_ofdm_rx_sf(&q->fft);
}
int get_pucch(srslte_enb_ul_t *q, uint16_t rnti,
uint32_t pdcch_n_cce, uint32_t sf_rx,
srslte_uci_data_t *uci_data, uint8_t bits[SRSLTE_PUCCH_MAX_BITS])
srslte_uci_data_t *uci_data, uint8_t bits[SRSLTE_PUCCH_MAX_BITS], uint32_t nof_bits)
{
float noise_power = srslte_chest_ul_get_noise_estimate(&q->chest);
srslte_pucch_format_t format = srslte_pucch_get_format(uci_data, q->cell.cp);
if (format == SRSLTE_PUCCH_FORMAT_ERROR) {
fprintf(stderr,"Error getting format\n");
return SRSLTE_ERROR;
}
uint32_t n_pucch = srslte_pucch_get_npucch(pdcch_n_cce, format, uci_data->scheduling_request, &q->users[rnti]->pucch_sched);
@ -273,7 +277,7 @@ int get_pucch(srslte_enb_ul_t *q, uint16_t rnti,
return SRSLTE_ERROR;
}
int ret_val = srslte_pucch_decode(&q->pucch, format, n_pucch, sf_rx, rnti, q->sf_symbols, q->ce, noise_power, bits);
int ret_val = srslte_pucch_decode(&q->pucch, format, n_pucch, sf_rx, rnti, q->sf_symbols, q->ce, noise_power, bits, nof_bits);
if (ret_val < 0) {
fprintf(stderr,"Error decoding PUCCH\n");
return SRSLTE_ERROR;
@ -286,16 +290,18 @@ int srslte_enb_ul_get_pucch(srslte_enb_ul_t *q, uint16_t rnti,
srslte_uci_data_t *uci_data)
{
uint8_t pucch_bits[SRSLTE_PUCCH_MAX_BITS];
if (q->users[rnti]) {
int ret_val = get_pucch(q, rnti, pdcch_n_cce, sf_rx, uci_data, pucch_bits);
if (q->users[rnti]) {
uint32_t nof_uci_bits = uci_data->ri_periodic_report ? uci_data->uci_ri_len : (uci_data->uci_cqi_len +
uci_data->uci_dif_cqi_len +
uci_data->uci_pmi_len);
int ret_val = get_pucch(q, rnti, pdcch_n_cce, sf_rx, uci_data, pucch_bits, nof_uci_bits);
// 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 (uci_data->scheduling_request && uci_data->uci_ack_len && ret_val != 1) {
uci_data->scheduling_request = false;
ret_val = get_pucch(q, rnti, pdcch_n_cce, sf_rx, uci_data, pucch_bits);
ret_val = get_pucch(q, rnti, pdcch_n_cce, sf_rx, uci_data, pucch_bits, nof_uci_bits);
}
// update schedulign request
@ -305,12 +311,32 @@ int srslte_enb_ul_get_pucch(srslte_enb_ul_t *q, uint16_t rnti,
// Save ACK bits
if (uci_data->uci_ack_len > 0) {
uci_data->uci_ack = pucch_bits[0];
uci_data->uci_ack = pucch_bits[0];
}
if (uci_data->uci_ack_len > 1) {
uci_data->uci_ack_2 = pucch_bits[1];
}
// PUCCH2 CQI bits are decoded inside srslte_pucch_decode()
if (uci_data->uci_cqi_len) {
memcpy(uci_data->uci_cqi, pucch_bits, uci_data->uci_cqi_len*sizeof(uint8_t));
}
if (uci_data->uci_dif_cqi_len) {
memcpy(uci_data->uci_dif_cqi, pucch_bits + uci_data->uci_cqi_len, uci_data->uci_dif_cqi_len*sizeof(uint8_t));
}
if (uci_data->uci_pmi_len) {
memcpy(uci_data->uci_pmi, pucch_bits + uci_data->uci_cqi_len + uci_data->uci_dif_cqi_len,
uci_data->uci_pmi_len*sizeof(uint8_t));
}
if (uci_data->uci_ri_len) {
uci_data->uci_ri = pucch_bits[0]; /* Assume only one bit of RI */
}
if (uci_data->uci_cqi_len || uci_data->uci_ri_len) {
if (uci_data->uci_ack_len >= 1) {
uci_data->uci_ack = pucch_bits[20];
}
@ -328,7 +354,7 @@ int srslte_enb_ul_get_pucch(srslte_enb_ul_t *q, uint16_t rnti,
int srslte_enb_ul_get_pusch(srslte_enb_ul_t *q, srslte_ra_ul_grant_t *grant, srslte_softbuffer_rx_t *softbuffer,
uint16_t rnti, uint32_t rv_idx, uint32_t current_tx_nb,
uint8_t *data, srslte_uci_data_t *uci_data, uint32_t tti)
uint8_t *data, srslte_cqi_value_t *cqi_value, srslte_uci_data_t *uci_data, uint32_t tti)
{
if (q->users[rnti]) {
if (srslte_pusch_cfg(&q->pusch,
@ -364,6 +390,7 @@ int srslte_enb_ul_get_pusch(srslte_enb_ul_t *q, srslte_ra_ul_grant_t *grant, srs
softbuffer, q->sf_symbols,
q->ce, noise_power,
rnti, data,
cqi_value,
uci_data);
}

View File

@ -199,17 +199,44 @@ int srslte_cqi_value_unpack(uint8_t buff[SRSLTE_CQI_MAX_BITS], srslte_cqi_value_
}
int srslte_cqi_size(srslte_cqi_value_t *value) {
int size = 0;
switch(value->type) {
case SRSLTE_CQI_TYPE_WIDEBAND:
return 4;
size = 4;
break;
case SRSLTE_CQI_TYPE_SUBBAND:
return 4+(value->subband.subband_label_2_bits)?2:1;
size = 4 + (value->subband.subband_label_2_bits) ? 2 : 1;
break;
case SRSLTE_CQI_TYPE_SUBBAND_UE:
return 4+2+value->subband_ue.L;
size = 4 + 2 + value->subband_ue.L;
break;
case SRSLTE_CQI_TYPE_SUBBAND_HL:
return 4+2*value->subband_hl.N;
/* First codeword */
size += 4 + 2 * value->subband_hl.N;
/* Add Second codeword if required */
if (value->subband_hl.rank_is_not_one && value->subband_hl.pmi_present) {
size += 4 + 2 * value->subband_hl.N;
}
/* Add PMI if required*/
if (value->subband_hl.pmi_present) {
if (value->subband_hl.four_antenna_ports) {
size += 4;
} else {
if (value->subband_hl.rank_is_not_one) {
size += 1;
} else {
size += 2;
}
}
}
break;
default:
size = SRSLTE_ERROR;
}
return -1;
return size;
}
static bool srslte_cqi_get_N(uint32_t I_cqi_pmi, uint32_t *N_p, uint32_t *N_offset) {

View File

@ -566,9 +566,9 @@ int srslte_pusch_decode(srslte_pusch_t *q,
srslte_pusch_cfg_t *cfg, srslte_softbuffer_rx_t *softbuffer,
cf_t *sf_symbols,
cf_t *ce, float noise_estimate, uint16_t rnti,
uint8_t *data, srslte_uci_data_t *uci_data)
uint8_t *data, srslte_cqi_value_t *cqi_value, srslte_uci_data_t *uci_data)
{
int ret = SRSLTE_ERROR_INVALID_INPUTS;
uint32_t n;
if (q != NULL &&
@ -607,19 +607,42 @@ int srslte_pusch_decode(srslte_pusch_t *q,
// Generate scrambling sequence if not pre-generated
srslte_sequence_t *seq = get_user_sequence(q, rnti, cfg->sf_idx, cfg->nbits.nof_bits);
// Set CQI len assuming RI = 1 (3GPP 36.212 Clause 5.2.4.1. Uplink control information on PUSCH without UL-SCH data)
if (cqi_value) {
if (cqi_value->type == SRSLTE_CQI_TYPE_SUBBAND_HL) {
cqi_value->subband_hl.rank_is_not_one = false;
}
uci_data->uci_cqi_len = (uint32_t) srslte_cqi_size(cqi_value);
uci_data->uci_ri_len = (q->cell.nof_ports == 4) ? 2 : 1;
}
// Decode RI/HARQ bits before descrambling
if (srslte_ulsch_uci_decode_ri_ack(&q->ul_sch, cfg, softbuffer, q->q, seq->c, uci_data)) {
fprintf(stderr, "Error decoding RI/HARQ bits\n");
return SRSLTE_ERROR;
}
// Set CQI len with corresponding RI
if (cqi_value) {
if (cqi_value->type == SRSLTE_CQI_TYPE_SUBBAND_HL) {
cqi_value->subband_hl.rank_is_not_one = (uci_data->uci_ri != 0);
}
uci_data->uci_cqi_len = (uint32_t) srslte_cqi_size(cqi_value);
}
// Descrambling
srslte_scrambling_s_offset(seq, q->q, 0, cfg->nbits.nof_bits);
return srslte_ulsch_uci_decode(&q->ul_sch, cfg, softbuffer, q->q, q->g, data, uci_data);
} else {
return SRSLTE_ERROR_INVALID_INPUTS;
// Decode
ret = srslte_ulsch_uci_decode(&q->ul_sch, cfg, softbuffer, q->q, q->g, data, uci_data);
// Unpack CQI value if available
if (cqi_value) {
srslte_cqi_value_unpack(uci_data->uci_cqi, cqi_value);
}
}
return ret;
}
uint32_t srslte_pusch_last_noi(srslte_pusch_t *q) {

View File

@ -658,7 +658,7 @@ int srslte_ulsch_uci_decode_ri_ack(srslte_sch_t *q, srslte_pusch_cfg_t *cfg, srs
if (cfg->cb_segm.tbs == 0) {
beta /= beta_cqi_offset[cfg->uci_cfg.I_offset_cqi];
}
ret = srslte_uci_decode_ack(cfg, q_bits, c_seq, beta, nb_q/Qm, uci_data->uci_cqi_len, q->ack_ri_bits, acks, uci_data->uci_ack_len);
ret = srslte_uci_decode_ack_ri(cfg, q_bits, c_seq, beta, nb_q/Qm, uci_data->uci_cqi_len, q->ack_ri_bits, acks, uci_data->uci_ack_len, false);
if (ret < 0) {
return ret;
}
@ -678,7 +678,7 @@ int srslte_ulsch_uci_decode_ri_ack(srslte_sch_t *q, srslte_pusch_cfg_t *cfg, srs
if (cfg->cb_segm.tbs == 0) {
beta /= beta_cqi_offset[cfg->uci_cfg.I_offset_cqi];
}
ret = srslte_uci_decode_ri(cfg, q_bits, c_seq, beta, nb_q/Qm, uci_data->uci_cqi_len, q->ack_ri_bits, &uci_data->uci_ri);
ret = srslte_uci_decode_ack_ri(cfg, q_bits, c_seq, beta, nb_q/Qm, uci_data->uci_cqi_len, q->ack_ri_bits, &uci_data->uci_ri, uci_data->uci_ri_len, true);
if (ret < 0) {
return ret;
}
@ -756,13 +756,18 @@ int srslte_ulsch_uci_encode(srslte_sch_t *q,
uint32_t nb_q = cfg->nbits.nof_bits;
uint32_t Qm = cfg->grant.Qm;
// Encode RI
if (uci_data.uci_ri_len > 0) {
// Encode RI if CQI enabled
if (uci_data.uci_ri_len > 0 || uci_data.uci_cqi_len > 0) {
/* If no RI is reported set it to zero as specified in 3GPP 36.213 clause 7.2.1 */
if (uci_data.uci_ri_len == 0) {
uci_data.uci_ri = 0;
}
float beta = beta_ri_offset[cfg->uci_cfg.I_offset_ri];
if (cfg->cb_segm.tbs == 0) {
beta /= beta_cqi_offset[cfg->uci_cfg.I_offset_cqi];
}
ret = srslte_uci_encode_ri(cfg, uci_data.uci_ri, uci_data.uci_cqi_len, beta, nb_q/Qm, q->ack_ri_bits);
uint8_t ri[2] = {uci_data.uci_ri, 0};
ret = srslte_uci_encode_ack_ri(cfg, ri, uci_data.uci_ri_len, uci_data.uci_cqi_len, beta, nb_q/Qm, q->ack_ri_bits, true);
if (ret < 0) {
return ret;
}
@ -809,8 +814,8 @@ int srslte_ulsch_uci_encode(srslte_sch_t *q,
if (cfg->cb_segm.tbs == 0) {
beta /= beta_cqi_offset[cfg->uci_cfg.I_offset_cqi];
}
ret = srslte_uci_encode_ack(cfg, acks, uci_data.uci_ack_len, uci_data.uci_cqi_len,
beta, nb_q / Qm, &q->ack_ri_bits[Q_prime_ri * Qm]);
ret = srslte_uci_encode_ack_ri(cfg, acks, uci_data.uci_ack_len, uci_data.uci_cqi_len,
beta, nb_q / Qm, &q->ack_ri_bits[Q_prime_ri * Qm], false);
if (ret < 0) {
return ret;
}

View File

@ -252,7 +252,7 @@ int main(int argc, char **argv) {
}
gettimeofday(&t[1], NULL);
int r = srslte_pusch_decode(&pusch_rx, &cfg, &softbuffer_rx, sf_symbols, ce, 0, rnti, data, &uci_data_rx);
int r = srslte_pusch_decode(&pusch_rx, &cfg, &softbuffer_rx, sf_symbols, ce, 0, rnti, data, NULL, &uci_data_rx);
gettimeofday(&t[2], NULL);
get_time_interval(t);
if (r) {

View File

@ -103,26 +103,29 @@ static uint8_t M_basis_seq_pucch[20][13]={
{1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1},
{1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0},
{1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0},
};
};
void srslte_uci_cqi_pucch_init(srslte_uci_cqi_pucch_t *q) {
uint8_t word[16];
uint32_t nwords = 16;
for (uint32_t w=0;w<nwords;w++) {
q->cqi_table[w] = srslte_vec_malloc(SRSLTE_UCI_CQI_CODED_PUCCH_B*sizeof(int8_t));
q->cqi_table_s[w] = srslte_vec_malloc(SRSLTE_UCI_CQI_CODED_PUCCH_B*sizeof(int16_t));
uint8_t word[16];
uint32_t nwords = 1 << SRSLTE_UCI_MAX_CQI_LEN_PUCCH;
q->cqi_table = srslte_vec_malloc(nwords * sizeof(int8_t *));
q->cqi_table_s = srslte_vec_malloc(nwords * sizeof(int16_t *));
for (uint32_t w = 0; w < nwords; w++) {
q->cqi_table[w] = srslte_vec_malloc(SRSLTE_UCI_CQI_CODED_PUCCH_B * sizeof(int8_t));
q->cqi_table_s[w] = srslte_vec_malloc(SRSLTE_UCI_CQI_CODED_PUCCH_B * sizeof(int16_t));
uint8_t *ptr = word;
srslte_bit_unpack(w, &ptr, 4);
srslte_uci_encode_cqi_pucch(word, 4, q->cqi_table[w]);
for (int j=0;j<SRSLTE_UCI_CQI_CODED_PUCCH_B;j++) {
q->cqi_table_s[w][j] = 2*q->cqi_table[w][j]-1;
srslte_bit_unpack(w, &ptr, SRSLTE_UCI_MAX_CQI_LEN_PUCCH);
srslte_uci_encode_cqi_pucch(word, SRSLTE_UCI_MAX_CQI_LEN_PUCCH, q->cqi_table[w]);
for (int j = 0; j < SRSLTE_UCI_CQI_CODED_PUCCH_B; j++) {
q->cqi_table_s[w][j] = (int16_t)(2 * q->cqi_table[w][j] - 1);
}
}
}
void srslte_uci_cqi_pucch_free(srslte_uci_cqi_pucch_t *q) {
uint32_t nwords = 16;
uint32_t nwords = 1 << SRSLTE_UCI_MAX_CQI_LEN_PUCCH;
for (uint32_t w=0;w<nwords;w++) {
if (q->cqi_table[w]) {
free(q->cqi_table[w]);
@ -131,6 +134,8 @@ void srslte_uci_cqi_pucch_free(srslte_uci_cqi_pucch_t *q) {
free(q->cqi_table_s[w]);
}
}
free(q->cqi_table);
free(q->cqi_table_s);
}
/* Encode UCI CQI/PMI as described in 5.2.3.3 of 36.212
@ -151,17 +156,32 @@ int srslte_uci_encode_cqi_pucch(uint8_t *cqi_data, uint32_t cqi_len, uint8_t b_b
}
}
int srslte_uci_encode_cqi_pucch_from_table(srslte_uci_cqi_pucch_t *q, uint8_t *cqi_data, uint32_t cqi_len, uint8_t b_bits[SRSLTE_UCI_CQI_CODED_PUCCH_B])
{
if (cqi_len <= SRSLTE_UCI_MAX_CQI_LEN_PUCCH) {
bzero(&cqi_data[cqi_len], SRSLTE_UCI_MAX_CQI_LEN_PUCCH - cqi_len);
uint8_t *ptr = cqi_data;
uint32_t packed = srslte_bit_pack(&ptr, SRSLTE_UCI_MAX_CQI_LEN_PUCCH);
memcpy(b_bits, q->cqi_table[packed], SRSLTE_UCI_CQI_CODED_PUCCH_B);
return SRSLTE_SUCCESS;
} else {
return SRSLTE_ERROR_INVALID_INPUTS;
}
}
/* Decode UCI CQI/PMI over PUCCH
*/
int16_t srslte_uci_decode_cqi_pucch(srslte_uci_cqi_pucch_t *q, int16_t b_bits[32], uint8_t *cqi_data, uint32_t cqi_len)
{
if (cqi_len == 4 &&
if (cqi_len < SRSLTE_UCI_MAX_CQI_LEN_PUCCH &&
b_bits != NULL &&
cqi_data != NULL)
{
uint32_t max_w = 0;
int32_t max_corr = INT32_MIN;
for (uint32_t w=0;w<16;w++) {
int32_t max_corr = INT32_MIN;
uint32_t nwords = 1 << SRSLTE_UCI_MAX_CQI_LEN_PUCCH;
for (uint32_t w=0;w<nwords;w += 1<<(SRSLTE_UCI_MAX_CQI_LEN_PUCCH - cqi_len)) {
// Calculate correlation with pregenerated word and select maximum
int32_t corr = srslte_vec_dot_prod_sss(q->cqi_table_s[w], b_bits, SRSLTE_UCI_CQI_CODED_PUCCH_B);
@ -172,7 +192,7 @@ int16_t srslte_uci_decode_cqi_pucch(srslte_uci_cqi_pucch_t *q, int16_t b_bits[32
}
// Convert word to bits again
uint8_t *ptr = cqi_data;
srslte_bit_unpack(max_w, &ptr, cqi_len);
srslte_bit_unpack(max_w, &ptr, SRSLTE_UCI_MAX_CQI_LEN_PUCCH);
INFO("Decoded CQI: w=%d, corr=%d\n", max_w, max_corr);
return max_corr;
@ -586,9 +606,7 @@ static uint32_t encode_ri_ack(uint8_t data[2], uint32_t data_len, srslte_uci_bit
/* Decode UCI HARQ/ACK bits as described in 5.2.2.6 of 36.212
* Currently only supporting 1-bit HARQ
*/
#ifndef MIMO_ENB
static int32_t decode_ri_ack(int16_t *q_bits, uint8_t *c_seq, srslte_uci_bit_t *pos)
static int32_t decode_ri_ack_1bit(int16_t *q_bits, uint8_t *c_seq, srslte_uci_bit_t *pos)
{
uint32_t p0 = pos[0].position;
uint32_t p1 = pos[1].position;
@ -598,33 +616,8 @@ static int32_t decode_ri_ack(int16_t *q_bits, uint8_t *c_seq, srslte_uci_bit_t *
return -(q0+q1);
}
int srslte_uci_decode_ack(srslte_pusch_cfg_t *cfg, int16_t *q_bits, uint8_t *c_seq,
float beta, uint32_t H_prime_total,
uint32_t O_cqi, srslte_uci_bit_t *ack_bits, uint8_t acks[2], uint32_t nof_acks)
{
int32_t rx_ack = 0;
if (beta < 0) {
fprintf(stderr, "Error beta is reserved\n");
return -1;
}
uint32_t Qprime = Q_prime_ri_ack(cfg, 1, O_cqi, beta);
// Use the same interleaver function to get the HARQ bit position
for (uint32_t i=0;i<Qprime;i++) {
uci_ulsch_interleave_ack_gen(i, cfg->grant.Qm, H_prime_total, cfg->nbits.nof_symb, cfg->cp, &ack_bits[cfg->grant.Qm*i]);
rx_ack += (int32_t) decode_ri_ack(q_bits, c_seq, &ack_bits[cfg->grant.Qm*i]);
}
if (acks) {
acks[0] = rx_ack>0;
}
return (int) Qprime;
}
#else
static void decode_ri_ack(int16_t *q_bits, uint8_t *c_seq, srslte_uci_bit_t *pos, uint32_t Qm, int32_t data[3])
static void decode_ri_ack_2bits(int16_t *q_bits, uint8_t *c_seq, srslte_uci_bit_t *pos, uint32_t Qm, int32_t data[3])
{
uint32_t p0 = pos[Qm * 0 + 0].position;
uint32_t p1 = pos[Qm * 0 + 1].position;
@ -645,118 +638,91 @@ static void decode_ri_ack(int16_t *q_bits, uint8_t *c_seq, srslte_uci_bit_t *pos
data[2] -= q2 + q5;
}
int srslte_uci_decode_ack(srslte_pusch_cfg_t *cfg, int16_t *q_bits, uint8_t *c_seq,
float beta, uint32_t H_prime_total,
uint32_t O_cqi, srslte_uci_bit_t *ack_bits, uint8_t acks[2], uint32_t nof_acks)
{
int32_t acks_sum[3] = {0, 0, 0};
/* Encode UCI ACK/RI bits as described in 5.2.2.6 of 36.212
* Currently only supporting 1-bit RI
*/
int srslte_uci_encode_ack_ri(srslte_pusch_cfg_t *cfg,
uint8_t *data, uint32_t data_len,
uint32_t O_cqi, float beta, uint32_t H_prime_total,
srslte_uci_bit_t *bits, bool ack_ri) {
if (beta < 0) {
fprintf(stderr, "Error beta is reserved\n");
return -1;
return -1;
}
uint32_t Qprime = Q_prime_ri_ack(cfg, data_len, O_cqi, beta);
srslte_uci_bit_type_t q_encoded_bits[18];
uint32_t Qprime = Q_prime_ri_ack(cfg, nof_acks, O_cqi, beta);
uint32_t nof_encoded_bits = encode_ri_ack(data, data_len, q_encoded_bits, cfg->grant.Qm);
// Use the same interleaver function to get the HARQ bit position
for (uint32_t i = 0; i < Qprime; i++) {
uci_ulsch_interleave_ack_gen(i, cfg->grant.Qm, H_prime_total, cfg->nbits.nof_symb, cfg->cp, &ack_bits[cfg->grant.Qm*i]);
if ((i % 3 == 0) && i > 0) {
decode_ri_ack(q_bits, &c_seq[0], &ack_bits[cfg->grant.Qm*(i-3)], cfg->grant.Qm, acks_sum);
if (ack_ri) {
uci_ulsch_interleave_ri_gen(i,
cfg->grant.Qm,
H_prime_total,
cfg->nbits.nof_symb,
cfg->cp,
&bits[cfg->grant.Qm * i]);
} else {
uci_ulsch_interleave_ack_gen(i,
cfg->grant.Qm,
H_prime_total,
cfg->nbits.nof_symb,
cfg->cp,
&bits[cfg->grant.Qm * i]);
}
uci_ulsch_interleave_put(&q_encoded_bits[(i * cfg->grant.Qm) % nof_encoded_bits],
cfg->grant.Qm,
&bits[cfg->grant.Qm * i]);
}
if (acks) {
acks[0] = (uint8_t)(acks_sum[0] > 0);
acks[1] = (uint8_t)(acks_sum[1] > 0);
// TODO: Do something with acks_sum[2]
}
return (int) Qprime;
}
#endif
/* Encode UCI HARQ/ACK bits as described in 5.2.2.6 of 36.212
* Currently only supporting 1-bit HARQ
*/
int srslte_uci_encode_ack(srslte_pusch_cfg_t *cfg, uint8_t acks[2], uint32_t nof_acks,
uint32_t O_cqi, float beta, uint32_t H_prime_total,
srslte_uci_bit_t *ack_bits)
{
if (beta < 0) {
fprintf(stderr, "Error beta is reserved\n");
return -1;
}
uint32_t Qprime = Q_prime_ri_ack(cfg, nof_acks, O_cqi, beta);
srslte_uci_bit_type_t q_encoded_bits[18];
uint32_t nof_encoded_bits = encode_ri_ack(acks, nof_acks, q_encoded_bits, cfg->grant.Qm);
for (uint32_t i=0;i<Qprime;i++) {
uci_ulsch_interleave_ack_gen(i, cfg->grant.Qm, H_prime_total, cfg->nbits.nof_symb, cfg->cp, &ack_bits[cfg->grant.Qm*i]);
uci_ulsch_interleave_put(&q_encoded_bits[(i*cfg->grant.Qm)%nof_encoded_bits], cfg->grant.Qm, &ack_bits[cfg->grant.Qm*i]);
}
return (int) Qprime;
}
/* Encode UCI RI bits as described in 5.2.2.6 of 36.212
/* Decode UCI ACK/RI bits as described in 5.2.2.6 of 36.212
* Currently only supporting 1-bit RI
*/
int srslte_uci_decode_ri(srslte_pusch_cfg_t *cfg, int16_t *q_bits, uint8_t *c_seq,
float beta, uint32_t H_prime_total,
uint32_t O_cqi, srslte_uci_bit_t *ri_bits, uint8_t *data)
int srslte_uci_decode_ack_ri(srslte_pusch_cfg_t *cfg, int16_t *q_bits, uint8_t *c_seq,
float beta, uint32_t H_prime_total,
uint32_t O_cqi, srslte_uci_bit_t *ack_ri_bits, uint8_t data[2], uint32_t nof_bits, bool is_ri)
{
int32_t ri_sum[3] = {0, 0, 0};
int32_t sum[3] = {0, 0, 0};
if (beta < 0) {
fprintf(stderr, "Error beta is reserved\n");
return -1;
return -1;
}
uint32_t Qprime = Q_prime_ri_ack(cfg, 1, O_cqi, beta);
uint32_t Qprime = Q_prime_ri_ack(cfg, nof_bits, O_cqi, beta);
// Use the same interleaver function to get the HARQ bit position
for (uint32_t i=0;i<Qprime;i++) {
uci_ulsch_interleave_ri_gen(i, cfg->grant.Qm, H_prime_total, cfg->nbits.nof_symb, cfg->cp, &ri_bits[cfg->grant.Qm*i]);
if ((i % 3 == 0) && i > 0) {
//decode_ri_ack(q_bits, &c_seq[0], &ri_bits[cfg->grant.Qm*(i-3)], cfg->grant.Qm, ri_sum);
for (uint32_t i = 0; i < Qprime; i++) {
if (is_ri) {
uci_ulsch_interleave_ri_gen(i,
cfg->grant.Qm,
H_prime_total,
cfg->nbits.nof_symb,
cfg->cp,
&ack_ri_bits[cfg->grant.Qm * i]);
} else {
uci_ulsch_interleave_ack_gen(i,
cfg->grant.Qm,
H_prime_total,
cfg->nbits.nof_symb,
cfg->cp,
&ack_ri_bits[cfg->grant.Qm * i]);
}
if (nof_bits == 2 && (i % 3 == 0) && i > 0) {
decode_ri_ack_2bits(q_bits, &c_seq[0], &ack_ri_bits[cfg->grant.Qm * (i - 3)], cfg->grant.Qm, sum);
} else if (nof_bits == 1) {
sum[0] += (int32_t) decode_ri_ack_1bit(q_bits, c_seq, &ack_ri_bits[cfg->grant.Qm * i]);
}
}
if (data) {
*data = (uint8_t) ((ri_sum[0] + ri_sum[1] + ri_sum[2]) > 0);
data[0] = (uint8_t) (sum[0] > 0);
if (nof_bits == 2) {
data[1] = (uint8_t) (sum[1] > 0);
}
return (int) Qprime;
}
/* Encode UCI RI bits as described in 5.2.2.6 of 36.212
* Currently only supporting 1-bit RI
*/
int srslte_uci_encode_ri(srslte_pusch_cfg_t *cfg,
uint8_t ri,
uint32_t O_cqi, float beta, uint32_t H_prime_total,
srslte_uci_bit_t *ri_bits)
{
// FIXME: It supports RI of 1 bit only
uint8_t data[2] = {ri, 0};
if (beta < 0) {
fprintf(stderr, "Error beta is reserved\n");
return -1;
}
uint32_t Qprime = Q_prime_ri_ack(cfg, 1, O_cqi, beta);
srslte_uci_bit_type_t q_encoded_bits[18];
uint32_t nof_encoded_bits = encode_ri_ack(data, 1, q_encoded_bits, cfg->grant.Qm);
for (uint32_t i=0;i<Qprime;i++) {
uci_ulsch_interleave_ri_gen(i, cfg->grant.Qm, H_prime_total, cfg->nbits.nof_symb, cfg->cp, &ri_bits[cfg->grant.Qm*i]);
uci_ulsch_interleave_put(&q_encoded_bits[(i*cfg->grant.Qm)%nof_encoded_bits], cfg->grant.Qm, &ri_bits[cfg->grant.Qm*i]);
}
return (int) Qprime;
}

View File

@ -725,7 +725,8 @@ int srslte_ue_dl_ri_pmi_select(srslte_ue_dl_t *q, uint8_t *ri, uint8_t *pmi, flo
/* Select the best Rank indicator (RI) and Precoding Matrix Indicator (PMI) */
for (uint32_t nof_layers = 1; nof_layers <= SRSLTE_MAX_LAYERS; nof_layers++) {
float _sinr = q->sinr[nof_layers - 1][q->pmi[nof_layers - 1]] * nof_layers * nof_layers;
if (_sinr > best_sinr + 0.1) {
/* Find best SINR, force maximum number of layers if SNR is higher than 30 dB */
if (_sinr > best_sinr + 0.1 || _sinr > 1.0e+3) {
best_sinr = _sinr;
best_pmi = (uint8_t) q->pmi[nof_layers - 1];
best_ri = (uint8_t) (nof_layers - 1);

View File

@ -88,16 +88,19 @@ void phch_worker::init(phch_common* phy_, srslte::log *log_h_)
pthread_mutex_init(&mutex, NULL);
// Init cell here
signal_buffer_rx = (cf_t*) srslte_vec_malloc(2*SRSLTE_SF_LEN_PRB(phy->cell.nof_prb)*sizeof(cf_t));
if (!signal_buffer_rx) {
fprintf(stderr, "Error allocating memory\n");
return;
}
bzero(&signal_buffer_tx, sizeof(cf_t *) * SRSLTE_MAX_PORTS);
signal_buffer_tx[0] = (cf_t*) srslte_vec_malloc(2*SRSLTE_SF_LEN_PRB(phy->cell.nof_prb)*sizeof(cf_t));
if (!signal_buffer_tx[0]) {
fprintf(stderr, "Error allocating memory\n");
return;
for(int p = 0; p < SRSLTE_MAX_PORTS; p++) {
signal_buffer_rx[p] = (cf_t *) srslte_vec_malloc(2 * SRSLTE_SF_LEN_PRB(phy->cell.nof_prb) * sizeof(cf_t));
if (!signal_buffer_rx[p]) {
fprintf(stderr, "Error allocating memory\n");
return;
}
bzero(signal_buffer_rx[p], 2 * SRSLTE_SF_LEN_PRB(phy->cell.nof_prb) * sizeof(cf_t));
signal_buffer_tx[p] = (cf_t *) srslte_vec_malloc(2 * SRSLTE_SF_LEN_PRB(phy->cell.nof_prb) * sizeof(cf_t));
if (!signal_buffer_tx[p]) {
fprintf(stderr, "Error allocating memory\n");
return;
}
bzero(signal_buffer_tx[p], 2 * SRSLTE_SF_LEN_PRB(phy->cell.nof_prb) * sizeof(cf_t));
}
if (srslte_enb_dl_init(&enb_dl, signal_buffer_tx, phy->cell.nof_prb)) {
fprintf(stderr, "Error initiating ENB DL\n");
@ -107,7 +110,7 @@ void phch_worker::init(phch_common* phy_, srslte::log *log_h_)
fprintf(stderr, "Error initiating ENB DL\n");
return;
}
if (srslte_enb_ul_init(&enb_ul, signal_buffer_rx, phy->cell.nof_prb)) {
if (srslte_enb_ul_init(&enb_ul, signal_buffer_rx[0], phy->cell.nof_prb)) {
fprintf(stderr, "Error initiating ENB UL\n");
return;
}
@ -154,12 +157,12 @@ void phch_worker::stop()
srslte_enb_dl_free(&enb_dl);
srslte_enb_ul_free(&enb_ul);
if (signal_buffer_rx) {
free(signal_buffer_rx);
}
for (int i = 0; i < SRSLTE_MAX_PORTS; i++) {
if (signal_buffer_tx[i]) {
free(signal_buffer_tx[i]);
for (int p = 0; p < SRSLTE_MAX_PORTS; p++) {
if (signal_buffer_rx[p]) {
free(signal_buffer_rx[p]);
}
if (signal_buffer_tx[p]) {
free(signal_buffer_tx[p]);
}
}
pthread_mutex_unlock(&mutex);
@ -171,9 +174,9 @@ void phch_worker::reset()
ue_db.clear();
}
cf_t* phch_worker::get_buffer_rx()
cf_t* phch_worker::get_buffer_rx(uint32_t antenna_idx)
{
return signal_buffer_rx;
return signal_buffer_rx[antenna_idx];
}
void phch_worker::set_time(uint32_t tti_, uint32_t tx_mutex_cnt_, srslte_timestamp_t tx_time_)
@ -214,12 +217,29 @@ uint32_t phch_worker::get_nof_rnti() {
return ue_db.size();
}
void phch_worker::set_conf_dedicated_ack(uint16_t rnti, bool ack){
pthread_mutex_lock(&mutex);
if (ue_db.count(rnti)) {
ue_db[rnti].dedicated_ack = ack;
} else {
Error("Setting dedicated ack: rnti=0x%x does not exist\n");
}
pthread_mutex_unlock(&mutex);
}
void phch_worker::set_config_dedicated(uint16_t rnti,
srslte_uci_cfg_t *uci_cfg,
srslte_pucch_sched_t *pucch_sched,
srslte_refsignal_srs_cfg_t *srs_cfg,
uint32_t I_sr, bool pucch_cqi, uint32_t pmi_idx, bool pucch_cqi_ack)
srslte_refsignal_srs_cfg_t *srs_cfg,
LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT* dedicated)
{
uint32_t I_sr = dedicated->sched_request_cnfg.sr_cnfg_idx;
bool pucch_cqi = dedicated->cqi_report_cnfg.report_periodic_setup_present;
uint32_t pmi_idx = dedicated->cqi_report_cnfg.report_periodic.pmi_cnfg_idx;
bool pucch_cqi_ack = dedicated->cqi_report_cnfg.report_periodic.simult_ack_nack_and_cqi;
bool pucch_ri = dedicated->cqi_report_cnfg.report_periodic.ri_cnfg_idx_present;
uint32_t ri_idx = dedicated->cqi_report_cnfg.report_periodic.ri_cnfg_idx;
pthread_mutex_lock(&mutex);
if (ue_db.count(rnti)) {
pucch_sched->N_pucch_1 = phy->pucch_cfg.n1_pucch_an;
@ -237,6 +257,16 @@ void phch_worker::set_config_dedicated(uint16_t rnti,
ue_db[rnti].cqi_en = false;
}
if (pucch_ri) {
ue_db[rnti].ri_idx = ri_idx;
ue_db[rnti].ri_en = true;
} else {
ue_db[rnti].ri_idx = 0;
ue_db[rnti].ri_en = false;
}
/* Copy all dedicated RRC configuration to UE */
memcpy(&ue_db[rnti].dedicated, dedicated, sizeof(LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT));
} else {
Error("Setting config dedicated: rnti=0x%x does not exist\n");
}
@ -278,7 +308,7 @@ void phch_worker::work_imp()
}
pthread_mutex_lock(&mutex);
mac_interface_phy::ul_sched_t *ul_grants = phy->ul_grants;
mac_interface_phy::dl_sched_t *dl_grants = phy->dl_grants;
mac_interface_phy *mac = phy->mac;
@ -293,7 +323,7 @@ void phch_worker::work_imp()
}
// Process UL signal
srslte_enb_ul_fft(&enb_ul, signal_buffer_rx);
srslte_enb_ul_fft(&enb_ul);
// Decode pending UL grants for the tti they were scheduled
decode_pusch(ul_grants[t_rx].sched_grants, ul_grants[t_rx].nof_grants);
@ -335,15 +365,22 @@ void phch_worker::work_imp()
phy->ack_clear(TTIMOD(TTI_TX(t_tx_dl)));
for (uint32_t i=0;i<dl_grants[t_tx_dl].nof_grants;i++) {
// SI-RNTI and RAR-RNTI do not have ACK
if (dl_grants[t_tx_dl].sched_grants[i].rnti >= SRSLTE_CRNTI_START && dl_grants[t_tx_dl].sched_grants[i].rnti <= SRSLTE_CRNTI_END) {
phy->ack_set_pending(TTIMOD(TTI_TX(t_tx_dl)), dl_grants[t_tx_dl].sched_grants[i].rnti, dl_grants[t_tx_dl].sched_grants[i].location.ncce);
uint16_t rnti = dl_grants[t_tx_dl].sched_grants[i].rnti;
if (rnti >= SRSLTE_CRNTI_START && rnti <= SRSLTE_CRNTI_END) {
/* For each TB */
for (uint32_t tb_idx = 0; tb_idx < SRSLTE_MAX_TB; tb_idx++) {
/* If TB enabled, set pending ACK */
if (dl_grants[t_tx_dl].sched_grants[i].grant.tb_en[tb_idx]) {
phy->ack_set_pending(TTIMOD(TTI_TX(t_tx_dl)), rnti, tb_idx, dl_grants[t_tx_dl].sched_grants[i].location.ncce);
}
}
}
}
// Generate signal and transmit
srslte_enb_dl_gen_signal(&enb_dl);
Debug("Sending to radio\n");
phy->worker_end(tx_mutex_cnt, signal_buffer_tx[0], SRSLTE_SF_LEN_PRB(phy->cell.nof_prb), tx_time);
phy->worker_end(tx_mutex_cnt, signal_buffer_tx, SRSLTE_SF_LEN_PRB(phy->cell.nof_prb), tx_time);
#ifdef DEBUG_WRITE_FILE
fwrite(signal_buffer_tx, SRSLTE_SF_LEN_PRB(phy->cell.nof_prb)*sizeof(cf_t), 1, f);
@ -387,24 +424,39 @@ int phch_worker::decode_pusch(srslte_enb_ul_pusch_t *grants, uint32_t nof_pusch)
gettimeofday(&t[1], NULL);
#endif
bool acks_pending[SRSLTE_MAX_TB] = {false};
// Get pending ACKs with an associated PUSCH transmission
if (phy->ack_is_pending(t_rx, rnti)) {
uci_data.uci_ack_len = 1;
for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) {
acks_pending[tb] = phy->ack_is_pending(t_rx, rnti, tb);
if (acks_pending[tb]) {
uci_data.uci_ack_len++;
}
}
// Configure PUSCH CQI channel
srslte_cqi_value_t cqi_value;
srslte_cqi_value_t cqi_value = {0};
bool cqi_enabled = false;
if (ue_db[rnti].cqi_en && srslte_cqi_send(ue_db[rnti].pmi_idx, tti_rx)) {
#if 0
if (ue_db[rnti].cqi_en && ue_db[rnti].ri_en && srslte_ri_send(ue_db[rnti].pmi_idx, ue_db[rnti].ri_idx, tti_rx) ) {
uci_data.uci_ri_len = 1; /* Asumes only 1 bit for RI */
ri_enabled = true;
} else if (ue_db[rnti].cqi_en && srslte_cqi_send(ue_db[rnti].pmi_idx, tti_rx)) {
cqi_value.type = SRSLTE_CQI_TYPE_WIDEBAND;
cqi_enabled = true;
} else if (grants[i].grant.cqi_request) {
if (ue_db[rnti].dedicated.antenna_info_explicit_value.tx_mode == LIBLTE_RRC_TRANSMISSION_MODE_4) {
//uci_data.uci_dif_cqi_len = 3;
uci_data.uci_pmi_len = 2;
}
} else
#endif
if (grants[i].grant.cqi_request) {
cqi_value.type = SRSLTE_CQI_TYPE_SUBBAND_HL;
cqi_value.subband_hl.N = (phy->cell.nof_prb > 7) ? srslte_cqi_hl_get_no_subbands(phy->cell.nof_prb) : 0;
cqi_value.subband_hl.four_antenna_ports = (phy->cell.nof_ports == 4);
cqi_value.subband_hl.pmi_present = (ue_db[rnti].dedicated.cqi_report_cnfg.report_mode_aperiodic == LIBLTE_RRC_CQI_REPORT_MODE_APERIODIC_RM31);
cqi_enabled = true;
}
if (cqi_enabled) {
uci_data.uci_cqi_len = srslte_cqi_size(&cqi_value);
}
// mark this tti as having an ul grant to avoid pucch
ue_db[rnti].has_grant_tti = tti_rx;
@ -412,22 +464,6 @@ int phch_worker::decode_pusch(srslte_enb_ul_pusch_t *grants, uint32_t nof_pusch)
srslte_ra_ul_grant_t phy_grant;
int res = -1;
if (!srslte_ra_ul_dci_to_grant(&grants[i].grant, enb_ul.cell.nof_prb, n_rb_ho, &phy_grant)) {
// Handle Format0 adaptive retx
// Use last TBS for this TB in case of mcs>28
if (phy_grant.mcs.idx > 28) {
phy_grant.mcs.tbs = ue_db[rnti].last_ul_tbs[TTI_RX(tti_rx)%(2*HARQ_DELAY_MS)];
Info("RETX: mcs=%d, old_tbs=%d pid=%d\n", phy_grant.mcs.idx, phy_grant.mcs.tbs, TTI_TX(tti_rx)%(2*HARQ_DELAY_MS));
}
ue_db[rnti].last_ul_tbs[TTI_RX(tti_rx)%(2*HARQ_DELAY_MS)] = phy_grant.mcs.tbs;
if (phy_grant.mcs.mod == SRSLTE_MOD_LAST) {
phy_grant.mcs.mod = ue_db[rnti].last_ul_mod[TTI_RX(tti_rx)%(2*HARQ_DELAY_MS)];
phy_grant.Qm = srslte_mod_bits_x_symbol(phy_grant.mcs.mod);
}
ue_db[rnti].last_ul_mod[TTI_RX(tti_rx)%(2*HARQ_DELAY_MS)] = phy_grant.mcs.mod;
if (phy_grant.mcs.mod == SRSLTE_MOD_64QAM) {
phy_grant.mcs.mod = SRSLTE_MOD_16QAM;
}
@ -436,6 +472,7 @@ int phch_worker::decode_pusch(srslte_enb_ul_pusch_t *grants, uint32_t nof_pusch)
rnti, grants[i].rv_idx,
grants[i].current_tx_nb,
grants[i].data,
(cqi_enabled) ? &cqi_value : NULL,
&uci_data,
sf_rx);
} else {
@ -457,11 +494,24 @@ int phch_worker::decode_pusch(srslte_enb_ul_pusch_t *grants, uint32_t nof_pusch)
char cqi_str[64];
if (cqi_enabled) {
srslte_cqi_value_unpack(uci_data.uci_cqi, &cqi_value);
if (ue_db[rnti].cqi_en) {
wideband_cqi_value = cqi_value.wideband.wideband_cqi;
} else if (grants[i].grant.cqi_request) {
wideband_cqi_value = cqi_value.subband_hl.wideband_cqi_cw0;
if (cqi_value.subband_hl.pmi_present) {
if (cqi_value.subband_hl.rank_is_not_one) {
Info("PUSCH: Aperiodic ri~1, CQI=%02d/%02d, pmi=%d for %d subbands\n",
cqi_value.subband_hl.wideband_cqi_cw0, cqi_value.subband_hl.wideband_cqi_cw1,
cqi_value.subband_hl.pmi, cqi_value.subband_hl.N);
} else {
Info("PUSCH: Aperiodic ri=1, CQI=%02d, pmi=%d for %d subbands\n",
cqi_value.subband_hl.wideband_cqi_cw0, cqi_value.subband_hl.pmi, cqi_value.subband_hl.N);
}
} else {
Info("PUSCH: Aperiodic ri%s, CQI=%02d for %d subbands\n",
cqi_value.subband_hl.rank_is_not_one?"~1":"=1",
cqi_value.subband_hl.wideband_cqi_cw0, cqi_value.subband_hl.N);
}
}
snprintf(cqi_str, 64, ", cqi=%d", wideband_cqi_value);
}
@ -481,14 +531,16 @@ int phch_worker::decode_pusch(srslte_enb_ul_pusch_t *grants, uint32_t nof_pusch)
}
*/
log_h->info_hex(grants[i].data, phy_grant.mcs.tbs/8,
"PUSCH: rnti=0x%x, prb=(%d,%d), tbs=%d, mcs=%d, rv=%d, snr=%.1f dB, n_iter=%d, crc=%s%s%s%s\n",
"PUSCH: rnti=0x%x, prb=(%d,%d), tbs=%d, mcs=%d, rv=%d, snr=%.1f dB, n_iter=%d, crc=%s%s%s%s%s\n",
rnti, phy_grant.n_prb[0], phy_grant.n_prb[0]+phy_grant.L_prb,
phy_grant.mcs.tbs/8, phy_grant.mcs.idx, grants[i].grant.rv_idx,
snr_db,
srslte_pusch_last_noi(&enb_ul.pusch),
crc_res?"OK":"KO",
uci_data.uci_ack_len>0?(uci_data.uci_ack?", ack=1":", ack=0"):"",
(uci_data.uci_ack_len)?(uci_data.uci_ack?"1":"0"):"",
(uci_data.uci_ack_len > 1)?(uci_data.uci_ack_2?"1":"0"):"",
uci_data.uci_cqi_len>0?cqi_str:"",
uci_data.uci_ri_len>0?(uci_data.uci_ri?", ri=0":", ri=1"):"",
timestr);
// Notify MAC of RL status
@ -503,17 +555,28 @@ int phch_worker::decode_pusch(srslte_enb_ul_pusch_t *grants, uint32_t nof_pusch)
// Notify MAC new received data and HARQ Indication value
phy->mac->crc_info(tti_rx, rnti, phy_grant.mcs.tbs/8, crc_res);
if (uci_data.uci_ack_len) {
phy->mac->ack_info(tti_rx, rnti, uci_data.uci_ack && (crc_res || snr_db > PUSCH_RL_SNR_DB_TH));
uint32_t ack_idx = 0;
for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) {
if (acks_pending[tb]) {
bool ack = ((ack_idx++ == 0) ? uci_data.uci_ack : uci_data.uci_ack_2);
bool valid = (crc_res || snr_db > PUSCH_RL_SNR_DB_TH);
phy->mac->ack_info(tti_rx, rnti, tb, ack && valid);
}
}
// Notify MAC of UL SNR and DL CQI
// Notify MAC of UL SNR, DL CQI and DL RI
if (snr_db >= PUSCH_RL_SNR_DB_TH) {
phy->mac->snr_info(tti_rx, rnti, snr_db);
}
if (uci_data.uci_cqi_len>0 && crc_res) {
phy->mac->cqi_info(tti_rx, rnti, wideband_cqi_value);
}
if (uci_data.uci_ri_len > 0 && crc_res) {
phy->mac->ri_info(tti_rx, rnti, uci_data.uci_ri);
}
if (cqi_value.subband_hl.pmi_present && crc_res) {
phy->mac->pmi_info(tti_rx, rnti, cqi_value.subband_hl.pmi);
}
// Save metrics stats
ue_db[rnti].metrics_ul(phy_grant.mcs.idx, 0, snr_db, srslte_pusch_last_noi(&enb_ul.pusch));
@ -532,7 +595,8 @@ int phch_worker::decode_pucch()
if (rnti >= SRSLTE_CRNTI_START && rnti <= SRSLTE_CRNTI_END && ue_db[rnti].has_grant_tti != (int) tti_rx) {
// Check if user needs to receive PUCCH
bool needs_pucch = false, needs_ack=false, needs_sr=false, needs_cqi=false;
bool needs_pucch = false, needs_ack[SRSLTE_MAX_TB] = {false}, needs_sr = false, needs_cqi = false,
needs_ri = false;
uint32_t last_n_pdcch = 0;
bzero(&uci_data, sizeof(srslte_uci_data_t));
@ -544,18 +608,32 @@ int phch_worker::decode_pucch()
}
}
if (phy->ack_is_pending(t_rx, rnti, &last_n_pdcch)) {
needs_pucch = true;
needs_ack = true;
uci_data.uci_ack_len = 1;
for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) {
needs_ack[tb] = phy->ack_is_pending(t_rx, rnti, tb, &last_n_pdcch);
if (needs_ack[tb]) {
needs_pucch = true;
uci_data.uci_ack_len++;
}
}
srslte_cqi_value_t cqi_value;
if (ue_db[rnti].cqi_en && (ue_db[rnti].pucch_cqi_ack || !needs_ack)) {
if (srslte_cqi_send(ue_db[rnti].pmi_idx, tti_rx)) {
LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT *dedicated = &ue_db[rnti].dedicated;
LIBLTE_RRC_TRANSMISSION_MODE_ENUM tx_mode = dedicated->antenna_info_explicit_value.tx_mode;
if (ue_db[rnti].cqi_en && (ue_db[rnti].pucch_cqi_ack || !needs_ack[0] || !needs_ack[1])) {
if (ue_db[rnti].ri_en && srslte_ri_send(ue_db[rnti].pmi_idx, ue_db[rnti].ri_idx, tti_rx)) {
needs_pucch = true;
needs_ri = true;
uci_data.uci_ri_len = 1;
uci_data.ri_periodic_report = true;
} else if (srslte_cqi_send(ue_db[rnti].pmi_idx, tti_rx)) {
needs_pucch = true;
needs_cqi = true;
cqi_value.type = SRSLTE_CQI_TYPE_WIDEBAND;
uci_data.uci_cqi_len = srslte_cqi_size(&cqi_value);
if (tx_mode == LIBLTE_RRC_TRANSMISSION_MODE_4) {
//uci_data.uci_dif_cqi_len = 3;
uci_data.uci_pmi_len = 2;
}
}
}
@ -564,26 +642,48 @@ int phch_worker::decode_pucch()
fprintf(stderr, "Error getting PUCCH\n");
return SRSLTE_ERROR;
}
if (uci_data.uci_ack_len > 0) {
phy->mac->ack_info(tti_rx, rnti, uci_data.uci_ack && (srslte_pucch_get_last_corr(&enb_ul.pucch) >= PUCCH_RL_CORR_TH));
/* 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 (needs_ack[tb]) {
bool ack = ((ack_idx++ == 0) ? uci_data.uci_ack : uci_data.uci_ack_2);
bool valid = srslte_pucch_get_last_corr(&enb_ul.pucch) >= PUCCH_RL_CORR_TH;
phy->mac->ack_info(tti_rx, rnti, tb, ack && valid);
}
}
if (uci_data.scheduling_request) {
phy->mac->sr_detected(tti_rx, rnti);
}
char cqi_ri_str[64];
if (srslte_pucch_get_last_corr(&enb_ul.pucch) > PUCCH_RL_CORR_TH) {
if (uci_data.uci_ri_len && needs_ri) {
phy->mac->ri_info(tti_rx, rnti, uci_data.uci_ri);
sprintf(cqi_ri_str, ", ri=%d", uci_data.uci_ri);
} else if (uci_data.uci_cqi_len && needs_cqi) {
srslte_cqi_value_unpack(uci_data.uci_cqi, &cqi_value);
phy->mac->cqi_info(tti_rx, rnti, cqi_value.wideband.wideband_cqi);
sprintf(cqi_ri_str, ", cqi=%d", cqi_value.wideband.wideband_cqi);
char cqi_str[64];
if (uci_data.uci_cqi_len) {
srslte_cqi_value_unpack(uci_data.uci_cqi, &cqi_value);
phy->mac->cqi_info(tti_rx, rnti, cqi_value.wideband.wideband_cqi);
sprintf(cqi_str, ", cqi=%d", cqi_value.wideband.wideband_cqi);
if (uci_data.uci_pmi_len) {
uint32_t packed_pmi = uci_data.uci_pmi[0];
if (uci_data.uci_pmi_len > 1) {
packed_pmi = (packed_pmi << 1) + uci_data.uci_pmi[1];
}
phy->mac->pmi_info(tti_rx, rnti, packed_pmi);
sprintf(cqi_ri_str, "%s, pmi=%c", cqi_ri_str, packed_pmi + 0x30);
}
}
}
log_h->info("PUCCH: rnti=0x%x, corr=%.2f, n_pucch=%d, n_prb=%d%s%s%s\n",
log_h->info("PUCCH: rnti=0x%x, corr=%.2f, n_pucch=%d, n_prb=%d%s%s%s%s\n",
rnti,
srslte_pucch_get_last_corr(&enb_ul.pucch),
enb_ul.pucch.last_n_pucch, enb_ul.pucch.last_n_prb,
needs_ack?(uci_data.uci_ack?", ack=1":", ack=0"):"",
(uci_data.uci_ack_len)?(uci_data.uci_ack?", ack=1":", ack=0"):"",
(uci_data.uci_ack_len > 1)?(uci_data.uci_ack_2?"1":"0"):"",
needs_sr?(uci_data.scheduling_request?", sr=yes":", sr=no"):"",
needs_cqi?cqi_str:"");
(needs_cqi || needs_ri)?cqi_ri_str:"");
// Notify MAC of RL status
@ -642,25 +742,16 @@ int phch_worker::encode_pdcch_ul(srslte_enb_ul_pusch_t *grants, uint32_t nof_gra
int phch_worker::encode_pdcch_dl(srslte_enb_dl_pdsch_t *grants, uint32_t nof_grants)
{
for (uint32_t i=0;i<nof_grants;i++) {
uint16_t rnti = grants[i].rnti;
srslte_enb_dl_pdsch_t *grant = &grants[i];
uint16_t rnti = grant->rnti;
if (rnti) {
srslte_dci_format_t format = SRSLTE_DCI_FORMAT1;
switch(grants[i].grant.alloc_type) {
case SRSLTE_RA_ALLOC_TYPE0:
case SRSLTE_RA_ALLOC_TYPE1:
format = SRSLTE_DCI_FORMAT1;
break;
case SRSLTE_RA_ALLOC_TYPE2:
format = SRSLTE_DCI_FORMAT1A;
break;
}
if (srslte_enb_dl_put_pdcch_dl(&enb_dl, &grants[i].grant, format, grants[i].location, rnti, sf_tx)) {
if (srslte_enb_dl_put_pdcch_dl(&enb_dl, &grants[i].grant, grant->dci_format, grants[i].location, rnti, sf_tx)) {
fprintf(stderr, "Error putting PDCCH %d\n",i);
return SRSLTE_ERROR;
}
if (LOG_THIS(rnti)) {
Info("PDCCH: DL DCI %s rnti=0x%x, cce_index=%d, L=%d, tti_tx_dl=%d\n", srslte_dci_format_string(format),
Info("PDCCH: DL DCI %s rnti=0x%x, cce_index=%d, L=%d, tti_tx_dl=%d\n", srslte_dci_format_string(grant->dci_format),
rnti, grants[i].location.ncce, (1<<grants[i].location.L), tti_tx_dl);
}
}
@ -668,9 +759,8 @@ int phch_worker::encode_pdcch_dl(srslte_enb_dl_pdsch_t *grants, uint32_t nof_gra
return 0;
}
int phch_worker::encode_pdsch(srslte_enb_dl_pdsch_t *grants, uint32_t nof_grants)
{
for (uint32_t i=0;i<nof_grants;i++) {
int phch_worker::encode_pdsch(srslte_enb_dl_pdsch_t *grants, uint32_t nof_grants) {
for (uint32_t i = 0; i < nof_grants; i++) {
uint16_t rnti = grants[i].rnti;
if (rnti) {
@ -678,53 +768,103 @@ int phch_worker::encode_pdsch(srslte_enb_dl_pdsch_t *grants, uint32_t nof_grants
if (rnti == SRSLTE_SIRNTI || rnti == SRSLTE_PRNTI || rnti == SRSLTE_MRNTI) {
rnti_is_user = false;
}
/* Mimo type (tx scheme) shall be single or tx diversity by default */
srslte_mimo_type_t mimo_type = (enb_dl.cell.nof_ports == 1) ? SRSLTE_MIMO_TYPE_SINGLE_ANTENNA
: SRSLTE_MIMO_TYPE_TX_DIVERSITY;
srslte_ra_dl_grant_t phy_grant;
srslte_ra_dl_dci_to_grant(&grants[i].grant, enb_dl.cell.nof_prb, rnti, &phy_grant);
char grant_str[64];
switch(grants[i].grant.alloc_type) {
switch (grants[i].grant.alloc_type) {
case SRSLTE_RA_ALLOC_TYPE0:
sprintf(grant_str, "mask=0x%x",grants[i].grant.type0_alloc.rbg_bitmask);
break;
sprintf(grant_str, "mask=0x%x", grants[i].grant.type0_alloc.rbg_bitmask);
break;
case SRSLTE_RA_ALLOC_TYPE1:
sprintf(grant_str, "mask=0x%x",grants[i].grant.type1_alloc.vrb_bitmask);
break;
sprintf(grant_str, "mask=0x%x", grants[i].grant.type1_alloc.vrb_bitmask);
break;
default:
sprintf(grant_str, "rb_start=%d",grants[i].grant.type2_alloc.RB_start);
break;
sprintf(grant_str, "rb_start=%d", grants[i].grant.type2_alloc.RB_start);
break;
}
srslte_dci_format_t dci_format = grants[i].dci_format;
switch (dci_format) {
case SRSLTE_DCI_FORMAT1:
case SRSLTE_DCI_FORMAT1A:
/* Do nothing, it keeps default */
break;
case SRSLTE_DCI_FORMAT2A:
if (SRSLTE_RA_DL_GRANT_NOF_TB(&phy_grant) == 1) {
mimo_type = SRSLTE_MIMO_TYPE_TX_DIVERSITY;
} else if (SRSLTE_RA_DL_GRANT_NOF_TB(&phy_grant) == 2) {
mimo_type = SRSLTE_MIMO_TYPE_CDD;
}
break;
case SRSLTE_DCI_FORMAT2:
if (SRSLTE_RA_DL_GRANT_NOF_TB(&phy_grant) == 1) {
if (phy_grant.pinfo == 0) {
mimo_type = SRSLTE_MIMO_TYPE_TX_DIVERSITY;
} else {
mimo_type = SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX;
}
} else if (SRSLTE_RA_DL_GRANT_NOF_TB(&phy_grant) == 2) {
mimo_type = SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX;
}
break;
case SRSLTE_DCI_FORMAT0:
case SRSLTE_DCI_FORMAT1C:
case SRSLTE_DCI_FORMAT1B:
case SRSLTE_DCI_FORMAT1D:
case SRSLTE_DCI_FORMAT2B:
default:
Error("Not implemented/Undefined DCI format (%d)\n", dci_format);
}
if (LOG_THIS(rnti)) {
uint8_t x = 0;
uint8_t *ptr = grants[i].data;
uint8_t *ptr = grants[i].data[0];
uint32_t len = phy_grant.mcs[0].tbs / (uint32_t) 8;
if (!ptr) {
ptr = &x;
len = 1;
}
char pinfo_str[16] = {0};
if (dci_format == SRSLTE_DCI_FORMAT2) {
snprintf(pinfo_str, 15, ", pinfo=%x", phy_grant.pinfo);
}
char tbstr[SRSLTE_MAX_TB][128];
for (int tb = 0; tb < SRSLTE_MAX_TB; tb++) {
if (phy_grant.tb_en[tb]) {
snprintf(tbstr[tb], 128, ", TB%d: tbs=%d, mcs=%d, rv=%d%s%s",
tb,
phy_grant.mcs[tb].tbs / 8,
phy_grant.mcs[tb].idx,
(tb == 0) ? grants[i].grant.rv_idx : grants[i].grant.rv_idx_1,
grants[i].softbuffers[tb]==NULL?", \e[31msoftbuffer=NULL\e[0m":"",
grants[i].data[tb]==NULL?", \e[31mdata=NULL\e[0m":"");
} else {
tbstr[tb][0] = '\0';
}
}
log_h->info_hex(ptr, len,
"PDSCH: rnti=0x%x, l_crb=%2d, %s, harq=%d, tbs=%d, mcs=%d, rv=%d, tti_tx_dl=%d\n",
rnti, phy_grant.nof_prb, grant_str, grants[i].grant.harq_process,
phy_grant.mcs[0].tbs/8, phy_grant.mcs[0].idx, grants[i].grant.rv_idx, tti_tx_dl);
"PDSCH: rnti=0x%x, l_crb=%2d, %s, harq=%d, tti_tx_dl=%d, tx_scheme=%s%s%s%s\n",
rnti, phy_grant.nof_prb, grant_str, grants[i].grant.harq_process, tti_tx_dl,
srslte_mimotype2str(mimo_type), pinfo_str, tbstr[0], tbstr[1]);
}
srslte_softbuffer_tx_t *sb[SRSLTE_MAX_CODEWORDS] = {grants[i].softbuffer, NULL};
uint8_t *d[SRSLTE_MAX_CODEWORDS] = {grants[i].data, NULL};
int rv[SRSLTE_MAX_CODEWORDS] = {grants[i].grant.rv_idx, 0};
int rv[SRSLTE_MAX_CODEWORDS] = {grants[i].grant.rv_idx, grants[i].grant.rv_idx_1};
if (srslte_enb_dl_put_pdsch(&enb_dl, &phy_grant, sb, rnti, rv, sf_tx, d, SRSLTE_MIMO_TYPE_SINGLE_ANTENNA, 0))
{
fprintf(stderr, "Error putting PDSCH %d\n",i);
return SRSLTE_ERROR;
if (srslte_enb_dl_put_pdsch(&enb_dl, &phy_grant, grants[i].softbuffers, rnti, rv, sf_tx, grants[i].data, mimo_type)) {
fprintf(stderr, "Error putting PDSCH %d\n", i);
return SRSLTE_ERROR;
}
// Save metrics stats
// Save metrics stats
ue_db[rnti].metrics_dl(phy_grant.mcs[0].idx);
}
}
return SRSLTE_SUCCESS;
return SRSLTE_SUCCESS;
}

View File

@ -1142,7 +1142,11 @@ void rrc::ue::send_connection_setup(bool is_setup)
phy_cfg->cqi_report_cnfg_present = true;
if(parent->cfg.cqi_cfg.mode == RRC_CFG_CQI_MODE_APERIODIC) {
phy_cfg->cqi_report_cnfg.report_mode_aperiodic_present = true;
phy_cfg->cqi_report_cnfg.report_mode_aperiodic = LIBLTE_RRC_CQI_REPORT_MODE_APERIODIC_RM30;
if (phy_cfg->antenna_info_explicit_value.tx_mode == LIBLTE_RRC_TRANSMISSION_MODE_4) {
phy_cfg->cqi_report_cnfg.report_mode_aperiodic = LIBLTE_RRC_CQI_REPORT_MODE_APERIODIC_RM31;
} else {
phy_cfg->cqi_report_cnfg.report_mode_aperiodic = LIBLTE_RRC_CQI_REPORT_MODE_APERIODIC_RM30;
}
} else {
phy_cfg->cqi_report_cnfg.report_periodic_present = true;
phy_cfg->cqi_report_cnfg.report_periodic_setup_present = true;

View File

@ -859,7 +859,9 @@ void phch_worker::set_uci_periodic_cqi()
if (period_cqi.configured && rnti_is_set) {
if (period_cqi.ri_idx_present && srslte_ri_send(period_cqi.pmi_idx, period_cqi.ri_idx, TTI_TX(tti))) {
/* Compute RI, PMI and SINR */
compute_ri();
uci_data.ri_periodic_report = true;
Info("PUCCH: Periodic RI=%d\n", uci_data.uci_ri);
} else if (srslte_cqi_send(period_cqi.pmi_idx, TTI_TX(tti))) {
@ -902,6 +904,9 @@ void phch_worker::set_uci_periodic_cqi()
void phch_worker::set_uci_aperiodic_cqi()
{
if (phy->config->dedicated.cqi_report_cnfg.report_mode_aperiodic_present) {
/* Compute RI, PMI and SINR */
compute_ri();
switch(phy->config->dedicated.cqi_report_cnfg.report_mode_aperiodic) {
case LIBLTE_RRC_CQI_REPORT_MODE_APERIODIC_RM30:
/* only Higher Layer-configured subband feedback support right now, according to TS36.213 section 7.2.1
@ -939,9 +944,6 @@ void phch_worker::set_uci_aperiodic_cqi()
other transmission modes they are reported conditioned on rank 1.
*/
if (rnti_is_set) {
/* Compute RI, PMI and SINR */
compute_ri();
/* Select RI, PMI and SINR */
uint32_t ri = ue_dl.ri; // Select RI (0: 1 layer, 1: 2 layer, otherwise: not implemented)
uint32_t pmi = ue_dl.pmi[ri]; // Select PMI
@ -972,9 +974,9 @@ void phch_worker::set_uci_aperiodic_cqi()
cqi_report.subband_hl.wideband_cqi_cw0, cqi_report.subband_hl.wideband_cqi_cw1,
sinr_db, sinr_db, pmi, cqi_report.subband_hl.N);
} else {
Info("PUSCH: Aperiodic ri=1, CQI=%d/%d, SINR=%2.1f dB, for %d subbands\n",
cqi_report.wideband.wideband_cqi,
phy->avg_snr_db, cqi_report.subband_hl.N);
Info("PUSCH: Aperiodic ri=1, CQI=%02d, SINR=%2.1f, pmi=%d for %d subbands\n",
cqi_report.subband_hl.wideband_cqi_cw0,
sinr_db, pmi, cqi_report.subband_hl.N);
}
uci_data.uci_cqi_len = srslte_cqi_value_pack(&cqi_report, uci_data.uci_cqi);
}