예제 #1
0
int main(int argc, char **argv) {

  parse_args(argc, argv);
  
  srslte_tcod_gentable();

  srslte_tcod_t tcod;
  srslte_tcod_init(&tcod, 6144);

  uint32_t st=0, end=187;
  if (long_cb) {
    st=srslte_cbsegm_cbindex(long_cb);
    end=st;
  }
  
  for (uint32_t len=st;len<=end;len++) {
    long_cb = srslte_cbsegm_cbsize(len); 
    printf("Checking long_cb=%d\n", long_cb);
    for (int i=0;i<long_cb/8;i++) {
      input_bytes[i] = rand()%256;
    }
    
    srslte_bit_unpack_vector(input_bytes, input_bits, long_cb);

    if (SRSLTE_VERBOSE_ISINFO()) {
      printf("Input bits:\n");
      for (int i=0;i<long_cb/8;i++) {
        srslte_vec_fprint_b(stdout, &input_bits[i*8], 8);
      }
    }

    srslte_tcod_encode(&tcod, input_bits, output_bits, long_cb);
    srslte_tcod_encode_lut(&tcod, input_bytes, parity, len);

    srslte_bit_unpack_vector(parity, parity_bits, 2*(long_cb+4));
    
    for (int i=0;i<long_cb;i++) {
      output_bits2[3*i] = input_bits[i];
      output_bits2[3*i+1] = parity_bits[i];
      output_bits2[3*i+2] = parity_bits[i+long_cb+4];
    }

    if (SRSLTE_VERBOSE_ISINFO()) {
      srslte_vec_fprint_b(stdout, output_bits2, 3*long_cb); 
      srslte_vec_fprint_b(stdout, output_bits, 3*long_cb);       
      printf("\n");
    }  
    for (int i=0;i<2*long_cb;i++) {
      if (output_bits2[long_cb+i] != output_bits[long_cb+i]) {
        printf("error in bit %d, len=%d\n", i, len);
        exit(-1);
      }
    }
  }
  
  srslte_tcod_free(&tcod);
  printf("Done\n");
  exit(0);
}
예제 #2
0
파일: uci.c 프로젝트: srsLTE/srsLTE
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;   
}
예제 #3
0
파일: uci.c 프로젝트: srsLTE/srsLTE
/* 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; 
  }
}
예제 #4
0
int main(int argc, char **argv) {

  parse_args(argc, argv);
  
  srslte_tcod_gentable();

  srslte_tcod_t tcod;
  srslte_tcod_init(&tcod, 6144);

  uint32_t st=0, end=187;
  if (long_cb) {
    st=srslte_cbsegm_cbindex(long_cb);
    end=st;
  }
  
  for (uint32_t len=st;len<=end;len++) {
    long_cb = srslte_cbsegm_cbsize(len); 
    printf("Checking long_cb=%d\n", long_cb);
    for (int i=0;i<long_cb/8;i++) {
      input_bytes[i] = rand()%256;
    }
    
    srslte_bit_unpack_vector(input_bytes, input_bits, long_cb);

    if (SRSLTE_VERBOSE_ISINFO()) {
      printf("Input bits:\n");
      for (int i=0;i<long_cb/8;i++) {
        srslte_vec_fprint_b(stdout, &input_bits[i*8], 8);
      }
    }

    srslte_tcod_encode(&tcod, input_bits, output_bits, long_cb);
    srslte_tcod_encode_lut(&tcod, input_bytes, output_bytes, long_cb);
    
    srslte_bit_unpack_vector(output_bytes, output_bits2, 2*long_cb+12);

    /* de-Interleace bits for comparison */
    for (int i=0;i<long_cb;i++) {
      for (int j=0;j<2;j++) {
        output_bits3[j*long_cb+i] = output_bits[3*i+j+1]; 
      }
    }
    // copy tail 
    memcpy(&output_bits3[2*long_cb], &output_bits[3*long_cb], 12);

    if (SRSLTE_VERBOSE_ISINFO()) {
      printf("1st encoder\n");
      srslte_vec_fprint_b(stdout, output_bits2, long_cb); 
      srslte_vec_fprint_b(stdout, output_bits3, long_cb); 
      
      printf("2nd encoder\n");
      srslte_vec_fprint_b(stdout, &output_bits2[long_cb], long_cb); 
      srslte_vec_fprint_b(stdout, &output_bits3[long_cb], long_cb); 

      printf("tail\n");
      srslte_vec_fprint_b(stdout, &output_bits2[2*long_cb], 12); 
      srslte_vec_fprint_b(stdout, &output_bits3[2*long_cb], 12); 
      printf("\n");
    }  
    for (int i=0;i<2*long_cb+12;i++) {
      if (output_bits2[i] != output_bits3[i]) {
        printf("error in bit %d, len=%d\n", i, len);
        exit(-1);
      }
    }
  }
  
  srslte_tcod_free(&tcod);
  printf("Done\n");
  exit(0);
}
예제 #5
0
파일: sch.c 프로젝트: okanakgunduz/srsLTE
/* 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;      
  } 
예제 #6
0
int main(int argc, char **argv) {
  srslte_pusch_t pusch;
  uint8_t *data = NULL;
  cf_t *sf_symbols = NULL;
  cf_t *ce = NULL; 
  int ret = -1;
  struct timeval t[3];
  srslte_pusch_cfg_t cfg; 
  srslte_softbuffer_tx_t softbuffer_tx;
  srslte_softbuffer_rx_t softbuffer_rx; 
  
  parse_args(argc,argv);

  bzero(&cfg, sizeof(srslte_pusch_cfg_t));

  srslte_ra_ul_dci_t dci;
  dci.freq_hop_fl = freq_hop;
  if (riv < 0) {
    dci.type2_alloc.L_crb = L_prb; 
    dci.type2_alloc.RB_start = n_prb;    
  } else {
    dci.type2_alloc.riv = riv;
  }
  dci.mcs_idx = mcs_idx;
  
  srslte_ra_ul_grant_t grant; 
  if (srslte_ra_ul_dci_to_grant(&dci, cell.nof_prb, 0, &grant, 0)) {
    fprintf(stderr, "Error computing resource allocation\n");
    return ret;
  }
      
  srslte_pusch_hopping_cfg_t ul_hopping; 
  ul_hopping.n_sb = 1; 
  ul_hopping.hopping_offset = 0;
  ul_hopping.hop_mode = SRSLTE_PUSCH_HOP_MODE_INTER_SF;
  
  if (srslte_pusch_init(&pusch, cell)) {
    fprintf(stderr, "Error creating PDSCH object\n");
    goto quit;
  }
  
  /* Configure PUSCH */
    
  printf("Encoding rv_idx=%d\n",rv_idx);
  
  srslte_uci_cfg_t uci_cfg; 
  uci_cfg.I_offset_cqi = 6; 
  uci_cfg.I_offset_ri = 2; 
  uci_cfg.I_offset_ack = 4; 

  if (srslte_pusch_cfg(&pusch, &cfg, &grant, &uci_cfg, &ul_hopping, NULL, subframe, 0, 0)) {
    fprintf(stderr, "Error configuring PDSCH\n");
    exit(-1);
  }
  
  srslte_pusch_set_rnti(&pusch, 1234);
  
  srslte_uci_data_t uci_data_tx; 
  srslte_uci_data_t uci_data_rx; 
  bzero(&uci_data_tx, sizeof(srslte_uci_data_t));
  uci_data_tx.uci_cqi_len = 4; 
  uci_data_tx.uci_ri_len = 0; 
  uci_data_tx.uci_ack_len = 0; 
  memcpy(&uci_data_rx, &uci_data_tx, sizeof(srslte_uci_data_t));
    
  for (uint32_t i=0;i<20;i++) {
    uci_data_tx.uci_cqi [i] = 1;
  }
  uci_data_tx.uci_ri = 1; 
  uci_data_tx.uci_ack = 1; 

  uint32_t nof_re = SRSLTE_NRE*cell.nof_prb*2*SRSLTE_CP_NSYMB(cell.cp);
  sf_symbols = srslte_vec_malloc(sizeof(cf_t) * nof_re);
  if (!sf_symbols) {
    perror("malloc");
    exit(-1);
  }
  
  data = srslte_vec_malloc(sizeof(uint8_t) * cfg.grant.mcs.tbs);
  if (!data) {
    perror("malloc");
    exit(-1);
  }
  
  for (uint32_t i=0;i<cfg.grant.mcs.tbs/8;i++) {
    data[i] = 1;
  }

  if (srslte_softbuffer_tx_init(&softbuffer_tx, 100)) {
    fprintf(stderr, "Error initiating soft buffer\n");
    goto quit;
  }
  if (srslte_softbuffer_rx_init(&softbuffer_rx, 100)) {
    fprintf(stderr, "Error initiating soft buffer\n");
    goto quit;
  }
  
  uint32_t ntrials = 100; 

  if (srslte_pusch_uci_encode(&pusch, &cfg, &softbuffer_tx, data, uci_data_tx, sf_symbols)) {
    fprintf(stderr, "Error encoding TB\n");
    exit(-1);
  }
  if (rv_idx > 0) {
    cfg.rv = rv_idx; 
    if (srslte_pusch_uci_encode(&pusch, &cfg, &softbuffer_tx, data, uci_data_tx, sf_symbols)) {
      fprintf(stderr, "Error encoding TB\n");
      exit(-1);
    }
  }

  ce = srslte_vec_malloc(sizeof(cf_t) * SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp));
  if (!ce) {
    perror("srslte_vec_malloc");
    goto quit;
  }
  for (int j=0;j<SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp);j++) {
    ce[j] = 1;
  }
  
  gettimeofday(&t[1], NULL);
  int r = srslte_pusch_uci_decode(&pusch, &cfg, &softbuffer_rx, sf_symbols, ce, 0, data, &uci_data_rx);
  gettimeofday(&t[2], NULL);
  get_time_interval(t);
  if (r) {
    printf("Error decoding\n");
    ret = -1;
  } else {
    ret = 0;
    printf("DECODED OK in %d:%d (TBS: %d bits, TX: %.2f Mbps, Processing: %.2f Mbps)\n", (int) t[0].tv_sec, 
           (int) t[0].tv_usec/ntrials, 
           cfg.grant.mcs.tbs,
           (float) cfg.grant.mcs.tbs/1000,
           (float) cfg.grant.mcs.tbs/t[0].tv_usec*ntrials);    
  }
  if (uci_data_tx.uci_ack_len) {
    if (uci_data_tx.uci_ack != uci_data_rx.uci_ack) {
      printf("UCI ACK bit error: %d != %d\n", uci_data_tx.uci_ack, uci_data_rx.uci_ack);
    }
  }
  if (uci_data_tx.uci_ri_len) {
    if (uci_data_tx.uci_ri != uci_data_rx.uci_ri) {
      printf("UCI RI bit error: %d != %d\n", uci_data_tx.uci_ri, uci_data_rx.uci_ri);
    }
  }
  if (uci_data_tx.uci_cqi_len) {
    printf("cqi_tx=");
    srslte_vec_fprint_b(stdout, uci_data_tx.uci_cqi, uci_data_tx.uci_cqi_len);
    printf("cqi_rx=");
    srslte_vec_fprint_b(stdout, uci_data_rx.uci_cqi, uci_data_rx.uci_cqi_len);
  }

quit:
  srslte_pusch_free(&pusch);
  srslte_softbuffer_tx_free(&softbuffer_tx);
  
  if (sf_symbols) {
    free(sf_symbols);
  }
  if (data) {
    free(data);
  }
  if (ce) {
    free(ce);
  }
  if (ret) {
    printf("Error\n");
  } else {
    printf("Ok\n");
  }
  exit(ret);
}
예제 #7
0
파일: sch.c 프로젝트: CodaCarlson/srsLTE
/* 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;
  }
}