From 2c1608f6f14c83861412a28c431c6b4ca6134ed8 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Mon, 2 Jul 2018 18:15:56 +0200 Subject: [PATCH] Fixed UCI short CQI decoder. Fixed possible interleaver segfault. PUSCH Unit test tidied up. --- lib/src/phy/fec/rm_turbo.c | 9 +- lib/src/phy/fec/turbocoder.c | 15 +- lib/src/phy/phch/test/pusch_test.c | 392 ++++++++++++++++------------- lib/src/phy/phch/uci.c | 2 +- 4 files changed, 236 insertions(+), 182 deletions(-) diff --git a/lib/src/phy/fec/rm_turbo.c b/lib/src/phy/fec/rm_turbo.c index b1cc95a8c..b327500c8 100644 --- a/lib/src/phy/fec/rm_turbo.c +++ b/lib/src/phy/fec/rm_turbo.c @@ -252,9 +252,12 @@ void srslte_rm_turbo_gentables() { } void srslte_rm_turbo_free_tables () { - for (int i = 0; i < SRSLTE_NOF_TC_CB_SIZES; i++) { - srslte_bit_interleaver_free(&bit_interleavers_systematic_bits[i]); - srslte_bit_interleaver_free(&bit_interleavers_parity_bits[i]); + if (rm_turbo_tables_generated) { + for (int i = 0; i < SRSLTE_NOF_TC_CB_SIZES; i++) { + srslte_bit_interleaver_free(&bit_interleavers_systematic_bits[i]); + srslte_bit_interleaver_free(&bit_interleavers_parity_bits[i]); + } + rm_turbo_tables_generated = false; } } diff --git a/lib/src/phy/fec/turbocoder.c b/lib/src/phy/fec/turbocoder.c index 64f05b5e8..69f40dd46 100644 --- a/lib/src/phy/fec/turbocoder.c +++ b/lib/src/phy/fec/turbocoder.c @@ -60,12 +60,15 @@ int srslte_tcod_init(srslte_tcod_t *h, uint32_t max_long_cb) { } void srslte_tcod_free(srslte_tcod_t *h) { - h->max_long_cb = 0; - if (h->temp) { - free(h->temp); - } - for (int i = 0; i < 188; i++) { - srslte_bit_interleaver_free(&tcod_interleavers[i]); + if (table_initiated) { + h->max_long_cb = 0; + if (h->temp) { + free(h->temp); + } + for (int i = 0; i < 188; i++) { + srslte_bit_interleaver_free(&tcod_interleavers[i]); + } + table_initiated = false; } } diff --git a/lib/src/phy/phch/test/pusch_test.c b/lib/src/phy/phch/test/pusch_test.c index 4e377b42a..38be7b70c 100644 --- a/lib/src/phy/phch/test/pusch_test.c +++ b/lib/src/phy/phch/test/pusch_test.c @@ -27,28 +27,27 @@ #include #include #include -#include #include #include #include "srslte/srslte.h" -srslte_cell_t cell = { - .nof_prb = 6, // nof_prb - .nof_ports = 1, // nof_ports - .id = 0, // cell_id - .cp = SRSLTE_CP_NORM, // cyclic prefix - .phich_length = SRSLTE_PHICH_NORM, // PHICH length - .phich_resources = SRSLTE_PHICH_R_1_6 // PHICH resources +static srslte_cell_t cell = { + .nof_prb = 6, // nof_prb + .nof_ports = 1, // nof_ports + .id = 0, // cell_id + .cp = SRSLTE_CP_NORM, // cyclic prefix + .phich_length = SRSLTE_PHICH_NORM, // PHICH length + .phich_resources = SRSLTE_PHICH_R_1_6 // PHICH resources }; -srslte_uci_cfg_t uci_cfg = { +static srslte_uci_cfg_t uci_cfg = { .I_offset_cqi = 6, .I_offset_ri = 2, .I_offset_ack = 9, }; -srslte_uci_data_t uci_data_tx = { +static srslte_uci_data_t uci_data_tx = { .uci_cqi = {0}, .uci_cqi_len = 0, .uci_ri = 0, @@ -64,14 +63,14 @@ srslte_uci_data_t uci_data_tx = { uint32_t cfi = 2; uint32_t tbs = 0; -uint32_t subframe = 1; +uint32_t subframe = 10; srslte_mod_t modulation = SRSLTE_MOD_QPSK; uint32_t rv_idx = 0; -uint32_t L_prb = 2; -uint32_t n_prb = 0; -int freq_hop = -1; -int riv = -1; -uint32_t mcs_idx = 0; +uint32_t L_prb = 2; +uint32_t n_prb = 0; +int freq_hop = -1; +int riv = -1; +uint32_t mcs_idx = 0; srslte_cqi_value_t cqi_value; void usage(char *prog) { @@ -95,56 +94,52 @@ void usage(char *prog) { printf("\t\t-p I_offset_ack (0-15) [Default %d]\n", uci_cfg.I_offset_ack); printf("\n\tCQI/RI/ACK Reporting contents:\n"); - printf("\t\t-p uci_cqi (zeros, ones, random) [Default zeros]\n"); - printf("\t\t-p uci_cqi_len (0-64) [Default %d]\n", uci_data_tx.uci_cqi_len); + printf("\t\t-p uci_cqi (none, wideband) [Default none]\n"); printf("\t\t-p uci_ri (0-1) (zeros, ones, random) [Default none]\n"); printf("\t\t-p uci_ack (0-1) [Default none]\n"); printf("\t\t-p uci_ack_2 (0-1) [Default none]\n"); printf("\n\tOther parameters:\n"); - printf("\t\t-s subframe [Default %d]\n", subframe); + printf("\t\t-s number of subframes [Default %d]\n", subframe); printf("\t-v [set srslte_verbose to debug, default none]\n"); } -void parse_extensive_param (char *param, char *arg) { +void parse_extensive_param(char *param, char *arg) { int ext_code = SRSLTE_SUCCESS; if (!strcmp(param, "I_offset_cqi")) { - uci_cfg.I_offset_cqi = (uint32_t) atoi(arg); + uci_cfg.I_offset_cqi = (uint32_t) strtol(arg, NULL, 10); if (uci_cfg.I_offset_cqi > 15) { ext_code = SRSLTE_ERROR; } } else if (!strcmp(param, "I_offset_ri")) { - uci_cfg.I_offset_ri = (uint32_t) atoi(arg); + uci_cfg.I_offset_ri = (uint32_t) strtol(arg, NULL, 10); if (uci_cfg.I_offset_ri > 15) { ext_code = SRSLTE_ERROR; } } else if (!strcmp(param, "I_offset_ack")) { - uci_cfg.I_offset_ack = (uint32_t) atoi(arg); + uci_cfg.I_offset_ack = (uint32_t) strtol(arg, NULL, 10); if (uci_cfg.I_offset_ack > 15) { ext_code = SRSLTE_ERROR; } } else if (!strcmp(param, "uci_cqi")) { if (!strcmp(arg, "wideband")) { cqi_value.type = SRSLTE_CQI_TYPE_WIDEBAND; - cqi_value.wideband.wideband_cqi = (uint8_t) (rand() & 0x03); - uci_data_tx.uci_cqi_len = (uint32_t) srslte_cqi_value_unpack(uci_data_tx.uci_cqi, &cqi_value); + cqi_value.wideband.wideband_cqi = (uint8_t) (random() & 0x0f); + uci_data_tx.uci_cqi_len = (uint32_t) srslte_cqi_value_pack(&cqi_value, uci_data_tx.uci_cqi); + } else if (!strcmp(arg, "none")) { + uci_data_tx.uci_cqi_len = 0; } else { ext_code = SRSLTE_ERROR; } - } else if (!strcmp(param, "uci_cqi_len")) { - uci_data_tx.uci_cqi_len = (uint32_t) atol(arg); - if (uci_data_tx.uci_cqi_len >= SRSLTE_CQI_MAX_BITS) { - ext_code = SRSLTE_ERROR; - } } else if (!strcmp(param, "uci_ri")) { - uci_data_tx.uci_ri = (uint8_t) atol(arg); + uci_data_tx.uci_ri = (uint8_t) strtol(arg, NULL, 10); if (uci_data_tx.uci_ri > 1) { ext_code = SRSLTE_ERROR; } else { uci_data_tx.uci_ri_len = 1; } } else if (!strcmp(param, "uci_ack")) { - uci_data_tx.uci_ack = (uint8_t) atol(arg); + uci_data_tx.uci_ack = (uint8_t) strtol(arg, NULL, 10); if (uci_data_tx.uci_ack > 1) { ext_code = SRSLTE_ERROR; } else { @@ -154,7 +149,7 @@ void parse_extensive_param (char *param, char *arg) { } } } else if (!strcmp(param, "uci_ack_2")) { - uci_data_tx.uci_ack_2 = (uint8_t) atol(arg); + uci_data_tx.uci_ack_2 = (uint8_t) strtol(arg, NULL, 10); if (uci_data_tx.uci_ack_2 > 1) { ext_code = SRSLTE_ERROR; } else { @@ -175,45 +170,48 @@ void parse_extensive_param (char *param, char *arg) { void parse_args(int argc, char **argv) { int opt; - while ((opt = getopt(argc, argv, "msLNRFrncpv")) != -1) { - switch(opt) { - case 'm': - mcs_idx = atoi(argv[optind]); - break; - case 's': - subframe = atoi(argv[optind]); - break; - case 'L': - L_prb = atoi(argv[optind]); - break; - case 'N': - n_prb = atoi(argv[optind]); - break; - case 'R': - riv = atoi(argv[optind]); - break; - case 'F': - freq_hop = atoi(argv[optind]); - break; - case 'r': - rv_idx = atoi(argv[optind]); - break; - case 'n': - cell.nof_prb = atoi(argv[optind]); - break; - case 'c': - cell.id = atoi(argv[optind]); - break; - case 'p': - parse_extensive_param(argv[optind], argv[optind + 1]); - optind++; - break; - case 'v': - srslte_verbose++; - break; - default: - usage(argv[0]); - exit(-1); + while ((opt = getopt(argc, argv, "msLNRFrncpvf")) != -1) { + switch (opt) { + case 'm': + mcs_idx = (uint32_t) strtol(argv[optind], NULL, 10); + break; + case 's': + subframe = (uint32_t) strtol(argv[optind], NULL, 10); + break; + case 'f': + cfi = (uint32_t) strtol(argv[optind], NULL, 10); + break; + case 'L': + L_prb = (uint32_t) strtol(argv[optind], NULL, 10); + break; + case 'N': + n_prb = (uint32_t) strtol(argv[optind], NULL, 10); + break; + case 'R': + riv = (int) strtol(argv[optind], NULL, 10); + break; + case 'F': + freq_hop = (int) strtol(argv[optind], NULL, 10); + break; + case 'r': + rv_idx = (uint32_t) strtol(argv[optind], NULL, 10); + break; + case 'n': + cell.nof_prb = (uint32_t) strtol(argv[optind], NULL, 10); + break; + case 'c': + cell.id = (uint32_t) strtol(argv[optind], NULL, 10); + break; + case 'p': + parse_extensive_param(argv[optind], argv[optind + 1]); + optind++; + break; + case 'v': + srslte_verbose++; + break; + default: + usage(argv[0]); + exit(-1); } } } @@ -222,15 +220,16 @@ int main(int argc, char **argv) { srslte_pusch_t pusch_tx; srslte_pusch_t pusch_rx; uint8_t *data = NULL; + uint8_t *data_rx = NULL; cf_t *sf_symbols = NULL; - cf_t *ce = NULL; + cf_t *ce = NULL; int ret = -1; struct timeval t[3]; - srslte_pusch_cfg_t cfg; + srslte_pusch_cfg_t cfg; srslte_softbuffer_tx_t softbuffer_tx; - srslte_softbuffer_rx_t softbuffer_rx; - - parse_args(argc,argv); + srslte_softbuffer_rx_t softbuffer_rx; + + parse_args(argc, argv); bzero(&cfg, sizeof(srslte_pusch_cfg_t)); @@ -239,24 +238,24 @@ int main(int argc, char **argv) { 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; + dci.type2_alloc.L_crb = L_prb; + dci.type2_alloc.RB_start = n_prb; } else { - dci.type2_alloc.riv = riv; + dci.type2_alloc.riv = (uint32_t) riv; } dci.mcs_idx = mcs_idx; - - srslte_ra_ul_grant_t grant; + + srslte_ra_ul_grant_t grant; if (srslte_ra_ul_dci_to_grant(&dci, cell.nof_prb, 0, &grant)) { fprintf(stderr, "Error computing resource allocation\n"); return ret; } - - srslte_pusch_hopping_cfg_t ul_hopping; - ul_hopping.n_sb = 1; + + 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; - + ul_hopping.hop_mode = 1; + if (srslte_pusch_init_ue(&pusch_tx, cell.nof_prb)) { fprintf(stderr, "Error creating PUSCH object\n"); goto quit; @@ -274,139 +273,188 @@ int main(int argc, char **argv) { goto quit; } - /* Configure PUSCH */ - - if (srslte_pusch_cfg(&pusch_tx, &cfg, &grant, &uci_cfg, &ul_hopping, NULL, subframe, 0, 0)) { - fprintf(stderr, "Error configuring PDSCH\n"); - exit(-1); - } - if (srslte_pusch_cfg(&pusch_rx, &cfg, &grant, &uci_cfg, &ul_hopping, NULL, subframe, 0, 0)) { - fprintf(stderr, "Error configuring PDSCH\n"); - exit(-1); - } - - uint16_t rnti = 1234; + uint16_t rnti = 1234; srslte_pusch_set_rnti(&pusch_tx, rnti); srslte_pusch_set_rnti(&pusch_rx, rnti); srslte_uci_data_t uci_data_rx; memcpy(&uci_data_rx, &uci_data_tx, sizeof(srslte_uci_data_t)); - - uint32_t nof_re = SRSLTE_NRE*cell.nof_prb*2*SRSLTE_CP_NSYMB(cell.cp); + + 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+24)); + + data = srslte_vec_malloc(sizeof(uint8_t) * 150000); if (!data) { perror("malloc"); exit(-1); } - - for (uint32_t i=0;i 0) { - cfg.rv = rv_idx; - if (srslte_pusch_encode(&pusch_tx, &cfg, &softbuffer_tx, data, uci_data_tx, rnti, 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 1) { - if (uci_data_tx.uci_ack_2 != uci_data_rx.uci_ack_2) { - printf("UCI ACK 2 bit error: %d != %d\n", uci_data_tx.uci_ack_2, uci_data_rx.uci_ack_2); - ret = SRSLTE_ERROR; + + if (srslte_pusch_cfg(&pusch_rx, &cfg, &grant, &uci_cfg, &ul_hopping, NULL, (uint32_t) n % 10, 0, 0)) { + fprintf(stderr, "Error configuring PDSCH\n"); + exit(-1); } - } - 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); - ret = SRSLTE_ERROR; + + srslte_softbuffer_tx_reset(&softbuffer_tx); + srslte_softbuffer_rx_reset(&softbuffer_rx); + + for (uint32_t i = 0; i < cfg.grant.mcs.tbs / 8; i++) { + data[i] = (uint8_t) (random() & 0xff); } - } - if (uci_data_tx.uci_cqi_len) { - if (memcmp(uci_data_tx.uci_cqi, uci_data_rx.uci_cqi, 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); - ret = SRSLTE_ERROR; + + for (uint32_t i = 0; i < uci_data_tx.uci_cqi_len; i++) { + uci_data_tx.uci_cqi[i] = (uint8_t) (random() & 0x1); + } + + if (uci_data_tx.uci_ack_len > 0) { + uci_data_tx.uci_ack = (uint8_t) (random() & 0x1); + } + + if (uci_data_tx.uci_ack_len > 1) { + uci_data_tx.uci_ack_2 = (uint8_t) (random() & 0x1); } + + if (srslte_pusch_encode(&pusch_tx, &cfg, &softbuffer_tx, data, uci_data_tx, rnti, sf_symbols)) { + fprintf(stderr, "Error encoding TB\n"); + exit(-1); + } + if (rv_idx > 0) { + cfg.rv = rv_idx; + if (srslte_pusch_encode(&pusch_tx, &cfg, &softbuffer_tx, data, uci_data_tx, rnti, sf_symbols)) { + fprintf(stderr, "Error encoding TB\n"); + exit(-1); + } + } + + gettimeofday(&t[1], NULL); + int r = srslte_pusch_decode(&pusch_rx, + &cfg, + &softbuffer_rx, + sf_symbols, + ce, + 0, + rnti, + data_rx, + (uci_data_tx.uci_cqi_len) ? &cqi_value : NULL, + &uci_data_rx); + gettimeofday(&t[2], NULL); + if (r) { + printf("Error returned while decoding\n"); + goto quit; + } + + if (memcmp(data_rx, data, (size_t) cfg.grant.mcs.tbs / 8) != 0) { + printf("Unmatched data detected\n"); + goto quit; + } else { + INFO("Rx Data is Ok\n"); + } + + 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); + ret = SRSLTE_ERROR; + } else { + INFO("Rx ACK is Ok\n"); + } + } + + if (uci_data_tx.uci_ack_len > 1) { + if (uci_data_tx.uci_ack_2 != uci_data_rx.uci_ack_2) { + printf("UCI ACK 2 bit error: %d != %d\n", uci_data_tx.uci_ack_2, uci_data_rx.uci_ack_2); + ret = SRSLTE_ERROR; + } else { + INFO("Rx ACK2 is Ok\n"); + } + } + + 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); + ret = SRSLTE_ERROR; + } else { + INFO("Rx RI is Ok\n"); + } + } + + if (uci_data_tx.uci_cqi_len) { + if (memcmp(uci_data_tx.uci_cqi, uci_data_rx.uci_cqi, uci_data_tx.uci_cqi_len) != 0) { + printf("CQI Decode failed at subframe %d\n", n); + 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); + ret = SRSLTE_ERROR; + } else { + INFO("Rx CQI is Ok\n"); + } + } + + if (ret) { + goto quit; + } + + get_time_interval(t); + 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, + cfg.grant.mcs.tbs, + (float) cfg.grant.mcs.tbs / 1000, + (float) cfg.grant.mcs.tbs / t[0].tv_usec); + } -quit: + quit: srslte_pusch_free(&pusch_tx); srslte_pusch_free(&pusch_rx); srslte_softbuffer_tx_free(&softbuffer_tx); srslte_softbuffer_rx_free(&softbuffer_rx); - + if (sf_symbols) { free(sf_symbols); } if (data) { free(data); } + if (data_rx) { + free(data_rx); + } if (ce) { free(ce); } diff --git a/lib/src/phy/phch/uci.c b/lib/src/phy/phch/uci.c index 1b7b43ecb..9d783a93d 100644 --- a/lib/src/phy/phch/uci.c +++ b/lib/src/phy/phch/uci.c @@ -331,7 +331,7 @@ int decode_cqi_short(srslte_uci_cqi_pusch_t *q, int16_t *q_bits, uint32_t Q, uin for (uint32_t w=0;w<(1<cqi_table_s[nof_bits-1][w*32], q_bits, 32); + int32_t corr = srslte_vec_dot_prod_sss(&q->cqi_table_s[nof_bits-1][w*32], q_bits, SRSLTE_MIN(32, Q)); if (corr > max_corr) { max_corr = corr; max_w = w;