Added DCI formats 2 and 2a inScheduler. Improved UE PHCH, corrected some MIMO bugs on both sides.

master
Xavier Arteaga 7 years ago
parent f9e428ef68
commit 75957d41d7

@ -942,7 +942,7 @@ int main(int argc, char **argv) {
} }
/* Configure pmch_cfg parameters */ /* Configure pmch_cfg parameters */
srslte_ra_dl_grant_t grant; srslte_ra_dl_grant_t grant;
grant.nof_tb = 1; grant.tb_en[0] = true;
grant.mcs[0].idx = 2; grant.mcs[0].idx = 2;
grant.mcs[0].mod = SRSLTE_MOD_QPSK; grant.mcs[0].mod = SRSLTE_MOD_QPSK;
grant.nof_prb = cell.nof_prb; grant.nof_prb = cell.nof_prb;

@ -68,7 +68,7 @@ public:
virtual int pmi_info(uint32_t tti, uint16_t rnti, uint32_t pmi_value) = 0; virtual int pmi_info(uint32_t tti, uint16_t rnti, uint32_t pmi_value) = 0;
virtual int cqi_info(uint32_t tti, uint16_t rnti, uint32_t cqi_value) = 0; virtual int cqi_info(uint32_t tti, uint16_t rnti, uint32_t cqi_value) = 0;
virtual int snr_info(uint32_t tti, uint16_t rnti, float snr_db) = 0; virtual int snr_info(uint32_t tti, uint16_t rnti, float snr_db) = 0;
virtual int ack_info(uint32_t tti, uint16_t rnti, bool ack) = 0; virtual int ack_info(uint32_t tti, uint16_t rnti, uint32_t tb_idx, bool ack) = 0;
virtual int crc_info(uint32_t tti, uint16_t rnti, uint32_t nof_bytes, bool crc_res) = 0; virtual int crc_info(uint32_t tti, uint16_t rnti, uint32_t nof_bytes, bool crc_res) = 0;
virtual int get_dl_sched(uint32_t tti, dl_sched_t *dl_sched_res) = 0; virtual int get_dl_sched(uint32_t tti, dl_sched_t *dl_sched_res) = 0;

@ -137,8 +137,8 @@ public:
uint32_t tbs[SRSLTE_MAX_TB]; uint32_t tbs[SRSLTE_MAX_TB];
bool mac_ce_ta; bool mac_ce_ta;
bool mac_ce_rnti; bool mac_ce_rnti;
uint32_t nof_pdu_elems; uint32_t nof_pdu_elems[SRSLTE_MAX_TB];
dl_sched_pdu_t pdu[MAX_RLC_PDU_LIST]; dl_sched_pdu_t pdu[SRSLTE_MAX_TB][MAX_RLC_PDU_LIST];
} dl_sched_data_t; } dl_sched_data_t;
typedef struct { typedef struct {
@ -226,7 +226,7 @@ public:
virtual int dl_mac_buffer_state(uint16_t rnti, uint32_t ce_code) = 0; virtual int dl_mac_buffer_state(uint16_t rnti, uint32_t ce_code) = 0;
/* DL information */ /* DL information */
virtual int dl_ack_info(uint32_t tti, uint16_t rnti, bool ack) = 0; virtual int dl_ack_info(uint32_t tti, uint16_t rnti, uint32_t tb_idx, bool ack) = 0;
virtual int dl_rach_info(uint32_t tti, uint32_t ra_id, uint16_t rnti, uint32_t estimated_size) = 0; virtual int dl_rach_info(uint32_t tti, uint32_t ra_id, uint16_t rnti, uint32_t estimated_size) = 0;
virtual int dl_ri_info(uint32_t tti, uint16_t rnti, uint32_t ri_value) = 0; virtual int dl_ri_info(uint32_t tti, uint16_t rnti, uint32_t ri_value) = 0;
virtual int dl_pmi_info(uint32_t tti, uint16_t rnti, uint32_t pmi_value) = 0; virtual int dl_pmi_info(uint32_t tti, uint16_t rnti, uint32_t pmi_value) = 0;

@ -48,6 +48,7 @@ typedef struct SRSLTE_API {
uint32_t nof_layers; uint32_t nof_layers;
uint32_t codebook_idx; uint32_t codebook_idx;
srslte_mimo_type_t mimo_type; srslte_mimo_type_t mimo_type;
bool tb_cw_swap;
} srslte_pdsch_cfg_t; } srslte_pdsch_cfg_t;
#endif #endif

@ -104,10 +104,10 @@ typedef struct SRSLTE_API {
uint32_t nof_prb; uint32_t nof_prb;
uint32_t Qm[SRSLTE_MAX_CODEWORDS]; uint32_t Qm[SRSLTE_MAX_CODEWORDS];
srslte_ra_mcs_t mcs[SRSLTE_MAX_CODEWORDS]; srslte_ra_mcs_t mcs[SRSLTE_MAX_CODEWORDS];
uint32_t nof_tb;
srslte_sf_t sf_type; srslte_sf_t sf_type;
bool tb_en[SRSLTE_MAX_CODEWORDS]; bool tb_en[SRSLTE_MAX_CODEWORDS];
uint32_t pinfo; uint32_t pinfo;
bool tb_cw_swap;
} srslte_ra_dl_grant_t; } srslte_ra_dl_grant_t;
#define SRSLTE_RA_DL_GRANT_NOF_TB(G) ((((G)->tb_en[0])?1:0)+(((G)->tb_en[1])?1:0)) #define SRSLTE_RA_DL_GRANT_NOF_TB(G) ((((G)->tb_en[0])?1:0)+(((G)->tb_en[1])?1:0))

@ -65,7 +65,7 @@ SRSLTE_API extern int srslte_verbose;
#if CMAKE_BUILD_TYPE==Debug #if CMAKE_BUILD_TYPE==Debug
/* In debug mode, it prints out the */ /* In debug mode, it prints out the */
#define ERROR(_fmt, ...) fprintf(stderr, "%s.%d: " _fmt "\n", __FILE__, __LINE__, ##__VA_ARGS__) #define ERROR(_fmt, ...) fprintf(stderr, "\e[31m%s.%d: " _fmt "\e[0m\n", __FILE__, __LINE__, ##__VA_ARGS__)
#else #else
#define ERROR(_fmt, ...) fprintf(stderr, "[ERROR in %s]:" _fmt "\n", __FUNCTION__, ##__VA_ARGS__) #define ERROR(_fmt, ...) fprintf(stderr, "[ERROR in %s]:" _fmt "\n", __FUNCTION__, ##__VA_ARGS__)
#endif /* CMAKE_BUILD_TYPE==Debug */ #endif /* CMAKE_BUILD_TYPE==Debug */

