/* 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; } }
int main(int argc, char **argv) { int i; uint8_t *rm_bits, *rm_bits2, *rm_bits2_bytes; short *rm_bits_s; float *rm_bits_f; parse_args(argc, argv); srslte_rm_turbo_gentables(); rm_bits_s = srslte_vec_malloc(sizeof(short) * nof_e_bits); if (!rm_bits_s) { perror("malloc"); exit(-1); } rm_bits_f = srslte_vec_malloc(sizeof(float) * nof_e_bits); if (!rm_bits_f) { perror("malloc"); exit(-1); } rm_bits = srslte_vec_malloc(sizeof(uint8_t) * nof_e_bits); if (!rm_bits) { perror("malloc"); exit(-1); } rm_bits2 = malloc(sizeof(uint8_t) * nof_e_bits); if (!rm_bits2) { perror("malloc"); exit(-1); } rm_bits2_bytes = malloc(sizeof(uint8_t) * nof_e_bits/8 + 1); if (!rm_bits2_bytes) { perror("malloc"); exit(-1); } uint32_t st=0, end=188; if (cb_idx != -1) { st=cb_idx; end=cb_idx+1; } uint32_t rv_st=0, rv_end=4; if (rv_idx != -1) { rv_st=rv_idx; rv_end=rv_idx+1; } for (cb_idx=st;cb_idx<end;cb_idx++) { for (rv_idx=rv_st;rv_idx<rv_end;rv_idx++) { uint32_t long_cb_enc = 3*srslte_cbsegm_cbsize(cb_idx)+12; printf("checking cb_idx=%3d rv_idx=%d...", cb_idx, rv_idx); for (i = 0; i < long_cb_enc; i++) { bits[i] = rand() % 2; } bzero(buff_b, BUFFSZ * sizeof(uint8_t)); srslte_rm_turbo_tx(buff_b, BUFFSZ, bits, long_cb_enc, rm_bits, nof_e_bits, 0); if (rv_idx > 0) { srslte_rm_turbo_tx(buff_b, BUFFSZ, bits, long_cb_enc, rm_bits, nof_e_bits, rv_idx); } for (int i=0;i<long_cb_enc/3;i++) { systematic[i] = bits[3*i]; parity[i] = bits[3*i+1]; parity[i+long_cb_enc/3] = bits[3*i+2]; } srslte_bit_pack_vector(systematic, systematic_bytes, long_cb_enc/3); srslte_bit_pack_vector(parity, parity_bytes, 2*long_cb_enc/3); bzero(buff_b, BUFFSZ * sizeof(uint8_t)); bzero(rm_bits2_bytes, nof_e_bits/8); srslte_rm_turbo_tx_lut(buff_b, systematic_bytes, parity_bytes, rm_bits2_bytes, cb_idx, nof_e_bits, 0, 0); if (rv_idx > 0) { bzero(rm_bits2_bytes, nof_e_bits/8); srslte_rm_turbo_tx_lut(buff_b, systematic_bytes, parity_bytes, rm_bits2_bytes, cb_idx, nof_e_bits, 0, rv_idx); } srslte_bit_unpack_vector(rm_bits2_bytes, rm_bits2, nof_e_bits); for (int i=0;i<nof_e_bits;i++) { if (rm_bits2[i] != rm_bits[i]) { printf("Error in TX bit %d\n", i); exit(-1); } } printf("OK TX..."); for (int i=0;i<nof_e_bits;i++) { rm_bits_f[i] = rand()%10-5; rm_bits_s[i] = (short) rm_bits_f[i]; } bzero(buff_f, BUFFSZ*sizeof(float)); srslte_rm_turbo_rx(buff_f, BUFFSZ, rm_bits_f, nof_e_bits, bits_f, long_cb_enc, rv_idx, 0); bzero(bits2_s, long_cb_enc*sizeof(short)); srslte_rm_turbo_rx_lut(rm_bits_s, bits2_s, nof_e_bits, cb_idx, rv_idx); for (int i=0;i<long_cb_enc;i++) { if (bits_f[i] != bits2_s[i]) { printf("error RX in bit %d %f!=%d\n", i, bits_f[i], bits2_s[i]); exit(-1); } } printf("OK RX\n"); } } free(rm_bits); free(rm_bits2); free(rm_bits2_bytes); exit(0); }