diff --git a/examples/pdsch_enodeb.c b/examples/pdsch_enodeb.c new file mode 100644 index 000000000..4cf26bb68 --- /dev/null +++ b/examples/pdsch_enodeb.c @@ -0,0 +1,283 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * A copy of the GNU Lesser General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#include +#include +#include +#include +#include + +#include "lte.h" + +#ifndef DISABLE_UHD + #include "cuhd.h" + void *uhd; +#endif + +char *output_file_name = NULL; +int nof_frames=-1; +int cell_id = 1; +int nof_prb = 6; +char *uhd_args = ""; + +float uhd_amp=0.25, uhd_gain=10.0, uhd_freq=2400000000; + +filesink_t fsink; +lte_fft_t ifft; +pbch_t pbch; + +cf_t *slot_buffer = NULL, *output_buffer = NULL; +int slot_n_re, slot_n_samples; + +#define UHD_SAMP_FREQ 1920000 + +void usage(char *prog) { + printf("Usage: %s [agmfoncvp]\n", prog); +#ifndef DISABLE_UHD + printf("\t-a UHD args [Default %s]\n", uhd_args); + printf("\t-g UHD TX gain [Default %.2f dB]\n", uhd_gain); + printf("\t-m UHD signal amplitude [Default %.2f]\n", uhd_amp); + printf("\t-f UHD TX frequency [Default %.1f MHz]\n", uhd_freq/1000000); +#else + printf("\t UHD is disabled. CUHD library not available\n"); +#endif + printf("\t-o output_file [Default USRP]\n"); + printf("\t-n number of frames [Default %d]\n", nof_frames); + printf("\t-c cell id [Default %d]\n", cell_id); + printf("\t-p nof_prb [Default %d]\n", nof_prb); + printf("\t-v [set verbose to debug, default none]\n"); +} + +void parse_args(int argc, char **argv) { + int opt; + while ((opt = getopt(argc, argv, "agfmoncpv")) != -1) { + switch(opt) { + case 'a': + uhd_args = argv[optind]; + break; + case 'g': + uhd_gain = atof(argv[optind]); + break; + case 'm': + uhd_amp = atof(argv[optind]); + break; + case 'f': + uhd_freq = atof(argv[optind]); + break; + case 'o': + output_file_name = argv[optind]; + break; + case 'n': + nof_frames = atoi(argv[optind]); + break; + case 'p': + nof_prb = atoi(argv[optind]); + break; + case 'c': + cell_id = atoi(argv[optind]); + break; + case 'v': + verbose++; + break; + default: + usage(argv[0]); + exit(-1); + } + } +#ifdef DISABLE_UHD + if (!output_file_name) { + usage(argv[0]); + exit(-1); + } +#endif +} + +void base_init() { + /* init memory */ + slot_buffer = malloc(sizeof(cf_t) * slot_n_re); + if (!slot_buffer) { + perror("malloc"); + exit(-1); + } + output_buffer = malloc(sizeof(cf_t) * slot_n_samples); + if (!output_buffer) { + perror("malloc"); + exit(-1); + } + /* open file or USRP */ + if (output_file_name) { + if (filesink_init(&fsink, output_file_name, COMPLEX_FLOAT_BIN)) { + fprintf(stderr, "Error opening file %s\n", output_file_name); + exit(-1); + } + } else { +#ifndef DISABLE_UHD + printf("Opening UHD device...\n"); + if (cuhd_open(uhd_args,&uhd)) { + fprintf(stderr, "Error opening uhd\n"); + exit(-1); + } +#else + printf("Error UHD not available. Select an output file\n"); + exit(-1); +#endif + } + + /* create ifft object */ + if (lte_ifft_init(&ifft, CPNORM, nof_prb)) { + fprintf(stderr, "Error creating iFFT object\n"); + exit(-1); + } + if (pbch_init(&pbch, 6, cell_id, CPNORM)) { + fprintf(stderr, "Error creating PBCH object\n"); + exit(-1); + } +} + +void base_free() { + + pbch_free(&pbch); + + lte_ifft_free(&ifft); + + if (slot_buffer) { + free(slot_buffer); + } + if (output_buffer) { + free(output_buffer); + } + if (output_file_name) { + filesink_free(&fsink); + } else { +#ifndef DISABLE_UHD + cuhd_close(&uhd); +#endif + } +} + +int main(int argc, char **argv) { + int nf, ns, N_id_2; + cf_t pss_signal[PSS_LEN]; + float sss_signal0[SSS_LEN]; // for subframe 0 + float sss_signal5[SSS_LEN]; // for subframe 5 + pbch_mib_t mib; + refsignal_t refs[NSLOTS_X_FRAME]; + int i; + cf_t *slot1_symbols[MAX_PORTS_CTRL]; + + +#ifdef DISABLE_UHD + if (argc < 3) { + usage(argv[0]); + exit(-1); + } +#endif + + parse_args(argc,argv); + + N_id_2 = cell_id%3; + slot_n_re = CPNORM_NSYMB * nof_prb * RE_X_RB; + slot_n_samples = SLOT_LEN_CPNORM(lte_symbol_sz(nof_prb)); + + /* this *must* be called after setting slot_len_* */ + base_init(); + + /* Generate PSS/SSS signals */ + pss_generate(pss_signal, N_id_2); + sss_generate(sss_signal0, sss_signal5, cell_id); + + /* Generate CRS signals */ + for (i=0;i= 0 && index < NOF_TC_CB_SIZES) { return tc_cb_sizes[index]; @@ -58,6 +61,9 @@ int lte_cb_size(int index) { } } +/* + * Finds index of minimum K>=long_cb in Table 5.1.3-3 of 36.212 + */ int lte_find_cb_index(int long_cb) { int j = 0; while (j < NOF_TC_CB_SIZES && tc_cb_sizes[j] < long_cb) { diff --git a/lte/lib/fec/src/rm_conv.c b/lte/lib/fec/src/rm_conv.c index b534b1c3a..6b90bf9a1 100644 --- a/lte/lib/fec/src/rm_conv.c +++ b/lte/lib/fec/src/rm_conv.c @@ -33,10 +33,10 @@ #define NCOLS 32 #define NROWS_MAX NCOLS -unsigned char RM_PERM_TC[NCOLS] = +unsigned char RM_PERM_CC[NCOLS] = { 1, 17, 9, 25, 5, 21, 13, 29, 3, 19, 11, 27, 7, 23, 15, 31, 0, 16, 8, 24, 4, 20, 12, 28, 2, 18, 10, 26, 6, 22, 14, 30 }; -unsigned char RM_PERM_TC_INV[NCOLS] = { 16, 0, 24, 8, 20, 4, 28, 12, 18, 2, 26, +unsigned char RM_PERM_CC_INV[NCOLS] = { 16, 0, 24, 8, 20, 4, 28, 12, 18, 2, 26, 10, 22, 6, 30, 14, 17, 1, 25, 9, 21, 5, 29, 13, 19, 3, 27, 11, 23, 7, 31, 15 }; @@ -63,10 +63,10 @@ int rm_conv_tx(char *input, int in_len, char *output, int out_len) { for (s = 0; s < 3; s++) { for (j = 0; j < NCOLS; j++) { for (i = 0; i < nrows; i++) { - if (i*NCOLS + RM_PERM_TC[j] < ndummy) { + if (i*NCOLS + RM_PERM_CC[j] < ndummy) { tmp[k] = TX_NULL; } else { - tmp[k] = input[(i*NCOLS + RM_PERM_TC[j]-ndummy)*3+s]; + tmp[k] = input[(i*NCOLS + RM_PERM_CC[j]-ndummy)*3+s]; } k++; } @@ -124,7 +124,7 @@ int rm_conv_rx(float *input, int in_len, float *output, int out_len) { d_i = (j % K_p) / nrows; d_j = (j % K_p) % nrows; - if (d_j * NCOLS + RM_PERM_TC[d_i] >= ndummy) { + if (d_j * NCOLS + RM_PERM_CC[d_i] >= ndummy) { if (tmp[j] == RX_NULL) { tmp[j] = input[k]; } else if (input[k] != RX_NULL) { @@ -143,7 +143,7 @@ int rm_conv_rx(float *input, int in_len, float *output, int out_len) { d_i = (i + ndummy) / NCOLS; d_j = (i + ndummy) % NCOLS; for (j = 0; j < 3; j++) { - float o = tmp[K_p * j + RM_PERM_TC_INV[d_j] * nrows + float o = tmp[K_p * j + RM_PERM_CC_INV[d_j] * nrows + d_i]; if (o != RX_NULL) { output[i * 3 + j] = o; diff --git a/lte/lib/fec/src/rm_turbo.c b/lte/lib/fec/src/rm_turbo.c index 2f39d0a49..858654abb 100644 --- a/lte/lib/fec/src/rm_turbo.c +++ b/lte/lib/fec/src/rm_turbo.c @@ -72,8 +72,8 @@ int rm_turbo_tx(rm_turbo_t *q, char *input, int in_len, char *output, int out_le K_p = nrows * NCOLS; if (3 * K_p > q->buffer_len) { fprintf(stderr, - "Input too large. Max input length including dummy bits is %d\n", - q->buffer_len); + "Input too large. Max input length including dummy bits is %d (3x%dx32, in_len %d)\n", + q->buffer_len, nrows, in_len); return -1; } @@ -146,8 +146,8 @@ int rm_turbo_rx(rm_turbo_t *q, float *input, int in_len, float *output, int out_ K_p = nrows * NCOLS; if (3 * K_p > q->buffer_len) { fprintf(stderr, - "Input too large. Max input length including dummy bits is %d\n", - q->buffer_len); + "Input too large. Max output length including dummy bits is %d (3x%dx32, in_len %d)\n", + q->buffer_len, nrows, out_len); return -1; } diff --git a/lte/lib/fec/src/tc_interl_lte.c b/lte/lib/fec/src/tc_interl_lte.c index 1db75cf92..bef066081 100644 --- a/lte/lib/fec/src/tc_interl_lte.c +++ b/lte/lib/fec/src/tc_interl_lte.c @@ -66,29 +66,21 @@ const int f2_list[NOF_TC_CB_SIZES] = { 10, 12, 42, 16, 18, 20, 22, 24, 26, 84, 9 158, 80, 96, 902, 166, 336, 170, 86, 174, 176, 178, 120, 182, 184, 186, 94, 190, 480 }; -int tc_interl_LTE_init(tc_interl_t *h, int long_cb) { +int tc_interl_LTE_gen(tc_interl_t *h, int long_cb) { int cb_table_idx, f1, f2; unsigned long long i, j; + if (long_cb > h->max_long_cb) { + fprintf(stderr, "Interleaver initiated for max_long_cb=%d\n",h->max_long_cb); + return -1; + } + cb_table_idx = lte_find_cb_index(long_cb); if (cb_table_idx == -1) { fprintf(stderr, "Can't find long_cb=%d in valid TC CB table\n", long_cb); return -1; } - h->forward = h->reverse = NULL; - h->forward = malloc(sizeof(int) * (long_cb)); - if (!h->forward) { - return -1; - } - h->reverse = malloc(sizeof(int) * (long_cb)); - if (!h->reverse) { - perror("malloc"); - free(h->forward); - h->forward = h->reverse = NULL; - return -1; - } - f1 = f1_list[cb_table_idx]; f2 = f2_list[cb_table_idx]; diff --git a/lte/lib/fec/src/tc_interl_umts.c b/lte/lib/fec/src/tc_interl_umts.c index a71d2f0e0..8d97f14cb 100644 --- a/lte/lib/fec/src/tc_interl_umts.c +++ b/lte/lib/fec/src/tc_interl_umts.c @@ -27,6 +27,7 @@ #include #include +#include #include "lte/fec/tc_interl.h" #include "lte/fec/turbocoder.h" @@ -52,6 +53,28 @@ const unsigned char table_v[52] = { 3, 2, 2, 3, 2, 5, 2, 3, 2, 6, 3, 5, 2, 2, 2, 2, 7, 5, 3, 2, 3, 5, 2, 5, 2, 6, 3, 3, 2, 3, 2, 2, 6, 5, 2, 5, 2, 2, 2, 19, 5, 2, 3, 2, 3, 2, 6, 3, 7, 7, 6, 3 }; + +int tc_interl_init(tc_interl_t *h, int max_long_cb) { + int ret = -1; + h->forward = malloc(sizeof(int) * max_long_cb); + if (!h->forward) { + perror("malloc"); + goto clean_exit; + } + h->reverse = malloc(sizeof(int) * max_long_cb); + if (!h->reverse) { + perror("malloc"); + goto clean_exit; + } + h->max_long_cb = max_long_cb; + ret = 0; +clean_exit: + if (ret == -1) { + tc_interl_free(h); + } + return ret; +} + void tc_interl_free(tc_interl_t *h) { if (h->forward) { free(h->forward); @@ -59,10 +82,10 @@ void tc_interl_free(tc_interl_t *h) { if (h->reverse) { free(h->reverse); } - h->forward = h->reverse = NULL; + bzero(h, sizeof(tc_interl_t)); } -int tc_interl_UMTS_init(tc_interl_t *h, int long_cb) { +int tc_interl_UMTS_gen(tc_interl_t *h, int long_cb) { int i, j; int res, prim, aux; @@ -74,20 +97,13 @@ int tc_interl_UMTS_init(tc_interl_t *h, int long_cb) { unsigned short U[MAX_COLS * MAX_ROWS]; int M_Rows, M_Cols, M_long; - h->forward = h->reverse = NULL; - h->forward = malloc(sizeof(int) * (long_cb)); - if (!h->forward) { - return -1; - } - h->reverse = malloc(sizeof(int) * (long_cb)); - if (!h->reverse) { - perror("malloc"); - free(h->forward); - h->forward = h->reverse = NULL; - return -1; - } M_long = long_cb; + if (long_cb > h->max_long_cb) { + fprintf(stderr, "Interleaver initiated for max_long_cb=%d\n",h->max_long_cb); + return -1; + } + /* Find R*/ if ((40 <= M_long) && (M_long <= 159)) M_Rows = 5; diff --git a/lte/lib/fec/src/turbocoder.c b/lte/lib/fec/src/turbocoder.c index 4ff72df26..48b6b3186 100644 --- a/lte/lib/fec/src/turbocoder.c +++ b/lte/lib/fec/src/turbocoder.c @@ -25,27 +25,27 @@ * */ - -#include "lte/fec/tc_interl.h" #include "lte/fec/turbocoder.h" +#include + #define NOF_REGS 3 -int tcod_init(tcod_t *h, int long_cb) { +int tcod_init(tcod_t *h, int max_long_cb) { - if (tc_interl_LTE_init(&h->interl, long_cb)) { + if (tc_interl_init(&h->interl, max_long_cb)) { return -1; } - h->long_cb = long_cb; + h->max_long_cb = max_long_cb; return 0; } void tcod_free(tcod_t *h) { tc_interl_free(&h->interl); - h->long_cb = 0; + h->max_long_cb = 0; } -void tcod_encode(tcod_t *h, char *input, char *output) { +int tcod_encode(tcod_t *h, char *input, char *output, int long_cb) { char reg1_0,reg1_1,reg1_2, reg2_0,reg2_1,reg2_2; int i,k=0,j; @@ -53,6 +53,16 @@ void tcod_encode(tcod_t *h, char *input, char *output) { char in,out; int *per; + if (long_cb > h->max_long_cb) { + fprintf(stderr, "Turbo coder initiated for max_long_cb=%d\n", h->max_long_cb); + return -1; + } + + if (tc_interl_LTE_gen(&h->interl, long_cb)) { + fprintf(stderr, "Error initiating TC interleaver\n"); + return -1; + } + per=h->interl.forward; reg1_0=0; @@ -64,7 +74,7 @@ void tcod_encode(tcod_t *h, char *input, char *output) { reg2_2=0; k=0; - for (i=0;ilong_cb;i++) { + for (i=0;ilong_cb; + k=3*long_cb; /* TAILING CODER #1 */ for (j=0;j #include #include #include -#include "lte/fec/tc_interl.h" #include "lte/fec/turbodecoder.h" /************************************************ @@ -12,11 +39,11 @@ * Decoder * ************************************************/ -void map_gen_beta(map_gen_t *s, llr_t *input, llr_t *parity) { +void map_gen_beta(map_gen_t *s, llr_t *input, llr_t *parity, int long_cb) { llr_t m_b[8], new[8], old[8]; llr_t x, y, xy; int k; - int end = s->long_cb + RATE; + int end = long_cb + RATE; llr_t *beta = s->beta; int i; @@ -57,13 +84,13 @@ void map_gen_beta(map_gen_t *s, llr_t *input, llr_t *parity) { } } -void map_gen_alpha(map_gen_t *s, llr_t *input, llr_t *parity, llr_t *output) { +void map_gen_alpha(map_gen_t *s, llr_t *input, llr_t *parity, llr_t *output, int long_cb) { llr_t m_b[8], new[8], old[8], max1[8], max0[8]; llr_t m1, m0; llr_t x, y, xy; llr_t out; int k; - int end = s->long_cb; + int end = long_cb; llr_t *beta = s->beta; int i; @@ -122,14 +149,14 @@ void map_gen_alpha(map_gen_t *s, llr_t *input, llr_t *parity, llr_t *output) { } } -int map_gen_init(map_gen_t *h, int long_cb) { +int map_gen_init(map_gen_t *h, int max_long_cb) { bzero(h, sizeof(map_gen_t)); - h->beta = malloc(sizeof(llr_t) * (long_cb + TOTALTAIL + 1)* NUMSTATES); + h->beta = malloc(sizeof(llr_t) * (max_long_cb + TOTALTAIL + 1)* NUMSTATES); if (!h->beta) { perror("malloc"); return -1; } - h->long_cb = long_cb; + h->max_long_cb = max_long_cb; return 0; } @@ -140,15 +167,15 @@ void map_gen_free(map_gen_t *h) { bzero(h, sizeof(map_gen_t)); } -void map_gen_dec(map_gen_t *h, llr_t *input, llr_t *parity, llr_t *output) { +void map_gen_dec(map_gen_t *h, llr_t *input, llr_t *parity, llr_t *output, int long_cb) { int k; - h->beta[(h->long_cb + TAIL) * NUMSTATES] = 0; + h->beta[(long_cb + TAIL) * NUMSTATES] = 0; for (k = 1; k < NUMSTATES; k++) - h->beta[(h->long_cb + TAIL) * NUMSTATES + k] = -INF; + h->beta[(long_cb + TAIL) * NUMSTATES + k] = -INF; - map_gen_beta(h, input, parity); - map_gen_alpha(h, input, parity, output); + map_gen_beta(h, input, parity, long_cb); + map_gen_alpha(h, input, parity, output, long_cb); } @@ -164,10 +191,12 @@ void map_gen_dec(map_gen_t *h, llr_t *input, llr_t *parity, llr_t *output) { * TURBO DECODER INTERFACE * ************************************************/ -int tdec_init(tdec_t *h, int long_cb) { +int tdec_init(tdec_t *h, int max_long_cb) { int ret = -1; bzero(h, sizeof(tdec_t)); - int len = long_cb + TOTALTAIL; + int len = max_long_cb + TOTALTAIL; + + h->max_long_cb = max_long_cb; h->llr1 = malloc(sizeof(llr_t) * len); if (!h->llr1) { @@ -195,13 +224,11 @@ int tdec_init(tdec_t *h, int long_cb) { goto clean_and_exit; } - if (map_gen_init(&h->dec, long_cb)) { + if (map_gen_init(&h->dec, h->max_long_cb)) { goto clean_and_exit; } - h->long_cb = long_cb; - - if (tc_interl_LTE_init(&h->interleaver, h->long_cb) < 0) { + if (tc_interl_init(&h->interleaver, h->max_long_cb) < 0) { goto clean_and_exit; } @@ -237,63 +264,68 @@ void tdec_free(tdec_t *h) { bzero(h, sizeof(tdec_t)); } -void tdec_iteration(tdec_t *h, llr_t *input) { +void tdec_iteration(tdec_t *h, llr_t *input, int long_cb) { int i; // Prepare systematic and parity bits for MAP DEC #1 - for (i = 0; i < h->long_cb; i++) { + for (i = 0; i < long_cb; i++) { h->syst[i] = input[RATE * i] + h->w[i]; h->parity[i] = input[RATE * i + 1]; } - for (i=h->long_cb;ilong_cb+RATE;i++) { - h->syst[i] = input[RATE * h->long_cb + NINPUTS * (i - h->long_cb)]; - h->parity[i] = input[RATE * h->long_cb + NINPUTS * (i - h->long_cb) + 1]; + for (i=long_cb;isyst[i] = input[RATE * long_cb + NINPUTS * (i - long_cb)]; + h->parity[i] = input[RATE * long_cb + NINPUTS * (i - long_cb) + 1]; } // Run MAP DEC #1 - map_gen_dec(&h->dec, h->syst, h->parity, h->llr1); + map_gen_dec(&h->dec, h->syst, h->parity, h->llr1, long_cb); // Prepare systematic and parity bits for MAP DEC #1 - for (i = 0; i < h->long_cb; i++) { + for (i = 0; i < long_cb; i++) { h->syst[i] = h->llr1[h->interleaver.forward[i]] - h->w[h->interleaver.forward[i]]; h->parity[i] = input[RATE * i + 2]; } - for (i=h->long_cb;ilong_cb+RATE;i++) { - h->syst[i] = input[RATE * h->long_cb + NINPUTS * RATE + NINPUTS * (i - h->long_cb)]; - h->parity[i] = input[RATE * h->long_cb + NINPUTS * RATE + NINPUTS * (i - h->long_cb) + 1]; + for (i=long_cb;isyst[i] = input[RATE * long_cb + NINPUTS * RATE + NINPUTS * (i - long_cb)]; + h->parity[i] = input[RATE * long_cb + NINPUTS * RATE + NINPUTS * (i - long_cb) + 1]; } // Run MAP DEC #1 - map_gen_dec(&h->dec, h->syst, h->parity, h->llr2); + map_gen_dec(&h->dec, h->syst, h->parity, h->llr2, long_cb); // Update a-priori LLR from the last iteration - for (i = 0; i < h->long_cb; i++) { + for (i = 0; i < long_cb; i++) { h->w[i] += h->llr2[h->interleaver.reverse[i]] - h->llr1[i]; } } -void tdec_reset(tdec_t *h) { - memset(h->w, 0, sizeof(llr_t) * h->long_cb); +int tdec_reset(tdec_t *h, int long_cb) { + memset(h->w, 0, sizeof(llr_t) * long_cb); + if (long_cb > h->max_long_cb) { + fprintf(stderr, "TDEC was initialized for max_long_cb=%d\n", h->max_long_cb); + return -1; + } + return tc_interl_LTE_gen(&h->interleaver, long_cb); } -void tdec_decision(tdec_t *h, char *output) { +void tdec_decision(tdec_t *h, char *output, int long_cb) { int i; - for (i = 0; i < h->long_cb; i++) { + for (i = 0; i < long_cb; i++) { output[i] = (h->llr2[h->interleaver.reverse[i]] > 0) ? 1 : 0; } } -void tdec_run_all(tdec_t *h, llr_t *input, char *output, int nof_iterations) { +void tdec_run_all(tdec_t *h, llr_t *input, char *output, int nof_iterations, int long_cb) { int iter = 0; - tdec_reset(h); + tdec_reset(h, long_cb); do { - tdec_iteration(h, input); + tdec_iteration(h, input, long_cb); iter++; } while (iter < nof_iterations); - tdec_decision(h, output); + tdec_decision(h, output, long_cb); } diff --git a/lte/lib/fec/test/turbocoder_test.c b/lte/lib/fec/test/turbocoder_test.c index ad28ee470..a4eca4d65 100644 --- a/lte/lib/fec/test/turbocoder_test.c +++ b/lte/lib/fec/test/turbocoder_test.c @@ -233,7 +233,7 @@ int main(int argc, char **argv) { symbols[j] = known_data_encoded[j]; } } else { - tcod_encode(&tcod, data_tx, symbols); + tcod_encode(&tcod, data_tx, symbols, frame_length); } for (j = 0; j < coded_length; j++) { @@ -243,7 +243,7 @@ int main(int argc, char **argv) { ch_awgn_f(llr, llr, var[i], coded_length); /* decoder */ - tdec_reset(&tdec); + tdec_reset(&tdec, frame_length); int t; if (nof_iterations == -1) { @@ -254,8 +254,8 @@ int main(int argc, char **argv) { for (j=0;j MAX_PORTS) { @@ -192,7 +192,7 @@ int predecoding_type(cf_t *y[MAX_PORTS], cf_t *ce[MAX_PORTS], switch(type) { case SINGLE_ANTENNA: if (nof_ports == 1 && nof_layers == 1) { - return predecoding_single_zf(y[0], ce[0], x[0], nof_symbols); + return predecoding_single_zf(y, ce[0], x[0], nof_symbols); } else{ fprintf(stderr, "Number of ports and layers must be 1 for transmission on single antenna ports\n"); return -1; diff --git a/lte/lib/mimo/test/precoding_test.c b/lte/lib/mimo/test/precoding_test.c index e913cc512..a0d00c4c1 100644 --- a/lte/lib/mimo/test/precoding_test.c +++ b/lte/lib/mimo/test/precoding_test.c @@ -159,7 +159,7 @@ int main(int argc, char **argv) { } /* predecoding / equalization */ - if (predecoding_type(r, h, xr, nof_ports, nof_layers, nof_symbols * nof_layers, type) < 0) { + if (predecoding_type(r[0], h, xr, nof_ports, nof_layers, nof_symbols * nof_layers, type) < 0) { fprintf(stderr, "Error layer mapper encoder\n"); exit(-1); } diff --git a/lte/lib/phch/src/dci.c b/lte/lib/phch/src/dci.c index c66abf6e1..0c26640ae 100644 --- a/lte/lib/phch/src/dci.c +++ b/lte/lib/phch/src/dci.c @@ -555,6 +555,7 @@ int dci_format1As_unpack(dci_msg_t *msg, ra_pdsch_t *data, int nof_prb, bool crc fprintf(stderr, "Invalid message length for format 1A\n"); return -1; } + if (*y++ != 1) { fprintf(stderr, "Invalid format differentiation field value. This is Format0\n"); return -1; @@ -602,7 +603,7 @@ int dci_format1As_unpack(dci_msg_t *msg, ra_pdsch_t *data, int nof_prb, bool crc y++; } else { y++; // MSB of TPC is reserved - *y++ = data->type2_alloc.n_prb1a; // LSB indicates N_prb_1a for TBS + data->type2_alloc.n_prb1a = *y++; // LSB indicates N_prb_1a for TBS } data->mcs.tbs_idx = data->mcs.mcs_idx; int n_prb; diff --git a/lte/lib/phch/src/pbch.c b/lte/lib/phch/src/pbch.c index 146bc9710..412411af0 100644 --- a/lte/lib/phch/src/pbch.c +++ b/lte/lib/phch/src/pbch.c @@ -469,7 +469,7 @@ int pbch_decode(pbch_t *q, cf_t *slot1_symbols, cf_t *ce[MAX_PORTS_CTRL], float /* no need for layer demapping */ predecoding_single_zf(q->pbch_symbols[0], q->ce[0], q->pbch_d, q->nof_symbols); } else { - predecoding_diversity_zf(q->pbch_symbols, q->ce, x, nant, q->nof_symbols); + predecoding_diversity_zf(q->pbch_symbols[0], q->ce, x, nant, q->nof_symbols); layerdemap_diversity(x, q->pbch_d, nant, q->nof_symbols/nant); } diff --git a/lte/lib/phch/src/pcfich.c b/lte/lib/phch/src/pcfich.c index 5422cf54f..c9dda4ba7 100644 --- a/lte/lib/phch/src/pcfich.c +++ b/lte/lib/phch/src/pcfich.c @@ -58,7 +58,7 @@ bool pcfich_exists(int nframe, int nslot) { } /** Initializes the pcfich channel receiver */ -int pcfich_init(pcfich_t *q, regs_t *regs, int cell_id, int nof_prb, int nof_tx_ports, lte_cp_t cp) { +int pcfich_init(pcfich_t *q, regs_t *regs, int cell_id, int nof_prb, int nof_ports, lte_cp_t cp) { int ret = -1; if (cell_id < 0) { return -1; @@ -68,7 +68,7 @@ int pcfich_init(pcfich_t *q, regs_t *regs, int cell_id, int nof_prb, int nof_tx_ q->cp = cp; q->regs = regs; q->nof_prb = nof_prb; - q->nof_tx_ports = nof_tx_ports; + q->nof_ports = nof_ports; if (modem_table_std(&q->mod, LTE_QPSK, false)) { goto clean; @@ -151,7 +151,6 @@ int pcfich_decode(pcfich_t *q, cf_t *slot_symbols, cf_t *ce[MAX_PORTS_CTRL], int int i; cf_t *x[MAX_LAYERS]; cf_t *ce_precoding[MAX_PORTS]; - cf_t *symbols_precoding[MAX_PORTS]; if (nsubframe < 0 || nsubframe > NSUBFRAMES_X_FRAME) { fprintf(stderr, "Invalid nslot %d\n", nsubframe); @@ -164,7 +163,6 @@ int pcfich_decode(pcfich_t *q, cf_t *slot_symbols, cf_t *ce[MAX_PORTS_CTRL], int } for (i=0;ice[i]; - symbols_precoding[i] = q->pcfich_symbols[i]; } /* extract symbols */ @@ -174,7 +172,7 @@ int pcfich_decode(pcfich_t *q, cf_t *slot_symbols, cf_t *ce[MAX_PORTS_CTRL], int } /* extract channel estimates */ - for (i=0;inof_tx_ports;i++) { + for (i=0;inof_ports;i++) { if (q->nof_symbols != regs_pcfich_get(q->regs, ce[i], q->ce[i])) { fprintf(stderr, "There was an error getting the PCFICH symbols\n"); return -1; @@ -182,12 +180,12 @@ int pcfich_decode(pcfich_t *q, cf_t *slot_symbols, cf_t *ce[MAX_PORTS_CTRL], int } /* in control channels, only diversity is supported */ - if (q->nof_tx_ports == 1) { + if (q->nof_ports == 1) { /* no need for layer demapping */ predecoding_single_zf(q->pcfich_symbols[0], q->ce[0], q->pcfich_d, q->nof_symbols); } else { - predecoding_diversity_zf(symbols_precoding, ce_precoding, x, q->nof_tx_ports, q->nof_symbols); - layerdemap_diversity(x, q->pcfich_d, q->nof_tx_ports, q->nof_symbols/q->nof_tx_ports); + predecoding_diversity_zf(q->pcfich_symbols[0], ce_precoding, x, q->nof_ports, q->nof_symbols); + layerdemap_diversity(x, q->pcfich_d, q->nof_ports, q->nof_symbols/q->nof_ports); } /* demodulate symbols */ @@ -224,7 +222,7 @@ int pcfich_encode(pcfich_t *q, int cfi, cf_t *slot_symbols[MAX_PORTS_CTRL], int cf_t *symbols_precoding[MAX_PORTS]; /* number of layers equals number of ports */ - for (i=0;inof_tx_ports;i++) { + for (i=0;inof_ports;i++) { x[i] = q->pcfich_x[i]; } for (i=0;imod, q->data, q->pcfich_d, PCFICH_CFI_LEN); /* layer mapping & precoding */ - if (q->nof_tx_ports > 1) { - layermap_diversity(q->pcfich_d, x, q->nof_tx_ports, q->nof_symbols); - precoding_diversity(x, symbols_precoding, q->nof_tx_ports, q->nof_symbols/q->nof_tx_ports); + if (q->nof_ports > 1) { + layermap_diversity(q->pcfich_d, x, q->nof_ports, q->nof_symbols); + precoding_diversity(x, symbols_precoding, q->nof_ports, q->nof_symbols/q->nof_ports); } else { memcpy(q->pcfich_symbols[0], q->pcfich_d, q->nof_symbols * sizeof(cf_t)); } /* mapping to resource elements */ - for (i=0;inof_tx_ports;i++) { + for (i=0;inof_ports;i++) { if (regs_pcfich_put(q->regs, q->pcfich_symbols[i], slot_symbols[i]) < 0) { fprintf(stderr, "Error putting PCHICH resource elements\n"); return -1; diff --git a/lte/lib/phch/src/pdcch.c b/lte/lib/phch/src/pdcch.c index 33bf768ac..d4be2163a 100644 --- a/lte/lib/phch/src/pdcch.c +++ b/lte/lib/phch/src/pdcch.c @@ -330,13 +330,6 @@ unsigned short dci_decode(pdcch_t *q, float *e, char *data, int E, assert(nof_bits < DCI_MAX_BITS); -/* char a[] = {1,1,0,0,1,0,0,0,0,0,0,1,1,0,0,1,0,0,0,0,0,0,1,1,1,1,0,0,0,0,1,1,0,1,0,1,1,0,1,1,1,1,1,0,1,0,1,1,0,1,0,0,0,1,0,0,1,1,1,1,0,1,0,1,1,0,0,0,0,0,1,1,0,0,0,0,1,0,0,1,0,0,0,0,1,1,1,1,1,0,1,1,1,0,1,1,1,1,0,0,1,1,0,0,1,0,1,1,1,0,0,1,1,0,1,0,1,1,0,0,1,0,0,1,1,0,0,1,0,0,0,0,0,0,1,1,0,0,1,0,0,0,0,0,0,1,1,1,1,0,0,0,0,1,1,0,1,0,1,1,0,1,1,1,1,1,0,1,0,1,1,0,1,0,0,0,1,0,0,1,1,1,1,0,1,0,1,1,0,0,0,0,0,1,1,0,0,0,0,1,0,0,1,0,0,0,0,1,1,1,1,1,0,1,1,1,0,1,1,1,1,0,0,1,1,0,0,1,0,1,1,1,0,0,1,1,0,1,0,1,1,0,0,1,0,0,1,1,0,0,1,0,0,0,0,0,0,1,1,0,0,1,0,0,0,0,0,0,1,1,1,1,0,0,0,0,1,1,0,1,0,1,1,0,1,1,1,1,1,0,1,0,1,1,0,1,0,0,0,1,0,0,1,1,1,1,0,1,0,1,1,0,0,0,0,0,1,1,0,0,0,0,1,0,0,1,0,0,0,0,1,1,1,1,1,0,1,1,1,0,1,1,1,1,0,0,1,1,0,0,1,0,1,1,1,0,0,1,1,0,1,0,1,1,0,0,1,0,0,1,1,0,0,1,0,0,0,0,0,0,1,1,0,0,1,0,0,0,0,0,0,1,1,1,1,0,0,0,0,1,1,0,1,0,1,1,0,1,1,1,1,1,0,1,0,1,1,0,1,0,0,0,1,0,0,1,1,1,1,0,1,0,1,1,0,0,0,0,0,1,1,0,0,0,0,1,0,0,1,0,0,0,0,1,1,1,1,1,0,1,1,1,0,1,1,1,1,0,0,1,1,0,0,1,0,1,1,1,0,0,1,1,0,1,0,1,1,0,0,1,0,0,1,1,0,0,1,0,0,0,0,0,0,1,1,0,0,1,0,0,0,0,0,0,1,1,1,1,0,0,0,0,1,1,0,1,0,1,1,0,1,1,1,1,1,0,1,0,1,1,0,1,0,0,0,1,0,0,1,1,1,1,0,1,0,1,1,0,0,0,0,0,1,1,0,0,0,0,1,0,0,1,0,0,0,0}; - - float *b = malloc(sizeof(E)); - for (int i=0;inof_ports], 0, sizeof(cf_t*) * (MAX_LAYERS - q->nof_ports)); /* extract symbols */ - int n = regs_pdcch_get(q->regs, slot1_symbols, q->pdcch_symbols[0]); + int n = regs_pdcch_get(q->regs, slot_symbols, q->pdcch_symbols[0]); if (q->nof_symbols != n) { fprintf(stderr, "Expected %d PDCCH symbols but got %d symbols\n", q->nof_symbols, n); return -1; @@ -424,7 +417,7 @@ int pdcch_extract_llr(pdcch_t *q, cf_t *slot1_symbols, cf_t *ce[MAX_PORTS_CTRL], predecoding_single_zf(q->pdcch_symbols[0], q->ce[0], q->pdcch_d, q->nof_symbols); } else { - predecoding_diversity_zf(q->pdcch_symbols, q->ce, x, q->nof_ports, + predecoding_diversity_zf(q->pdcch_symbols[0], q->ce, x, q->nof_ports, q->nof_symbols); layerdemap_diversity(x, q->pdcch_d, q->nof_ports, q->nof_symbols / q->nof_ports); @@ -490,10 +483,10 @@ int pdcch_decode_ue(pdcch_t *q, float *llr, dci_t *dci, int nsubframe) { * * Returns number of messages stored in dci */ -int pdcch_decode(pdcch_t *q, cf_t *slot1_symbols, cf_t *ce[MAX_PORTS_CTRL], +int pdcch_decode(pdcch_t *q, cf_t *slot_symbols, cf_t *ce[MAX_PORTS_CTRL], dci_t *dci, int nsubframe, float ebno) { - if (pdcch_extract_llr(q, slot1_symbols, ce, q->pdcch_llr, nsubframe, + if (pdcch_extract_llr(q, slot_symbols, ce, q->pdcch_llr, nsubframe, ebno)) { return -1; } @@ -546,9 +539,9 @@ void dci_encode(pdcch_t *q, char *data, char *e, int nof_bits, int E, unsigned s rm_conv_tx(tmp, 3 * (nof_bits + 16), e, E); } -/** Converts the MIB message to symbols mapped to SLOT #1 ready for transmission +/** Converts the set of DCI messages to symbols mapped to the slot ready for transmission */ -int pdcch_encode(pdcch_t *q, dci_t *dci, cf_t *slot1_symbols[MAX_PORTS_CTRL], +int pdcch_encode(pdcch_t *q, dci_t *dci, cf_t *slot_symbols[MAX_PORTS_CTRL], int nsubframe) { int i; /* Set pointers for layermapping & precoding */ @@ -601,7 +594,7 @@ int pdcch_encode(pdcch_t *q, dci_t *dci, cf_t *slot1_symbols[MAX_PORTS_CTRL], /* mapping to resource elements */ for (i = 0; i < q->nof_ports; i++) { - regs_pdcch_put(q->regs, q->pdcch_symbols[i], slot1_symbols[i]); + regs_pdcch_put(q->regs, q->pdcch_symbols[i], slot_symbols[i]); } return 0; } diff --git a/lte/lib/phch/src/pdsch.c b/lte/lib/phch/src/pdsch.c new file mode 100644 index 000000000..2b7db80bb --- /dev/null +++ b/lte/lib/phch/src/pdsch.c @@ -0,0 +1,695 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * A copy of the GNU Lesser General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "prb.h" +#include "lte/phch/pdsch.h" +#include "lte/common/base.h" +#include "lte/utils/bit.h" +#include "lte/utils/debug.h" +#include "lte/utils/vector.h" + +const enum modem_std modulations[4] = + { LTE_BPSK, LTE_QPSK, LTE_QAM16, LTE_QAM64 }; + +#define MAX_PDSCH_RE(cp) (2 * (CP_NSYMB(cp) - 1) * 12 - 6) +#define HAS_REF(l, cp, nof_ports) ((l == 1 && nof_ports == 4) \ + || l == 0 \ + || l == CP_NSYMB(cp) - 3) + +int pdsch_cp(pdsch_t *q, cf_t *input, cf_t *output, ra_prb_t *prb_alloc, + int nsubframe, bool put) { + int s, n, l, lp, lstart, lend, nof_refs; + bool is_pbch, is_sss; + cf_t *in_ptr = input, *out_ptr = output; + int offset; + + assert(q->cell_id >= 0); + + INFO("%s %d RE from %d PRB\n", put?"Putting":"Getting", prb_alloc->re_sf[nsubframe], prb_alloc->slot[0].nof_prb); + + if (q->nof_ports == 1) { + nof_refs = 2; + } else { + nof_refs = 4; + } + + for (s = 0; s < 2; s++) { + if (s == 0) { + lstart = prb_alloc->lstart; + } else { + lstart = 0; + } + + for (l = lstart; l < CP_NSYMB(q->cp); l++) { + for (n = 0; n < prb_alloc->slot[s].nof_prb; n++) { + lend = CP_NSYMB(q->cp); + is_pbch = is_sss = false; + + // Skip PSS/SSS signals + if (s == 0 && (nsubframe == 0 || nsubframe == 5)) { + if (prb_alloc->slot[s].prb_idx[n] >= q->nof_prb / 2 - 3 + && prb_alloc->slot[s].prb_idx[n] + <= q->nof_prb / 2 + 3) { + lend = CP_NSYMB(q->cp) - 2; + is_sss = true; + } + } + // Skip PBCH + if (s == 1 && nsubframe == 0) { + if (prb_alloc->slot[s].prb_idx[n] >= q->nof_prb / 2 - 3 + && prb_alloc->slot[s].prb_idx[n] + <= q->nof_prb / 2 + 3) { + lstart = 4; + is_pbch = true; + } + } + lp = l+s*CP_NSYMB(q->cp); + if (put) { + out_ptr = &output[(lp*q->nof_prb+prb_alloc->slot[s].prb_idx[n]) * RE_X_RB]; + } else { + in_ptr = &input[(lp*q->nof_prb+prb_alloc->slot[s].prb_idx[n]) * RE_X_RB]; + } + + if (is_pbch && (q->nof_prb%2) && (prb_alloc->slot[s].prb_idx[n] == q->nof_prb / 2 - 3 + && prb_alloc->slot[s].prb_idx[n] + == q->nof_prb / 2 + 3)) { + if (l < lstart) { + prb_cp_half(&in_ptr, &out_ptr, 1); + } + } + if (l >= lstart && l < lend) { + if (HAS_REF(l, q->cp, q->nof_ports)) { + if (nof_refs == 2 && l != 0) { + offset = q->cell_id % 3 + 3; + } else { + offset = q->cell_id % 3; + } + prb_cp_ref(&in_ptr, &out_ptr, offset, nof_refs, 1, put); + } else { + prb_cp(&in_ptr, &out_ptr, 1); + } + } + if (is_sss && (q->nof_prb%2) && (prb_alloc->slot[s].prb_idx[n] == q->nof_prb / 2 - 3 + && prb_alloc->slot[s].prb_idx[n] + == q->nof_prb / 2 + 3)) { + if (l >= lend) { + prb_cp_half(&in_ptr, &out_ptr, 1); + } + } + } + } + } + + if (put) { + return (int) (input - in_ptr); + } else { + return (int) (output - out_ptr); + } +} + +/** + * Puts PDSCH in slot number 1 + * + * Returns the number of symbols written to sf_symbols + * + * 36.211 10.3 section 6.3.5 + */ +int pdsch_put(pdsch_t *q, cf_t *pdsch_symbols, cf_t *sf_symbols, + ra_prb_t *prb_alloc, int nsubframe) { + return pdsch_cp(q, pdsch_symbols, sf_symbols, prb_alloc, nsubframe, true); +} + +/** + * Extracts PDSCH from slot number 1 + * + * Returns the number of symbols written to PDSCH + * + * 36.211 10.3 section 6.3.5 + */ +int pdsch_get(pdsch_t *q, cf_t *sf_symbols, cf_t *pdsch_symbols, + ra_prb_t *prb_alloc, int nsubframe) { + return pdsch_cp(q, sf_symbols, pdsch_symbols, prb_alloc, nsubframe, false); +} + +/** Initializes the PDCCH transmitter and receiver */ +int pdsch_init(pdsch_t *q, unsigned short user_rnti, int nof_prb, int nof_ports, + int cell_id, lte_cp_t cp) { + int ret = -1; + int i; + + if (cell_id < 0) { + return -1; + } + + if (nof_ports > MAX_PORTS) { + fprintf(stderr, "Invalid number of ports %d\n", nof_ports); + return -1; + } + + bzero(q, sizeof(pdsch_t)); + q->cell_id = cell_id; + q->cp = cp; + q->nof_ports = nof_ports; + q->nof_prb = nof_prb; + q->rnti = user_rnti; + + q->max_symbols = nof_prb * MAX_PDSCH_RE(cp); + + INFO("Init PDSCH: %d ports %d PRBs, max_symbols: %d\n", q->nof_ports, + q->nof_prb, q->max_symbols); + + for (i = 0; i < 4; i++) { + if (modem_table_std(&q->mod[i], modulations[i], true)) { + goto clean; + } + } + if (crc_init(&q->crc_tb, LTE_CRC24A, 24)) { + goto clean; + } + if (crc_init(&q->crc_cb, LTE_CRC24B, 24)) { + goto clean; + } + + demod_soft_init(&q->demod); + demod_soft_alg_set(&q->demod, APPROX); + + for (i = 0; i < NSUBFRAMES_X_FRAME; i++) { + if (sequence_pdsch(&q->seq_pdsch[i], q->rnti, 0, 2 * i, q->cell_id, + q->max_symbols * q->mod[3].nbits_x_symbol)) { + goto clean; + } + } + + if (tcod_init(&q->encoder, MAX_LONG_CB)) { + goto clean; + } + if (tdec_init(&q->decoder, MAX_LONG_CB)) { + goto clean; + } + if (rm_turbo_init(&q->rm_turbo, 3 * MAX_LONG_CB)) { + goto clean; + } + + q->cb_in_b = malloc(sizeof(char) * MAX_LONG_CB); + if (!q->cb_in_b) { + goto clean; + } + q->cb_out_b = malloc(sizeof(char) * (3 * MAX_LONG_CB + 12)); + if (!q->cb_out_b) { + goto clean; + } + + q->pdsch_rm_f = malloc(sizeof(float) * (3 * MAX_LONG_CB + 12)); + if (!q->pdsch_rm_f) { + goto clean; + } + + q->pdsch_e_bits = malloc( + sizeof(char) * q->max_symbols * q->mod[3].nbits_x_symbol); + if (!q->pdsch_e_bits) { + goto clean; + } + + q->pdsch_llr = malloc( + sizeof(float) * q->max_symbols * q->mod[3].nbits_x_symbol); + if (!q->pdsch_llr) { + goto clean; + } + + q->pdsch_d = malloc(sizeof(cf_t) * q->max_symbols); + if (!q->pdsch_d) { + goto clean; + } + + for (i = 0; i < nof_ports; i++) { + q->ce[i] = malloc(sizeof(cf_t) * q->max_symbols); + if (!q->ce[i]) { + goto clean; + } + q->pdsch_x[i] = malloc(sizeof(cf_t) * q->max_symbols); + if (!q->pdsch_x[i]) { + goto clean; + } + q->pdsch_symbols[i] = malloc(sizeof(cf_t) * q->max_symbols); + if (!q->pdsch_symbols[i]) { + goto clean; + } + } + + ret = 0; + clean: if (ret == -1) { + pdsch_free(q); + } + return ret; +} + +void pdsch_free(pdsch_t *q) { + int i; + + if (q->cb_in_b) { + free(q->cb_in_b); + } + if (q->cb_out_b) { + free(q->cb_out_b); + } + if (q->pdsch_e_bits) { + free(q->pdsch_e_bits); + } + if (q->pdsch_rm_f) { + free(q->pdsch_rm_f); + } + if (q->pdsch_llr) { + free(q->pdsch_llr); + } + if (q->pdsch_d) { + free(q->pdsch_d); + } + for (i = 0; i < q->nof_ports; i++) { + if (q->ce[i]) { + free(q->ce[i]); + } + if (q->pdsch_x[i]) { + free(q->pdsch_x[i]); + } + if (q->pdsch_symbols[i]) { + free(q->pdsch_symbols[i]); + } + } + + for (i = 0; i < NSUBFRAMES_X_FRAME; i++) { + sequence_free(&q->seq_pdsch[i]); + } + + for (i = 0; i < 4; i++) { + modem_table_free(&q->mod[i]); + } + tdec_free(&q->decoder); + tcod_free(&q->encoder); + rm_turbo_free(&q->rm_turbo); + +} + +struct cb_segm { + int F; + int C; + int K1; + int K2; + int C1; + int C2; +}; + +/* Calculate Codeblock Segmentation as in Section 5.1.2 of 36.212 */ +void codeblock_segmentation(struct cb_segm *s, int tbs) { + int Bp, B, idx1; + + B = tbs + 24; + + /* Calculate CB sizes */ + if (B < 6114) { + s->C = 1; + Bp = B; + } else { + s->C = (int) ceilf((float) B / (6114 - 24)); + Bp = B + 24 * s->C; + } + idx1 = lte_find_cb_index(Bp / s->C); + s->K1 = lte_cb_size(idx1); + if (s->C == 1) { + s->K2 = 0; + s->C2 = 0; + s->C1 = 1; + } else { + s->K2 = lte_cb_size(idx1 - 1); + s->C2 = (s->C * s->K1 - Bp) / (s->K1 - s->K2); + s->C1 = s->C - s->C2; + } + s->F = s->C1 * s->K1 + s->C2 * s->K2 - Bp; + INFO( + "CB Segmentation: TBS: %d, C=%d, C+=%d K+=%d, C-=%d, K-=%d, F=%d, Bp=%d\n", + tbs, s->C, s->C1, s->K1, s->C2, s->K2, s->F, Bp); +} + +/* Decode a transport block according to 36.212 5.3.2 + * + */ +int pdsch_decode_tb(pdsch_t *q, char *data, int tbs, int nb_e, int rv_idx) { + char parity[24]; + char *p_parity = parity; + unsigned int par_rx, par_tx; + int i; + int cb_len, rp, wp, rlen, F, n_e; + struct cb_segm cbs; + + /* Compute CB segmentation for this TBS */ + codeblock_segmentation(&cbs, tbs); + + rp = 0; + rp = 0; + wp = 0; + for (i = 0; i < cbs.C; i++) { + + /* Get read/write lengths */ + if (i < cbs.C - cbs.C2) { + cb_len = cbs.K1; + } else { + cb_len = cbs.K2; + } + if (cbs.C == 1) { + rlen = cb_len; + } else { + rlen = cb_len - 24; + } + if (i == 0) { + F = cbs.F; + } else { + F = 0; + } + + if (i < cbs.C - 1) { + n_e = nb_e / cbs.C; + } else { + n_e = nb_e - rp; + } + + 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 */ + rm_turbo_rx(&q->rm_turbo, &q->pdsch_llr[rp], n_e, q->pdsch_rm_f, + 3 * cb_len + 12, rv_idx); + + /* Turbo Decoding */ + tdec_run_all(&q->decoder, q->pdsch_rm_f, q->cb_in_b, TDEC_ITERATIONS, + cb_len); + + if (cbs.C > 1) { + /* Check Codeblock CRC */ + //crc_attach(&q->crc_cb, q->pdsch_b[wp], cb_len); + } + + if (VERBOSE_ISDEBUG()) { + DEBUG("CB#%d Len=%d: ", i, cb_len); + vec_fprint_b(stdout, q->cb_in_b, cb_len); + } + + /* Copy data to another buffer, removing the Codeblock CRC */ + if (i < cbs.C - 1) { + memcpy(&data[wp], &q->cb_in_b[F], (rlen - F) * sizeof(char)); + } else { + INFO("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_b[F], (rlen - F - 24) * sizeof(char)); + memcpy(parity, &q->cb_in_b[rlen - 24], 24 * sizeof(char)); + } + + /* Set read/write pointers */ + wp += (rlen - F); + rp += n_e; + } + + INFO("END CB#%d: wp: %d, rp: %d\n", i, wp, rp); + + // Compute transport block CRC + par_rx = crc_checksum(&q->crc_tb, data, tbs); + + // check parity bits + par_tx = bit_unpack(&p_parity, 24); + + if (VERBOSE_ISDEBUG()) { + DEBUG("DATA: ", 0); + vec_fprint_b(stdout, data, tbs); + DEBUG("PARITY: ", 0); + vec_fprint_b(stdout, parity, 24); + } + + if (!par_rx) { + printf("\n\tCAUTION!! Received all-zero transport block\n\n"); + } + + return (par_rx != par_tx); +} + +/** Decodes the PDSCH from the received symbols + */ +int pdsch_decode(pdsch_t *q, cf_t *sf_symbols, cf_t *ce[MAX_PORTS], + char *data, int nsubframe, ra_mcs_t mcs, ra_prb_t *prb_alloc) { + + /* Set pointers for layermapping & precoding */ + int i; + cf_t *x[MAX_LAYERS]; + int nof_symbols, nof_bits, nof_bits_e; + + nof_bits = mcs.tbs; + nof_symbols = prb_alloc->re_sf[nsubframe]; + nof_bits_e = nof_symbols * q->mod[mcs.mod - 1].nbits_x_symbol; + + if (nof_bits > nof_bits_e) { + fprintf(stderr, "Invalid code rate %.2f\n", + (float) nof_bits / nof_bits_e); + return -1; + } + + if (nof_symbols > q->max_symbols) { + fprintf(stderr, "Error too many RE per subframe (%d). PDSCH configured for %d RE (%d PRB)\n", + nof_symbols, q->max_symbols, q->nof_prb); + return -1; + } + + INFO("Decoding PDSCH SF: %d, Mod %d, NofBits: %d, NofSymbols: %d, NofBitsE: %d\n", + nsubframe, mcs.mod, nof_bits, nof_symbols, nof_bits_e); + + if (nsubframe < 0 || nsubframe > NSUBFRAMES_X_FRAME) { + fprintf(stderr, "Invalid subframe %d\n", nsubframe); + return -1; + } + + /* number of layers equals number of ports */ + for (i = 0; i < q->nof_ports; i++) { + x[i] = q->pdsch_x[i]; + } + memset(&x[q->nof_ports], 0, sizeof(cf_t*) * (MAX_LAYERS - q->nof_ports)); + + /* extract symbols */ + pdsch_get(q, sf_symbols, q->pdsch_symbols[0], prb_alloc, nsubframe); + + /* extract channel estimates */ + for (i = 0; i < q->nof_ports; i++) { + pdsch_get(q, ce[i], q->ce[i], prb_alloc, nsubframe); + } + + /* TODO: only diversity is supported */ + if (q->nof_ports == 1) { + /* no need for layer demapping */ + predecoding_single_zf(q->pdsch_symbols[0], q->ce[0], q->pdsch_d, + nof_symbols); + } else { + predecoding_diversity_zf(q->pdsch_symbols[0], q->ce, x, q->nof_ports, + nof_symbols); + layerdemap_diversity(x, q->pdsch_d, q->nof_ports, + nof_symbols / q->nof_ports); + } + + /* demodulate symbols */ + demod_soft_sigma_set(&q->demod, 2.0 / q->mod[mcs.mod-1].nbits_x_symbol); + demod_soft_table_set(&q->demod, &q->mod[mcs.mod - 1]); + demod_soft_demodulate(&q->demod, q->pdsch_d, q->pdsch_llr, nof_symbols); + + /* descramble */ + scrambling_f_offset(&q->seq_pdsch[nsubframe], q->pdsch_llr, 0, nof_bits_e); + + return pdsch_decode_tb(q, data, nof_bits, nof_bits_e, 0); +} + +/* Encode a transport block according to 36.212 5.3.2 + * + */ +void pdsch_encode_tb(pdsch_t *q, char *data, int tbs, int nb_e, int rv_idx) { + char parity[24]; + char *p_parity = parity; + unsigned int par; + int i; + int cb_len, rp, wp, rlen, F, n_e; + struct cb_segm cbs; + + /* Compute CB segmentation */ + codeblock_segmentation(&cbs, tbs); + + /* Compute transport block CRC */ + par = crc_checksum(&q->crc_tb, data, tbs); + + /* parity bits will be appended later */ + bit_pack(par, &p_parity, 24); + + if (VERBOSE_ISDEBUG()) { + DEBUG("DATA: ", 0); + vec_fprint_b(stdout, data, tbs); + DEBUG("PARITY: ", 0); + vec_fprint_b(stdout, parity, 24); + } + + /* Add filler bits to the new data buffer */ + for (i = 0; i < cbs.F; i++) { + q->cb_in_b[i] = LTE_NULL_BIT; + } + + wp = 0; + rp = 0; + for (i = 0; i < cbs.C; i++) { + + /* Get read lengths */ + if (i < cbs.C - cbs.C2) { + cb_len = cbs.K1; + } else { + cb_len = cbs.K2; + } + if (cbs.C > 1) { + rlen = cb_len - 24; + } else { + rlen = cb_len; + } + if (i == 0) { + F = cbs.F; + } else { + F = 0; + } + + if (i < cbs.C - 1) { + n_e = nb_e / cbs.C; + } else { + n_e = nb_e - wp; + } + + 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); + + /* Copy data to another buffer, making space for the Codeblock CRC */ + if (i < cbs.C - 1) { + memcpy(&q->cb_in_b[F], &data[rp], (rlen - F) * sizeof(char)); + } 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_b[F], &data[rp], (rlen - F - 24) * sizeof(char)); + memcpy(&q->cb_in_b[rlen - 24], parity, 24 * sizeof(char)); + } + + if (cbs.C > 1) { + /* Attach Codeblock CRC */ + crc_attach(&q->crc_cb, q->cb_in_b, rlen); + } + + if (VERBOSE_ISDEBUG()) { + DEBUG("CB#%d Len=%d: ", i, cb_len); + vec_fprint_b(stdout, q->cb_in_b, cb_len); + } + + /* Turbo Encoding */ + tcod_encode(&q->encoder, q->cb_in_b, q->cb_out_b, cb_len); + + /* Rate matching */ + rm_turbo_tx(&q->rm_turbo, q->cb_out_b, 3 * cb_len + 12, + &q->pdsch_e_bits[wp], n_e, rv_idx); + + /* Set read/write pointers */ + rp += (rlen - F); + wp += n_e; + } + + INFO("END CB#%d: wp: %d, rp: %d\n", i, wp, rp); +} + +/** Converts the PDSCH data bits to symbols mapped to the slot ready for transmission + */ +int pdsch_encode(pdsch_t *q, char *data, cf_t *sf_symbols[MAX_PORTS], + int nsubframe, ra_mcs_t mcs, ra_prb_t *prb_alloc) { + int i; + int nof_symbols, nof_bits, nof_bits_e; + /* Set pointers for layermapping & precoding */ + cf_t *x[MAX_LAYERS]; + + if (nsubframe < 0 || nsubframe > NSUBFRAMES_X_FRAME) { + fprintf(stderr, "Invalid subframe %d\n", nsubframe); + return -1; + } + + nof_bits = mcs.tbs; + nof_symbols = prb_alloc->re_sf[nsubframe]; + nof_bits_e = nof_symbols * q->mod[mcs.mod - 1].nbits_x_symbol; + + if (nof_bits > nof_bits_e) { + fprintf(stderr, "Invalid code rate %.2f\n", (float) nof_bits / nof_bits_e); + return -1; + } + + if (nof_symbols > q->max_symbols) { + fprintf(stderr, "Error too many RE per subframe (%d). PDSCH configured for %d RE (%d PRB)\n", + nof_symbols, q->max_symbols, q->nof_prb); + return -1; + } + + INFO("Encoding PDSCH SF: %d, Mod %d, NofBits: %d, NofSymbols: %d, NofBitsE: %d\n", + nsubframe, mcs.mod, nof_bits, nof_symbols, nof_bits_e); + + /* number of layers equals number of ports */ + for (i = 0; i < q->nof_ports; i++) { + x[i] = q->pdsch_x[i]; + } + memset(&x[q->nof_ports], 0, sizeof(cf_t*) * (MAX_LAYERS - q->nof_ports)); + + pdsch_encode_tb(q, data, nof_bits, nof_bits_e, 0); + + scrambling_b_offset(&q->seq_pdsch[nsubframe], q->pdsch_e_bits, 0, + nof_bits_e); + + mod_modulate(&q->mod[mcs.mod - 1], q->pdsch_e_bits, q->pdsch_d, nof_bits_e); + + /* TODO: only diversity supported */ + if (q->nof_ports > 1) { + layermap_diversity(q->pdsch_d, x, q->nof_ports, nof_symbols); + precoding_diversity(x, q->pdsch_symbols, q->nof_ports, + nof_symbols / q->nof_ports); + } else { + memcpy(q->pdsch_symbols[0], q->pdsch_d, nof_symbols * sizeof(cf_t)); + } + + /* mapping to resource elements */ + for (i = 0; i < q->nof_ports; i++) { + pdsch_put(q, q->pdsch_symbols[i], sf_symbols[i], prb_alloc, nsubframe); + } + return 0; +} + diff --git a/lte/lib/phch/src/phich.c b/lte/lib/phch/src/phich.c index d38c5ea67..939815c91 100644 --- a/lte/lib/phch/src/phich.c +++ b/lte/lib/phch/src/phich.c @@ -143,7 +143,6 @@ int phich_decode(phich_t *q, cf_t *slot_symbols, cf_t *ce[MAX_PORTS_CTRL], int i, j; cf_t *x[MAX_LAYERS]; cf_t *ce_precoding[MAX_PORTS]; - cf_t *symbols_precoding[MAX_PORTS]; DEBUG("Decoding PHICH Ngroup: %d, Nseq: %d\n", ngroup, nseq); @@ -174,7 +173,6 @@ int phich_decode(phich_t *q, cf_t *slot_symbols, cf_t *ce[MAX_PORTS_CTRL], } for (i = 0; i < MAX_PORTS; i++) { ce_precoding[i] = q->ce[i]; - symbols_precoding[i] = q->phich_symbols[i]; } /* extract symbols */ @@ -200,7 +198,7 @@ int phich_decode(phich_t *q, cf_t *slot_symbols, cf_t *ce[MAX_PORTS_CTRL], predecoding_single_zf(q->phich_symbols[0], q->ce[0], q->phich_d0, PHICH_MAX_NSYMB); } else { - predecoding_diversity_zf(symbols_precoding, ce_precoding, x, + predecoding_diversity_zf(q->phich_symbols[0], ce_precoding, x, q->nof_tx_ports, PHICH_MAX_NSYMB); layerdemap_diversity(x, q->phich_d0, q->nof_tx_ports, PHICH_MAX_NSYMB / q->nof_tx_ports); @@ -349,14 +347,15 @@ int phich_encode(phich_t *q, char ack, int ngroup, int nseq, int nsubframe, } DEBUG("d0: ",0); - if (VERBOSE_ISDEBUG()) vec_fprint_c(stdout, q->phich_d0, PHICH_MAX_NSYMB); + if (VERBOSE_ISDEBUG()) + vec_fprint_c(stdout, q->phich_d0, PHICH_MAX_NSYMB); /* layer mapping & precoding */ if (q->nof_tx_ports > 1) { layermap_diversity(q->phich_d0, x, q->nof_tx_ports, PHICH_MAX_NSYMB); precoding_diversity(x, symbols_precoding, q->nof_tx_ports, - PHICH_MAX_NSYMB / q->nof_tx_ports); + PHICH_MAX_NSYMB / q->nof_tx_ports); /**FIXME: According to 6.9.2, Precoding for 4 tx ports is different! */ } else { memcpy(q->phich_symbols[0], q->phich_d0, PHICH_MAX_NSYMB * sizeof(cf_t)); diff --git a/lte/lib/phch/src/prb.c b/lte/lib/phch/src/prb.c index bf3651867..5b1a5e053 100644 --- a/lte/lib/phch/src/prb.c +++ b/lte/lib/phch/src/prb.c @@ -68,6 +68,13 @@ void prb_cp(cf_t **input, cf_t **output, int nof_prb) { *output += nof_prb * RE_X_RB; } + +void prb_cp_half(cf_t **input, cf_t **output, int nof_prb) { + memcpy(*output, *input, sizeof(cf_t) * RE_X_RB * nof_prb / 2); + *input += nof_prb * RE_X_RB / 2; + *output += nof_prb * RE_X_RB / 2; +} + void prb_put_ref_(cf_t **input, cf_t **output, int offset, int nof_refs, int nof_prb) { prb_cp_ref(input, output, offset, nof_refs, nof_prb, false); diff --git a/lte/lib/phch/src/prb.h b/lte/lib/phch/src/prb.h index 4adf29389..b017d1910 100644 --- a/lte/lib/phch/src/prb.h +++ b/lte/lib/phch/src/prb.h @@ -31,6 +31,7 @@ typedef _Complex float cf_t; void prb_cp_ref(cf_t **input, cf_t **output, int offset, int nof_refs, int nof_prb, bool advance_input); void prb_cp(cf_t **input, cf_t **output, int nof_prb); +void prb_cp_half(cf_t **input, cf_t **output, int nof_prb); void prb_put_ref_(cf_t **input, cf_t **output, int offset, int nof_refs, int nof_prb); void phch_get_prb_ref(cf_t **input, cf_t **output, int offset, int nof_refs, diff --git a/lte/lib/phch/src/ra.c b/lte/lib/phch/src/ra.c index 936d2169a..5261c3ec5 100644 --- a/lte/lib/phch/src/ra.c +++ b/lte/lib/phch/src/ra.c @@ -26,6 +26,7 @@ */ #include +#include #include #include #include "lte/common/base.h" @@ -39,6 +40,90 @@ #define min(a,b) (a= nof_prb/2-3 && prb_idx <= nof_prb/2+3)) { + if (nsubframe == 0) { + if (nslot == 0) { + re = (CP_NSYMB(cp) - nof_ctrl_symbols - 2) * RE_X_RB; + } else { + if (CP_ISEXT(cp)) { + re = (CP_NSYMB(cp) - 4) * RE_X_RB; + skip_refs = true; + } else { + re = (CP_NSYMB(cp) - 4) * RE_X_RB + 2*nof_ports; + } + } + } else if (nsubframe == 5) { + if (nslot == 0) { + re = (CP_NSYMB(cp) - nof_ctrl_symbols - 2) * RE_X_RB; + } + } + if ((nof_prb%2) && (prb_idx == nof_prb/2-3 || prb_idx == nof_prb/2+3)) { + if (nslot == 0) { + re += 2 * RE_X_RB / 2; + } else if (nsubframe == 0) { + re += 4 * RE_X_RB / 2 - nof_ports; + if (CP_ISEXT(cp)) { + re -= nof_ports>2?2:nof_ports; + } + } + } + } + + // remove references + if (!skip_refs) { + switch(nof_ports) { + case 1: + case 2: + re -= 2 * (nslot + 1) * nof_ports; + break; + case 4: + if (nslot == 1) { + re -= 12; + } else { + re -= 4; + if (nof_ctrl_symbols == 1) { + re -= 4; + } + } + break; + } + } + + return re; +} + +/* Computes the number of RE for each PRB in the prb_dist structure */ +void ra_prb_get_re(ra_prb_t *prb_dist, int nof_prb, int nof_ports, int nof_ctrl_symbols, lte_cp_t cp) { + int i, j, s; + + /* Set start symbol according to Section 7.1.6.4 in 36.213 */ + prb_dist->lstart = nof_ctrl_symbols; + // Compute number of RE per subframe + for (i=0;islot[s].nof_prb;j++) { + prb_dist->re_sf[i] += ra_re_x_prb(i, s, prb_dist->slot[s].prb_idx[j], nof_prb, + nof_ports, nof_ctrl_symbols, cp); + } + } + } +} + void ra_prb_fprint(FILE *f, ra_prb_slot_t *prb) { int i, j, nrows; @@ -65,34 +150,31 @@ int ra_prb_get_ul(ra_prb_slot_t *prb, ra_pusch_t *ra, int nof_prb) { return 0; } + /** Compute PRB allocation for Downlink as defined in 7.1.6 of 36.213 */ int ra_prb_get_dl(ra_prb_t *prb_dist, ra_pdsch_t *ra, int nof_prb) { int i, j; uint32_t bitmask; int P = ra_type0_P(nof_prb); - ra_prb_slot_t *prb; + int n_rb_rbg_subset, n_rb_type1; bzero(prb_dist, sizeof(ra_prb_t)); switch(ra->alloc_type) { case alloc_type0: - prb = &prb_dist->slot1; - prb_dist->is_dist = false; bitmask = ra->type0_alloc.rbg_bitmask; int nb = (int) ceilf((float)nof_prb/P); for (i=0;iprb_idx[prb->nof_prb] = i*P+j; - prb->nof_prb++; + prb_dist->slot[0].prb_idx[prb_dist->slot[0].nof_prb] = i*P+j; + prb_dist->slot[0].nof_prb++; } } } + memcpy(&prb_dist->slot[1], &prb_dist->slot[0], sizeof(ra_prb_slot_t)); break; case alloc_type1: - prb = &prb_dist->slot1; - prb_dist->is_dist = false; - int n_rb_type1 = ra_type1_N_rb(nof_prb); - int n_rb_rbg_subset; + n_rb_type1 = ra_type1_N_rb(nof_prb); if (ra->type1_alloc.rbg_subset < (nof_prb/P) % P) { n_rb_rbg_subset = ((nof_prb-1)/(P*P)) * P + P; } else if (ra->type1_alloc.rbg_subset == ((nof_prb/P) % P)) { @@ -104,25 +186,24 @@ int ra_prb_get_dl(ra_prb_t *prb_dist, ra_pdsch_t *ra, int nof_prb) { bitmask = ra->type1_alloc.vrb_bitmask; for (i=0;iprb_idx[prb->nof_prb] = ((i+shift)/P)*P*P+ + prb_dist->slot[0].prb_idx[prb_dist->slot[0].nof_prb] = ((i+shift)/P)*P*P+ ra->type1_alloc.rbg_subset*P+(i+shift)%P; - prb->nof_prb++; + prb_dist->slot[0].nof_prb++; } } + memcpy(&prb_dist->slot[1], &prb_dist->slot[0], sizeof(ra_prb_slot_t)); break; case alloc_type2: if (ra->type2_alloc.mode == t2_loc) { - prb = &prb_dist->slot1; - prb_dist->is_dist = false; for (i=0;itype2_alloc.L_crb;i++) { - prb->prb_idx[i] = i+ra->type2_alloc.RB_start; - prb->nof_prb++; + prb_dist->slot[0].prb_idx[i] = i+ra->type2_alloc.RB_start; + prb_dist->slot[0].nof_prb++; } + memcpy(&prb_dist->slot[1], &prb_dist->slot[0], sizeof(ra_prb_slot_t)); } else { /* Mapping of Virtual to Physical RB for distributed type is defined in * 6.2.3.2 of 36.211 */ - prb_dist->is_dist = true; int N_gap, N_tilde_vrb, n_tilde_vrb, n_tilde_prb, n_tilde2_prb, N_null, N_row, n_vrb; int n_tilde_prb_odd, n_tilde_prb_even; if (ra->type2_alloc.n_gap == t2_ng1) { @@ -152,23 +233,24 @@ int ra_prb_get_dl(ra_prb_t *prb_dist, ra_pdsch_t *ra, int nof_prb) { n_tilde_prb_even = (n_tilde_prb_odd+N_tilde_vrb/2)%N_tilde_vrb+N_tilde_vrb*(n_vrb/N_tilde_vrb); if (n_tilde_prb_odd < N_tilde_vrb/2) { - prb_dist->slot1.prb_idx[i] = n_tilde_prb_odd; + prb_dist->slot[0].prb_idx[i] = n_tilde_prb_odd; } else { - prb_dist->slot1.prb_idx[i] = n_tilde_prb_odd+N_gap-N_tilde_vrb/2; + prb_dist->slot[0].prb_idx[i] = n_tilde_prb_odd+N_gap-N_tilde_vrb/2; } - prb_dist->slot1.nof_prb++; + prb_dist->slot[0].nof_prb++; if (n_tilde_prb_even < N_tilde_vrb/2) { - prb_dist->slot2.prb_idx[i] = n_tilde_prb_even; + prb_dist->slot[1].prb_idx[i] = n_tilde_prb_even; } else { - prb_dist->slot2.prb_idx[i] = n_tilde_prb_even+N_gap-N_tilde_vrb/2; + prb_dist->slot[1].prb_idx[i] = n_tilde_prb_even+N_gap-N_tilde_vrb/2; } - prb_dist->slot2.nof_prb++; + prb_dist->slot[1].nof_prb++; } } break; default: return -1; } + return 0; } @@ -496,14 +578,9 @@ void ra_pdsch_fprint(FILE *f, ra_pdsch_t *ra, int nof_prb) { ra_prb_t alloc; ra_prb_get_dl(&alloc, ra, nof_prb); - if (alloc.is_dist) { - fprintf(f, " - PRB Bitmap Assignment 1st slot:\n"); - ra_prb_fprint(f, &alloc.slot1); - fprintf(f, " - PRB Bitmap Assignment 2nd slot:\n"); - ra_prb_fprint(f, &alloc.slot2); - } else { - fprintf(f, " - PRB Bitmap Assignment:\n"); - ra_prb_fprint(f, &alloc.slot1); + for (int s=0;s<2;s++) { + fprintf(f, " - PRB Bitmap Assignment %dst slot:\n", s); + ra_prb_fprint(f, &alloc.slot[s]); } fprintf(f, " - Number of PRBs:\t\t\t%d\n", ra_nprb_dl(ra, nof_prb)); diff --git a/lte/lib/phch/src/sequences.c b/lte/lib/phch/src/sequences.c index 21a851300..343b2a6ab 100644 --- a/lte/lib/phch/src/sequences.c +++ b/lte/lib/phch/src/sequences.c @@ -62,3 +62,11 @@ int sequence_pdcch(sequence_t *seq, int nslot, int cell_id, int len) { bzero(seq, sizeof(sequence_t)); return sequence_LTEPRS(seq, len, (nslot/2) * 512 + cell_id); } + +/** + * 36.211 6.3.1 + */ +int sequence_pdsch(sequence_t *seq, unsigned short rnti, int q, int nslot, int cell_id, int len) { + bzero(seq, sizeof(sequence_t)); + return sequence_LTEPRS(seq, len, (rnti<<14) + (q<<13) + ((nslot/2)<<9) + cell_id); +} diff --git a/lte/lib/phch/test/CMakeLists.txt b/lte/lib/phch/test/CMakeLists.txt index f7a6c00d1..5d248ffe7 100644 --- a/lte/lib/phch/test/CMakeLists.txt +++ b/lte/lib/phch/test/CMakeLists.txt @@ -80,6 +80,19 @@ ADD_TEST(pdcch_test pdcch_test) ADD_EXECUTABLE(dci_unpacking dci_unpacking.c) TARGET_LINK_LIBRARIES(dci_unpacking lte) +######################################################################## +# PDSCH TEST +######################################################################## + +ADD_EXECUTABLE(pdsch_test pdsch_test.c) +TARGET_LINK_LIBRARIES(pdsch_test lte) + +ADD_EXECUTABLE(pdsch_re_test pdsch_re_test.c) +TARGET_LINK_LIBRARIES(pdsch_re_test lte) + +ADD_TEST(pdsch_re_test pdsch_re_test) +ADD_TEST(pdsch_test pdsch_test -l 50000 -m 4 -n 110) + ######################################################################## # FILE TEST ######################################################################## @@ -96,8 +109,14 @@ TARGET_LINK_LIBRARIES(phich_file_test lte) ADD_EXECUTABLE(pdcch_file_test pdcch_file_test.c) TARGET_LINK_LIBRARIES(pdcch_file_test lte) +ADD_EXECUTABLE(pdsch_file_test pdsch_file_test.c) +TARGET_LINK_LIBRARIES(pdsch_file_test lte) + ADD_TEST(pbch_file_test pbch_file_test -i ${CMAKE_CURRENT_SOURCE_DIR}/signal.1.92M.dat) ADD_TEST(pcfich_file_test pcfich_file_test -c 150 -n 50 -p 2 -i ${CMAKE_CURRENT_SOURCE_DIR}/signal.10M.dat) ADD_TEST(phich_file_test phich_file_test -c 150 -n 50 -p 2 -i ${CMAKE_CURRENT_SOURCE_DIR}/signal.10M.dat) ADD_TEST(pdcch_file_test pdcch_file_test -c 1 -f 3 -n 6 -p 1 -i ${CMAKE_CURRENT_SOURCE_DIR}/signal.1.92M.amar.dat) +ADD_TEST(pdsch_file_test pdsch_file_test -c 1 -f 3 -n 6 -p 1 -i ${CMAKE_CURRENT_SOURCE_DIR}/signal.1.92M.amar.dat) + + \ No newline at end of file diff --git a/lte/lib/phch/test/dci_unpacking.c b/lte/lib/phch/test/dci_unpacking.c index 97b3266ee..81b9e0343 100644 --- a/lte/lib/phch/test/dci_unpacking.c +++ b/lte/lib/phch/test/dci_unpacking.c @@ -40,7 +40,6 @@ void usage(char *prog) { int main(int argc, char **argv) { dci_msg_t msg; ra_pdsch_t ra_dl; - ra_pdsch_t ra_ul; int len, rlen; int nof_prb; int nwords; diff --git a/lte/lib/phch/test/pdcch_test.c b/lte/lib/phch/test/pdcch_test.c index a6d0d9b42..604a6d143 100644 --- a/lte/lib/phch/test/pdcch_test.c +++ b/lte/lib/phch/test/pdcch_test.c @@ -113,7 +113,7 @@ int main(int argc, char **argv) { int i, j; cf_t *ce[MAX_PORTS_CTRL]; int nof_re; - cf_t *slot1_symbols[MAX_PORTS_CTRL]; + cf_t *slot_symbols[MAX_PORTS_CTRL]; int nof_dcis; int ret = -1; @@ -135,8 +135,8 @@ int main(int argc, char **argv) { for (j=0;j +#include +#include +#include +#include + +#include "lte.h" + +char *input_file_name = NULL; +char *matlab_file_name = NULL; +int cell_id = 0; +int cfi = 2; +lte_cp_t cp = CPNORM; +int nof_prb = 6; +int nof_ports = 1; +int flen; +unsigned short rnti = SIRNTI; +int max_frames = 10; +FILE *fmatlab = NULL; + +filesource_t fsrc; +pdcch_t pdcch; +pdsch_t pdsch; +cf_t *input_buffer, *fft_buffer, *ce[MAX_PORTS_CTRL]; +regs_t regs; +lte_fft_t fft; +chest_t chest; +dci_t dci_rx; + +void usage(char *prog) { + printf("Usage: %s [vcfoe] -i input_file\n", prog); + printf("\t-o output matlab file name [Default Disabled]\n"); + printf("\t-c cell_id [Default %d]\n", cell_id); + printf("\t-f cfi [Default %d]\n", cfi); + printf("\t-r rnti [Default SI-RNTI]\n"); + printf("\t-p nof_ports [Default %d]\n", nof_ports); + printf("\t-n nof_prb [Default %d]\n", nof_prb); + printf("\t-m max_frames [Default %d]\n", max_frames); + printf("\t-e Set extended prefix [Default Normal]\n"); + printf("\t-v [set verbose to debug, default none]\n"); +} + +void parse_args(int argc, char **argv) { + int opt; + while ((opt = getopt(argc, argv, "irovfcenmp")) != -1) { + switch(opt) { + case 'i': + input_file_name = argv[optind]; + break; + case 'c': + cell_id = atoi(argv[optind]); + break; + case 'r': + rnti = strtoul(argv[optind], NULL, 0); + break; + case 'm': + max_frames = strtoul(argv[optind], NULL, 0); + break; + case 'f': + cfi = atoi(argv[optind]); + break; + case 'n': + nof_prb = atoi(argv[optind]); + break; + case 'p': + nof_ports = atoi(argv[optind]); + break; + case 'o': + matlab_file_name = argv[optind]; + break; + case 'v': + verbose++; + break; + case 'e': + cp = CPEXT; + break; + default: + usage(argv[0]); + exit(-1); + } + } + if (!input_file_name) { + usage(argv[0]); + exit(-1); + } +} + +int base_init() { + int i; + + if (filesource_init(&fsrc, input_file_name, COMPLEX_FLOAT_BIN)) { + fprintf(stderr, "Error opening file %s\n", input_file_name); + exit(-1); + } + + if (matlab_file_name) { + fmatlab = fopen(matlab_file_name, "w"); + if (!fmatlab) { + perror("fopen"); + return -1; + } + } else { + fmatlab = NULL; + } + + flen = 2 * (SLOT_LEN(lte_symbol_sz(nof_prb), cp)); + + input_buffer = malloc(flen * sizeof(cf_t)); + if (!input_buffer) { + perror("malloc"); + exit(-1); + } + + fft_buffer = malloc(2 * CP_NSYMB(cp) * nof_prb * RE_X_RB * sizeof(cf_t)); + if (!fft_buffer) { + perror("malloc"); + return -1; + } + + for (i=0;i +#include +#include +#include +#include +#include + +#include "lte.h" + +#define N_TESTS 10 + +const lte_cp_t test_re_cp[N_TESTS] = {CPNORM, CPNORM, CPNORM, CPNORM, CPNORM, CPNORM, CPEXT, CPEXT, CPEXT, CPEXT}; +const int test_re_ports[N_TESTS] = {1, 1, 1, 2, 4, 4, 1, 4, 1, 4}; +const int test_re_csymb[N_TESTS] = {2, 1, 3, 3, 1, 3, 2, 2, 1, 2}; +const int test_re_prb[N_TESTS] = {6, 15, 15, 15, 15, 15, 6, 6, 15, 15}; +const int test_re_num[N_TESTS][3] = { + {408, 684, 828 }, // sf 0, 5 and the rest + {1830, 2106, 2250}, + {1470, 1746, 1890}, + {1392, 1656, 1800}, + {1656, 1896, 2040}, + {1356, 1596, 1740}, + {276, 540, 684}, + {264, 480, 624}, + {1482, 1746, 1890}, + {1200, 1416, 1560} +}; + +int main(int argc, char **argv) { + int i, n, np; + ra_prb_t prb_alloc; + int ret = -1; + + while (getopt(argc, argv, "v") == 'v') { + verbose++; + } + + for (i=0;i<110;i++) { + prb_alloc.slot[0].prb_idx[i] = i; + prb_alloc.slot[1].prb_idx[i] = i; + } + + for (i=0;i +#include +#include +#include +#include +#include + +#include "lte.h" + +int cell_id = 1; +int nof_prb = 6; +int nof_ports = 1; +int cfi = 1; +int tbs = -1; +int subframe = 1; +ra_mod_t modulation = BPSK; + +void usage(char *prog) { + printf("Usage: %s [cpnfvmt] -l TBS \n", prog); + printf("\t-m modulation (1: BPSK, 2: QPSK, 3: QAM16, 4: QAM64) [Default BPSK]\n"); + printf("\t-c cell id [Default %d]\n", cell_id); + printf("\t-s subframe [Default %d]\n", subframe); + printf("\t-f cfi [Default %d]\n", cfi); + printf("\t-p nof_ports [Default %d]\n", nof_ports); + printf("\t-n nof_prb [Default %d]\n", nof_prb); + printf("\t-v [set verbose to debug, default none]\n"); +} + +void parse_args(int argc, char **argv) { + int opt; + while ((opt = getopt(argc, argv, "lcpnfvmt")) != -1) { + switch(opt) { + case 'm': + switch(atoi(argv[optind])) { + case 1: + modulation = BPSK; + break; + case 2: + modulation = QPSK; + break; + case 4: + modulation = QAM16; + break; + case 6: + modulation = QAM64; + break; + default: + fprintf(stderr, "Invalid modulation %d. Possible values: " + "(1: BPSK, 2: QPSK, 3: QAM16, 4: QAM64)\n", atoi(argv[optind])); + break; + } + break; + case 'l': + tbs = atoi(argv[optind]); + break; + case 'p': + nof_ports = atoi(argv[optind]); + break; + case 'n': + nof_prb = atoi(argv[optind]); + break; + case 'c': + cell_id = atoi(argv[optind]); + break; + case 'v': + verbose++; + break; + default: + usage(argv[0]); + exit(-1); + } + } + if (tbs == -1) { + usage(argv[0]); + exit(-1); + } +} + +int main(int argc, char **argv) { + pdsch_t pdsch; + int i, j; + char *data = NULL; + cf_t *ce[MAX_PORTS_CTRL]; + int nof_re; + cf_t *slot_symbols[MAX_PORTS_CTRL]; + int ret = -1; + struct timeval t[3]; + ra_mcs_t mcs; + ra_prb_t prb_alloc; + + parse_args(argc,argv); + + nof_re = 2 * CPNORM_NSYMB * nof_prb * RE_X_RB; + + mcs.tbs = tbs; + mcs.mod = modulation; + prb_alloc.slot[0].nof_prb = nof_prb; + for (i=0;i 0) { + slot_symbols[0][j] += slot_symbols[i][j]; + } + ce[i][j] = 1; + } + } + + gettimeofday(&t[1], NULL); + int r = pdsch_decode(&pdsch, slot_symbols[0], ce, data, subframe, mcs, &prb_alloc); + gettimeofday(&t[2], NULL); + get_time_interval(t); + if (r) { + printf("Error decoding\n"); + ret = -1; + } else { + printf("DECODED OK in %d:%d (%.2f Mbps)\n", (int) t[0].tv_sec, (int) t[0].tv_usec, (float) mcs.tbs/t[0].tv_usec); + } + ret = 0; +quit: + pdsch_free(&pdsch); + + for (i=0;iobj.seq[0], h->init.nof_symbols == CPNORM_NSYMB?CPNORM:CPEXT, h->init.cell_id); case SCRAMBLING_PDSCH: + for (int ns=0;nsobj.seq[ns], h->init.nrnti, 0, 2*ns, h->init.cell_id, LTE_NSOFT_BITS); + } + return 0; case SCRAMBLING_PCFICH: for (int ns=0;nsobj.seq[ns], 2*ns, h->init.cell_id); } return 0; case SCRAMBLING_PDCCH: + for (int ns=0;nsobj.seq[ns], 2*ns, h->init.cell_id, LTE_NSOFT_BITS); + } + return 0; case SCRAMBLING_PMCH: case SCRAMBLING_PUCCH: fprintf(stderr, "Not implemented\n");