@ -341,26 +341,34 @@ int srslte_enb_dl_put_pdsch(srslte_enb_dl_t *q, srslte_ra_dl_grant_t *grant, srs
/* Translates Precoding Information (pinfo) to Precoding matrix Index (pmi) as 3GPP 36.212 Table 5.3.3.1.5-4 */ /* Translates Precoding Information (pinfo) to Precoding matrix Index (pmi) as 3GPP 36.212 Table 5.3.3.1.5-4 */
if (mimo_type == SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX) { if (mimo_type == SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX) {
if (nof_tb == 1) { switch(nof_tb) {
if (grant->pinfo > 0 && grant->pinfo < 5) { case 1:
pmi = grant->pinfo - 1; if (grant->pinfo == 0) {
} else { mimo_type = SRSLTE_MIMO_TYPE_TX_DIVERSITY;
ERROR("Not Implemented (nof_tb=%d, pinfo=%d)", nof_tb, grant->pinfo); } else if (grant->pinfo > 0 && grant->pinfo < 5) {
return SRSLTE_ERROR; pmi = grant->pinfo - 1;
} } else {
} else { ERROR("Not Implemented (nof_tb=%d, pinfo=%d)", nof_tb, grant->pinfo);
if (grant->pinfo < 2) { return SRSLTE_ERROR;
pmi = grant->pinfo; }
} else { break;
case 2:
if (grant->pinfo < 2) {
pmi = grant->pinfo;
} else {
ERROR("Not Implemented (nof_tb=%d, pinfo=%d)", nof_tb, grant->pinfo);
return SRSLTE_ERROR;
}
break;
default:
ERROR("Not Implemented (nof_tb=%d, pinfo=%d)", nof_tb, grant->pinfo); ERROR("Not Implemented (nof_tb=%d, pinfo=%d)", nof_tb, grant->pinfo);
return SRSLTE_ERROR; return SRSLTE_ERROR;
}
} }
} }
/* Configure pdsch_cfg parameters */ /* Configure pdsch_cfg parameters */
if (srslte_pdsch_cfg_mimo(&q->pdsch_cfg, q->cell, grant, q->cfi, sf_idx, rv_idx, mimo_type, pmi)) { if (srslte_pdsch_cfg_mimo(&q->pdsch_cfg, q->cell, grant, q->cfi, sf_idx, rv_idx, mimo_type, pmi)) {
fprintf(stderr, "Error configuring PDSCH\n"); ERROR("Error configuring PDSCH (rnti=0x%04x)", rnti);
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }

@ -467,7 +467,7 @@ int srslte_pdsch_cfg_mimo(srslte_pdsch_cfg_t *cfg, srslte_cell_t cell, srslte_ra
for (int cw = 0; cw < SRSLTE_MAX_CODEWORDS; cw++) { for (int cw = 0; cw < SRSLTE_MAX_CODEWORDS; cw++) {
if (grant->tb_en[cw]) { if (grant->tb_en[cw]) {
if (srslte_cbsegm(&cfg->cb_segm[cw], (uint32_t) cfg->grant.mcs[cw].tbs)) { if (srslte_cbsegm(&cfg->cb_segm[cw], (uint32_t) cfg->grant.mcs[cw].tbs)) {
fprintf(stderr, "Error computing Codeblock (1) segmentation for TBS=%d\n", cfg->grant.mcs[cw].tbs); fprintf(stderr, "Error computing Codeword (%d) segmentation for TBS=%d\n", cw, cfg->grant.mcs[cw].tbs);
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
} }
@ -477,6 +477,7 @@ int srslte_pdsch_cfg_mimo(srslte_pdsch_cfg_t *cfg, srslte_cell_t cell, srslte_ra
cfg->sf_idx = sf_idx; cfg->sf_idx = sf_idx;
memcpy(cfg->rv, rvidx, sizeof(uint32_t) * SRSLTE_MAX_CODEWORDS); memcpy(cfg->rv, rvidx, sizeof(uint32_t) * SRSLTE_MAX_CODEWORDS);
cfg->mimo_type = mimo_type; cfg->mimo_type = mimo_type;
cfg->tb_cw_swap = grant->tb_cw_swap;
/* Check and configure PDSCH transmission modes */ /* Check and configure PDSCH transmission modes */
switch(mimo_type) { switch(mimo_type) {
@ -492,7 +493,7 @@ int srslte_pdsch_cfg_mimo(srslte_pdsch_cfg_t *cfg, srslte_cell_t cell, srslte_ra
ERROR("Wrong number of transport blocks (%d) for transmit diversity.", nof_tb); ERROR("Wrong number of transport blocks (%d) for transmit diversity.", nof_tb);
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
cfg->nof_layers = 2; cfg->nof_layers = cell.nof_ports;
break; break;
case SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX: case SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX:
if (nof_tb == 1) { if (nof_tb == 1) {
@ -543,19 +544,30 @@ static srslte_sequence_t *get_user_sequence(srslte_pdsch_t *q, uint16_t rnti,
static int srslte_pdsch_codeword_encode(srslte_pdsch_t *q, srslte_pdsch_cfg_t *cfg, static int srslte_pdsch_codeword_encode(srslte_pdsch_t *q, srslte_pdsch_cfg_t *cfg,
srslte_softbuffer_tx_t *softbuffer, uint16_t rnti, uint8_t *data, srslte_softbuffer_tx_t *softbuffer, uint16_t rnti, uint8_t *data,
uint32_t codeword_idx) { uint32_t codeword_idx, uint32_t tb_idx) {
srslte_ra_nbits_t *nbits = &cfg->nbits[codeword_idx]; srslte_ra_nbits_t *nbits = &cfg->nbits[tb_idx];
srslte_ra_mcs_t *mcs = &cfg->grant.mcs[codeword_idx]; srslte_ra_mcs_t *mcs = &cfg->grant.mcs[tb_idx];
uint32_t rv = cfg->rv[codeword_idx]; uint32_t rv = cfg->rv[tb_idx];
bool valid_inputs = true;
if (nbits->nof_bits) {
INFO("Encoding PDSCH SF: %d (TB %d), Mod %s, NofBits: %d, NofSymbols: %d, NofBitsE: %d, rv_idx: %d\n", if (!softbuffer) {
cfg->sf_idx, codeword_idx, srslte_mod_string(mcs->mod), mcs->tbs, ERROR("Error encoding (TB%d -> CW%d), softbuffer=NULL", tb_idx, codeword_idx);
valid_inputs = false;
}
if (!data) {
ERROR("Error encoding (TB%d -> CW%d), data=NULL", tb_idx, codeword_idx);
valid_inputs = false;
}
if (nbits->nof_bits && valid_inputs) {
INFO("Encoding PDSCH SF: %d (TB%d -> CW%d), Mod %s, NofBits: %d, NofSymbols: %d, NofBitsE: %d, rv_idx: %d\n",
cfg->sf_idx, tb_idx, codeword_idx, srslte_mod_string(mcs->mod), mcs->tbs,
nbits->nof_re, nbits->nof_bits, rv); nbits->nof_re, nbits->nof_bits, rv);
/* Channel coding */ /* Channel coding */
if (srslte_dlsch_encode2(&q->dl_sch, cfg, softbuffer, data, q->e[codeword_idx], codeword_idx)) { if (srslte_dlsch_encode2(&q->dl_sch, cfg, softbuffer, data, q->e[codeword_idx], tb_idx)) {
ERROR("Error encoding TB %d", codeword_idx); ERROR("Error encoding (TB%d -> CW%d)", tb_idx, codeword_idx);
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
@ -570,6 +582,8 @@ static int srslte_pdsch_codeword_encode(srslte_pdsch_t *q, srslte_pdsch_cfg_t *c
(uint8_t *) q->e[codeword_idx], (uint8_t *) q->e[codeword_idx],
q->d[codeword_idx], nbits->nof_bits); q->d[codeword_idx], nbits->nof_bits);
} else {
return SRSLTE_ERROR_INVALID_INPUTS;
} }
return SRSLTE_SUCCESS; return SRSLTE_SUCCESS;
@ -577,15 +591,15 @@ static int srslte_pdsch_codeword_encode(srslte_pdsch_t *q, srslte_pdsch_cfg_t *c
static int srslte_pdsch_codeword_decode(srslte_pdsch_t *q, srslte_pdsch_cfg_t *cfg, static int srslte_pdsch_codeword_decode(srslte_pdsch_t *q, srslte_pdsch_cfg_t *cfg,
srslte_softbuffer_rx_t *softbuffer, uint16_t rnti, uint8_t *data, srslte_softbuffer_rx_t *softbuffer, uint16_t rnti, uint8_t *data,
uint32_t codeword_idx, bool *ack) { uint32_t codeword_idx, uint32_t tb_idx, bool *ack) {
srslte_ra_nbits_t *nbits = &cfg->nbits[codeword_idx]; srslte_ra_nbits_t *nbits = &cfg->nbits[tb_idx];
srslte_ra_mcs_t *mcs = &cfg->grant.mcs[codeword_idx]; srslte_ra_mcs_t *mcs = &cfg->grant.mcs[tb_idx];
uint32_t rv = cfg->rv[codeword_idx]; uint32_t rv = cfg->rv[tb_idx];
int ret = SRSLTE_ERROR_INVALID_INPUTS; int ret = SRSLTE_ERROR_INVALID_INPUTS;
if (softbuffer && data && ack) { if (softbuffer && data && ack) {
INFO("Decoding PDSCH SF: %d (TB %d), Mod %s, NofBits: %d, NofSymbols: %d, NofBitsE: %d, rv_idx: %d\n", INFO("Decoding PDSCH SF: %d (CW%d -> TB%d), Mod %s, NofBits: %d, NofSymbols: %d, NofBitsE: %d, rv_idx: %d\n",
cfg->sf_idx, codeword_idx, srslte_mod_string(mcs->mod), mcs->tbs, cfg->sf_idx, codeword_idx, tb_idx, srslte_mod_string(mcs->mod), mcs->tbs,
nbits->nof_re, nbits->nof_bits, rv); nbits->nof_re, nbits->nof_bits, rv);
/* demodulate symbols /* demodulate symbols
@ -601,7 +615,7 @@ static int srslte_pdsch_codeword_decode(srslte_pdsch_t *q, srslte_pdsch_cfg_t *c
srslte_scrambling_s_offset(seq, q->e[codeword_idx], 0, nbits->nof_bits); srslte_scrambling_s_offset(seq, q->e[codeword_idx], 0, nbits->nof_bits);
/* Return */ /* Return */
ret = srslte_dlsch_decode2(&q->dl_sch, cfg, softbuffer, q->e[codeword_idx], data, codeword_idx); ret = srslte_dlsch_decode2(&q->dl_sch, cfg, softbuffer, q->e[codeword_idx], data, tb_idx);
q->last_nof_iterations[codeword_idx] = srslte_sch_last_noi(&q->dl_sch); q->last_nof_iterations[codeword_idx] = srslte_sch_last_noi(&q->dl_sch);
@ -610,6 +624,9 @@ static int srslte_pdsch_codeword_decode(srslte_pdsch_t *q, srslte_pdsch_cfg_t *c
} else if (ret == SRSLTE_ERROR) { } else if (ret == SRSLTE_ERROR) {
*ack = false; *ack = false;
ret = SRSLTE_SUCCESS; ret = SRSLTE_SUCCESS;
} else if (ret == SRSLTE_ERROR_INVALID_INPUTS) {
*ack = false;
ret = SRSLTE_ERROR;
} }
} else { } else {
ERROR("Detected NULL pointer in TB%d &softbuffer=%p &data=%p &ack=%p", codeword_idx, softbuffer, (void*)data, ack); ERROR("Detected NULL pointer in TB%d &softbuffer=%p &data=%p &ack=%p", codeword_idx, softbuffer, (void*)data, ack);
@ -677,24 +694,32 @@ int srslte_pdsch_decode(srslte_pdsch_t *q,
} }
// Pre-decoder // Pre-decoder
srslte_predecoding_type_multi(q->symbols, q->ce, x, q->nof_rx_antennas, q->cell.nof_ports, cfg->nof_layers, if (srslte_predecoding_type_multi(q->symbols, q->ce, x, q->nof_rx_antennas, q->cell.nof_ports, cfg->nof_layers,
cfg->codebook_idx, cfg->nbits[0].nof_re, cfg->mimo_type, noise_estimate); cfg->codebook_idx, cfg->nbits[0].nof_re, cfg->mimo_type, noise_estimate)<0) {
return -1;
}
// Layer demapping only if necessary // Layer demapping only if necessary
if (cfg->nof_layers != nof_tb) { if (cfg->nof_layers != nof_tb) {
srslte_layerdemap_type(x, q->d, cfg->nof_layers, nof_tb, srslte_layerdemap_type(x, q->d, cfg->nof_layers, nof_tb,
nof_symbols[0], nof_symbols, cfg->mimo_type); nof_symbols[0], nof_symbols, cfg->mimo_type);
} }
// Codeword decoding
for (uint32_t tb = 0; tb < SRSLTE_MAX_CODEWORDS; tb ++) { /* Codeword decoding: Implementation of 3GPP 36.212 Table 5.3.3.1.5-1 and Table 5.3.3.1.5-2 */
uint32_t cw_idx = (nof_tb == SRSLTE_MAX_TB && cfg->tb_cw_swap) ? 1 : 0;
for (uint32_t tb_idx = 0; tb_idx < SRSLTE_MAX_TB; tb_idx++) {
/* Decode only if transport block is enabled and the default ACK is not true */ /* Decode only if transport block is enabled and the default ACK is not true */
if (cfg->grant.tb_en[tb] && !acks[tb]) { if (cfg->grant.tb_en[tb_idx]) {
int ret = srslte_pdsch_codeword_decode(q, cfg, softbuffers[tb], rnti, data[tb], tb, &acks[tb]); if (!acks[tb_idx]) {
int ret = srslte_pdsch_codeword_decode(q, cfg, softbuffers[tb_idx], rnti, data[tb_idx], cw_idx, tb_idx, &acks[tb_idx]);
/* Check if there has been any execution error */ /* Check if there has been any execution error */
if (ret) { if (ret) {
return ret; return ret;
}
} }
cw_idx = (cw_idx + 1) % SRSLTE_MAX_CODEWORDS;
} }
} }
@ -767,20 +792,23 @@ int srslte_pdsch_encode(srslte_pdsch_t *q,
} }
/* If both transport block size is zero return error */ /* If both transport block size is zero return error */
if (cfg->grant.mcs[0].tbs == 0) { if (!nof_tb) {
return SRSLTE_ERROR_INVALID_INPUTS; return SRSLTE_ERROR_INVALID_INPUTS;
} }
if (cfg->nbits[0].nof_re > q->max_re) { if (cfg->nbits[0].nof_re > q->max_re || cfg->nbits[1].nof_re > q->max_re) {
fprintf(stderr, fprintf(stderr,
"Error too many RE per subframe (%d). PDSCH configured for %d RE (%d PRB)\n", "Error too many RE per subframe (%d). PDSCH configured for %d RE (%d PRB)\n",
cfg->nbits[0].nof_re, q->max_re, q->cell.nof_prb); cfg->nbits[0].nof_re, q->max_re, q->cell.nof_prb);
return SRSLTE_ERROR_INVALID_INPUTS; return SRSLTE_ERROR_INVALID_INPUTS;
} }
for (uint32_t tb = 0; tb < SRSLTE_MAX_CODEWORDS; tb ++) { /* Implementation of 3GPP 36.212 Table 5.3.3.1.5-1 and Table 5.3.3.1.5-2 */
if (cfg->grant.tb_en[tb]) { uint32_t cw_idx = (nof_tb == SRSLTE_MAX_TB && cfg->tb_cw_swap) ? 1 : 0;
ret |= srslte_pdsch_codeword_encode(q, cfg, softbuffers[tb], rnti, data[tb], tb); for (uint32_t tb_idx = 0; tb_idx < SRSLTE_MAX_TB; tb_idx++) {
if (cfg->grant.tb_en[tb_idx]) {
ret |= srslte_pdsch_codeword_encode(q, cfg, softbuffers[tb_idx], rnti, data[tb_idx], cw_idx, tb_idx);
cw_idx = (cw_idx + 1) % SRSLTE_MAX_CODEWORDS;
} }
} }

@ -791,7 +791,7 @@ int srslte_pucch_decode(srslte_pucch_t* q, srslte_pucch_format_t format,
// Perform ML-decoding // Perform ML-decoding
float corr=0, corr_max=-1e9; float corr=0, corr_max=-1e9;
int b_max = 0; // default bit value, eg. HI is NACK uint8_t b_max = 0, b2_max = 0; // default bit value, eg. HI is NACK
switch(format) { switch(format) {
case SRSLTE_PUCCH_FORMAT_1: case SRSLTE_PUCCH_FORMAT_1:
bzero(bits, SRSLTE_PUCCH_MAX_BITS*sizeof(uint8_t)); bzero(bits, SRSLTE_PUCCH_MAX_BITS*sizeof(uint8_t));
@ -808,7 +808,7 @@ int srslte_pucch_decode(srslte_pucch_t* q, srslte_pucch_format_t format,
case SRSLTE_PUCCH_FORMAT_1A: case SRSLTE_PUCCH_FORMAT_1A:
bzero(bits, SRSLTE_PUCCH_MAX_BITS*sizeof(uint8_t)); bzero(bits, SRSLTE_PUCCH_MAX_BITS*sizeof(uint8_t));
ret = 0; ret = 0;
for (int b=0;b<2;b++) { for (uint8_t b=0;b<2;b++) {
bits[0] = b; bits[0] = b;
pucch_encode(q, format, n_pucch, sf_idx, rnti, bits, q->z_tmp); pucch_encode(q, format, n_pucch, sf_idx, rnti, bits, q->z_tmp);
corr = srslte_vec_corr_ccc(q->z, q->z_tmp, nof_re); corr = srslte_vec_corr_ccc(q->z, q->z_tmp, nof_re);
@ -824,6 +824,30 @@ int srslte_pucch_decode(srslte_pucch_t* q, srslte_pucch_format_t format,
q->last_corr = corr_max; q->last_corr = corr_max;
bits[0] = b_max; bits[0] = b_max;
break; break;
case SRSLTE_PUCCH_FORMAT_1B:
bzero(bits, SRSLTE_PUCCH_MAX_BITS*sizeof(uint8_t));
ret = 0;
for (uint8_t b=0;b<2;b++) {
for (uint8_t b2 = 0; b2 < 2; b2++) {
bits[0] = b;
bits[1] = b2;
pucch_encode(q, format, n_pucch, sf_idx, rnti, bits, q->z_tmp);
corr = srslte_vec_corr_ccc(q->z, q->z_tmp, nof_re);
if (corr > corr_max) {
corr_max = corr;
b_max = b;
b2_max = b2;
}
if (corr_max > q->threshold_format1) { // check with format1 in case ack+sr because ack only is binary
ret = 1;
}
DEBUG("format1b b=%d, corr=%f, nof_re=%d\n", b, corr, nof_re);
}
}
q->last_corr = corr_max;
bits[0] = b_max;
bits[1] = b2_max;
break;
case SRSLTE_PUCCH_FORMAT_2: case SRSLTE_PUCCH_FORMAT_2:
case SRSLTE_PUCCH_FORMAT_2A: case SRSLTE_PUCCH_FORMAT_2A:
case SRSLTE_PUCCH_FORMAT_2B: case SRSLTE_PUCCH_FORMAT_2B:

@ -526,11 +526,9 @@ static int dl_dci_to_grant_mcs(srslte_ra_dl_dci_t *dci, srslte_ra_dl_grant_t *gr
grant->mcs[0].tbs = (uint32_t) tbs; grant->mcs[0].tbs = (uint32_t) tbs;
} else { } else {
n_prb = grant->nof_prb; n_prb = grant->nof_prb;
grant->nof_tb = 0;
if (dci->tb_en[0]) { if (dci->tb_en[0]) {
grant->mcs[0].idx = dci->mcs_idx; grant->mcs[0].idx = dci->mcs_idx;
grant->mcs[0].tbs = srslte_dl_fill_ra_mcs(&grant->mcs[0], n_prb); grant->mcs[0].tbs = srslte_dl_fill_ra_mcs(&grant->mcs[0], n_prb);
grant->nof_tb++;
} else { } else {
grant->mcs[0].tbs = 0; grant->mcs[0].tbs = 0;
} }
@ -560,16 +558,16 @@ void srslte_ra_dl_grant_to_nbits(srslte_ra_dl_grant_t *grant, uint32_t cfi, srsl
srslte_ra_nbits_t nbits [SRSLTE_MAX_CODEWORDS]) srslte_ra_nbits_t nbits [SRSLTE_MAX_CODEWORDS])
{ {
// Compute number of RE // Compute number of RE
for (int i = 0; i < SRSLTE_MAX_CODEWORDS; i++) { for (int i = 0; i < SRSLTE_MAX_TB; i++) {
/* Compute number of RE for first transport block */
nbits[i].nof_re = srslte_ra_dl_grant_nof_re(grant, cell, sf_idx, cell.nof_prb < 10 ? (cfi + 1) : cfi);
nbits[i].lstart = cell.nof_prb < 10 ? (cfi + 1) : cfi;
if (SRSLTE_SF_NORM == grant->sf_type) {
nbits[i].nof_symb = 2 * SRSLTE_CP_NSYMB(cell.cp) - nbits[0].lstart;
} else if (SRSLTE_SF_MBSFN == grant->sf_type) {
nbits[i].nof_symb = 2 * SRSLTE_CP_EXT_NSYMB - nbits[0].lstart;
}
if (grant->tb_en[i]) { if (grant->tb_en[i]) {
/* Compute number of RE for first transport block */
nbits[i].nof_re = srslte_ra_dl_grant_nof_re(grant, cell, sf_idx, cell.nof_prb < 10 ? (cfi + 1) : cfi);
nbits[i].lstart = cell.nof_prb < 10 ? (cfi + 1) : cfi;
if (SRSLTE_SF_NORM == grant->sf_type) {
nbits[i].nof_symb = 2 * SRSLTE_CP_NSYMB(cell.cp) - nbits[0].lstart;
} else if (SRSLTE_SF_MBSFN == grant->sf_type) {
nbits[i].nof_symb = 2 * SRSLTE_CP_EXT_NSYMB - nbits[0].lstart;
}
nbits[i].nof_bits = nbits[i].nof_re * grant->Qm[i]; nbits[i].nof_bits = nbits[i].nof_re * grant->Qm[i];
} }
} }

@ -167,7 +167,6 @@ int main(int argc, char **argv) {
/* If transport block 0 is enabled */ /* If transport block 0 is enabled */
grant.tb_en[0] = true; grant.tb_en[0] = true;
grant.tb_en[1] = false; grant.tb_en[1] = false;
grant.nof_tb = 1;
grant.mcs[0].idx = mcs_idx; grant.mcs[0].idx = mcs_idx;
grant.nof_prb = cell.nof_prb; grant.nof_prb = cell.nof_prb;

@ -686,7 +686,9 @@ int srslte_uci_decode_ack(srslte_pusch_cfg_t *cfg, int16_t *q_bits, uint8_t *c_s
} }
} }
if (acks) { if (nof_acks == 1 && acks) {
acks[0] = (uint8_t)(acks_sum[0] + acks_sum[1] + acks_sum[2] > 0);
} else if (acks) {
acks[0] = (uint8_t)(acks_sum[0] > 0); acks[0] = (uint8_t)(acks_sum[0] > 0);
acks[1] = (uint8_t)(acks_sum[1] > 0); acks[1] = (uint8_t)(acks_sum[1] > 0);
// TODO: Do something with acks_sum[2] // TODO: Do something with acks_sum[2]

@ -608,7 +608,6 @@ int srslte_ue_dl_decode_mbsfn(srslte_ue_dl_t * q,
//float noise_estimate = 0; //float noise_estimate = 0;
grant.sf_type = SRSLTE_SF_MBSFN; grant.sf_type = SRSLTE_SF_MBSFN;
grant.nof_tb = 1;
grant.mcs[0].idx = 2; grant.mcs[0].idx = 2;
grant.tb_en[0] = true; grant.tb_en[0] = true;
grant.tb_en[1] = false; grant.tb_en[1] = false;

@ -78,7 +78,7 @@ public:
int pmi_info(uint32_t tti, uint16_t rnti, uint32_t pmi_value); int pmi_info(uint32_t tti, uint16_t rnti, uint32_t pmi_value);
int cqi_info(uint32_t tti, uint16_t rnti, uint32_t cqi_value); int cqi_info(uint32_t tti, uint16_t rnti, uint32_t cqi_value);
int snr_info(uint32_t tti, uint16_t rnti, float snr); int snr_info(uint32_t tti, uint16_t rnti, float snr);
int ack_info(uint32_t tti, uint16_t rnti, bool ack); int ack_info(uint32_t tti, uint16_t rnti, uint32_t tb_idx, bool ack);
int crc_info(uint32_t tti, uint16_t rnti, uint32_t nof_bytes, bool crc_res); int crc_info(uint32_t tti, uint16_t rnti, uint32_t nof_bytes, bool crc_res);
int get_dl_sched(uint32_t tti, dl_sched_t *dl_sched_res); int get_dl_sched(uint32_t tti, dl_sched_t *dl_sched_res);

@ -104,7 +104,7 @@ public:
int dl_mac_buffer_state(uint16_t rnti, uint32_t ce_code); int dl_mac_buffer_state(uint16_t rnti, uint32_t ce_code);
int dl_ant_info(uint16_t rnti, LIBLTE_RRC_ANTENNA_INFO_DEDICATED_STRUCT *dedicated); int dl_ant_info(uint16_t rnti, LIBLTE_RRC_ANTENNA_INFO_DEDICATED_STRUCT *dedicated);
int dl_ack_info(uint32_t tti, uint16_t rnti, bool ack); int dl_ack_info(uint32_t tti, uint16_t rnti, uint32_t tb_idx, bool ack);
int dl_rach_info(uint32_t tti, uint32_t ra_id, uint16_t rnti, uint32_t estimated_size); int dl_rach_info(uint32_t tti, uint32_t ra_id, uint16_t rnti, uint32_t estimated_size);
int dl_ri_info(uint32_t tti, uint16_t rnti, uint32_t ri_value); int dl_ri_info(uint32_t tti, uint16_t rnti, uint32_t ri_value);
int dl_pmi_info(uint32_t tti, uint16_t rnti, uint32_t pmi_value); int dl_pmi_info(uint32_t tti, uint16_t rnti, uint32_t pmi_value);

@ -58,7 +58,7 @@ protected:
bool has_pending_retx_common(uint32_t tb_idx); bool has_pending_retx_common(uint32_t tb_idx);
bool ack[SRSLTE_MAX_TB]; bool ack[SRSLTE_MAX_TB];
bool active; bool active[SRSLTE_MAX_TB];
bool ndi[SRSLTE_MAX_TB]; bool ndi[SRSLTE_MAX_TB];
uint32_t id; uint32_t id;
uint32_t max_retx; uint32_t max_retx;

@ -73,7 +73,7 @@ public:
void set_dl_ri(uint32_t tti, uint32_t ri); void set_dl_ri(uint32_t tti, uint32_t ri);
void set_dl_pmi(uint32_t tti, uint32_t ri); void set_dl_pmi(uint32_t tti, uint32_t ri);
void set_dl_cqi(uint32_t tti, uint32_t cqi); void set_dl_cqi(uint32_t tti, uint32_t cqi);
int set_ack_info(uint32_t tti, bool ack); int set_ack_info(uint32_t tti, uint32_t tb_idx, bool ack);
void set_ul_crc(uint32_t tti, bool crc_res); void set_ul_crc(uint32_t tti, bool crc_res);
/******************************************************* /*******************************************************

@ -75,7 +75,7 @@ public:
uint8_t* generate_pdu(sched_interface::dl_sched_pdu_t pdu[sched_interface::MAX_RLC_PDU_LIST], uint8_t* generate_pdu(sched_interface::dl_sched_pdu_t pdu[sched_interface::MAX_RLC_PDU_LIST],
uint32_t nof_pdu_elems, uint32_t grant_size); uint32_t nof_pdu_elems, uint32_t grant_size);
srslte_softbuffer_tx_t* get_tx_softbuffer(uint32_t harq_process); srslte_softbuffer_tx_t* get_tx_softbuffer(uint32_t harq_process, uint32_t tb_idx);
srslte_softbuffer_rx_t* get_rx_softbuffer(uint32_t tti); srslte_softbuffer_rx_t* get_rx_softbuffer(uint32_t tti);
bool process_pdus(); bool process_pdus();
@ -122,9 +122,9 @@ private:
uint32_t last_tti; uint32_t last_tti;
uint32_t nof_failures; uint32_t nof_failures;
const static int NOF_HARQ_PROCESSES = 2*HARQ_DELAY_MS; const static int NOF_HARQ_PROCESSES = 2 * HARQ_DELAY_MS * SRSLTE_MAX_TB;
srslte_softbuffer_tx_t softbuffer_tx[NOF_HARQ_PROCESSES]; srslte_softbuffer_tx_t softbuffer_tx[NOF_HARQ_PROCESSES];
srslte_softbuffer_rx_t softbuffer_rx[NOF_HARQ_PROCESSES]; srslte_softbuffer_rx_t softbuffer_rx[NOF_HARQ_PROCESSES];

@ -83,7 +83,7 @@ public:
// Map of pending ACKs for each user // Map of pending ACKs for each user
typedef struct { typedef struct {
bool is_pending[TTIMOD_SZ]; bool is_pending[TTIMOD_SZ][SRSLTE_MAX_TB];
uint16_t n_pdcch[TTIMOD_SZ]; uint16_t n_pdcch[TTIMOD_SZ];
} pending_ack_t; } pending_ack_t;
std::map<uint16_t,pending_ack_t> pending_ack; std::map<uint16_t,pending_ack_t> pending_ack;
@ -91,8 +91,8 @@ public:
void ack_add_rnti(uint16_t rnti); void ack_add_rnti(uint16_t rnti);
void ack_rem_rnti(uint16_t rnti); void ack_rem_rnti(uint16_t rnti);
void ack_clear(uint32_t sf_idx); void ack_clear(uint32_t sf_idx);
void ack_set_pending(uint32_t sf_idx, uint16_t rnti, uint32_t n_pdcch); void ack_set_pending(uint32_t sf_idx, uint16_t rnti, uint32_t tb_idx, uint32_t n_pdcch);
bool ack_is_pending(uint32_t sf_idx, uint16_t rnti, uint32_t *last_n_pdcch = NULL); bool ack_is_pending(uint32_t sf_idx, uint16_t rnti, uint32_t tb_idx, uint32_t *last_n_pdcch = NULL);
private: private:
std::vector<pthread_mutex_t> tx_mutex; std::vector<pthread_mutex_t> tx_mutex;

@ -106,8 +106,10 @@ private:
dedicated_ack(false) {bzero(&metrics, sizeof(phy_metrics_t));} dedicated_ack(false) {bzero(&metrics, sizeof(phy_metrics_t));}
uint32_t I_sr; uint32_t I_sr;
uint32_t pmi_idx; uint32_t pmi_idx;
uint32_t ri_idx;
bool I_sr_en; bool I_sr_en;
bool cqi_en; bool cqi_en;
bool ri_en;
bool pucch_cqi_ack; bool pucch_cqi_ack;
int has_grant_tti; int has_grant_tti;
LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT dedicated; LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT dedicated;

@ -262,10 +262,10 @@ void mac::rl_ok(uint16_t rnti)
} }
} }
int mac::ack_info(uint32_t tti, uint16_t rnti, bool ack) int mac::ack_info(uint32_t tti, uint16_t rnti, uint32_t tb_idx, bool ack)
{ {
log_h->step(tti); log_h->step(tti);
uint32_t nof_bytes = scheduler.dl_ack_info(tti, rnti, ack); uint32_t nof_bytes = scheduler.dl_ack_info(tti, rnti, tb_idx, ack);
ue_db[rnti]->metrics_tx(ack, nof_bytes); ue_db[rnti]->metrics_tx(ack, nof_bytes);
if (ack) { if (ack) {
@ -474,25 +474,39 @@ int mac::get_dl_sched(uint32_t tti, dl_sched_t *dl_sched_res)
dl_sched_res->sched_grants[n].dci_format = sched_result.data[i].dci_format; dl_sched_res->sched_grants[n].dci_format = sched_result.data[i].dci_format;
memcpy(&dl_sched_res->sched_grants[n].grant, &sched_result.data[i].dci, sizeof(srslte_ra_dl_dci_t)); memcpy(&dl_sched_res->sched_grants[n].grant, &sched_result.data[i].dci, sizeof(srslte_ra_dl_dci_t));
memcpy(&dl_sched_res->sched_grants[n].location, &sched_result.data[i].dci_location, sizeof(srslte_dci_location_t)); memcpy(&dl_sched_res->sched_grants[n].location, &sched_result.data[i].dci_location, sizeof(srslte_dci_location_t));
dl_sched_res->sched_grants[n].softbuffers[0] = ue_db[rnti]->get_tx_softbuffer(sched_result.data[i].dci.harq_process);
// Get PDU if it's a new transmission
if (sched_result.data[i].nof_pdu_elems > 0) {
dl_sched_res->sched_grants[n].data[0] = ue_db[rnti]->generate_pdu(sched_result.data[i].pdu,
sched_result.data[i].nof_pdu_elems,
sched_result.data[i].tbs[0]);
if (pcap) { for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) {
pcap->write_dl_crnti(dl_sched_res->sched_grants[n].data[0], sched_result.data[i].tbs[0], rnti, true, tti); if (sched_result.data[i].dci.tb_en[tb] && sched_result.data[i].nof_pdu_elems[tb] > 0) {
dl_sched_res->sched_grants[n].softbuffers[tb] =
ue_db[rnti]->get_tx_softbuffer(sched_result.data[i].dci.harq_process, tb);
/* Get PDU if it's a new transmission */
dl_sched_res->sched_grants[n].data[tb] = ue_db[rnti]->generate_pdu(sched_result.data[i].pdu[tb],
sched_result.data[i].nof_pdu_elems[tb],
sched_result.data[i].tbs[tb]);
if (!dl_sched_res->sched_grants[n].data[tb]) {
Error("Error! PDU was not generated (rnti=0x%04x, tb=%d)\n", rnti, tb);
sched_result.data[i].dci.tb_en[tb] = false;
}
if (pcap) {
pcap->write_dl_crnti(dl_sched_res->sched_grants[n].data[tb], sched_result.data[i].tbs[tb], rnti, true, tti);
}
} else {
/* TB not enabled OR no data to send: set pointers to NULL */
dl_sched_res->sched_grants[n].softbuffers[tb] = NULL;
dl_sched_res->sched_grants[n].data[tb] = NULL;
if (sched_result.data[i].dci.tb_en[tb]) {
Warning("Transport block without PDU elements (rnti: %04x)\n", rnti);
sched_result.data[i].dci.tb_en[tb] = false;
}
} }
} else {
dl_sched_res->sched_grants[n].data[0] = NULL;
} }
n++; n++;
} }
// Copy RAR grants // Copy RAR grants
for (uint32_t i=0;i<sched_result.nof_rar_elems;i++) { for (uint32_t i=0;i<sched_result.nof_rar_elems;i++) {
// Copy grant info // Copy grant info

@ -251,12 +251,12 @@ int sched::dl_ant_info(uint16_t rnti, LIBLTE_RRC_ANTENNA_INFO_DEDICATED_STRUCT *
return ret; return ret;
} }
int sched::dl_ack_info(uint32_t tti, uint16_t rnti, bool ack) int sched::dl_ack_info(uint32_t tti, uint16_t rnti, uint32_t tb_idx, bool ack)
{ {
pthread_mutex_lock(&mutex); pthread_mutex_lock(&mutex);
int ret = 0; int ret = 0;
if (ue_db.count(rnti)) { if (ue_db.count(rnti)) {
ret = ue_db[rnti].set_ack_info(tti, ack); ret = ue_db[rnti].set_ack_info(tti, tb_idx, ack);
} else { } else {
Error("User rnti=0x%x not found\n", rnti); Error("User rnti=0x%x not found\n", rnti);
ret = -1; ret = -1;
@ -663,10 +663,11 @@ int sched::dl_sched_data(dl_sched_data_t data[MAX_DATA_LIST])
Error("DCI format (%d) not implemented\n", dci_format); Error("DCI format (%d) not implemented\n", dci_format);
} }
if (tbs >= 0) { if (tbs >= 0) {
log_h->info("SCHED: DL %s rnti=0x%x, pid=%d, mask=0x%x, dci=%d,%d, n_rtx=%d, tbs=%d, buffer=%d\n", log_h->info("SCHED: DL %s rnti=0x%x, pid=%d, mask=0x%x, dci=%d,%d, n_rtx=%d, tbs=%d, buffer=%d, tb_en={%s,%s}\n",
!is_newtx?"retx":"tx", rnti, h->get_id(), h->get_rbgmask(), !is_newtx?"retx":"tx", rnti, h->get_id(), h->get_rbgmask(),
data[nof_data_elems].dci_location.L, data[nof_data_elems].dci_location.ncce, h->nof_retx(0), data[nof_data_elems].dci_location.L, data[nof_data_elems].dci_location.ncce, h->nof_retx(0) + h->nof_retx(1),
tbs, user->get_pending_dl_new_data(current_tti)); tbs, user->get_pending_dl_new_data(current_tti), data[nof_data_elems].dci.tb_en[0]?"y":"n",
data[nof_data_elems].dci.tb_en[1]?"y":"n");
nof_data_elems++; nof_data_elems++;
} else { } else {
log_h->warning("SCHED: Error DL %s rnti=0x%x, pid=%d, mask=0x%x, dci=%d,%d, tbs=%d, buffer=%d\n", log_h->warning("SCHED: Error DL %s rnti=0x%x, pid=%d, mask=0x%x, dci=%d,%d, tbs=%d, buffer=%d\n",
@ -675,7 +676,9 @@ int sched::dl_sched_data(dl_sched_data_t data[MAX_DATA_LIST])
tbs, user->get_pending_dl_new_data(current_tti)); tbs, user->get_pending_dl_new_data(current_tti));
} }
} else { } else {
h->reset(0); for(uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) {
h->reset(tb);
}
Warning("SCHED: Could not schedule DL DCI for rnti=0x%x, pid=%d\n", rnti, h->get_id()); Warning("SCHED: Could not schedule DL DCI for rnti=0x%x, pid=%d\n", rnti, h->get_id());
} }
} }

@ -67,7 +67,7 @@ uint32_t harq_proc::get_id()
void harq_proc::reset(uint32_t tb_idx) void harq_proc::reset(uint32_t tb_idx)
{ {
active = false; active[tb_idx] = false;
ack[tb_idx] = true; ack[tb_idx] = true;
ack_received[tb_idx] = false; ack_received[tb_idx] = false;
n_rtx[tb_idx] = 0; n_rtx[tb_idx] = 0;
@ -79,7 +79,7 @@ void harq_proc::reset(uint32_t tb_idx)
bool harq_proc::is_empty(uint32_t tb_idx) bool harq_proc::is_empty(uint32_t tb_idx)
{ {
return !active || (active && ack[tb_idx] && ack_received[tb_idx]); return !active[tb_idx] || (active[tb_idx] && ack[tb_idx] && ack_received[tb_idx]);
} }
bool harq_proc::has_pending_retx_common(uint32_t tb_idx) bool harq_proc::has_pending_retx_common(uint32_t tb_idx)
@ -104,7 +104,7 @@ void harq_proc::set_ack(uint32_t tb_idx, bool ack_)
log_h->debug("ACK=%d received pid=%d, tb_idx=%d, n_rtx=%d, max_retx=%d\n", ack_, id, tb_idx, n_rtx[tb_idx], max_retx); log_h->debug("ACK=%d received pid=%d, tb_idx=%d, n_rtx=%d, max_retx=%d\n", ack_, id, tb_idx, n_rtx[tb_idx], max_retx);
if (n_rtx[tb_idx] + 1 >= max_retx) { if (n_rtx[tb_idx] + 1 >= max_retx) {
Warning("SCHED: discarting TB %d pid=%d, tti=%d, maximum number of retx exceeded (%d)\n", tb_idx, id, tti, max_retx); Warning("SCHED: discarting TB %d pid=%d, tti=%d, maximum number of retx exceeded (%d)\n", tb_idx, id, tti, max_retx);
active = false; active[tb_idx] = false;
} }
} }
@ -118,9 +118,9 @@ void harq_proc::new_tx_common(uint32_t tb_idx, uint32_t tti_, int mcs, int tbs)
last_tbs[tb_idx] = tbs; last_tbs[tb_idx] = tbs;
if (max_retx) { if (max_retx) {
active = true; active[tb_idx] = true;
} else { } else {
active = false; // Can reuse this process if no retx are allowed active[tb_idx] = false; // Can reuse this process if no retx are allowed
} }
} }
@ -227,10 +227,10 @@ bool ul_harq_proc::has_pending_ack()
bool ret = need_ack; bool ret = need_ack;
// Reset if already received a positive ACK // Reset if already received a positive ACK
if (active && ack[0]) { if (active[0] && ack[0]) {
active = false; active[0] = false;
} }
if (!active) { if (!active[0]) {
need_ack = false; need_ack = false;
} }
return ret; return ret;
@ -240,7 +240,7 @@ bool ul_harq_proc::has_pending_ack()
void ul_harq_proc::reset_pending_data() void ul_harq_proc::reset_pending_data()
{ {
if (!active) { if (!active[0]) {
pending_data = 0; pending_data = 0;
} }
} }

@ -27,11 +27,7 @@
#include <string.h> #include <string.h>
#include <boost/concept_check.hpp> #include <boost/concept_check.hpp>
#include <srslte/interfaces/sched_interface.h> #include <srslte/interfaces/sched_interface.h>
#include <srslte/phy/phch/pucch.h>
#include <srslte/srslte.h>
#include <srslte/phy/common/phy_common.h>
#include "srslte/srslte.h"
#include "srslte/common/pdu.h" #include "srslte/common/pdu.h"
#include "mac/scheduler_ue.h" #include "mac/scheduler_ue.h"
#include "mac/scheduler.h" #include "mac/scheduler.h"
@ -109,8 +105,10 @@ void sched_ue::reset()
ul_cqi_tti = 0; ul_cqi_tti = 0;
cqi_request_tti = 0; cqi_request_tti = 0;
for (int i=0;i<SCHED_MAX_HARQ_PROC;i++) { for (int i=0;i<SCHED_MAX_HARQ_PROC;i++) {
dl_harq[i].reset(0); for(uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) {
ul_harq[i].reset(0); dl_harq[i].reset(tb);
ul_harq[i].reset(tb);
}
} }
for (int i=0;i<sched_interface::MAX_LC; i++) { for (int i=0;i<sched_interface::MAX_LC; i++) {
rem_bearer(i); rem_bearer(i);
@ -286,13 +284,13 @@ bool sched_ue::get_pucch_sched(uint32_t current_tti, uint32_t prb_idx[2])
return false; return false;
} }
int sched_ue::set_ack_info(uint32_t tti, bool ack) int sched_ue::set_ack_info(uint32_t tti, uint32_t tb_idx, bool ack)
{ {
for (int i=0;i<SCHED_MAX_HARQ_PROC;i++) { for (int i=0;i<SCHED_MAX_HARQ_PROC;i++) {
if (TTI_TX(dl_harq[i].get_tti()) == tti) { if (TTI_TX(dl_harq[i].get_tti()) == tti) {
Debug("SCHED: Set ACK=%d for rnti=0x%x, pid=%d, tti=%d\n", ack, rnti, i, tti); Debug("SCHED: Set ACK=%d for rnti=0x%x, pid=%d.%d, tti=%d\n", ack, rnti, i, tb_idx, tti);
dl_harq[i].set_ack(0, ack); dl_harq[i].set_ack(tb_idx, ack);
return dl_harq[i].get_tbs(0); return dl_harq[i].get_tbs(tb_idx);
} }
} }
Warning("SCHED: Received ACK info for unknown TTI=%d\n", tti); Warning("SCHED: Received ACK info for unknown TTI=%d\n", tti);
@ -422,18 +420,18 @@ int sched_ue::generate_format1(dl_harq_proc *h,
// Allocate MAC ConRes CE // Allocate MAC ConRes CE
if (need_conres_ce) { if (need_conres_ce) {
data->pdu[0].lcid = srslte::sch_subh::CON_RES_ID; data->pdu[0][0].lcid = srslte::sch_subh::CON_RES_ID;
data->nof_pdu_elems++; data->nof_pdu_elems[0]++;
Info("SCHED: Added MAC Contention Resolution CE for rnti=0x%x\n", rnti); Info("SCHED: Added MAC Contention Resolution CE for rnti=0x%x\n", rnti);
} }
int rem_tbs = tbs; int rem_tbs = tbs;
int x = 0; int x = 0;
do { do {
x = alloc_pdu(rem_tbs, &data->pdu[data->nof_pdu_elems]); x = alloc_pdu(rem_tbs, &data->pdu[0][data->nof_pdu_elems[0]]);
rem_tbs -= x; rem_tbs -= x;
if (x) { if (x) {
data->nof_pdu_elems++; data->nof_pdu_elems[0]++;
} }
} while(rem_tbs > 0 && x > 0); } while(rem_tbs > 0 && x > 0);
@ -441,13 +439,14 @@ int sched_ue::generate_format1(dl_harq_proc *h,
if (tbs > 0) { if (tbs > 0) {
dci->harq_process = h->get_id(); dci->harq_process = h->get_id();
dci->mcs_idx = mcs; dci->mcs_idx = (uint32_t) mcs;
dci->rv_idx = sched::get_rvidx(h->nof_retx(0)); dci->rv_idx = sched::get_rvidx(h->nof_retx(0));
dci->ndi = h->get_ndi(0); dci->ndi = h->get_ndi(0);
dci->tpc_pucch = next_tpc_pucch; dci->tpc_pucch = (uint8_t) next_tpc_pucch;
next_tpc_pucch = 1; next_tpc_pucch = 1;
data->tbs[0] = tbs; data->tbs[0] = (uint32_t) tbs;
dci->tb_en[0] = true; data->tbs[1] = 0;
dci->tb_en[0] = true;
dci->tb_en[1] = false; dci->tb_en[1] = false;
} }
return tbs; return tbs;
@ -464,60 +463,90 @@ int sched_ue::generate_format2a(dl_harq_proc *h,
uint32_t sf_idx = tti%10; uint32_t sf_idx = tti%10;
int mcs = 0;
int tbs = 0;
dci->alloc_type = SRSLTE_RA_ALLOC_TYPE0; dci->alloc_type = SRSLTE_RA_ALLOC_TYPE0;
dci->type0_alloc.rbg_bitmask = h->get_rbgmask(); dci->type0_alloc.rbg_bitmask = h->get_rbgmask();
if (h->is_empty(0)) { uint32_t nof_prb = format1_count_prb(h->get_rbgmask(), cell.nof_prb);
uint32_t nof_ctrl_symbols = cfi + (cell.nof_prb < 10 ? 1 : 0);
srslte_ra_dl_grant_t grant;
srslte_ra_dl_dci_to_grant_prb_allocation(dci, &grant, cell.nof_prb);
uint32_t nof_re = srslte_ra_dl_grant_nof_re(&grant, cell, sf_idx, nof_ctrl_symbols);
uint32_t req_bytes = get_pending_dl_new_data(tti);
for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) {
int mcs = 0;
int tbs = 0;
/*
* If one layer (RI = 0) Then
* If TB1 has pending harq
* Send TB1 only
* Else
* Send TB0 Only
* End If
* Else (RI != 0)
* Send TB0 and TB1
* End If
*/
if (dl_ri == 1 || (dl_ri == 0 && ((tb == 0 && h->is_empty(1)) || (tb == 1 && !h->is_empty(1))))) {
if (h->is_empty(tb)) {
if (fixed_mcs_dl < 0) {
tbs = alloc_tbs_dl(nof_prb, nof_re, req_bytes, &mcs);
} else {
tbs = srslte_ra_tbs_from_idx((uint32_t) srslte_ra_tbs_idx_from_mcs((uint32_t) fixed_mcs_dl), nof_prb) / 8;
mcs = fixed_mcs_dl;
}
uint32_t req_bytes = get_pending_dl_new_data(tti); h->new_tx(tb, tti, mcs, tbs, data->dci_location.ncce);
uint32_t nof_prb = format1_count_prb(h->get_rbgmask(), cell.nof_prb); Debug("SCHED: Alloc format2/2a new mcs=%d, tbs=%d, nof_prb=%d, req_bytes=%d\n", mcs, tbs, nof_prb, req_bytes);
srslte_ra_dl_grant_t grant; } else {
srslte_ra_dl_dci_to_grant_prb_allocation(dci, &grant, cell.nof_prb); h->new_retx(tb, tti, &mcs, &tbs);
uint32_t nof_ctrl_symbols = cfi+(cell.nof_prb<10?1:0); Debug("SCHED: Alloc format2/2a previous mcs=%d, tbs=%d\n", mcs, tbs);
uint32_t nof_re = srslte_ra_dl_grant_nof_re(&grant, cell, sf_idx, nof_ctrl_symbols); }
if (fixed_mcs_dl < 0) {
tbs = alloc_tbs_dl(nof_prb, nof_re, req_bytes, &mcs);
} else {
tbs = srslte_ra_tbs_from_idx(srslte_ra_tbs_idx_from_mcs(fixed_mcs_dl), nof_prb)/8;
mcs = fixed_mcs_dl;
} }
h->new_tx(0, tti, mcs, tbs, data->dci_location.ncce); int rem_tbs = tbs;
int x = 0;
do {
x = alloc_pdu(rem_tbs, &data->pdu[tb][data->nof_pdu_elems[tb]]);
rem_tbs -= x;
if (x) {
data->nof_pdu_elems[tb]++;
}
} while (rem_tbs > 0 && x > 0);
Debug("SCHED: Alloc format1 new mcs=%d, tbs=%d, nof_prb=%d, req_bytes=%d\n", mcs, tbs, nof_prb, req_bytes); data->rnti = rnti;
} else {
h->new_retx(0, tti, &mcs, &tbs);
Debug("SCHED: Alloc format1 previous mcs=%d, tbs=%d\n", mcs, tbs);
}
int rem_tbs = tbs; if (tbs > 0 && data->nof_pdu_elems[tb]) {
int x = 0; if (tb == 0) {
do { dci->mcs_idx = (uint32_t) mcs;
x = alloc_pdu(rem_tbs, &data->pdu[data->nof_pdu_elems]); dci->rv_idx = sched::get_rvidx(h->nof_retx(tb));
rem_tbs -= x; dci->ndi = h->get_ndi(tb);
if (x) { } else {
data->nof_pdu_elems++; dci->mcs_idx_1 = (uint32_t) mcs;
dci->rv_idx_1 = sched::get_rvidx(h->nof_retx(tb));
dci->ndi_1 = h->get_ndi(tb);
}
data->tbs[tb] = (uint32_t) tbs;
dci->tb_en[tb] = true;
} else {
data->tbs[tb] = 0;
dci->tb_en[tb] = false;
} }
} while(rem_tbs > 0 && x > 0);
data->rnti = rnti; if ( req_bytes > (uint32_t) tbs) {
req_bytes -= tbs;
if (tbs > 0) { } else {
dci->harq_process = h->get_id(); req_bytes = 0;
dci->mcs_idx = mcs; }
dci->rv_idx = sched::get_rvidx(h->nof_retx(0));
dci->ndi = h->get_ndi(0);
dci->tpc_pucch = next_tpc_pucch;
next_tpc_pucch = 1;
data->tbs[0] = tbs;
dci->tb_en[0] = true;
dci->tb_en[1] = false;
} }
return tbs;
dci->harq_process = h->get_id();
dci->tpc_pucch = (uint8_t) next_tpc_pucch;
next_tpc_pucch = 1;
return data->tbs[0] + data->tbs[1];
} }
// Generates a Format2 grant // Generates a Format2 grant
@ -526,71 +555,17 @@ int sched_ue::generate_format2(dl_harq_proc *h,
uint32_t tti, uint32_t tti,
uint32_t cfi) uint32_t cfi)
{ {
srslte_ra_dl_dci_t *dci = &data->dci; /* Call Format 2a (common) */
bzero(dci, sizeof(srslte_ra_dl_dci_t)); int ret = generate_format2a(h, data, tti, cfi);
uint32_t sf_idx = tti%10;
int mcs = 0;
int tbs = 0;
dci->alloc_type = SRSLTE_RA_ALLOC_TYPE0;
dci->type0_alloc.rbg_bitmask = h->get_rbgmask();
if (h->is_empty(0)) {
uint32_t req_bytes = get_pending_dl_new_data(tti);
uint32_t nof_prb = format1_count_prb(h->get_rbgmask(), cell.nof_prb);
srslte_ra_dl_grant_t grant;
srslte_ra_dl_dci_to_grant_prb_allocation(dci, &grant, cell.nof_prb);
uint32_t nof_ctrl_symbols = cfi+(cell.nof_prb<10?1:0);
uint32_t nof_re = srslte_ra_dl_grant_nof_re(&grant, cell, sf_idx, nof_ctrl_symbols);
if (fixed_mcs_dl < 0) {
tbs = alloc_tbs_dl(nof_prb, nof_re, req_bytes, &mcs);
} else {
tbs = srslte_ra_tbs_from_idx(srslte_ra_tbs_idx_from_mcs(fixed_mcs_dl), nof_prb)/8;
mcs = fixed_mcs_dl;
}
h->new_tx(0, tti, mcs, tbs, data->dci_location.ncce); /* Compute precoding information */
if (SRSLTE_RA_DL_GRANT_NOF_TB(&data->dci) == 1) {
Debug("SCHED: Alloc format2 new mcs=%d, tbs=%d, nof_prb=%d, req_bytes=%d\n", mcs, tbs, nof_prb, req_bytes); data->dci.pinfo = (uint8_t) (dl_pmi + 1) % (uint8_t) 5;
} else { } else {
h->new_retx(0, tti, &mcs, &tbs); data->dci.pinfo = (uint8_t) (dl_pmi & 1);
Debug("SCHED: Alloc format2 previous mcs=%d, tbs=%d\n", mcs, tbs);
} }
int rem_tbs = tbs; return ret;
int x = 0;
do {
x = alloc_pdu(rem_tbs, &data->pdu[data->nof_pdu_elems]);
rem_tbs -= x;
if (x) {
data->nof_pdu_elems++;
}
} while(rem_tbs > 0 && x > 0);
data->rnti = rnti;
if (tbs > 0) {
dci->pinfo = (uint8_t) (dl_pmi + 1);
/* if (SRSLTE_RA_DL_GRANT_NOF_TB(dci) == 1) {
dci->pinfo = (uint8_t) (dl_pmi + 1);
} else {
dci->pinfo = (uint8_t) (dl_pmi & 1);
}*/
dci->harq_process = h->get_id();
dci->mcs_idx = mcs;
dci->rv_idx = sched::get_rvidx(h->nof_retx(0));
dci->ndi = h->get_ndi(0);
dci->tpc_pucch = next_tpc_pucch;
next_tpc_pucch = 1;
data->tbs[0] = tbs;
dci->tb_en[0] = true;
dci->tb_en[1] = false;
}
return tbs;
} }
@ -818,7 +793,7 @@ dl_harq_proc* sched_ue::get_pending_dl_harq(uint32_t tti)
int oldest_idx=-1; int oldest_idx=-1;
uint32_t oldest_tti = 0; uint32_t oldest_tti = 0;
for (int i=0;i<SCHED_MAX_HARQ_PROC;i++) { for (int i=0;i<SCHED_MAX_HARQ_PROC;i++) {
if (dl_harq[i].has_pending_retx(0, tti)) { if (dl_harq[i].has_pending_retx(0, tti) || dl_harq[i].has_pending_retx(1, tti)) {
uint32_t x = srslte_tti_interval(tti, dl_harq[i].get_tti()); uint32_t x = srslte_tti_interval(tti, dl_harq[i].get_tti());
if (x > oldest_tti) { if (x > oldest_tti) {
oldest_idx = i; oldest_idx = i;
@ -839,7 +814,7 @@ dl_harq_proc* sched_ue::get_pending_dl_harq(uint32_t tti)
dl_harq_proc* sched_ue::get_empty_dl_harq() dl_harq_proc* sched_ue::get_empty_dl_harq()
{ {
for (int i=0;i<SCHED_MAX_HARQ_PROC;i++) { for (int i=0;i<SCHED_MAX_HARQ_PROC;i++) {
if (dl_harq[i].is_empty(0)) { if (dl_harq[i].is_empty(0) && dl_harq[i].is_empty(1)) {
return &dl_harq[i]; return &dl_harq[i];
} }
} }

@ -107,9 +107,9 @@ srslte_softbuffer_rx_t* ue::get_rx_softbuffer(uint32_t tti)
return &softbuffer_rx[tti%NOF_HARQ_PROCESSES]; return &softbuffer_rx[tti%NOF_HARQ_PROCESSES];
} }
srslte_softbuffer_tx_t* ue::get_tx_softbuffer(uint32_t harq_process) srslte_softbuffer_tx_t* ue::get_tx_softbuffer(uint32_t harq_process, uint32_t tb_idx)
{ {
return &softbuffer_tx[harq_process%NOF_HARQ_PROCESSES]; return &softbuffer_tx[(harq_process * SRSLTE_MAX_TB + tb_idx )%NOF_HARQ_PROCESSES];
} }
uint8_t* ue::request_buffer(uint32_t tti, uint32_t len) uint8_t* ue::request_buffer(uint32_t tti, uint32_t len)

@ -30,7 +30,6 @@
#include "phy/txrx.h" #include "phy/txrx.h"
#include <assert.h> #include <assert.h>
#include <string.h>
#define Error(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->error_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) #define Error(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->error_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
#define Warning(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->warning_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) #define Warning(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->warning_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
@ -98,14 +97,18 @@ void phch_common::ack_clear(uint32_t sf_idx)
{ {
for(std::map<uint16_t,pending_ack_t>::iterator iter=pending_ack.begin(); iter!=pending_ack.end(); ++iter) { for(std::map<uint16_t,pending_ack_t>::iterator iter=pending_ack.begin(); iter!=pending_ack.end(); ++iter) {
pending_ack_t *p = (pending_ack_t*) &iter->second; pending_ack_t *p = (pending_ack_t*) &iter->second;
p->is_pending[sf_idx] = false; for (uint32_t tb_idx = 0; tb_idx < SRSLTE_MAX_TB; tb_idx++) {
p->is_pending[sf_idx][tb_idx] = false;
}
} }
} }
void phch_common::ack_add_rnti(uint16_t rnti) void phch_common::ack_add_rnti(uint16_t rnti)
{ {
for (int sf_idx=0;sf_idx<TTIMOD_SZ;sf_idx++) { for (int sf_idx=0;sf_idx<TTIMOD_SZ;sf_idx++) {
pending_ack[rnti].is_pending[sf_idx] = false; for (uint32_t tb_idx = 0; tb_idx < SRSLTE_MAX_TB; tb_idx++) {
pending_ack[rnti].is_pending[sf_idx][tb_idx] = false;
}
} }
} }
@ -114,19 +117,18 @@ void phch_common::ack_rem_rnti(uint16_t rnti)
pending_ack.erase(rnti); pending_ack.erase(rnti);
} }
void phch_common::ack_set_pending(uint32_t sf_idx, uint16_t rnti, uint32_t last_n_pdcch) void phch_common::ack_set_pending(uint32_t sf_idx, uint16_t rnti, uint32_t tb_idx, uint32_t last_n_pdcch)
{ {
if (pending_ack.count(rnti)) { if (pending_ack.count(rnti)) {
pending_ack[rnti].is_pending[sf_idx] = true; pending_ack[rnti].is_pending[sf_idx][tb_idx] = true;
pending_ack[rnti].n_pdcch[sf_idx] = last_n_pdcch; pending_ack[rnti].n_pdcch[sf_idx] = (uint16_t) last_n_pdcch;
} }
} }
bool phch_common::ack_is_pending(uint32_t sf_idx, uint16_t rnti, uint32_t *last_n_pdcch) bool phch_common::ack_is_pending(uint32_t sf_idx, uint16_t rnti, uint32_t tb_idx, uint32_t *last_n_pdcch) {
{
if (pending_ack.count(rnti)) { if (pending_ack.count(rnti)) {
bool ret = pending_ack[rnti].is_pending[sf_idx]; bool ret = pending_ack[rnti].is_pending[sf_idx][tb_idx];
pending_ack[rnti].is_pending[sf_idx] = false; pending_ack[rnti].is_pending[sf_idx][tb_idx] = false;
if (ret && last_n_pdcch) { if (ret && last_n_pdcch) {
*last_n_pdcch = pending_ack[rnti].n_pdcch[sf_idx]; *last_n_pdcch = pending_ack[rnti].n_pdcch[sf_idx];

@ -237,6 +237,8 @@ void phch_worker::set_config_dedicated(uint16_t rnti,
bool pucch_cqi = dedicated->cqi_report_cnfg.report_periodic_setup_present; bool pucch_cqi = dedicated->cqi_report_cnfg.report_periodic_setup_present;
uint32_t pmi_idx = dedicated->cqi_report_cnfg.report_periodic.pmi_cnfg_idx; 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_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)) {
@ -255,6 +257,14 @@ 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 */ /* Copy all dedicated RRC configuration to UE */
memcpy(&ue_db[rnti].dedicated, dedicated, sizeof(LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT)); memcpy(&ue_db[rnti].dedicated, dedicated, sizeof(LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT));
} else { } else {
@ -355,8 +365,15 @@ 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);
}
}
} }
} }
@ -407,17 +424,33 @@ 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;
bool cqi_enabled = false; bool cqi_enabled = false, ri_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_enabled = true; cqi_enabled = true;
@ -485,14 +518,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
@ -507,8 +542,13 @@ 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 and DL CQI
@ -536,7 +576,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, needs_ri=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));
@ -548,23 +589,23 @@ 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;
LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT *dedicated = &ue_db[rnti].dedicated; 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; LIBLTE_RRC_TRANSMISSION_MODE_ENUM tx_mode = dedicated->antenna_info_explicit_value.tx_mode;
bool ri_report_present = dedicated->cqi_report_cnfg.report_periodic.ri_cnfg_idx_present;
uint32_t pmi_idx = dedicated->cqi_report_cnfg.report_periodic.pmi_cnfg_idx;
uint32_t ri_idx = dedicated->cqi_report_cnfg.report_periodic.ri_cnfg_idx;
if (ue_db[rnti].cqi_en && (ue_db[rnti].pucch_cqi_ack || !needs_ack)) { if (ue_db[rnti].cqi_en && (ue_db[rnti].pucch_cqi_ack || !needs_ack[0] || !needs_ack[1])) {
if (ri_report_present && srslte_ri_send(pmi_idx, ri_idx, tti_rx)) { 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_pucch = true;
needs_ri = true; needs_ri = true;
uci_data.uci_ri_len = 1; uci_data.uci_ri_len = 1;
uci_data.ri_periodic_report = true;
} else if (srslte_cqi_send(ue_db[rnti].pmi_idx, tti_rx)) { } else if (srslte_cqi_send(ue_db[rnti].pmi_idx, tti_rx)) {
needs_pucch = true; needs_pucch = true;
needs_cqi = true; needs_cqi = true;
@ -582,8 +623,14 @@ 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);
@ -609,12 +656,13 @@ int phch_worker::decode_pucch()
} }
} }
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"):"",
needs_sr?(uci_data.scheduling_request?", sr=yes":", sr=no"):"", (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 || needs_ri)?cqi_ri_str:""); (needs_cqi || needs_ri)?cqi_ri_str:"");
@ -728,7 +776,7 @@ int phch_worker::encode_pdsch(srslte_enb_dl_pdsch_t *grants, uint32_t nof_grants
break; break;
case SRSLTE_DCI_FORMAT2A: case SRSLTE_DCI_FORMAT2A:
if (SRSLTE_RA_DL_GRANT_NOF_TB(&phy_grant) == 1) { if (SRSLTE_RA_DL_GRANT_NOF_TB(&phy_grant) == 1) {
mimo_type = SRSLTE_MIMO_TYPE_TX_DIVERSITY; mimo_type = SRSLTE_MIMO_TYPE_TX_DIVERSITY;
} else if (SRSLTE_RA_DL_GRANT_NOF_TB(&phy_grant) == 2) { } else if (SRSLTE_RA_DL_GRANT_NOF_TB(&phy_grant) == 2) {
mimo_type = SRSLTE_MIMO_TYPE_CDD; mimo_type = SRSLTE_MIMO_TYPE_CDD;
} }
@ -765,26 +813,29 @@ int phch_worker::encode_pdsch(srslte_enb_dl_pdsch_t *grants, uint32_t nof_grants
if (dci_format == SRSLTE_DCI_FORMAT2) { if (dci_format == SRSLTE_DCI_FORMAT2) {
snprintf(pinfo_str, 15, ", pinfo=%x", phy_grant.pinfo); 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, tx_scheme=%s%s\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_mimotype2str(mimo_type), pinfo_str);
}
srslte_softbuffer_tx_t *sb[SRSLTE_MAX_CODEWORDS];
uint8_t *d[SRSLTE_MAX_CODEWORDS];
int rv[SRSLTE_MAX_CODEWORDS];
for (int tb = 0; tb < 2; tb++) {
sb[tb] = grants[tb].softbuffers[tb];
d[tb] = grants[tb].data[tb];
} }
rv[0] = grants[i].grant.rv_idx;
rv[1] = grants[i].grant.rv_idx_1;
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, mimo_type)) { 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); fprintf(stderr, "Error putting PDSCH %d\n", i);
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }

@ -389,7 +389,7 @@ void phch_worker::compute_ri() {
uci_data.uci_dif_cqi_len = 3; uci_data.uci_dif_cqi_len = 3;
} }
srslte_bit_unpack_vector(&packed_pmi, uci_data.uci_pmi, uci_data.uci_pmi_len); srslte_bit_unpack_vector(&packed_pmi, uci_data.uci_pmi, uci_data.uci_pmi_len);
Info("pmi=%d\n", packed_pmi); Info("ri=%d; pmi=%d; SINR=%.1fdB\n", ue_dl.ri, ue_dl.pmi[ue_dl.ri], 10*log10f(ue_dl.sinr[ue_dl.ri][ue_dl.pmi[ue_dl.ri]]));
/* If only one antenna in TM4 print limitation warning */ /* If only one antenna in TM4 print limitation warning */
if (ue_dl.nof_rx_antennas < 2) { if (ue_dl.nof_rx_antennas < 2) {
@ -604,7 +604,8 @@ int phch_worker::decode_pdsch(srslte_ra_dl_grant_t *grant, uint8_t *payload[SRSL
/* Setup PDSCH configuration for this CFI, SFIDX and RVIDX */ /* Setup PDSCH configuration for this CFI, SFIDX and RVIDX */
if (valid_config) { if (valid_config) {
if (!srslte_ue_dl_cfg_grant(&ue_dl, grant, cfi, tti%10, rv, mimo_type)) { if (!srslte_ue_dl_cfg_grant(&ue_dl, grant, cfi, tti%10, rv, mimo_type)) {
if (ue_dl.pdsch_cfg.grant.mcs[0].mod > 0 && ue_dl.pdsch_cfg.grant.mcs[0].tbs >= 0) { if ((ue_dl.pdsch_cfg.grant.mcs[0].mod > 0 && ue_dl.pdsch_cfg.grant.mcs[0].tbs >= 0) ||
(ue_dl.pdsch_cfg.grant.mcs[1].mod > 0 && ue_dl.pdsch_cfg.grant.mcs[1].tbs >= 0)) {
float noise_estimate = srslte_chest_dl_get_noise_estimate(&ue_dl.chest); float noise_estimate = srslte_chest_dl_get_noise_estimate(&ue_dl.chest);
@ -796,21 +797,15 @@ void phch_worker::reset_uci()
void phch_worker::set_uci_ack(bool ack[SRSLTE_MAX_CODEWORDS], bool tb_en[SRSLTE_MAX_CODEWORDS]) void phch_worker::set_uci_ack(bool ack[SRSLTE_MAX_CODEWORDS], bool tb_en[SRSLTE_MAX_CODEWORDS])
{ {
uint32_t nof_tb = 0; /* Map ACK according to 3GPP 36.212 clause 5.2.3.1 */
if (tb_en[0]) { uint32_t nof_ack = 0;
uci_data.uci_ack = (uint8_t) ((ack[0]) ? 1 : 0); for (uint32_t tb = 0; tb < SRSLTE_MAX_CODEWORDS; tb++) {
nof_tb = 1; if (tb_en[tb]) {
} else { ((nof_ack == 0)?uci_data.uci_ack:uci_data.uci_ack_2) = (uint8_t)(ack[tb]?1:0);
uci_data.uci_ack = 1; nof_ack++;
} }
if (tb_en[1]) {
uci_data.uci_ack_2 = (uint8_t) ((ack[1]) ? 1 : 0);
nof_tb = 2;
} }
uci_data.uci_ack_len = nof_ack;
uci_data.uci_ack_len = nof_tb;
} }
void phch_worker::set_uci_sr() void phch_worker::set_uci_sr()

Loading…
Cancel
Save