int decode_cqi_long(srslte_uci_cqi_pusch_t *q, int16_t *q_bits, uint32_t Q, uint8_t *data, uint32_t nof_bits) { int ret = SRSLTE_ERROR_INVALID_INPUTS; if (nof_bits + 8 < SRSLTE_UCI_MAX_CQI_LEN_PUSCH && q != NULL && data != NULL && q_bits != NULL) { srslte_rm_conv_rx_s(q_bits, Q, q->encoded_cqi_s, 3 * (nof_bits + 8)); DEBUG("cconv_rx="); if (SRSLTE_VERBOSE_ISDEBUG()) { srslte_vec_fprint_s(stdout, q->encoded_cqi_s, 3 * (nof_bits + 8)); } srslte_viterbi_decode_s(&q->viterbi, q->encoded_cqi_s, q->tmp_cqi, nof_bits + 8); DEBUG("cqi_crc_rx="); if (SRSLTE_VERBOSE_ISDEBUG()) { srslte_vec_fprint_b(stdout, q->tmp_cqi, nof_bits+8); } ret = srslte_crc_checksum(&q->crc, q->tmp_cqi, nof_bits + 8); if (ret == 0) { memcpy(data, q->tmp_cqi, nof_bits*sizeof(uint8_t)); ret = 1; } else { ret = 0; } } return ret; }
/* Encode UCI CQI/PMI for payloads greater than 11 bits (go through CRC, conv coder and rate match) */ int encode_cqi_long(srslte_uci_cqi_pusch_t *q, uint8_t *data, uint32_t nof_bits, uint8_t *q_bits, uint32_t Q) { srslte_convcoder_t encoder; if (nof_bits + 8 < SRSLTE_UCI_MAX_CQI_LEN_PUSCH && q != NULL && data != NULL && q_bits != NULL) { int poly[3] = { 0x6D, 0x4F, 0x57 }; encoder.K = 7; encoder.R = 3; encoder.tail_biting = true; memcpy(encoder.poly, poly, 3 * sizeof(int)); memcpy(q->tmp_cqi, data, sizeof(uint8_t) * nof_bits); srslte_crc_attach(&q->crc, q->tmp_cqi, nof_bits); DEBUG("cqi_crc_tx="); if (SRSLTE_VERBOSE_ISDEBUG()) { srslte_vec_fprint_b(stdout, q->tmp_cqi, nof_bits+8); } srslte_convcoder_encode(&encoder, q->tmp_cqi, q->encoded_cqi, nof_bits + 8); DEBUG("cconv_tx="); if (SRSLTE_VERBOSE_ISDEBUG()) { srslte_vec_fprint_b(stdout, q->encoded_cqi, 3 * (nof_bits + 8)); } srslte_rm_conv_tx(q->encoded_cqi, 3 * (nof_bits + 8), q_bits, Q); return SRSLTE_SUCCESS; } else { return SRSLTE_ERROR_INVALID_INPUTS; } }
int srslte_ue_dl_decode_rnti_rv_packet(srslte_ue_dl_t *q, srslte_dci_msg_t *dci_msg, uint8_t *data, uint32_t cfi, uint32_t sf_idx, uint16_t rnti, uint32_t rvidx) { int ret = SRSLTE_ERROR; q->nof_detected++; /* Setup PDSCH configuration for this CFI, SFIDX and RVIDX */ if (srslte_ue_dl_cfg_grant(q, dci_msg, cfi, sf_idx, rnti, rvidx)) { return SRSLTE_ERROR; } if (q->pdsch_cfg.rv == 0) { srslte_softbuffer_rx_reset(&q->softbuffer); } #ifdef PDSCH_DO_ZF float noise_estimate = 0; #else float noise_estimate = srslte_chest_dl_get_noise_estimate(&q->chest); #endif if (q->pdsch_cfg.grant.mcs.mod > 0 && q->pdsch_cfg.grant.mcs.tbs >= 0) { ret = srslte_pdsch_decode_rnti(&q->pdsch, &q->pdsch_cfg, &q->softbuffer, q->sf_symbols, q->ce, noise_estimate, rnti, data); if (ret == SRSLTE_ERROR) { q->pkt_errors++; } else if (ret == SRSLTE_ERROR_INVALID_INPUTS) { fprintf(stderr, "Error calling srslte_pdsch_decode()\n"); } else if (ret == SRSLTE_SUCCESS) { if (SRSLTE_VERBOSE_ISDEBUG()) { INFO("Decoded Message: ", 0); srslte_vec_fprint_hex(stdout, data, q->pdsch_cfg.grant.mcs.tbs); } } q->pkts_total++; } return ret; }
static void pdsch_decode_debug(srslte_pdsch_t *q, srslte_pdsch_cfg_t *cfg, cf_t *sf_symbols[SRSLTE_MAX_PORTS], cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS]) { if (SRSLTE_VERBOSE_ISDEBUG()) { char filename[FILENAME_MAX]; for (int j = 0; j < q->nof_rx_antennas; j++) { if (snprintf(filename, FILENAME_MAX, "subframe_p%d.dat", j) < 0) { ERROR("Generating file name"); break; } DEBUG("SAVED FILE %s: received subframe symbols\n", filename); srslte_vec_save_file(filename, sf_symbols[j], SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp)*sizeof(cf_t)); for (int i = 0; i < q->cell.nof_ports; i++) { if (snprintf(filename, FILENAME_MAX, "hest_%d%d.dat", i, j) < 0) { ERROR("Generating file name"); break; } DEBUG("SAVED FILE %s: channel estimates for Tx %d and Rx %d\n", filename, j, i); srslte_vec_save_file(filename, ce[i][j], SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp)*sizeof(cf_t)); } } for (int i=0;i<cfg->nof_layers;i++) { if (snprintf(filename, FILENAME_MAX, "pdsch_symbols_%d.dat", i) < 0) { ERROR("Generating file name"); break; } DEBUG("SAVED FILE %s: symbols after equalization\n", filename); srslte_vec_save_file(filename, q->d[i], cfg->nbits[0].nof_re*sizeof(cf_t)); if (snprintf(filename, FILENAME_MAX, "llr_%d.dat", i) < 0) { ERROR("Generating file name"); break; } DEBUG("SAVED FILE %s: LLR estimates after demodulation and descrambling\n", filename); srslte_vec_save_file(filename, q->e[i], cfg->nbits[0].nof_bits*sizeof(int16_t)); } } }
/** Decodes the pmch from the received symbols */ int srslte_pmch_decode_multi(srslte_pmch_t *q, srslte_pdsch_cfg_t *cfg, srslte_softbuffer_rx_t *softbuffer, cf_t *sf_symbols[SRSLTE_MAX_PORTS], cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], float noise_estimate, uint16_t area_id, uint8_t *data) { /* Set pointers for layermapping & precoding */ uint32_t i, n; cf_t *x[SRSLTE_MAX_LAYERS]; if (q != NULL && sf_symbols != NULL && data != NULL && cfg != NULL) { INFO("Decoding PMCH SF: %d, MBSFN area ID: 0x%x, Mod %s, TBS: %d, NofSymbols: %d, NofBitsE: %d, rv_idx: %d, C_prb=%d, cfi=%d\n", cfg->sf_idx, area_id, srslte_mod_string(cfg->grant.mcs[0].mod), cfg->grant.mcs[0].tbs, cfg->nbits[0].nof_re, cfg->nbits[0].nof_bits, 0, cfg->grant.nof_prb, cfg->nbits[0].lstart-1); /* number of layers equals number of ports */ for (i = 0; i < q->cell.nof_ports; i++) { x[i] = q->x[i]; } memset(&x[q->cell.nof_ports], 0, sizeof(cf_t*) * (SRSLTE_MAX_LAYERS - q->cell.nof_ports)); for (int j=0;j<q->nof_rx_antennas;j++) { /* extract symbols */ n = srslte_pmch_get(q, sf_symbols[j], q->symbols[j], cfg->nbits[0].lstart); if (n != cfg->nbits[0].nof_re) { fprintf(stderr, "PMCH 1 extract symbols error expecting %d symbols but got %d, lstart %d\n", cfg->nbits[0].nof_re, n, cfg->nbits[0].lstart); return SRSLTE_ERROR; } /* extract channel estimates */ for (i = 0; i < q->cell.nof_ports; i++) { n = srslte_pmch_get(q, ce[i][j], q->ce[i][j], cfg->nbits[0].lstart); if (n != cfg->nbits[0].nof_re) { fprintf(stderr, "PMCH 2 extract chest error expecting %d symbols but got %d\n", cfg->nbits[0].nof_re, n); return SRSLTE_ERROR; } } } // No tx diversity in MBSFN srslte_predecoding_single_multi(q->symbols, q->ce[0], q->d, NULL, q->nof_rx_antennas, cfg->nbits[0].nof_re, 1.0f, noise_estimate); if (SRSLTE_VERBOSE_ISDEBUG()) { DEBUG("SAVED FILE subframe.dat: received subframe symbols\n"); srslte_vec_save_file("subframe.dat", sf_symbols, SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp)*sizeof(cf_t)); DEBUG("SAVED FILE hest0.dat: channel estimates for port 4\n"); srslte_vec_save_file("hest0.dat", ce[0], SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp)*sizeof(cf_t)); DEBUG("SAVED FILE pmch_symbols.dat: symbols after equalization\n"); srslte_vec_save_file("pmch_symbols.bin", q->d, cfg->nbits[0].nof_re*sizeof(cf_t)); } /* demodulate symbols * The MAX-log-MAP algorithm used in turbo decoding is unsensitive to SNR estimation, * thus we don't need tot set it in thde LLRs normalization */ srslte_demod_soft_demodulate_s(cfg->grant.mcs[0].mod, q->d, q->e, cfg->nbits[0].nof_re); /* descramble */ srslte_scrambling_s_offset(&q->seqs[area_id]->seq[cfg->sf_idx], q->e, 0, cfg->nbits[0].nof_bits); if (SRSLTE_VERBOSE_ISDEBUG()) { DEBUG("SAVED FILE llr.dat: LLR estimates after demodulation and descrambling\n"); srslte_vec_save_file("llr.dat", q->e, cfg->nbits[0].nof_bits*sizeof(int16_t)); } return srslte_dlsch_decode(&q->dl_sch, cfg, softbuffer, q->e, data); } else { return SRSLTE_ERROR_INVALID_INPUTS; } }
/** Decodes the PDSCH from the received symbols */ int srslte_pdsch_decode_rnti(srslte_pdsch_t *q, srslte_pdsch_cfg_t *cfg, srslte_softbuffer_rx_t *softbuffer, cf_t *sf_symbols, cf_t *ce[SRSLTE_MAX_PORTS], float noise_estimate, uint16_t rnti, uint8_t *data) { /* Set pointers for layermapping & precoding */ uint32_t i, n; cf_t *x[SRSLTE_MAX_LAYERS]; if (q != NULL && sf_symbols != NULL && data != NULL && cfg != NULL) { INFO("Decoding PDSCH SF: %d, RNTI: 0x%x, Mod %s, TBS: %d, NofSymbols: %d, NofBitsE: %d, rv_idx: %d, C_prb=%d\n", cfg->sf_idx, rnti, srslte_mod_string(cfg->grant.mcs.mod), cfg->grant.mcs.tbs, cfg->nbits.nof_re, cfg->nbits.nof_bits, cfg->rv, cfg->grant.nof_prb); /* number of layers equals number of ports */ for (i = 0; i < q->cell.nof_ports; i++) { x[i] = q->x[i]; } memset(&x[q->cell.nof_ports], 0, sizeof(cf_t*) * (SRSLTE_MAX_LAYERS - q->cell.nof_ports)); /* extract symbols */ n = srslte_pdsch_get(q, sf_symbols, q->symbols[0], &cfg->grant, cfg->nbits.lstart, cfg->sf_idx); if (n != cfg->nbits.nof_re) { fprintf(stderr, "Error expecting %d symbols but got %d\n", cfg->nbits.nof_re, n); return SRSLTE_ERROR; } /* extract channel estimates */ for (i = 0; i < q->cell.nof_ports; i++) { n = srslte_pdsch_get(q, ce[i], q->ce[i], &cfg->grant, cfg->nbits.lstart, cfg->sf_idx); if (n != cfg->nbits.nof_re) { fprintf(stderr, "Error expecting %d symbols but got %d\n", cfg->nbits.nof_re, n); return SRSLTE_ERROR; } } /* TODO: only diversity is supported */ if (q->cell.nof_ports == 1) { /* no need for layer demapping */ srslte_predecoding_single(q->symbols[0], q->ce[0], q->d, cfg->nbits.nof_re, noise_estimate); } else { srslte_predecoding_diversity(&q->precoding, q->symbols[0], q->ce, x, q->cell.nof_ports, cfg->nbits.nof_re, noise_estimate); srslte_layerdemap_diversity(x, q->d, q->cell.nof_ports, cfg->nbits.nof_re / q->cell.nof_ports); } if (SRSLTE_VERBOSE_ISDEBUG()) { DEBUG("SAVED FILE pdsch_symbols.dat: symbols after equalization\n",0); srslte_vec_save_file("pdsch_symbols.dat", q->d, cfg->nbits.nof_re*sizeof(cf_t)); } /* demodulate symbols * The MAX-log-MAP algorithm used in turbo decoding is unsensitive to SNR estimation, * thus we don't need tot set it in the LLRs normalization */ srslte_demod_soft_demodulate_s(cfg->grant.mcs.mod, q->d, q->e, cfg->nbits.nof_re); /* descramble */ if (rnti != q->rnti) { srslte_sequence_t seq; if (srslte_sequence_pdsch(&seq, rnti, 0, 2 * cfg->sf_idx, q->cell.id, cfg->nbits.nof_bits)) { return SRSLTE_ERROR; } srslte_scrambling_s_offset(&seq, q->e, 0, cfg->nbits.nof_bits); srslte_sequence_free(&seq); } else { srslte_scrambling_s_offset(&q->seq[cfg->sf_idx], q->e, 0, cfg->nbits.nof_bits); } if (SRSLTE_VERBOSE_ISDEBUG()) { DEBUG("SAVED FILE llr.dat: LLR estimates after demodulation and descrambling\n",0); srslte_vec_save_file("llr.dat", q->e, cfg->nbits.nof_bits*sizeof(int16_t)); } return srslte_dlsch_decode(&q->dl_sch, cfg, softbuffer, q->e, data); } else { return SRSLTE_ERROR_INVALID_INPUTS; } }
/* Encode a transport block according to 36.212 5.3.2 * */ static int encode_tb(srslte_sch_t *q, srslte_softbuffer_tx_t *soft_buffer, srslte_cbsegm_t *cb_segm, uint32_t Qm, uint32_t rv, uint32_t nof_e_bits, uint8_t *data, uint8_t *e_bits) { uint8_t parity[3] = {0, 0, 0}; uint32_t par; uint32_t i; uint32_t cb_len, rp, wp, rlen, F, n_e; int ret = SRSLTE_ERROR_INVALID_INPUTS; if (q != NULL && e_bits != NULL && cb_segm != NULL && soft_buffer != NULL) { uint32_t Gp = nof_e_bits / Qm; uint32_t gamma = Gp; if (cb_segm->C > 0) { gamma = Gp%cb_segm->C; } if (data) { /* Compute transport block CRC */ par = srslte_crc_checksum_byte(&q->crc_tb, data, cb_segm->tbs); /* parity bits will be appended later */ parity[0] = (par&(0xff<<16))>>16; parity[1] = (par&(0xff<<8))>>8; parity[2] = par&0xff; if (SRSLTE_VERBOSE_ISDEBUG()) { DEBUG("DATA: ", 0); srslte_vec_fprint_byte(stdout, data, cb_segm->tbs/8); DEBUG("PARITY: ", 0); srslte_vec_fprint_byte(stdout, parity, 3); } } wp = 0; rp = 0; for (i = 0; i < cb_segm->C; i++) { /* Get read lengths */ if (i < cb_segm->C2) { cb_len = cb_segm->K2; } else { cb_len = cb_segm->K1; } if (cb_segm->C > 1) { rlen = cb_len - 24; } else { rlen = cb_len; } if (i == 0) { F = cb_segm->F; } else { F = 0; } if (i <= cb_segm->C - gamma - 1) { n_e = Qm * (Gp/cb_segm->C); } else { n_e = Qm * ((uint32_t) ceilf((float) Gp/cb_segm->C)); } INFO("CB#%d: cb_len: %d, rlen: %d, wp: %d, rp: %d, F: %d, E: %d\n", i, cb_len, rlen - F, wp, rp, F, n_e); if (data) { /* Copy data to another buffer, making space for the Codeblock CRC */ if (i < cb_segm->C - 1) { // Copy data memcpy(&q->cb_in[F/8], &data[rp/8], (rlen - F) * sizeof(uint8_t)/8); } else { INFO("Last CB, appending parity: %d from %d and 24 to %d\n", rlen - F - 24, rp, rlen - 24); /* Append Transport Block parity bits to the last CB */ memcpy(&q->cb_in[F/8], &data[rp/8], (rlen - 24 - F) * sizeof(uint8_t)/8); memcpy(&q->cb_in[(rlen - 24)/8], parity, 3 * sizeof(uint8_t)); } /* Filler bits are treated like zeros for the CB CRC calculation */ for (int j = 0; j < F/8; j++) { q->cb_in[j] = 0; } /* Attach Codeblock CRC */ if (cb_segm->C > 1) { srslte_crc_attach_byte(&q->crc_cb, q->cb_in, rlen); } /* pack bits to temporal buffer for encoding */ srslte_bit_unpack_vector(q->cb_in, q->cb_temp, cb_len); /* Set the filler bits to <NULL> */ for (int j = 0; j < F; j++) { q->cb_temp[j] = SRSLTE_TX_NULL; } if (SRSLTE_VERBOSE_ISDEBUG()) { DEBUG("CB#%d: ", i); srslte_vec_fprint_hex(stdout, q->cb_temp, cb_len); } /* Turbo Encoding */ srslte_tcod_encode(&q->encoder, q->cb_temp, (uint8_t*) q->cb_out, cb_len); if (SRSLTE_VERBOSE_ISDEBUG()) { DEBUG("CB#%d encoded: ", i); srslte_vec_fprint_b(stdout, q->cb_out, 3*cb_len+12); } } /* Rate matching */ if (srslte_rm_turbo_tx(soft_buffer->buffer_b[i], soft_buffer->buff_size, (uint8_t*) q->cb_out, 3 * cb_len + 12, &e_bits[wp], n_e, rv)) { fprintf(stderr, "Error in rate matching\n"); return SRSLTE_ERROR; } /* Set read/write pointers */ rp += (rlen - F); wp += n_e; } INFO("END CB#%d: wp: %d, rp: %d\n", i, wp, rp); ret = SRSLTE_SUCCESS; }
/** Encodes ACK/NACK bits, modulates and inserts into resource. * The parameter ack is an array of srslte_phich_ngroups() pointers to buffers of nof_sequences uint8_ts */ int srslte_phich_encode(srslte_phich_t *q, uint8_t ack, uint32_t ngroup, uint32_t nseq, uint32_t subframe, cf_t *slot_symbols[SRSLTE_MAX_PORTS]) { int i; if (q == NULL || slot_symbols == NULL) { return SRSLTE_ERROR_INVALID_INPUTS; } if (subframe >= SRSLTE_NSUBFRAMES_X_FRAME) { fprintf(stderr, "Invalid nslot %d\n", subframe); return SRSLTE_ERROR_INVALID_INPUTS; } if (SRSLTE_CP_ISEXT(q->cell.cp)) { if (nseq >= SRSLTE_PHICH_EXT_NSEQUENCES) { fprintf(stderr, "Invalid nseq %d\n", nseq); return SRSLTE_ERROR_INVALID_INPUTS; } } else { if (nseq >= SRSLTE_PHICH_NORM_NSEQUENCES) { fprintf(stderr, "Invalid nseq %d\n", nseq); return SRSLTE_ERROR_INVALID_INPUTS; } } if (ngroup >= srslte_regs_phich_ngroups(q->regs)) { fprintf(stderr, "Invalid ngroup %d\n", ngroup); return SRSLTE_ERROR_INVALID_INPUTS; } /* Set pointers for layermapping & precoding */ cf_t *x[SRSLTE_MAX_LAYERS]; cf_t *symbols_precoding[SRSLTE_MAX_PORTS]; /* number of layers equals number of ports */ for (i = 0; i < q->cell.nof_ports; i++) { x[i] = q->x[i]; } for (i = 0; i < SRSLTE_MAX_PORTS; i++) { symbols_precoding[i] = q->symbols[i]; } /* encode ACK/NACK bit */ srslte_phich_ack_encode(ack, q->data); srslte_mod_modulate(&q->mod, q->data, q->z, SRSLTE_PHICH_NBITS); DEBUG("data: ", 0); if (SRSLTE_VERBOSE_ISDEBUG()) srslte_vec_fprint_c(stdout, q->z, SRSLTE_PHICH_NBITS); /* Spread with w */ if (SRSLTE_CP_ISEXT(q->cell.cp)) { for (i = 0; i < SRSLTE_PHICH_EXT_MSYMB; i++) { q->d[i] = w_ext[nseq][i % SRSLTE_PHICH_EXT_NSF] * q->z[i / SRSLTE_PHICH_EXT_NSF]; } } else { for (i = 0; i < SRSLTE_PHICH_NORM_MSYMB; i++) { q->d[i] = w_normal[nseq][i % SRSLTE_PHICH_NORM_NSF] * q->z[i / SRSLTE_PHICH_NORM_NSF]; } } DEBUG("d: ", 0); if (SRSLTE_VERBOSE_ISDEBUG()) srslte_vec_fprint_c(stdout, q->d, SRSLTE_PHICH_EXT_MSYMB); srslte_scrambling_c(&q->seq[subframe], q->d); /* align to REG */ if (SRSLTE_CP_ISEXT(q->cell.cp)) { if (ngroup % 2) { for (i = 0; i < SRSLTE_PHICH_EXT_MSYMB / 2; i++) { q->d0[4 * i + 0] = 0; q->d0[4 * i + 1] = 0; q->d0[4 * i + 2] = q->d[2 * i]; q->d0[4 * i + 3] = q->d[2 * i + 1]; } } else { for (i = 0; i < SRSLTE_PHICH_EXT_MSYMB / 2; i++) { q->d0[4 * i + 0] = q->d[2 * i]; q->d0[4 * i + 1] = q->d[2 * i + 1]; q->d0[4 * i + 2] = 0; q->d0[4 * i + 3] = 0; } } } else { memcpy(q->d0, q->d, SRSLTE_PHICH_MAX_NSYMB * sizeof(cf_t)); } DEBUG("d0: ", 0); if (SRSLTE_VERBOSE_ISDEBUG()) srslte_vec_fprint_c(stdout, q->d0, SRSLTE_PHICH_MAX_NSYMB); /* layer mapping & precoding */ if (q->cell.nof_ports > 1) { srslte_layermap_diversity(q->d0, x, q->cell.nof_ports, SRSLTE_PHICH_MAX_NSYMB); srslte_precoding_diversity(&q->precoding, x, symbols_precoding, q->cell.nof_ports, SRSLTE_PHICH_MAX_NSYMB / q->cell.nof_ports); /**FIXME: According to 6.9.2, Precoding for 4 tx ports is different! */ } else { memcpy(q->symbols[0], q->d0, SRSLTE_PHICH_MAX_NSYMB * sizeof(cf_t)); } /* mapping to resource elements */ for (i = 0; i < q->cell.nof_ports; i++) { if (srslte_regs_phich_add(q->regs, q->symbols[i], ngroup, slot_symbols[i]) < 0) { fprintf(stderr, "Error putting PCHICH resource elements\n"); return SRSLTE_ERROR; } } return SRSLTE_SUCCESS; }
/* Decodes the phich channel and saves the CFI in the cfi pointer. * * Returns 1 if successfully decoded the CFI, 0 if not and -1 on error */ int srslte_phich_decode(srslte_phich_t *q, cf_t *slot_symbols, cf_t *ce[SRSLTE_MAX_PORTS], float noise_estimate, uint32_t ngroup, uint32_t nseq, uint32_t subframe, uint8_t *ack, float *distance) { /* Set pointers for layermapping & precoding */ int i, j; cf_t *x[SRSLTE_MAX_LAYERS]; cf_t *ce_precoding[SRSLTE_MAX_PORTS]; if (q == NULL || slot_symbols == NULL) { return SRSLTE_ERROR_INVALID_INPUTS; } if (subframe >= SRSLTE_NSUBFRAMES_X_FRAME) { fprintf(stderr, "Invalid nslot %d\n", subframe); return SRSLTE_ERROR_INVALID_INPUTS; } if (SRSLTE_CP_ISEXT(q->cell.cp)) { if (nseq >= SRSLTE_PHICH_EXT_NSEQUENCES) { fprintf(stderr, "Invalid nseq %d\n", nseq); return SRSLTE_ERROR_INVALID_INPUTS; } } else { if (nseq >= SRSLTE_PHICH_NORM_NSEQUENCES) { fprintf(stderr, "Invalid nseq %d\n", nseq); return SRSLTE_ERROR_INVALID_INPUTS; } } if (ngroup >= srslte_regs_phich_ngroups(q->regs)) { fprintf(stderr, "Invalid ngroup %d\n", ngroup); return SRSLTE_ERROR_INVALID_INPUTS; } DEBUG("Decoding PHICH Ngroup: %d, Nseq: %d\n", ngroup, nseq); /* number of layers equals number of ports */ for (i = 0; i < SRSLTE_MAX_PORTS; i++) { x[i] = q->x[i]; } for (i = 0; i < SRSLTE_MAX_PORTS; i++) { ce_precoding[i] = q->ce[i]; } /* extract symbols */ if (SRSLTE_PHICH_MAX_NSYMB != srslte_regs_phich_get(q->regs, slot_symbols, q->symbols[0], ngroup)) { fprintf(stderr, "There was an error getting the phich symbols\n"); return SRSLTE_ERROR; } /* extract channel estimates */ for (i = 0; i < q->cell.nof_ports; i++) { if (SRSLTE_PHICH_MAX_NSYMB != srslte_regs_phich_get(q->regs, ce[i], q->ce[i], ngroup)) { fprintf(stderr, "There was an error getting the phich symbols\n"); return SRSLTE_ERROR; } } /* in control channels, only diversity is supported */ if (q->cell.nof_ports == 1) { /* no need for layer demapping */ srslte_predecoding_single(q->symbols[0], q->ce[0], q->d0, SRSLTE_PHICH_MAX_NSYMB, noise_estimate); } else { srslte_predecoding_diversity(&q->precoding, q->symbols[0], ce_precoding, x, q->cell.nof_ports, SRSLTE_PHICH_MAX_NSYMB, noise_estimate); srslte_layerdemap_diversity(x, q->d0, q->cell.nof_ports, SRSLTE_PHICH_MAX_NSYMB / q->cell.nof_ports); } DEBUG("Recv!!: \n", 0); DEBUG("d0: ", 0); if (SRSLTE_VERBOSE_ISDEBUG()) srslte_vec_fprint_c(stdout, q->d0, SRSLTE_PHICH_MAX_NSYMB); if (SRSLTE_CP_ISEXT(q->cell.cp)) { if (ngroup % 2) { for (i = 0; i < SRSLTE_PHICH_EXT_MSYMB / 2; i++) { q->d[2 * i + 0] = q->d0[4 * i + 2]; q->d[2 * i + 1] = q->d0[4 * i + 3]; } } else { for (i = 0; i < SRSLTE_PHICH_EXT_MSYMB / 2; i++) { q->d[2 * i + 0] = q->d0[4 * i]; q->d[2 * i + 1] = q->d0[4 * i + 1]; } } } else { memcpy(q->d, q->d0, SRSLTE_PHICH_MAX_NSYMB * sizeof(cf_t)); } DEBUG("d: ", 0); if (SRSLTE_VERBOSE_ISDEBUG()) srslte_vec_fprint_c(stdout, q->d, SRSLTE_PHICH_EXT_MSYMB); srslte_scrambling_c(&q->seq[subframe], q->d); /* De-spreading */ if (SRSLTE_CP_ISEXT(q->cell.cp)) { for (i = 0; i < SRSLTE_PHICH_NBITS; i++) { q->z[i] = 0; for (j = 0; j < SRSLTE_PHICH_EXT_NSF; j++) { q->z[i] += conjf(w_ext[nseq][j]) * q->d[i * SRSLTE_PHICH_EXT_NSF + j] / SRSLTE_PHICH_EXT_NSF; } } } else { for (i = 0; i < SRSLTE_PHICH_NBITS; i++) { q->z[i] = 0; for (j = 0; j < SRSLTE_PHICH_NORM_NSF; j++) { q->z[i] += conjf(w_normal[nseq][j]) * q->d[i * SRSLTE_PHICH_NORM_NSF + j] / SRSLTE_PHICH_NORM_NSF; } } } DEBUG("z: ", 0); if (SRSLTE_VERBOSE_ISDEBUG()) srslte_vec_fprint_c(stdout, q->z, SRSLTE_PHICH_NBITS); srslte_demod_soft_demodulate(SRSLTE_MOD_BPSK, q->z, q->data_rx, SRSLTE_PHICH_NBITS); if (ack) { *ack = srslte_phich_ack_decode(q->data_rx, distance); } return SRSLTE_SUCCESS; }
/* Decode a transport block according to 36.212 5.3.2 * */ static int decode_tb(srslte_sch_t *q, srslte_softbuffer_rx_t *softbuffer, srslte_cbsegm_t *cb_segm, uint32_t Qm, uint32_t rv, uint32_t nof_e_bits, float *e_bits, uint8_t *data) { uint8_t parity[24]; uint8_t *p_parity = parity; uint32_t par_rx, par_tx; uint32_t i; uint32_t cb_len, rp, wp, rlen, F, n_e; if (q != NULL && data != NULL && softbuffer != NULL && e_bits != NULL && cb_segm != NULL) { if (cb_segm->tbs == 0 || cb_segm->C == 0) { return SRSLTE_SUCCESS; } rp = 0; rp = 0; wp = 0; uint32_t Gp = nof_e_bits / Qm; uint32_t gamma=Gp; if (cb_segm->C>0) { gamma = Gp%cb_segm->C; } bool early_stop = true; for (i = 0; i < cb_segm->C && early_stop; i++) { /* Get read/write lengths */ if (i < cb_segm->C2) { cb_len = cb_segm->K2; } else { cb_len = cb_segm->K1; } if (cb_segm->C == 1) { rlen = cb_len; } else { rlen = cb_len - 24; } if (i == 0) { F = cb_segm->F; } else { F = 0; } if (i <= cb_segm->C - gamma - 1) { n_e = Qm * (Gp/cb_segm->C); } else { n_e = Qm * ((uint32_t) ceilf((float) Gp/cb_segm->C)); } INFO("CB#%d: cb_len: %d, rlen: %d, wp: %d, rp: %d, F: %d, E: %d\n", i, cb_len, rlen - F, wp, rp, F, n_e); /* Rate Unmatching */ if (srslte_rm_turbo_rx(softbuffer->buffer_f[i], softbuffer->buff_size, &e_bits[rp], n_e, (float*) q->cb_out, 3 * cb_len + 12, rv, F)) { fprintf(stderr, "Error in rate matching\n"); return SRSLTE_ERROR; } if (SRSLTE_VERBOSE_ISDEBUG()) { DEBUG("CB#%d RMOUT: ", i); srslte_vec_fprint_f(stdout, q->cb_out, 3*cb_len+12); } /* Turbo Decoding with CRC-based early stopping */ q->nof_iterations = 0; uint32_t len_crc; uint8_t *cb_in_ptr; srslte_crc_t *crc_ptr; early_stop = false; srslte_tdec_reset(&q->decoder, cb_len); do { srslte_tdec_iteration(&q->decoder, (float*) q->cb_out, cb_len); q->nof_iterations++; if (cb_segm->C > 1) { len_crc = cb_len; cb_in_ptr = q->cb_in; crc_ptr = &q->crc_cb; } else { len_crc = cb_segm->tbs+24; cb_in_ptr = &q->cb_in[F]; crc_ptr = &q->crc_tb; } srslte_tdec_decision(&q->decoder, q->cb_in, cb_len); /* Check Codeblock CRC and stop early if incorrect */ if (!srslte_crc_checksum(crc_ptr, cb_in_ptr, len_crc)) { early_stop = true; } } while (q->nof_iterations < SRSLTE_PDSCH_MAX_TDEC_ITERS && !early_stop); q->average_nof_iterations = SRSLTE_VEC_EMA((float) q->nof_iterations, q->average_nof_iterations, 0.2); if (SRSLTE_VERBOSE_ISDEBUG()) { DEBUG("CB#%d IN: ", i); srslte_vec_fprint_b(stdout, q->cb_in, cb_len); } // If CB CRC is not correct, early_stop will be false and wont continue with rest of CBs /* Copy data to another buffer, removing the Codeblock CRC */ if (i < cb_segm->C - 1) { memcpy(&data[wp], &q->cb_in[F], (rlen - F) * sizeof(uint8_t)); } else { DEBUG("Last CB, appending parity: %d to %d from %d and 24 from %d\n", rlen - F - 24, wp, F, rlen - 24); /* Append Transport Block parity bits to the last CB */ memcpy(&data[wp], &q->cb_in[F], (rlen - F - 24) * sizeof(uint8_t)); memcpy(parity, &q->cb_in[rlen - 24], 24 * sizeof(uint8_t)); } /* Set read/write pointers */ wp += (rlen - F); rp += n_e; } if (!early_stop) { INFO("CB %d failed. TB is erroneous.\n",i-1); return SRSLTE_ERROR; } else { INFO("END CB#%d: wp: %d, rp: %d\n", i, wp, rp); // Compute transport block CRC par_rx = srslte_crc_checksum(&q->crc_tb, data, cb_segm->tbs); // check parity bits par_tx = srslte_bit_unpack(&p_parity, 24); if (!par_rx) { INFO("\n\tCAUTION!! Received all-zero transport block\n\n", 0); } if (par_rx == par_tx) { INFO("TB decoded OK\n",i); return SRSLTE_SUCCESS; } else { INFO("Error in TB parity\n",i); return SRSLTE_ERROR; } } } else { return SRSLTE_ERROR_INVALID_INPUTS; } }