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

master
Xavier Arteaga 7 years ago committed by Ismael Gomez
parent 0bd683b3c4
commit 8ab196901f

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

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

@ -131,31 +131,25 @@ SRSLTE_API int srslte_uci_encode_ack(srslte_pusch_cfg_t *cfg,
uint32_t H_prime_total, uint32_t H_prime_total,
srslte_uci_bit_t *ri_bits); srslte_uci_bit_t *ri_bits);
SRSLTE_API int srslte_uci_decode_ack(srslte_pusch_cfg_t *cfg, SRSLTE_API int srslte_uci_encode_ack_ri(srslte_pusch_cfg_t *cfg,
int16_t *q_bits, uint8_t *data,
uint8_t *c_seq, uint32_t data_len,
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,
uint32_t O_cqi, uint32_t O_cqi,
float beta, float beta,
uint32_t H_prime_total, 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, 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 #endif

@ -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); srslte_ofdm_rx_sf(&q->fft);
} }
int get_pucch(srslte_enb_ul_t *q, uint16_t rnti, int get_pucch(srslte_enb_ul_t *q, uint16_t rnti,
uint32_t pdcch_n_cce, uint32_t sf_rx, 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); 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); 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); 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; 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) { if (ret_val < 0) {
fprintf(stderr,"Error decoding PUCCH\n"); fprintf(stderr,"Error decoding PUCCH\n");
return SRSLTE_ERROR; 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) srslte_uci_data_t *uci_data)
{ {
uint8_t pucch_bits[SRSLTE_PUCCH_MAX_BITS]; 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. // 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 // try again to decode ACK only
if (uci_data->scheduling_request && uci_data->uci_ack_len && ret_val != 1) { if (uci_data->scheduling_request && uci_data->uci_ack_len && ret_val != 1) {
uci_data->scheduling_request = false; 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 // update schedulign request
@ -305,12 +311,32 @@ int srslte_enb_ul_get_pucch(srslte_enb_ul_t *q, uint16_t rnti,
// Save ACK bits // Save ACK bits
if (uci_data->uci_ack_len > 0) { 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() // PUCCH2 CQI bits are decoded inside srslte_pucch_decode()
if (uci_data->uci_cqi_len) { if (uci_data->uci_cqi_len) {
memcpy(uci_data->uci_cqi, pucch_bits, uci_data->uci_cqi_len*sizeof(uint8_t)); 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) { if (uci_data->uci_ack_len >= 1) {
uci_data->uci_ack = pucch_bits[20]; 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, 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, 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 (q->users[rnti]) {
if (srslte_pusch_cfg(&q->pusch, 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, softbuffer, q->sf_symbols,
q->ce, noise_power, q->ce, noise_power,
rnti, data, rnti, data,
cqi_value,
uci_data); uci_data);
} }

@ -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 srslte_cqi_size(srslte_cqi_value_t *value) {
int size = 0;
switch(value->type) { switch(value->type) {
case SRSLTE_CQI_TYPE_WIDEBAND: case SRSLTE_CQI_TYPE_WIDEBAND:
return 4; size = 4;
break;
case SRSLTE_CQI_TYPE_SUBBAND: 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: 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: 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) { static bool srslte_cqi_get_N(uint32_t I_cqi_pmi, uint32_t *N_p, uint32_t *N_offset) {

@ -566,9 +566,9 @@ int srslte_pusch_decode(srslte_pusch_t *q,
srslte_pusch_cfg_t *cfg, srslte_softbuffer_rx_t *softbuffer, srslte_pusch_cfg_t *cfg, srslte_softbuffer_rx_t *softbuffer,
cf_t *sf_symbols, cf_t *sf_symbols,
cf_t *ce, float noise_estimate, uint16_t rnti, 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; uint32_t n;
if (q != NULL && if (q != NULL &&
@ -607,19 +607,42 @@ int srslte_pusch_decode(srslte_pusch_t *q,
// Generate scrambling sequence if not pre-generated // Generate scrambling sequence if not pre-generated
srslte_sequence_t *seq = get_user_sequence(q, rnti, cfg->sf_idx, cfg->nbits.nof_bits); 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 // Decode RI/HARQ bits before descrambling
if (srslte_ulsch_uci_decode_ri_ack(&q->ul_sch, cfg, softbuffer, q->q, seq->c, uci_data)) { 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"); fprintf(stderr, "Error decoding RI/HARQ bits\n");
return SRSLTE_ERROR; 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 // Descrambling
srslte_scrambling_s_offset(seq, q->q, 0, cfg->nbits.nof_bits); 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); // Decode
} else { ret = srslte_ulsch_uci_decode(&q->ul_sch, cfg, softbuffer, q->q, q->g, data, uci_data);
return SRSLTE_ERROR_INVALID_INPUTS;
// 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) { uint32_t srslte_pusch_last_noi(srslte_pusch_t *q) {

@ -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) { if (cfg->cb_segm.tbs == 0) {
beta /= beta_cqi_offset[cfg->uci_cfg.I_offset_cqi]; 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) { if (ret < 0) {
return ret; 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) { if (cfg->cb_segm.tbs == 0) {
beta /= beta_cqi_offset[cfg->uci_cfg.I_offset_cqi]; 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) { if (ret < 0) {
return ret; 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 nb_q = cfg->nbits.nof_bits;
uint32_t Qm = cfg->grant.Qm; uint32_t Qm = cfg->grant.Qm;
// Encode RI // Encode RI if CQI enabled
if (uci_data.uci_ri_len > 0) { 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]; float beta = beta_ri_offset[cfg->uci_cfg.I_offset_ri];
if (cfg->cb_segm.tbs == 0) { if (cfg->cb_segm.tbs == 0) {
beta /= beta_cqi_offset[cfg->uci_cfg.I_offset_cqi]; 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) { if (ret < 0) {
return ret; return ret;
} }
@ -809,8 +814,8 @@ int srslte_ulsch_uci_encode(srslte_sch_t *q,
if (cfg->cb_segm.tbs == 0) { if (cfg->cb_segm.tbs == 0) {
beta /= beta_cqi_offset[cfg->uci_cfg.I_offset_cqi]; 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, 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]); beta, nb_q / Qm, &q->ack_ri_bits[Q_prime_ri * Qm], false);
if (ret < 0) { if (ret < 0) {
return ret; return ret;
} }

@ -252,7 +252,7 @@ int main(int argc, char **argv) {
} }
gettimeofday(&t[1], NULL); 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); gettimeofday(&t[2], NULL);
get_time_interval(t); get_time_interval(t);
if (r) { if (r) {

@ -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, 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, 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}, {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) { void srslte_uci_cqi_pucch_init(srslte_uci_cqi_pucch_t *q) {
uint8_t word[16]; uint8_t word[16];
uint32_t nwords = 16; uint32_t nwords = 1 << SRSLTE_UCI_MAX_CQI_LEN_PUCCH;
for (uint32_t w=0;w<nwords;w++) { q->cqi_table = srslte_vec_malloc(nwords * sizeof(int8_t *));
q->cqi_table[w] = srslte_vec_malloc(SRSLTE_UCI_CQI_CODED_PUCCH_B*sizeof(int8_t)); q->cqi_table_s = srslte_vec_malloc(nwords * sizeof(int16_t *));
q->cqi_table_s[w] = srslte_vec_malloc(SRSLTE_UCI_CQI_CODED_PUCCH_B*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; uint8_t *ptr = word;
srslte_bit_unpack(w, &ptr, 4); srslte_bit_unpack(w, &ptr, SRSLTE_UCI_MAX_CQI_LEN_PUCCH);
srslte_uci_encode_cqi_pucch(word, 4, q->cqi_table[w]); 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++) { 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; 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) { 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++) { for (uint32_t w=0;w<nwords;w++) {
if (q->cqi_table[w]) { if (q->cqi_table[w]) {
free(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_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 /* 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 /* 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) 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 && b_bits != NULL &&
cqi_data != NULL) cqi_data != NULL)
{ {
uint32_t max_w = 0; uint32_t max_w = 0;
int32_t max_corr = INT32_MIN; int32_t max_corr = INT32_MIN;
for (uint32_t w=0;w<16;w++) { 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 // 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); 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 // Convert word to bits again
uint8_t *ptr = cqi_data; 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); INFO("Decoded CQI: w=%d, corr=%d\n", max_w, max_corr);
return 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 /* Decode UCI HARQ/ACK bits as described in 5.2.2.6 of 36.212
* Currently only supporting 1-bit HARQ * Currently only supporting 1-bit HARQ
*/ */
#ifndef MIMO_ENB static int32_t decode_ri_ack_1bit(int16_t *q_bits, uint8_t *c_seq, srslte_uci_bit_t *pos)
static int32_t decode_ri_ack(int16_t *q_bits, uint8_t *c_seq, srslte_uci_bit_t *pos)
{ {
uint32_t p0 = pos[0].position; uint32_t p0 = pos[0].position;
uint32_t p1 = pos[1].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); 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) { 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])
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])
{ {
uint32_t p0 = pos[Qm * 0 + 0].position; uint32_t p0 = pos[Qm * 0 + 0].position;
uint32_t p1 = pos[Qm * 0 + 1].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; data[2] -= q2 + q5;
} }
int srslte_uci_decode_ack(srslte_pusch_cfg_t *cfg, int16_t *q_bits, uint8_t *c_seq, /* Encode UCI ACK/RI bits as described in 5.2.2.6 of 36.212
float beta, uint32_t H_prime_total, * Currently only supporting 1-bit RI
uint32_t O_cqi, srslte_uci_bit_t *ack_bits, uint8_t acks[2], uint32_t nof_acks) */
{ int srslte_uci_encode_ack_ri(srslte_pusch_cfg_t *cfg,
int32_t acks_sum[3] = {0, 0, 0}; 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) { if (beta < 0) {
fprintf(stderr, "Error beta is reserved\n"); 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++) { 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 (ack_ri) {
if ((i % 3 == 0) && i > 0) { uci_ulsch_interleave_ri_gen(i,
decode_ri_ack(q_bits, &c_seq[0], &ack_bits[cfg->grant.Qm*(i-3)], cfg->grant.Qm, acks_sum); 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; 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 * Currently only supporting 1-bit RI
*/ */
int srslte_uci_decode_ri(srslte_pusch_cfg_t *cfg, int16_t *q_bits, uint8_t *c_seq, 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, float beta, uint32_t H_prime_total,
uint32_t O_cqi, srslte_uci_bit_t *ri_bits, uint8_t *data) 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) { if (beta < 0) {
fprintf(stderr, "Error beta is reserved\n"); 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++) {
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, &ri_bits[cfg->grant.Qm*i]); uci_ulsch_interleave_ri_gen(i,
if ((i % 3 == 0) && i > 0) { cfg->grant.Qm,
//decode_ri_ack(q_bits, &c_seq[0], &ri_bits[cfg->grant.Qm*(i-3)], cfg->grant.Qm, ri_sum); 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 (data) { }
*data = (uint8_t) ((ri_sum[0] + ri_sum[1] + ri_sum[2]) > 0); 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]);
}
} }
return (int) Qprime; data[0] = (uint8_t) (sum[0] > 0);
} if (nof_bits == 2) {
data[1] = (uint8_t) (sum[1] > 0);
/* 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; return (int) Qprime;
} }

@ -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) */ /* Select the best Rank indicator (RI) and Precoding Matrix Indicator (PMI) */
for (uint32_t nof_layers = 1; nof_layers <= SRSLTE_MAX_LAYERS; nof_layers++) { 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; 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_sinr = _sinr;
best_pmi = (uint8_t) q->pmi[nof_layers - 1]; best_pmi = (uint8_t) q->pmi[nof_layers - 1];
best_ri = (uint8_t) (nof_layers - 1); best_ri = (uint8_t) (nof_layers - 1);

@ -88,16 +88,19 @@ void phch_worker::init(phch_common* phy_, srslte::log *log_h_)
pthread_mutex_init(&mutex, NULL); pthread_mutex_init(&mutex, NULL);
// Init cell here // Init cell here
signal_buffer_rx = (cf_t*) srslte_vec_malloc(2*SRSLTE_SF_LEN_PRB(phy->cell.nof_prb)*sizeof(cf_t)); for(int p = 0; p < SRSLTE_MAX_PORTS; p++) {
if (!signal_buffer_rx) { signal_buffer_rx[p] = (cf_t *) srslte_vec_malloc(2 * SRSLTE_SF_LEN_PRB(phy->cell.nof_prb) * sizeof(cf_t));
fprintf(stderr, "Error allocating memory\n"); if (!signal_buffer_rx[p]) {
return; 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)); bzero(signal_buffer_rx[p], 2 * SRSLTE_SF_LEN_PRB(phy->cell.nof_prb) * sizeof(cf_t));
if (!signal_buffer_tx[0]) { signal_buffer_tx[p] = (cf_t *) srslte_vec_malloc(2 * SRSLTE_SF_LEN_PRB(phy->cell.nof_prb) * sizeof(cf_t));
fprintf(stderr, "Error allocating memory\n"); if (!signal_buffer_tx[p]) {
return; 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)) { if (srslte_enb_dl_init(&enb_dl, signal_buffer_tx, phy->cell.nof_prb)) {
fprintf(stderr, "Error initiating ENB DL\n"); 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"); fprintf(stderr, "Error initiating ENB DL\n");
return; 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"); fprintf(stderr, "Error initiating ENB UL\n");
return; return;
} }
@ -154,12 +157,12 @@ void phch_worker::stop()
srslte_enb_dl_free(&enb_dl); srslte_enb_dl_free(&enb_dl);
srslte_enb_ul_free(&enb_ul); srslte_enb_ul_free(&enb_ul);
if (signal_buffer_rx) { for (int p = 0; p < SRSLTE_MAX_PORTS; p++) {
free(signal_buffer_rx); if (signal_buffer_rx[p]) {
} free(signal_buffer_rx[p]);
for (int i = 0; i < SRSLTE_MAX_PORTS; i++) { }
if (signal_buffer_tx[i]) { if (signal_buffer_tx[p]) {
free(signal_buffer_tx[i]); free(signal_buffer_tx[p]);
} }
} }
pthread_mutex_unlock(&mutex); pthread_mutex_unlock(&mutex);
@ -171,9 +174,9 @@ void phch_worker::reset()
ue_db.clear(); 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_) 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(); 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, void phch_worker::set_config_dedicated(uint16_t rnti,
srslte_uci_cfg_t *uci_cfg, srslte_uci_cfg_t *uci_cfg,
srslte_pucch_sched_t *pucch_sched, srslte_pucch_sched_t *pucch_sched,
srslte_refsignal_srs_cfg_t *srs_cfg, srslte_refsignal_srs_cfg_t *srs_cfg,
uint32_t I_sr, bool pucch_cqi, uint32_t pmi_idx, bool pucch_cqi_ack) 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); pthread_mutex_lock(&mutex);
if (ue_db.count(rnti)) { if (ue_db.count(rnti)) {
pucch_sched->N_pucch_1 = phy->pucch_cfg.n1_pucch_an; 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; 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 { } else {
Error("Setting config dedicated: rnti=0x%x does not exist\n"); Error("Setting config dedicated: rnti=0x%x does not exist\n");
} }
@ -278,7 +308,7 @@ void phch_worker::work_imp()
} }
pthread_mutex_lock(&mutex); pthread_mutex_lock(&mutex);
mac_interface_phy::ul_sched_t *ul_grants = phy->ul_grants; 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::dl_sched_t *dl_grants = phy->dl_grants;
mac_interface_phy *mac = phy->mac; mac_interface_phy *mac = phy->mac;
@ -293,7 +323,7 @@ void phch_worker::work_imp()
} }
// Process UL signal // 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 pending UL grants for the tti they were scheduled
decode_pusch(ul_grants[t_rx].sched_grants, ul_grants[t_rx].nof_grants); 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))); phy->ack_clear(TTIMOD(TTI_TX(t_tx_dl)));
for (uint32_t i=0;i<dl_grants[t_tx_dl].nof_grants;i++) { for (uint32_t i=0;i<dl_grants[t_tx_dl].nof_grants;i++) {
// SI-RNTI and RAR-RNTI do not have ACK // 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) { uint16_t rnti = dl_grants[t_tx_dl].sched_grants[i].rnti;
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); 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 // Generate signal and transmit
srslte_enb_dl_gen_signal(&enb_dl); srslte_enb_dl_gen_signal(&enb_dl);
Debug("Sending to radio\n"); 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 #ifdef DEBUG_WRITE_FILE
fwrite(signal_buffer_tx, SRSLTE_SF_LEN_PRB(phy->cell.nof_prb)*sizeof(cf_t), 1, f); 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); gettimeofday(&t[1], NULL);
#endif #endif
bool acks_pending[SRSLTE_MAX_TB] = {false};
// Get pending ACKs with an associated PUSCH transmission // Get pending ACKs with an associated PUSCH transmission
if (phy->ack_is_pending(t_rx, rnti)) { for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) {
uci_data.uci_ack_len = 1; acks_pending[tb] = phy->ack_is_pending(t_rx, rnti, tb);
if (acks_pending[tb]) {
uci_data.uci_ack_len++;
}
} }
// Configure PUSCH CQI channel // Configure PUSCH CQI channel
srslte_cqi_value_t cqi_value; srslte_cqi_value_t cqi_value = {0};
bool cqi_enabled = false; 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_value.type = SRSLTE_CQI_TYPE_WIDEBAND;
cqi_enabled = true; 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.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.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; 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 // mark this tti as having an ul grant to avoid pucch
ue_db[rnti].has_grant_tti = tti_rx; 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; srslte_ra_ul_grant_t phy_grant;
int res = -1; int res = -1;
if (!srslte_ra_ul_dci_to_grant(&grants[i].grant, enb_ul.cell.nof_prb, n_rb_ho, &phy_grant)) { 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) { if (phy_grant.mcs.mod == SRSLTE_MOD_64QAM) {
phy_grant.mcs.mod = SRSLTE_MOD_16QAM; 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, rnti, grants[i].rv_idx,
grants[i].current_tx_nb, grants[i].current_tx_nb,
grants[i].data, grants[i].data,
(cqi_enabled) ? &cqi_value : NULL,
&uci_data, &uci_data,
sf_rx); sf_rx);
} else { } else {
@ -457,11 +494,24 @@ int phch_worker::decode_pusch(srslte_enb_ul_pusch_t *grants, uint32_t nof_pusch)
char cqi_str[64]; char cqi_str[64];
if (cqi_enabled) { if (cqi_enabled) {
srslte_cqi_value_unpack(uci_data.uci_cqi, &cqi_value);
if (ue_db[rnti].cqi_en) { if (ue_db[rnti].cqi_en) {
wideband_cqi_value = cqi_value.wideband.wideband_cqi; wideband_cqi_value = cqi_value.wideband.wideband_cqi;
} else if (grants[i].grant.cqi_request) { } else if (grants[i].grant.cqi_request) {
wideband_cqi_value = cqi_value.subband_hl.wideband_cqi_cw0; 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); 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, 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, 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, phy_grant.mcs.tbs/8, phy_grant.mcs.idx, grants[i].grant.rv_idx,
snr_db, snr_db,
srslte_pusch_last_noi(&enb_ul.pusch), srslte_pusch_last_noi(&enb_ul.pusch),
crc_res?"OK":"KO", 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_cqi_len>0?cqi_str:"",
uci_data.uci_ri_len>0?(uci_data.uci_ri?", ri=0":", ri=1"):"",
timestr); timestr);
// Notify MAC of RL status // 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 // Notify MAC new received data and HARQ Indication value
phy->mac->crc_info(tti_rx, rnti, phy_grant.mcs.tbs/8, crc_res); phy->mac->crc_info(tti_rx, rnti, phy_grant.mcs.tbs/8, crc_res);
if (uci_data.uci_ack_len) { uint32_t ack_idx = 0;
phy->mac->ack_info(tti_rx, rnti, uci_data.uci_ack && (crc_res || snr_db > PUSCH_RL_SNR_DB_TH)); 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) { if (snr_db >= PUSCH_RL_SNR_DB_TH) {
phy->mac->snr_info(tti_rx, rnti, snr_db); phy->mac->snr_info(tti_rx, rnti, snr_db);
} }
if (uci_data.uci_cqi_len>0 && crc_res) { if (uci_data.uci_cqi_len>0 && crc_res) {
phy->mac->cqi_info(tti_rx, rnti, wideband_cqi_value); 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 // Save metrics stats
ue_db[rnti].metrics_ul(phy_grant.mcs.idx, 0, snr_db, srslte_pusch_last_noi(&enb_ul.pusch)); 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) { 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 // 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; uint32_t last_n_pdcch = 0;
bzero(&uci_data, sizeof(srslte_uci_data_t)); 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)) { for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) {
needs_pucch = true; needs_ack[tb] = phy->ack_is_pending(t_rx, rnti, tb, &last_n_pdcch);
needs_ack = true; if (needs_ack[tb]) {
uci_data.uci_ack_len = 1; needs_pucch = true;
uci_data.uci_ack_len++;
}
} }
srslte_cqi_value_t cqi_value; srslte_cqi_value_t cqi_value;
if (ue_db[rnti].cqi_en && (ue_db[rnti].pucch_cqi_ack || !needs_ack)) { LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT *dedicated = &ue_db[rnti].dedicated;
if (srslte_cqi_send(ue_db[rnti].pmi_idx, tti_rx)) { 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_pucch = true;
needs_cqi = true; needs_cqi = true;
cqi_value.type = SRSLTE_CQI_TYPE_WIDEBAND; cqi_value.type = SRSLTE_CQI_TYPE_WIDEBAND;
uci_data.uci_cqi_len = srslte_cqi_size(&cqi_value); 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"); fprintf(stderr, "Error getting PUCCH\n");
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
if (uci_data.uci_ack_len > 0) { /* If only one ACK is required, it can be for TB0 or TB1 */
phy->mac->ack_info(tti_rx, rnti, uci_data.uci_ack && (srslte_pucch_get_last_corr(&enb_ul.pucch) >= PUCCH_RL_CORR_TH)); 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) { if (uci_data.scheduling_request) {
phy->mac->sr_detected(tti_rx, rnti); 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);
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);
}
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);
} }
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, rnti,
srslte_pucch_get_last_corr(&enb_ul.pucch), srslte_pucch_get_last_corr(&enb_ul.pucch),
enb_ul.pucch.last_n_pucch, enb_ul.pucch.last_n_prb, 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_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 // 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) 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++) { 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) { if (rnti) {
srslte_dci_format_t format = SRSLTE_DCI_FORMAT1; if (srslte_enb_dl_put_pdcch_dl(&enb_dl, &grants[i].grant, grant->dci_format, grants[i].location, rnti, sf_tx)) {
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)) {
fprintf(stderr, "Error putting PDCCH %d\n",i); fprintf(stderr, "Error putting PDCCH %d\n",i);
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
if (LOG_THIS(rnti)) { 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); 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; return 0;
} }
int phch_worker::encode_pdsch(srslte_enb_dl_pdsch_t *grants, uint32_t nof_grants) int phch_worker::encode_pdsch(srslte_enb_dl_pdsch_t *grants, uint32_t nof_grants) {
{ for (uint32_t i = 0; i < nof_grants; i++) {
for (uint32_t i=0;i<nof_grants;i++) {
uint16_t rnti = grants[i].rnti; uint16_t rnti = grants[i].rnti;
if (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) { if (rnti == SRSLTE_SIRNTI || rnti == SRSLTE_PRNTI || rnti == SRSLTE_MRNTI) {
rnti_is_user = false; 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_grant_t phy_grant;
srslte_ra_dl_dci_to_grant(&grants[i].grant, enb_dl.cell.nof_prb, rnti, &phy_grant); srslte_ra_dl_dci_to_grant(&grants[i].grant, enb_dl.cell.nof_prb, rnti, &phy_grant);
char grant_str[64]; char grant_str[64];
switch(grants[i].grant.alloc_type) { switch (grants[i].grant.alloc_type) {
case SRSLTE_RA_ALLOC_TYPE0: case SRSLTE_RA_ALLOC_TYPE0:
sprintf(grant_str, "mask=0x%x",grants[i].grant.type0_alloc.rbg_bitmask); sprintf(grant_str, "mask=0x%x", grants[i].grant.type0_alloc.rbg_bitmask);
break; break;
case SRSLTE_RA_ALLOC_TYPE1: case SRSLTE_RA_ALLOC_TYPE1:
sprintf(grant_str, "mask=0x%x",grants[i].grant.type1_alloc.vrb_bitmask); sprintf(grant_str, "mask=0x%x", grants[i].grant.type1_alloc.vrb_bitmask);
break; break;
default:
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: default:
sprintf(grant_str, "rb_start=%d",grants[i].grant.type2_alloc.RB_start); Error("Not implemented/Undefined DCI format (%d)\n", dci_format);
break;
} }
if (LOG_THIS(rnti)) { if (LOG_THIS(rnti)) {
uint8_t x = 0; 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; uint32_t len = phy_grant.mcs[0].tbs / (uint32_t) 8;
if (!ptr) { if (!ptr) {
ptr = &x; ptr = &x;
len = 1; 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, 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", "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, rnti, phy_grant.nof_prb, grant_str, grants[i].grant.harq_process, tti_tx_dl,
phy_grant.mcs[0].tbs/8, phy_grant.mcs[0].idx, grants[i].grant.rv_idx, 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}; int rv[SRSLTE_MAX_CODEWORDS] = {grants[i].grant.rv_idx, grants[i].grant.rv_idx_1};
uint8_t *d[SRSLTE_MAX_CODEWORDS] = {grants[i].data, NULL};
int rv[SRSLTE_MAX_CODEWORDS] = {grants[i].grant.rv_idx, 0};
if (srslte_enb_dl_put_pdsch(&enb_dl, &phy_grant, grants[i].softbuffers, rnti, rv, sf_tx, grants[i].data, mimo_type)) {
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;
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); ue_db[rnti].metrics_dl(phy_grant.mcs[0].idx);
} }
} }
return SRSLTE_SUCCESS; return SRSLTE_SUCCESS;
} }

@ -1142,7 +1142,11 @@ void rrc::ue::send_connection_setup(bool is_setup)
phy_cfg->cqi_report_cnfg_present = true; phy_cfg->cqi_report_cnfg_present = true;
if(parent->cfg.cqi_cfg.mode == RRC_CFG_CQI_MODE_APERIODIC) { 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_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 { } else {
phy_cfg->cqi_report_cnfg.report_periodic_present = true; phy_cfg->cqi_report_cnfg.report_periodic_present = true;
phy_cfg->cqi_report_cnfg.report_periodic_setup_present = true; phy_cfg->cqi_report_cnfg.report_periodic_setup_present = true;

@ -859,7 +859,9 @@ void phch_worker::set_uci_periodic_cqi()
if (period_cqi.configured && rnti_is_set) { 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))) { 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(); compute_ri();
uci_data.ri_periodic_report = true; uci_data.ri_periodic_report = true;
Info("PUCCH: Periodic RI=%d\n", uci_data.uci_ri); Info("PUCCH: Periodic RI=%d\n", uci_data.uci_ri);
} else if (srslte_cqi_send(period_cqi.pmi_idx, TTI_TX(tti))) { } 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() void phch_worker::set_uci_aperiodic_cqi()
{ {
if (phy->config->dedicated.cqi_report_cnfg.report_mode_aperiodic_present) { 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) { switch(phy->config->dedicated.cqi_report_cnfg.report_mode_aperiodic) {
case LIBLTE_RRC_CQI_REPORT_MODE_APERIODIC_RM30: 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 /* 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. other transmission modes they are reported conditioned on rank 1.
*/ */
if (rnti_is_set) { if (rnti_is_set) {
/* Compute RI, PMI and SINR */
compute_ri();
/* Select RI, PMI and SINR */ /* Select RI, PMI and SINR */
uint32_t ri = ue_dl.ri; // Select RI (0: 1 layer, 1: 2 layer, otherwise: not implemented) 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 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, cqi_report.subband_hl.wideband_cqi_cw0, cqi_report.subband_hl.wideband_cqi_cw1,
sinr_db, sinr_db, pmi, cqi_report.subband_hl.N); sinr_db, sinr_db, pmi, cqi_report.subband_hl.N);
} else { } else {
Info("PUSCH: Aperiodic ri=1, CQI=%d/%d, SINR=%2.1f dB, for %d subbands\n", Info("PUSCH: Aperiodic ri=1, CQI=%02d, SINR=%2.1f, pmi=%d for %d subbands\n",
cqi_report.wideband.wideband_cqi, cqi_report.subband_hl.wideband_cqi_cw0,
phy->avg_snr_db, cqi_report.subband_hl.N); sinr_db, pmi, cqi_report.subband_hl.N);
} }
uci_data.uci_cqi_len = srslte_cqi_value_pack(&cqi_report, uci_data.uci_cqi); uci_data.uci_cqi_len = srslte_cqi_value_pack(&cqi_report, uci_data.uci_cqi);
} }

Loading…
Cancel
Save