Example #1
0
/* 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;      
  } 
Example #2
0
int main(int argc, char **argv) {
  int ret; 
  cf_t *sf_buffer; 
  prog_args_t prog_args; 
  srslte_cell_t cell;  
  int64_t sf_cnt;
  srslte_ue_sync_t ue_sync; 
  srslte_ue_mib_t ue_mib; 
  void *uhd; 
  srslte_ue_dl_t ue_dl; 
  srslte_ofdm_t fft; 
  srslte_chest_dl_t chest; 
  uint32_t nframes=0;
  uint32_t nof_trials = 0; 
  uint32_t sfn = 0; // system frame number
  int n; 
  uint8_t bch_payload[SRSLTE_BCH_PAYLOAD_LEN];
  uint32_t sfn_offset; 
  float rssi_utra=0,rssi=0, rsrp=0, rsrq=0, snr=0;
  cf_t *ce[SRSLTE_MAX_PORTS];

  if (parse_args(&prog_args, argc, argv)) {
    exit(-1);
  }

  if (prog_args.uhd_gain > 0) {
    printf("Opening UHD device...\n");
    if (cuhd_open(prog_args.uhd_args, &uhd)) {
      fprintf(stderr, "Error opening uhd\n");
      exit(-1);
    }
    cuhd_set_rx_gain(uhd, prog_args.uhd_gain);      
  } else {
    printf("Opening UHD device with threaded RX Gain control ...\n");
    if (cuhd_open_th(prog_args.uhd_args, &uhd, false)) {
      fprintf(stderr, "Error opening uhd\n");
      exit(-1);
    }
    cuhd_set_rx_gain(uhd, 50);      
  }

  sigset_t sigset;
  sigemptyset(&sigset);
  sigaddset(&sigset, SIGINT);
  sigprocmask(SIG_UNBLOCK, &sigset, NULL);
  signal(SIGINT, sig_int_handler);

  cuhd_set_master_clock_rate(uhd, 30.72e6);        

  /* set receiver frequency */
  cuhd_set_rx_freq(uhd, (double) prog_args.uhd_freq);
  cuhd_rx_wait_lo_locked(uhd);
  printf("Tunning receiver to %.3f MHz\n", (double ) prog_args.uhd_freq/1000000);
  
  uint32_t ntrial=0; 
  do {
    ret = cuhd_search_and_decode_mib(uhd, &cell_detect_config, prog_args.force_N_id_2, &cell);
    if (ret < 0) {
      fprintf(stderr, "Error searching for cell\n");
      exit(-1); 
    } else if (ret == 0 && !go_exit) {
      printf("Cell not found after %d trials. Trying again (Press Ctrl+C to exit)\n", ntrial++);
    }      
  } while (ret == 0 && !go_exit); 
  
  if (go_exit) {
    exit(0);
  }
  
  /* set sampling frequency */
    int srate = srslte_sampling_freq_hz(cell.nof_prb);    
    if (srate != -1) {  
      if (srate < 10e6) {          
        cuhd_set_master_clock_rate(uhd, 4*srate);        
      } else {
        cuhd_set_master_clock_rate(uhd, srate);        
      }
      printf("Setting sampling rate %.2f MHz\n", (float) srate/1000000);
      float srate_uhd = cuhd_set_rx_srate(uhd, (double) srate);
      if (srate_uhd != srate) {
        fprintf(stderr, "Could not set sampling rate\n");
        exit(-1);
      }
    } else {
      fprintf(stderr, "Invalid number of PRB %d\n", cell.nof_prb);
      exit(-1);
    }

  INFO("Stopping UHD and flushing buffer...\n",0);
  cuhd_stop_rx_stream(uhd);
  cuhd_flush_buffer(uhd);
  
  if (srslte_ue_sync_init(&ue_sync, cell, cuhd_recv_wrapper, uhd)) {
    fprintf(stderr, "Error initiating ue_sync\n");
    return -1; 
  }
  if (srslte_ue_dl_init(&ue_dl, cell)) { 
    fprintf(stderr, "Error initiating UE downlink processing module\n");
    return -1;
  }
  if (srslte_ue_mib_init(&ue_mib, cell)) {
    fprintf(stderr, "Error initaiting UE MIB decoder\n");
    return -1;
  }
  
  /* Configure downlink receiver for the SI-RNTI since will be the only one we'll use */
  srslte_ue_dl_set_rnti(&ue_dl, SRSLTE_SIRNTI); 

  /* Initialize subframe counter */
  sf_cnt = 0;
    
  if (srslte_ofdm_rx_init(&fft, cell.cp, cell.nof_prb)) {
    fprintf(stderr, "Error initiating FFT\n");
    return -1;
  }
  if (srslte_chest_dl_init(&chest, cell)) {
    fprintf(stderr, "Error initiating channel estimator\n");
    return -1;
  }
  
  int sf_re = SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp);

  cf_t *sf_symbols = srslte_vec_malloc(sf_re * sizeof(cf_t));

  for (int i=0;i<SRSLTE_MAX_PORTS;i++) {
    ce[i] = srslte_vec_malloc(sizeof(cf_t) * sf_re);
  }
  
  cuhd_start_rx_stream(uhd);
  
  float rx_gain_offset = 0;

  /* Main loop */
  while ((sf_cnt < prog_args.nof_subframes || prog_args.nof_subframes == -1) && !go_exit) {
    
    ret = srslte_ue_sync_get_buffer(&ue_sync, &sf_buffer);
    if (ret < 0) {
      fprintf(stderr, "Error calling srslte_ue_sync_work()\n");
    }

        
    /* srslte_ue_sync_get_buffer returns 1 if successfully read 1 aligned subframe */
    if (ret == 1) {
      switch (state) {
        case DECODE_MIB:
          if (srslte_ue_sync_get_sfidx(&ue_sync) == 0) {
            srslte_pbch_decode_reset(&ue_mib.pbch);
            n = srslte_ue_mib_decode(&ue_mib, sf_buffer, bch_payload, NULL, &sfn_offset);
            if (n < 0) {
              fprintf(stderr, "Error decoding UE MIB\n");
              return -1;
            } else if (n == SRSLTE_UE_MIB_FOUND) {   
              srslte_pbch_mib_unpack(bch_payload, &cell, &sfn);
              printf("Decoded MIB. SFN: %d, offset: %d\n", sfn, sfn_offset);
              sfn = (sfn + sfn_offset)%1024; 
              state = DECODE_SIB; 
            }
          }
          break;
        case DECODE_SIB:
          /* We are looking for SI Blocks, search only in appropiate places */
          if ((srslte_ue_sync_get_sfidx(&ue_sync) == 5 && (sfn%2)==0)) {
            n = srslte_ue_dl_decode_rnti_rv(&ue_dl, sf_buffer, data, srslte_ue_sync_get_sfidx(&ue_sync), SRSLTE_SIRNTI,
                                 ((int) ceilf((float)3*(((sfn)/2)%4)/2))%4);
            if (n < 0) {
              fprintf(stderr, "Error decoding UE DL\n");fflush(stdout);
              return -1;
            } else if (n == 0) {
              printf("CFO: %+6.4f KHz, SFO: %+6.4f Khz, NOI: %.2f, PDCCH-Det: %.3f\r",
                      srslte_ue_sync_get_cfo(&ue_sync)/1000, srslte_ue_sync_get_sfo(&ue_sync)/1000, 
                      srslte_sch_average_noi(&ue_dl.pdsch.dl_sch),
                      (float) ue_dl.nof_detected/nof_trials);                
              nof_trials++; 
            } else {
              printf("Decoded SIB1. Payload: ");
              srslte_vec_fprint_byte(stdout, data, n/8);;
              state = MEASURE;
            }
          }
        break;
        
      case MEASURE:
        
        if (srslte_ue_sync_get_sfidx(&ue_sync) == 5) {
          /* Run FFT for all subframe data */
          srslte_ofdm_rx_sf(&fft, sf_buffer, sf_symbols);
          
          srslte_chest_dl_estimate(&chest, sf_symbols, ce, srslte_ue_sync_get_sfidx(&ue_sync));
                  
          rssi = SRSLTE_VEC_EMA(srslte_vec_avg_power_cf(sf_buffer,SRSLTE_SF_LEN(srslte_symbol_sz(cell.nof_prb))),rssi,0.05);
          rssi_utra = SRSLTE_VEC_EMA(srslte_chest_dl_get_rssi(&chest),rssi_utra,0.05);
          rsrq = SRSLTE_VEC_EMA(srslte_chest_dl_get_rsrq(&chest),rsrq,0.05);
          rsrp = SRSLTE_VEC_EMA(srslte_chest_dl_get_rsrp(&chest),rsrp,0.05);      
          snr = SRSLTE_VEC_EMA(srslte_chest_dl_get_snr(&chest),snr,0.05);      
          
          nframes++;          
        } 
        
        
        if ((nframes%100) == 0 || rx_gain_offset == 0) {
          if (cuhd_has_rssi(uhd)) {
            rx_gain_offset = 10*log10(rssi)-cuhd_get_rssi(uhd);
          } else {
            rx_gain_offset = cuhd_get_rx_gain(uhd);
          }
        }
        
        // Plot and Printf
        if ((nframes%10) == 0) {

          printf("CFO: %+8.4f KHz, SFO: %+8.4f Khz, RSSI: %5.1f dBm, RSSI/ref-symbol: %+5.1f dBm, "
                 "RSRP: %+5.1f dBm, RSRQ: %5.1f dB, SNR: %5.1f dB\r",
                srslte_ue_sync_get_cfo(&ue_sync)/1000, srslte_ue_sync_get_sfo(&ue_sync)/1000, 
                10*log10(rssi*1000) - rx_gain_offset,                                  
                10*log10(rssi_utra*1000)- rx_gain_offset, 
                10*log10(rsrp*1000) - rx_gain_offset, 
                10*log10(rsrq), 10*log10(snr));                
          if (srslte_verbose != SRSLTE_VERBOSE_NONE) {
            printf("\n");
          }
        }
        break;
      }
      if (srslte_ue_sync_get_sfidx(&ue_sync) == 9) {
        sfn++; 
        if (sfn == 1024) {
          sfn = 0; 
        }
      }
    } else if (ret == 0) {
      printf("Finding PSS... Peak: %8.1f, FrameCnt: %d, State: %d\r", 
        srslte_sync_get_peak_value(&ue_sync.sfind), 
        ue_sync.frame_total_cnt, ue_sync.state);      
    }
   
        
    sf_cnt++;                  
  } // Main loop

  srslte_ue_sync_free(&ue_sync);
  cuhd_close(uhd);
  printf("\nBye\n");
  exit(0);
}
Example #3
0
int main(int argc, char** argv)
{

  srslte_chest_dl_res_t chest_dl_res;
  srslte_pdcch_t pdcch_tx, pdcch_rx;
  testcase_dci_t testcases[10];
  srslte_regs_t regs;
  int i;
  int nof_re;
  cf_t *slot_symbols[SRSLTE_MAX_PORTS];
  int nof_dcis;

  bzero(&testcases, sizeof(testcase_dci_t)*10);

  int ret = -1;

  parse_args(argc, argv);

  nof_re = SRSLTE_CP_NORM_NSYMB * cell.nof_prb * SRSLTE_NRE;

  if (test_dci_payload_size()) {
    exit(-1);
  }

  /* init memory */

  srslte_chest_dl_res_init(&chest_dl_res, cell.nof_prb);
  srslte_chest_dl_res_set_identity(&chest_dl_res);

  for (i = 0; i < SRSLTE_MAX_PORTS; i++) {
    slot_symbols[i] = malloc(sizeof(cf_t) * nof_re);
    if (!slot_symbols[i]) {
      perror("malloc");
      exit(-1);
    }
    bzero(slot_symbols[i], sizeof(cf_t) * nof_re);
  }

  if (srslte_regs_init(&regs, cell)) {
    ERROR("Error initiating regs\n");
    exit(-1);
  }

  if (srslte_pdcch_init_enb(&pdcch_tx, cell.nof_prb)) {
    ERROR("Error creating PDCCH object\n");
    exit(-1);
  }
  if (srslte_pdcch_set_cell(&pdcch_tx, &regs, cell)) {
    ERROR("Error setting cell in PDCCH object\n");
    exit(-1);
  }

  if (srslte_pdcch_init_ue(&pdcch_rx, cell.nof_prb, nof_rx_ant)) {
    ERROR("Error creating PDCCH object\n");
    exit(-1);
  }
  if (srslte_pdcch_set_cell(&pdcch_rx, &regs, cell)) {
    ERROR("Error setting cell in PDCCH object\n");
    exit(-1);
  }

  /* Resource allocate init */
  nof_dcis = 0;
  srslte_dci_dl_t dci;
  ZERO_OBJECT(dci);
  dci.pid                     = 5;
  dci.tb[0].mcs_idx           = 5;
  dci.tb[0].ndi               = 0;
  dci.tb[0].rv                = 1;
  dci.alloc_type              = SRSLTE_RA_ALLOC_TYPE0;
  dci.type0_alloc.rbg_bitmask = 0x5;
  dci.cif_present             = dci_cfg.cif_enabled;
  if (dci_cfg.cif_enabled) {
    dci.cif = (uint32_t)(random() & 0x7);
  }

  /* Format 1 Test case */
  if (cell.nof_ports == 1) {
    testcases[nof_dcis].dci_format = SRSLTE_DCI_FORMAT1;
    if (dci_cfg.cif_enabled) {
      dci.cif = (uint32_t)(random() & 0x7);
    }
    testcases[nof_dcis].ra_dl_tx = dci;
    nof_dcis++;

    /* Format 1 Test case */
    dci.tb[0].mcs_idx              = 15;
    testcases[nof_dcis].dci_format = SRSLTE_DCI_FORMAT1;
    if (dci_cfg.cif_enabled) {
      dci.cif = (uint32_t)(random() & 0x7);
    }
    testcases[nof_dcis].ra_dl_tx = dci;
    nof_dcis++;
  }

  /* Tx Diversity Test case */
  if (cell.nof_ports > 1) {
    dci.tb[1].mcs_idx              = 13;
    dci.tb[1].rv                   = 3;
    dci.tb[1].ndi                  = true;
    testcases[nof_dcis].dci_format = SRSLTE_DCI_FORMAT2A;
    if (dci_cfg.cif_enabled) {
      dci.cif = (uint32_t)(random() & 0x7);
    }
    testcases[nof_dcis].ra_dl_tx = dci;
    nof_dcis++;
  }

  /* CDD Spatial Multiplexing Test case */
  if (cell.nof_ports > 1) {
    dci.tb[1].mcs_idx              = 28;
    dci.tb[1].rv                   = 1;
    dci.tb[1].ndi                  = false;
    testcases[nof_dcis].dci_format = SRSLTE_DCI_FORMAT2;
    if (dci_cfg.cif_enabled) {
      dci.cif = (uint32_t)(random() & 0x7);
    }
    testcases[nof_dcis].ra_dl_tx = dci;
    nof_dcis++;
  }

  srslte_dci_cfg_t dci_cfg;
  ZERO_OBJECT(dci_cfg);

  srslte_dl_sf_cfg_t dl_sf;
  ZERO_OBJECT(dl_sf);
  dl_sf.cfi = cfi;

  for (int s=0;s<10;s++) {
    dl_sf.tti = s;
    printf("Encoding %d DCIs for sf_idx=%d\n", nof_dcis, s);
    /* Execute Rx */
    for (i=0;i<nof_dcis;i++) {
      testcases[i].ra_dl_tx.rnti   = (uint16_t) (1234 + i);
      testcases[i].ra_dl_tx.format = testcases[i].dci_format;

      srslte_dci_msg_pack_pdsch(&cell, &dl_sf, &dci_cfg, &testcases[i].ra_dl_tx, &testcases[i].dci_tx);
      srslte_dci_location_set(&testcases[i].dci_location, 0, (uint32_t) i);

      testcases[i].dci_tx.format   = testcases[i].dci_format;
      testcases[i].dci_tx.location = testcases[i].dci_location;

      // Enable just 1 TB per default
      if (testcases[i].dci_format < SRSLTE_DCI_FORMAT2) {
        for (int j=1;j<SRSLTE_MAX_CODEWORDS;j++) {
          SRSLTE_DCI_TB_DISABLE(testcases[i].ra_dl_tx.tb[j]);
        }
      }

      if (srslte_pdcch_encode(&pdcch_tx, &dl_sf, &testcases[i].dci_tx, slot_symbols)) {
        ERROR("Error encoding DCI message\n");
        goto quit;
      }
    }

    /* Execute 'Rx' */
    if (srslte_pdcch_extract_llr(&pdcch_rx, &dl_sf, &chest_dl_res, slot_symbols)) {
      ERROR("Error extracting LLRs\n");
      goto quit;
    }

    /* Decode DCIs */
    for (i=0;i<nof_dcis;i++) {
      testcases[i].dci_rx.format   = testcases[i].dci_format;
      testcases[i].dci_rx.location = testcases[i].dci_location;
      if (srslte_pdcch_decode_msg(&pdcch_rx, &dl_sf, &dci_cfg, &testcases[i].dci_rx)) {
        ERROR("Error decoding DCI message\n");
        goto quit;
      }
      if (srslte_dci_msg_unpack_pdsch(&cell, &dl_sf, &dci_cfg, &testcases[i].dci_rx, &testcases[i].ra_dl_rx)) {
        ERROR("Error unpacking DCI message\n");
        goto quit;
      }
      if (testcases[i].dci_rx.rnti >= 1234 && testcases[i].dci_rx.rnti < 1234 + nof_dcis) {
        testcases[i].dci_rx.rnti -= 1234;
      } else {
        printf("Received invalid DCI CRC %d\n", testcases[i].dci_rx.rnti);
        goto quit;
      }
    }

    /* Compare Tx and Rx */
    for (i = 0; i < nof_dcis; i++) {
      if (memcmp(testcases[i].dci_tx.payload, testcases[i].dci_rx.payload, testcases[i].dci_tx.nof_bits)) {
        printf("Error in DCI %d: Received data does not match\n", i);
        goto quit;
      }
#if SRSLTE_DCI_HEXDEBUG
      // Ignore Hex str
    bzero(testcases[i].ra_dl_rx.hex_str, sizeof(testcases[i].ra_dl_rx.hex_str));
    testcases[i].ra_dl_rx.nof_bits = 0;
#endif
      // Ignore DCI location
      testcases[i].ra_dl_rx.location = testcases[i].ra_dl_tx.location;
      // Ignore cw_idx
      for (int j=0;j<SRSLTE_MAX_CODEWORDS;j++) {
        testcases[i].ra_dl_rx.tb[j].cw_idx = testcases[i].ra_dl_tx.tb[j].cw_idx;
      }
      if (memcmp(&testcases[i].ra_dl_tx, &testcases[i].ra_dl_rx, sizeof(srslte_dci_dl_t))) {
        uint8_t *x=(uint8_t*) &testcases[i].ra_dl_rx;
        uint8_t *y=(uint8_t*) &testcases[i].ra_dl_tx;
        for (int j=0;j<sizeof(srslte_dci_dl_t);j++) {
          if (x[j] != y[j]) {
            printf("error in byte %d, rx=%d, tx=%d\n", j, x[j], y[j]);
          }
        }
        printf("tx: "); srslte_vec_fprint_byte(stdout, (uint8_t*) &testcases[i].ra_dl_tx, sizeof(srslte_dci_dl_t));
        printf("rx: "); srslte_vec_fprint_byte(stdout, (uint8_t*) &testcases[i].ra_dl_rx, sizeof(srslte_dci_dl_t));
        printf("Error in RA %d: Received data does not match\n", i);
        printf("     Field    |    Tx    |    Rx    \n");
        printf("--------------+----------+----------\n");
        if (testcases[i].ra_dl_tx.cif) {
          printf("          cif | %8d | %8d\n", testcases[i].ra_dl_tx.cif, testcases[i].ra_dl_rx.cif);
        }
        printf(" harq_process | %8d | %8d\n", testcases[i].ra_dl_tx.pid, testcases[i].ra_dl_rx.pid);
        printf("      mcs_idx | %8d | %8d\n", testcases[i].ra_dl_tx.tb[0].mcs_idx, testcases[i].ra_dl_rx.tb[0].mcs_idx);
        printf("       rv_idx | %8d | %8d\n", testcases[i].ra_dl_tx.tb[0].rv, testcases[i].ra_dl_rx.tb[0].rv);
        printf("          ndi | %8d | %8d\n", testcases[i].ra_dl_tx.tb[0].ndi, testcases[i].ra_dl_rx.tb[0].ndi);
        printf("    mcs_idx_1 | %8d | %8d\n", testcases[i].ra_dl_tx.tb[1].mcs_idx, testcases[i].ra_dl_rx.tb[1].mcs_idx);
        printf("     rv_idx_1 | %8d | %8d\n", testcases[i].ra_dl_tx.tb[1].rv, testcases[i].ra_dl_rx.tb[1].rv);
        printf("        ndi_1 | %8d | %8d\n", testcases[i].ra_dl_tx.tb[1].ndi, testcases[i].ra_dl_rx.tb[1].ndi);
        printf("   tb_cw_swap | %8d | %8d\n", testcases[i].ra_dl_tx.tb_cw_swap, testcases[i].ra_dl_rx.tb_cw_swap);
        printf("      sram_id | %8d | %8d\n", testcases[i].ra_dl_tx.sram_id, testcases[i].ra_dl_rx.sram_id);
        printf("        pinfo | %8d | %8d\n", testcases[i].ra_dl_tx.pinfo, testcases[i].ra_dl_rx.pinfo);
        printf("        pconf | %8d | %8d\n", testcases[i].ra_dl_tx.pconf, testcases[i].ra_dl_rx.pconf);
        printf(" power_offset | %8d | %8d\n", testcases[i].ra_dl_tx.power_offset, testcases[i].ra_dl_rx.power_offset);
        printf("    tpc_pucch | %8d | %8d\n", testcases[i].ra_dl_tx.tpc_pucch, testcases[i].ra_dl_rx.tpc_pucch);
        goto quit;
      }
    }
  }
  ret = 0;

quit: 
  srslte_pdcch_free(&pdcch_tx);
  srslte_pdcch_free(&pdcch_rx);
  srslte_chest_dl_res_free(&chest_dl_res);
  srslte_regs_free(&regs);

  for (i = 0; i < SRSLTE_MAX_PORTS; i++) {
    free(slot_symbols[i]);
  }
  if (ret) {
    printf("Error\n");
  } else {
    printf("Ok\n");
  }
  srslte_dft_exit();
  exit(ret);
}