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 #include -#include "lte/config.h" - /** Structures and utility functions for DL/UL resource * allocation. */ -typedef enum { - MOD_NULL = 0, BPSK = 1, QPSK = 2, QAM16 = 4, QAM64 = 16 +typedef enum LIBLTE_API { + MOD_NULL = 0, BPSK = 1, QPSK = 2, QAM16 = 3, QAM64 = 4 } ra_mod_t; typedef struct LIBLTE_API { ra_mod_t mod; // By default, mod = MOD_NULL and the mcs_idx value is taken by the packing functions - // otherwise mod + tbs values are used to generate the mcs_idx automatically. + // otherwise mod + tbs values are used to generate the mcs_idx automatically. uint8_t tbs_idx; uint8_t mcs_idx; - int tbs; // If tbs<=0, the tbs_idx value is taken by the packing functions to generate the DCI - // message. Otherwise the tbs_idx corresponding to the lower nearest TBS is taken. -}ra_mcs_t; + int tbs;// If tbs<=0, the tbs_idx value is taken by the packing functions to generate the DCI + // message. Otherwise the tbs_idx corresponding to the lower nearest TBS is taken. +} ra_mcs_t; - -typedef enum { +typedef enum LIBLTE_API { alloc_type0 = 0, alloc_type1 = 1, alloc_type2 = 2 -}ra_type_t; +} ra_type_t; typedef struct LIBLTE_API { uint32_t rbg_bitmask; -}ra_type0_t; +} ra_type0_t; typedef struct LIBLTE_API { uint32_t vrb_bitmask; - uint8_t rbg_subset; - bool shift; -}ra_type1_t; + uint8_t rbg_subset;bool shift; +} ra_type1_t; typedef struct LIBLTE_API { - uint32_t riv; // if L_crb==0, DCI message packer will take this value directly + uint32_t riv; // if L_crb==0, DCI message packer will take this value directly uint16_t L_crb; uint16_t RB_start; - enum {nprb1a_2 = 0, nprb1a_3 = 1} n_prb1a; - enum {t2_ng1 = 0, t2_ng2 = 1} n_gap; - enum {t2_loc = 0, t2_dist = 1} mode; -}ra_type2_t; + enum { + nprb1a_2 = 0, nprb1a_3 = 1 + } n_prb1a; + enum { + t2_ng1 = 0, t2_ng2 = 1 + } n_gap; + enum { + t2_loc = 0, t2_dist = 1 + } mode; +} ra_type2_t; typedef struct LIBLTE_API { unsigned short rnti; @@ -84,8 +86,7 @@ typedef struct LIBLTE_API { }; ra_mcs_t mcs; uint8_t harq_process; - uint8_t rv_idx; - bool ndi; + uint8_t rv_idx;bool ndi; } ra_pdsch_t; typedef struct LIBLTE_API { @@ -102,30 +103,34 @@ typedef struct LIBLTE_API { ra_type2_t type2_alloc; ra_mcs_t mcs; - uint8_t rv_idx; // If set to non-zero, a retransmission is requested with the same modulation - // than before (Format0 message, see also 8.6.1 in 36.2313). - bool ndi; - bool cqi_request; + uint8_t rv_idx; // If set to non-zero, a retransmission is requested with the same modulation + // than before (Format0 message, see also 8.6.1 in 36.2313). + bool ndi;bool cqi_request; } ra_pusch_t; typedef struct LIBLTE_API { uint8_t prb_idx[110]; int nof_prb; -}ra_prb_slot_t; +} ra_prb_slot_t; typedef struct LIBLTE_API { - ra_prb_slot_t slot1; - ra_prb_slot_t slot2; - bool is_dist; -}ra_prb_t; - + ra_prb_slot_t slot[2]; + int lstart; + int re_sf[NSUBFRAMES_X_FRAME]; +} ra_prb_t; LIBLTE_API void ra_prb_fprint(FILE *f, ra_prb_slot_t *prb); + LIBLTE_API int ra_prb_get_dl(ra_prb_t *prb, ra_pdsch_t *ra, int nof_prb); LIBLTE_API int ra_prb_get_ul(ra_prb_slot_t *prb, ra_pusch_t *ra, int nof_prb); +LIBLTE_API void ra_prb_get_re(ra_prb_t *prb_dist, int nof_prb, int nof_ports, + int nof_ctrl_symbols, lte_cp_t cp); + LIBLTE_API int ra_nprb_dl(ra_pdsch_t *ra, int nof_prb); LIBLTE_API int ra_nprb_ul(ra_pusch_t *ra, int nof_prb); +LIBLTE_API int ra_re_x_prb(int nsubframe, int nslot, int prb_idx, int nof_prb, + int nof_ports, int nof_ctrl_symbols, lte_cp_t cp); LIBLTE_API uint8_t ra_mcs_to_table_idx(ra_mcs_t *mcs); LIBLTE_API int ra_mcs_from_idx_dl(uint8_t idx, ra_mcs_t *mcs); @@ -144,7 +149,8 @@ LIBLTE_API char *ra_mod_string(ra_mod_t mod); LIBLTE_API int ra_type0_P(int nof_prb); LIBLTE_API uint32_t ra_type2_to_riv(uint16_t L_crb, uint16_t RB_start, int nof_prb); -LIBLTE_API void ra_type2_from_riv(uint32_t riv, uint16_t *L_crb, uint16_t *RB_start, int nof_prb, int nof_vrb); +LIBLTE_API void ra_type2_from_riv(uint32_t riv, uint16_t *L_crb, uint16_t *RB_start, + int nof_prb, int nof_vrb); LIBLTE_API int ra_type2_n_vrb_dl(int nof_prb, bool ngap_is_1); LIBLTE_API int ra_type2_n_rb_step(int nof_prb); LIBLTE_API int ra_type2_ngap(int nof_prb, bool ngap_is_1); @@ -155,4 +161,4 @@ LIBLTE_API void ra_pdsch_set_mcs(ra_pdsch_t *ra, ra_mod_t mod, uint8_t tbs_idx); LIBLTE_API void ra_pdsch_fprint(FILE *f, ra_pdsch_t *ra, int nof_prb); LIBLTE_API void ra_pusch_fprint(FILE *f, ra_pusch_t *ra, int nof_prb); -#endif // RB_ALLOC_H_ +#endif /* RB_ALLOC_H_ */ diff --git a/lte/lib/common/src/lte.c b/lte/lib/common/src/lte.c index 909359c80..aa62988b9 100644 --- a/lte/lib/common/src/lte.c +++ b/lte/lib/common/src/lte.c @@ -50,6 +50,9 @@ const int tc_cb_sizes[NOF_TC_CB_SIZES] = { 40, 48, 56, 64, 72, 80, 88, 96, 104, 4800, 4864, 4928, 4992, 5056, 5120, 5184, 5248, 5312, 5376, 5440, 5504, 5568, 5632, 5696, 5760, 5824, 5888, 5952, 6016, 6080, 6144 }; +/* + * Returns Turbo coder interleaver size for Table 5.1.3-3 (36.212) index + */ int lte_cb_size(int index) { if (index >= 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/parity.c b/lte/lib/fec/src/parity.c new file mode 100644 index 000000000..568994888 --- /dev/null +++ b/lte/lib/fec/src/parity.c @@ -0,0 +1,29 @@ +/* + * Copyright 2004, Phil Karn, KA9Q + * May be used under the terms of the GNU Lesser General Public License (LGPL) + */ + +#include + +unsigned char Partab[256]; +int P_init; + +/* Create 256-entry odd-parity lookup table + * Needed only on non-ia32 machines + */ +void partab_init(void) { + int i, cnt, ti; + + /* Initialize parity lookup table */ + for (i = 0; i < 256; i++) { + cnt = 0; + ti = i; + while (ti) { + if (ti & 1) + cnt++; + ti >>= 1; + } + Partab[i] = cnt & 1; + } + P_init = 1; +} diff --git a/lte/lib/fec/src/rm_conv.c b/lte/lib/fec/src/rm_conv.c index 2e8a2653e..464f635e4 100644 --- a/lte/lib/fec/src/rm_conv.c +++ b/lte/lib/fec/src/rm_conv.c @@ -25,49 +25,46 @@ * */ - #include #include #include "lte/fec/rm_conv.h" #define NCOLS 32 #define NROWS_MAX NCOLS -#define RATE 3 -unsigned char RM_CONV_PERM_TC[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_CONV_PERM_TC_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 }; +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_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 }; int rm_conv_tx(char *input, int in_len, char *output, int out_len) { - char tmp[RATE * NCOLS * NROWS_MAX]; + char tmp[3 * NCOLS * NROWS_MAX]; int nrows, ndummy, K_p; int i, j, k, s; - nrows = (int) (in_len / RATE - 1) / NCOLS + 1; + nrows = (int) (in_len / 3 - 1) / NCOLS + 1; if (nrows > NROWS_MAX) { fprintf(stderr, "Input too large. Max input length is %d\n", - RATE * NCOLS * NROWS_MAX); + 3 * NCOLS * NROWS_MAX); return -1; } K_p = nrows * NCOLS; - ndummy = K_p - in_len / RATE; + ndummy = K_p - in_len / 3; if (ndummy < 0) { ndummy = 0; } /* Sub-block interleaver 5.1.4.2.1 */ - k=0; + k = 0; for (s = 0; s < 3; s++) { for (j = 0; j < NCOLS; j++) { for (i = 0; i < nrows; i++) { - if (i*NCOLS + RM_CONV_PERM_TC[j] < ndummy) { + if (i * NCOLS + RM_PERM_CC[j] < ndummy) { tmp[k] = TX_NULL; } else { - tmp[k] = input[(i*NCOLS + RM_CONV_PERM_TC[j]-ndummy)*3+s]; + tmp[k] = input[(i * NCOLS + RM_PERM_CC[j] - ndummy) * 3 + s]; } k++; } @@ -82,14 +79,13 @@ int rm_conv_tx(char *input, int in_len, char *output, int out_len) { k++; } j++; - if (j == RATE * K_p) { + if (j == 3 * K_p) { j = 0; } } return 0; } - /* Undoes Convolutional Code Rate Matching. * 3GPP TS 36.212 v10.1.0 section 5.1.4.2 */ @@ -99,22 +95,22 @@ int rm_conv_rx(float *input, int in_len, float *output, int out_len) { int i, j, k; int d_i, d_j; - float tmp[RATE * NCOLS * NROWS_MAX]; + float tmp[3 * NCOLS * NROWS_MAX]; - nrows = (int) (out_len / RATE - 1) / NCOLS + 1; + nrows = (int) (out_len / 3 - 1) / NCOLS + 1; if (nrows > NROWS_MAX) { fprintf(stderr, "Output too large. Max output length is %d\n", - RATE * NCOLS * NROWS_MAX); + 3 * NCOLS * NROWS_MAX); return -1; } K_p = nrows * NCOLS; - ndummy = K_p - out_len / RATE; + ndummy = K_p - out_len / 3; if (ndummy < 0) { ndummy = 0; } - for (i = 0; i < RATE * K_p; i++) { + for (i = 0; i < 3 * K_p; i++) { tmp[i] = RX_NULL; } @@ -125,7 +121,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_CONV_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) { @@ -134,22 +130,21 @@ int rm_conv_rx(float *input, int in_len, float *output, int out_len) { k++; } j++; - if (j == RATE * K_p) { + if (j == 3 * K_p) { j = 0; } } /* interleaving and bit selection */ - for (i = 0; i < out_len / RATE; i++) { + for (i = 0; i < out_len / 3; i++) { d_i = (i + ndummy) / NCOLS; d_j = (i + ndummy) % NCOLS; - for (j = 0; j < RATE; j++) { - float o = tmp[K_p * j + RM_CONV_PERM_TC_INV[d_j] * nrows - + d_i]; + for (j = 0; j < 3; j++) { + float o = tmp[K_p * j + RM_PERM_CC_INV[d_j] * nrows + d_i]; if (o != RX_NULL) { - output[i * RATE + j] = o; + output[i * 3 + j] = o; } else { - output[i * RATE + j] = 0; + output[i * 3 + j] = 0; } } } @@ -166,11 +161,11 @@ int rm_conv_initialize(rm_conv_hl* h) { /** This function can be called in a subframe (1ms) basis */ int rm_conv_work(rm_conv_hl* hl) { if (hl->init.direction) { - //rm_conv_tx(hl->input, hl->output, hl->in_len, hl->ctrl_in.S); - hl->out_len = hl->ctrl_in.S; - } else { - rm_conv_rx(hl->input, hl->output, hl->in_len, hl->ctrl_in.E); + rm_conv_tx(hl->input, hl->in_len, hl->output, hl->ctrl_in.E); hl->out_len = hl->ctrl_in.E; + } else { + rm_conv_rx(hl->input, hl->in_len, hl->output, hl->ctrl_in.S); + hl->out_len = hl->ctrl_in.S; } return 0; } diff --git a/lte/lib/fec/src/rm_turbo.c b/lte/lib/fec/src/rm_turbo.c index 5c7acd792..16736bc88 100644 --- a/lte/lib/fec/src/rm_turbo.c +++ b/lte/lib/fec/src/rm_turbo.c @@ -35,11 +35,9 @@ #define NCOLS 32 #define NROWS_MAX NCOLS -#define RATE 3 -unsigned char RM_PERM_TC[NCOLS] = - { 0, 16, 8, 24, 4, 20, 12, 28, 2, 18, 10, 26, 6, 22, 14, 30, 1, 17, 9, - 25, 5, 21, 13, 29, 3, 19, 11, 27, 7, 23, 15, 31 }; +unsigned char RM_PERM_TC[NCOLS] = { 0, 16, 8, 24, 4, 20, 12, 28, 2, 18, 10, 26, + 6, 22, 14, 30, 1, 17, 9, 25, 5, 21, 13, 29, 3, 19, 11, 27, 7, 23, 15, 31 }; int rm_turbo_init(rm_turbo_t *q, int buffer_len) { q->buffer_len = buffer_len; @@ -48,11 +46,6 @@ int rm_turbo_init(rm_turbo_t *q, int buffer_len) { perror("malloc"); return -1; } - q->d2_perm = malloc(buffer_len * sizeof(int) / 3 + 1); - if (!q->d2_perm) { - perror("malloc"); - return -1; - } return 0; } @@ -67,23 +60,24 @@ void rm_turbo_free(rm_turbo_t *q) { * * TODO: Soft buffer size limitation according to UE category */ -int rm_turbo_tx(rm_turbo_t *q, char *input, int in_len, char *output, int out_len, int rv_idx) { +int rm_turbo_tx(rm_turbo_t *q, char *input, int in_len, char *output, + int out_len, int rv_idx) { char *tmp = (char*) q->buffer; int nrows, ndummy, K_p; int i, j, k, s, kidx, N_cb, k0; - nrows = (int) (in_len / RATE - 1) / NCOLS + 1; + nrows = (int) (in_len / 3 - 1) / NCOLS + 1; 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; } - ndummy = K_p - in_len / RATE; + ndummy = K_p - in_len / 3; if (ndummy < 0) { ndummy = 0; } @@ -94,9 +88,9 @@ int rm_turbo_tx(rm_turbo_t *q, char *input, int in_len, char *output, int out_le for (j = 0; j < NCOLS; j++) { for (i = 0; i < nrows; i++) { if (s == 0) { - kidx = k%K_p; + kidx = k % K_p; } else { - kidx = K_p + 2 * (k%K_p); + kidx = K_p + 2 * (k % K_p); } if (i * NCOLS + RM_PERM_TC[j] < ndummy) { tmp[kidx] = TX_NULL; @@ -119,10 +113,10 @@ int rm_turbo_tx(rm_turbo_t *q, char *input, int in_len, char *output, int out_le } /* Bit selection and transmission 5.1.4.1.2 */ - N_cb = 3 * K_p; // TODO: Soft buffer size limitation + N_cb = 3 * K_p; // TODO: Soft buffer size limitation - k0 = nrows * (2 * (int) ceilf((float) N_cb / (float) (8 * nrows)) - * rv_idx + 2); + k0 = nrows + * (2 * (int) ceilf((float) N_cb / (float) (8 * nrows)) * rv_idx + 2); k = 0; j = 0; @@ -139,7 +133,8 @@ int rm_turbo_tx(rm_turbo_t *q, char *input, int in_len, char *output, int out_le /* Undoes Turbo Code Rate Matching. * 3GPP TS 36.212 v10.1.0 section 5.1.4.1 */ -int rm_turbo_rx(rm_turbo_t *q, float *input, int in_len, float *output, int out_len, int rv_idx) { +int rm_turbo_rx(rm_turbo_t *q, float *input, int in_len, float *output, + int out_len, int rv_idx) { int nrows, ndummy, K_p, k0, N_cb, jp, kidx; int i, j, k; @@ -148,41 +143,38 @@ int rm_turbo_rx(rm_turbo_t *q, float *input, int in_len, float *output, int out_ float *tmp = (float*) q->buffer; - nrows = (int) (out_len / RATE - 1) / NCOLS + 1; + nrows = (int) (out_len / 3 - 1) / NCOLS + 1; 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; } - ndummy = K_p - out_len / RATE; + ndummy = K_p - out_len / 3; if (ndummy < 0) { ndummy = 0; } - for (i = 0; i < RATE * K_p; i++) { + for (i = 0; i < 3 * K_p; i++) { tmp[i] = RX_NULL; } /* Undo bit collection. Account for dummy bits */ - N_cb = 3 * K_p; // TODO: Soft buffer size limitation - k0 = nrows * (2 * (int) ceilf((float) N_cb / (float) (8 * nrows)) - * rv_idx + 2); + N_cb = 3 * K_p; // TODO: Soft buffer size limitation + k0 = nrows + * (2 * (int) ceilf((float) N_cb / (float) (8 * nrows)) * rv_idx + 2); + k = 0; j = 0; while (k < in_len) { jp = (k0 + j) % N_cb; - if (jp == 32 || jp == 95 || jp == 0) { - i=0; - } - - if (jp < K_p || !(jp%2)) { + if (jp < K_p || !(jp % 2)) { if (jp >= K_p) { - d_i = ((jp-K_p) / 2) / nrows; - d_j = ((jp-K_p) / 2) % nrows; + d_i = ((jp - K_p) / 2) / nrows; + d_j = ((jp - K_p) / 2) % nrows; } else { d_i = jp / nrows; d_j = jp % nrows; @@ -193,9 +185,8 @@ int rm_turbo_rx(rm_turbo_t *q, float *input, int in_len, float *output, int out_ isdummy = true; } } else { - int jpp = (jp-K_p-1)/2; + int jpp = (jp - K_p - 1) / 2; kidx = (RM_PERM_TC[jpp / nrows] + NCOLS * (jpp % nrows) + 1) % K_p; - q->d2_perm[kidx] = jpp; // save the permutation in a temporary buffer if ((kidx - ndummy) < 0) { isdummy = true; } else { @@ -215,28 +206,30 @@ int rm_turbo_rx(rm_turbo_t *q, float *input, int in_len, float *output, int out_ } /* interleaving and bit selection */ - for (i = 0; i < out_len / RATE; i++) { + for (i = 0; i < out_len / 3; i++) { d_i = (i + ndummy) / NCOLS; d_j = (i + ndummy) % NCOLS; - for (j = 0; j < RATE; j++) { + for (j = 0; j < 3; j++) { if (j != 2) { - kidx = K_p * j + (j+1)*(RM_PERM_TC[d_j] * nrows + d_i); + kidx = K_p * j + (j + 1) * (RM_PERM_TC[d_j] * nrows + d_i); } else { - // use the saved permuatation function to avoid computing the inverse - kidx = 2*q->d2_perm[(i+ndummy)%K_p]+K_p+1; + + k = (i + ndummy - 1) % K_p; + if (k < 0) + k += K_p; + kidx = (k / NCOLS + nrows * RM_PERM_TC[k % NCOLS]) % K_p; + kidx = 2 * kidx + K_p + 1; } - float o = tmp[kidx]; - if (o != RX_NULL) { - output[i * RATE + j] = o; + if (tmp[kidx] != RX_NULL) { + output[i * 3 + j] = tmp[kidx]; } else { - output[i * RATE + j] = 0; + output[i * 3 + j] = 0; } } } return 0; } - /** High-level API */ int rm_turbo_initialize(rm_turbo_hl* h) { @@ -246,10 +239,12 @@ int rm_turbo_initialize(rm_turbo_hl* h) { /** This function can be called in a subframe (1ms) basis */ int rm_turbo_work(rm_turbo_hl* hl) { if (hl->init.direction) { - rm_turbo_tx(&hl->q, hl->input, hl->in_len, hl->output, hl->ctrl_in.E, hl->ctrl_in.rv_idx); + rm_turbo_tx(&hl->q, hl->input, hl->in_len, hl->output, hl->ctrl_in.E, + hl->ctrl_in.rv_idx); hl->out_len = hl->ctrl_in.E; } else { - rm_turbo_rx(&hl->q, hl->input, hl->in_len, hl->output, hl->ctrl_in.S, hl->ctrl_in.rv_idx); + rm_turbo_rx(&hl->q, hl->input, hl->in_len, hl->output, hl->ctrl_in.S, + hl->ctrl_in.rv_idx); hl->out_len = hl->ctrl_in.S; } return 0; diff --git a/lte/lib/fec/src/tc_interl_lte.c b/lte/lib/fec/src/tc_interl_lte.c index bfaf4232c..0731221b6 100644 --- a/lte/lib/fec/src/tc_interl_lte.c +++ b/lte/lib/fec/src/tc_interl_lte.c @@ -39,56 +39,48 @@ * ************************************************/ -const int f1_list[NOF_TC_CB_SIZES] = { 3, 7, 19, 7, 7, 11, 5, 11, 7, 41, 103, 15, 9, 17, - 9, 21, 101, 21, 57, 23, 13, 27, 11, 27, 85, 29, 33, 15, 17, 33, 103, 19, - 19, 37, 19, 21, 21, 115, 193, 21, 133, 81, 45, 23, 243, 151, 155, 25, - 51, 47, 91, 29, 29, 247, 29, 89, 91, 157, 55, 31, 17, 35, 227, 65, 19, - 37, 41, 39, 185, 43, 21, 155, 79, 139, 23, 217, 25, 17, 127, 25, 239, - 17, 137, 215, 29, 15, 147, 29, 59, 65, 55, 31, 17, 171, 67, 35, 19, 39, - 19, 199, 21, 211, 21, 43, 149, 45, 49, 71, 13, 17, 25, 183, 55, 127, 27, - 29, 29, 57, 45, 31, 59, 185, 113, 31, 17, 171, 209, 253, 367, 265, 181, - 39, 27, 127, 143, 43, 29, 45, 157, 47, 13, 111, 443, 51, 51, 451, 257, - 57, 313, 271, 179, 331, 363, 375, 127, 31, 33, 43, 33, 477, 35, 233, - 357, 337, 37, 71, 71, 37, 39, 127, 39, 39, 31, 113, 41, 251, 43, 21, 43, - 45, 45, 161, 89, 323, 47, 23, 47, 263 }; +const int f1_list[NOF_TC_CB_SIZES] = { 3, 7, 19, 7, 7, 11, 5, 11, 7, 41, 103, + 15, 9, 17, 9, 21, 101, 21, 57, 23, 13, 27, 11, 27, 85, 29, 33, 15, 17, 33, + 103, 19, 19, 37, 19, 21, 21, 115, 193, 21, 133, 81, 45, 23, 243, 151, 155, + 25, 51, 47, 91, 29, 29, 247, 29, 89, 91, 157, 55, 31, 17, 35, 227, 65, 19, + 37, 41, 39, 185, 43, 21, 155, 79, 139, 23, 217, 25, 17, 127, 25, 239, 17, + 137, 215, 29, 15, 147, 29, 59, 65, 55, 31, 17, 171, 67, 35, 19, 39, 19, 199, + 21, 211, 21, 43, 149, 45, 49, 71, 13, 17, 25, 183, 55, 127, 27, 29, 29, 57, + 45, 31, 59, 185, 113, 31, 17, 171, 209, 253, 367, 265, 181, 39, 27, 127, + 143, 43, 29, 45, 157, 47, 13, 111, 443, 51, 51, 451, 257, 57, 313, 271, 179, + 331, 363, 375, 127, 31, 33, 43, 33, 477, 35, 233, 357, 337, 37, 71, 71, 37, + 39, 127, 39, 39, 31, 113, 41, 251, 43, 21, 43, 45, 45, 161, 89, 323, 47, 23, + 47, 263 }; -const int f2_list[NOF_TC_CB_SIZES] = { 10, 12, 42, 16, 18, 20, 22, 24, 26, 84, 90, 32, - 34, 108, 38, 120, 84, 44, 46, 48, 50, 52, 36, 56, 58, 60, 62, 32, 198, - 68, 210, 36, 74, 76, 78, 120, 82, 84, 86, 44, 90, 46, 94, 48, 98, 40, - 102, 52, 106, 72, 110, 168, 114, 58, 118, 180, 122, 62, 84, 64, 66, 68, - 420, 96, 74, 76, 234, 80, 82, 252, 86, 44, 120, 92, 94, 48, 98, 80, 102, - 52, 106, 48, 110, 112, 114, 58, 118, 60, 122, 124, 84, 64, 66, 204, 140, - 72, 74, 76, 78, 240, 82, 252, 86, 88, 60, 92, 846, 48, 28, 80, 102, 104, - 954, 96, 110, 112, 114, 116, 354, 120, 610, 124, 420, 64, 66, 136, 420, - 216, 444, 456, 468, 80, 164, 504, 172, 88, 300, 92, 188, 96, 28, 240, - 204, 104, 212, 192, 220, 336, 228, 232, 236, 120, 244, 248, 168, 64, - 130, 264, 134, 408, 138, 280, 142, 480, 146, 444, 120, 152, 462, 234, - 158, 80, 96, 902, 166, 336, 170, 86, 174, 176, 178, 120, 182, 184, 186, - 94, 190, 480 }; +const int f2_list[NOF_TC_CB_SIZES] = { 10, 12, 42, 16, 18, 20, 22, 24, 26, 84, + 90, 32, 34, 108, 38, 120, 84, 44, 46, 48, 50, 52, 36, 56, 58, 60, 62, 32, + 198, 68, 210, 36, 74, 76, 78, 120, 82, 84, 86, 44, 90, 46, 94, 48, 98, 40, + 102, 52, 106, 72, 110, 168, 114, 58, 118, 180, 122, 62, 84, 64, 66, 68, 420, + 96, 74, 76, 234, 80, 82, 252, 86, 44, 120, 92, 94, 48, 98, 80, 102, 52, 106, + 48, 110, 112, 114, 58, 118, 60, 122, 124, 84, 64, 66, 204, 140, 72, 74, 76, + 78, 240, 82, 252, 86, 88, 60, 92, 846, 48, 28, 80, 102, 104, 954, 96, 110, + 112, 114, 116, 354, 120, 610, 124, 420, 64, 66, 136, 420, 216, 444, 456, + 468, 80, 164, 504, 172, 88, 300, 92, 188, 96, 28, 240, 204, 104, 212, 192, + 220, 336, 228, 232, 236, 120, 244, 248, 168, 64, 130, 264, 134, 408, 138, + 280, 142, 480, 146, 444, 120, 152, 462, 234, 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]; @@ -97,7 +89,7 @@ int tc_interl_LTE_init(tc_interl_t *h, int long_cb) { h->forward[0] = 0; h->reverse[0] = 0; for (i = 1; i < long_cb; i++) { - j = (f1*i + f2*i*i) % (long_cb); + j = (f1 * i + f2 * i * i) % (long_cb); h->forward[i] = j; h->reverse[j] = i; } @@ -105,13 +97,3 @@ int tc_interl_LTE_init(tc_interl_t *h, int long_cb) { } - - - - - - - - - - diff --git a/lte/lib/fec/src/tc_interl_umts.c b/lte/lib/fec/src/tc_interl_umts.c index 635afd761..3699a2d93 100644 --- a/lte/lib/fec/src/tc_interl_umts.c +++ b/lte/lib/fec/src/tc_interl_umts.c @@ -27,11 +27,12 @@ #include #include +#include #include "lte/fec/tc_interl.h" #include "lte/fec/turbocoder.h" -#define TURBO_RATE 3 +#define TURBO_RATE 3 int mcd(int x, int y); @@ -41,16 +42,36 @@ int mcd(int x, int y); * ************************************************/ -#define MAX_ROWS 20 -#define MAX_COLS 256 +#define MAX_ROWS 20 +#define MAX_COLS 256 const unsigned short table_p[52] = { 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, - 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, - 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, - 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257 }; + 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, + 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, + 211, 223, 227, 229, 233, 239, 241, 251, 257 }; 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 }; + 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) { @@ -59,10 +80,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 +95,14 @@ 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 509cef252..895a409b9 100644 --- a/lte/lib/fec/src/turbocoder.c +++ b/lte/lib/fec/src/turbocoder.c @@ -25,110 +25,122 @@ * */ - -#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) { - - char reg1_0,reg1_1,reg1_2, reg2_0,reg2_1,reg2_2; - int i,k=0,j; +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; char bit; - char in,out; + char in, out; int *per; - per=h->interl.forward; - - reg1_0=0; - reg1_1=0; - reg1_2=0; - - reg2_0=0; - reg2_1=0; - reg2_2=0; - - k=0; - for (i=0;ilong_cb;i++) { - bit=input[i]; - - output[k]=bit; - k++; - - in=bit^(reg1_2^reg1_1); - out=reg1_2^(reg1_0^in); + if (long_cb > h->max_long_cb) { + fprintf(stderr, "Turbo coder initiated for max_long_cb=%d\n", + h->max_long_cb); + return -1; + } - reg1_2=reg1_1; - reg1_1=reg1_0; - reg1_0=in; - - output[k]=out; - k++; - - bit=input[per[i]]; - - in=bit^(reg2_2^reg2_1); - out=reg2_2^(reg2_0^in); + if (tc_interl_LTE_gen(&h->interl, long_cb)) { + fprintf(stderr, "Error initiating TC interleaver\n"); + return -1; + } - reg2_2=reg2_1; - reg2_1=reg2_0; - reg2_0=in; - - output[k]=out; + per = h->interl.forward; + + reg1_0 = 0; + reg1_1 = 0; + reg1_2 = 0; + + reg2_0 = 0; + reg2_1 = 0; + reg2_2 = 0; + + k = 0; + for (i = 0; i < long_cb; i++) { + bit = input[i]; + + output[k] = bit; + k++; + + in = bit ^ (reg1_2 ^ reg1_1); + out = reg1_2 ^ (reg1_0 ^ in); + + reg1_2 = reg1_1; + reg1_1 = reg1_0; + reg1_0 = in; + + output[k] = out; + k++; + + bit = input[per[i]]; + + in = bit ^ (reg2_2 ^ reg2_1); + out = reg2_2 ^ (reg2_0 ^ in); + + reg2_2 = reg2_1; + reg2_1 = reg2_0; + reg2_0 = in; + + output[k] = out; k++; } - - k=3*h->long_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,15 +38,15 @@ * 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; - for (i=0;i<8;i++) { + for (i = 0; i < 8; i++) { old[i] = beta[8 * (end) + i]; } @@ -48,7 +74,7 @@ void map_gen_beta(map_gen_t *s, llr_t *input, llr_t *parity) { new[6] = old[3] + xy; new[7] = old[3]; - for (i=0;i<8;i++) { + for (i = 0; i < 8; i++) { if (m_b[i] > new[i]) new[i] = m_b[i]; beta[8 * k + i] = new[i]; @@ -57,18 +83,19 @@ 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; old[0] = 0; - for (i=1;i<8;i++) { + for (i = 1; i < 8; i++) { old[i] = -INF; } @@ -96,7 +123,7 @@ void map_gen_alpha(map_gen_t *s, llr_t *input, llr_t *parity, llr_t *output) { new[6] = old[4] + x; new[7] = old[7] + xy; - for (i=0;i<8;i++) { + for (i = 0; i < 8; i++) { max0[i] = m_b[i] + beta[8 * k + i]; max1[i] = new[i] + beta[8 * k + i]; } @@ -104,14 +131,14 @@ void map_gen_alpha(map_gen_t *s, llr_t *input, llr_t *parity, llr_t *output) { m1 = max1[0]; m0 = max0[0]; - for (i=1;i<8;i++) { + for (i = 1; i < 8; i++) { if (max1[i] > m1) m1 = max1[i]; if (max0[i] > m0) m0 = max0[i]; } - for (i=0;i<8;i++) { + for (i = 0; i < 8; i++) { if (m_b[i] > new[i]) new[i] = m_b[i]; old[i] = new[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,34 +167,29 @@ 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); } - - - - - - - - /************************************************ * * 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,19 +217,16 @@ 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; } ret = 0; -clean_and_exit: - if (ret == -1) { + clean_and_exit: if (ret == -1) { tdec_free(h); } return ret; @@ -237,63 +256,73 @@ 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; i < long_cb + RATE; i++) { + h->syst[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++) { - h->syst[i] = h->llr1[h->interleaver.forward[i]] - h->w[h->interleaver.forward[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; i < long_cb + RATE; i++) { + h->syst[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/CMakeLists.txt b/lte/lib/fec/test/CMakeLists.txt index 1d0cc28bb..9cafc646f 100644 --- a/lte/lib/fec/test/CMakeLists.txt +++ b/lte/lib/fec/test/CMakeLists.txt @@ -32,6 +32,11 @@ TARGET_LINK_LIBRARIES(rm_turbo_test lte) ADD_TEST(rm_conv_test_1 rm_conv_test -t 480 -r 1920) ADD_TEST(rm_conv_test_2 rm_conv_test -t 1920 -r 480) + +ADD_TEST(rm_turbo_test_1 rm_turbo_test -t 480 -r 1920 -i 0) +ADD_TEST(rm_turbo_test_2 rm_turbo_test -t 1920 -r 480 -i 1) +ADD_TEST(rm_turbo_test_1 rm_turbo_test -t 480 -r 1920 -i 2) +ADD_TEST(rm_turbo_test_2 rm_turbo_test -t 1920 -r 480 -i 3) ######################################################################## diff --git a/lte/lib/fec/test/rm_turbo_test.c b/lte/lib/fec/test/rm_turbo_test.c index f76109f68..872b91ba8 100644 --- a/lte/lib/fec/test/rm_turbo_test.c +++ b/lte/lib/fec/test/rm_turbo_test.c @@ -36,7 +36,7 @@ #include "lte.h" -int nof_tx_bits=-1, nof_rx_bits=-1; +int nof_tx_bits = -1, nof_rx_bits = -1; int rv_idx = 0; void usage(char *prog) { @@ -101,25 +101,25 @@ int main(int argc, char **argv) { exit(-1); } - for (i=0;i 0) != bits[i]) { + for (i = 0; i < nof_tx_bits; i++) { + if (unrm_symbols[i] > 0 && ((unrm_symbols[i] > 0) != bits[i])) { nof_errors++; - printf("%.2f != %d\n", unrm_symbols[i], bits[i]); } } @@ -130,11 +130,9 @@ int main(int argc, char **argv) { free(rm_symbols); free(unrm_symbols); - if (nof_tx_bits >= nof_rx_bits) { - if (nof_errors) { - printf("nof_errors=%d\n", nof_errors); - exit(-1); - } + if (nof_errors) { + printf("nof_errors=%d\n", nof_errors); + exit(-1); } printf("Ok\n"); diff --git a/lte/lib/fec/test/turbocoder_test.c b/lte/lib/fec/test/turbocoder_test.c index d7bcdae3e..352e02877 100644 --- a/lte/lib/fec/test/turbocoder_test.c +++ b/lte/lib/fec/test/turbocoder_test.c @@ -41,23 +41,24 @@ typedef _Complex float cf_t; -int frame_length = 1000, nof_frames=100; +int frame_length = 1000, nof_frames = 100; float ebno_db = 100.0; unsigned int seed = 0; int K = -1; -#define MAX_ITERATIONS 4 +#define MAX_ITERATIONS 4 int nof_iterations = MAX_ITERATIONS; int test_known_data = 0; int test_errors = 0; -#define SNR_POINTS 8 -#define SNR_MIN 0.0 -#define SNR_MAX 4.0 +#define SNR_POINTS 8 +#define SNR_MIN 0.0 +#define SNR_MAX 4.0 void usage(char *prog) { printf("Usage: %s [nlesv]\n", prog); - printf("\t-k Test with known data (ignores frame_length) [Default disabled]\n"); + printf( + "\t-k Test with known data (ignores frame_length) [Default disabled]\n"); printf("\t-i nof_iterations [Default %d]\n", nof_iterations); printf("\t-n nof_frames [Default %d]\n", nof_frames); printf("\t-l frame_length [Default %d]\n", frame_length); @@ -109,7 +110,7 @@ void output_matlab(float ber[MAX_ITERATIONS][SNR_POINTS], int snr_points) { exit(-1); } fprintf(f, "ber=["); - for (j=0;j known_data_errors[j]) { fprintf(stderr, "Expected %d errors but got %d\n", known_data_errors[j], errors[j]); exit(-1); - }else { - printf("Iter %d ok\n", j+1); + } else { + printf("Iter %d ok\n", j + 1); } } } else { - for (j=0;j get_expected_errors(frame_cnt, seed, j+1, frame_length, ebno_db)) { + if (errors[j] + > get_expected_errors(frame_cnt, seed, j + 1, frame_length, + ebno_db)) { fprintf(stderr, "Expected %d errors but got %d\n", - get_expected_errors(frame_cnt, seed, j+1, frame_length, ebno_db), - errors[j]); + get_expected_errors(frame_cnt, seed, j + 1, frame_length, + ebno_db), errors[j]); exit(-1); } else { - printf("Iter %d ok\n", j+1); + printf("Iter %d ok\n", j + 1); } } } diff --git a/lte/lib/mimo/src/precoding.c b/lte/lib/mimo/src/precoding.c index f6ed753aa..0d570abd7 100644 --- a/lte/lib/mimo/src/precoding.c +++ b/lte/lib/mimo/src/precoding.c @@ -25,8 +25,6 @@ * */ - - #include #include #include @@ -41,42 +39,43 @@ int precoding_single(cf_t *x, cf_t *y, int nof_symbols) { memcpy(y, x, nof_symbols * sizeof(cf_t)); return nof_symbols; } -int precoding_diversity(cf_t *x[MAX_LAYERS], cf_t *y[MAX_PORTS], int nof_ports, int nof_symbols) { +int precoding_diversity(cf_t *x[MAX_LAYERS], cf_t *y[MAX_PORTS], int nof_ports, + int nof_symbols) { int i; if (nof_ports == 2) { /* FIXME: Use VOLK here */ - for (i=0;i MAX_PORTS) { - fprintf(stderr, "Maximum number of ports is %d (nof_ports=%d)\n", MAX_PORTS, nof_ports); + fprintf(stderr, "Maximum number of ports is %d (nof_ports=%d)\n", MAX_PORTS, + nof_ports); return -1; } if (nof_layers > MAX_LAYERS) { - fprintf(stderr, "Maximum number of layers is %d (nof_layers=%d)\n", MAX_LAYERS, nof_layers); + fprintf(stderr, "Maximum number of layers is %d (nof_layers=%d)\n", + MAX_LAYERS, nof_layers); return -1; } - switch(type) { + switch (type) { case SINGLE_ANTENNA: if (nof_ports == 1 && nof_layers == 1) { return precoding_single(x[0], y[0], nof_symbols); } else { - fprintf(stderr, "Number of ports and layers must be 1 for transmission on single antenna ports\n"); + fprintf(stderr, + "Number of ports and layers must be 1 for transmission on single antenna ports\n"); return -1; } break; @@ -109,7 +111,8 @@ int precoding_type(cf_t *x[MAX_LAYERS], cf_t *y[MAX_PORTS], int nof_layers, int if (nof_ports == nof_layers) { return precoding_diversity(x, y, nof_ports, nof_symbols); } else { - fprintf(stderr, "Error number of layers must equal number of ports in transmit diversity\n"); + fprintf(stderr, + "Error number of layers must equal number of ports in transmit diversity\n"); return -1; } case SPATIAL_MULTIPLEX: @@ -119,7 +122,6 @@ int precoding_type(cf_t *x[MAX_LAYERS], cf_t *y[MAX_PORTS], int nof_layers, int return 0; } - /* ZF detector */ int predecoding_single_zf(cf_t *y, cf_t *ce, cf_t *x, int nof_symbols) { vec_div_ccc(y, ce, x, nof_symbols); @@ -127,45 +129,45 @@ int predecoding_single_zf(cf_t *y, cf_t *ce, cf_t *x, int nof_symbols) { } /* ZF detector */ -int predecoding_diversity_zf(cf_t *y[MAX_PORTS], cf_t *ce[MAX_PORTS], - cf_t *x[MAX_LAYERS], int nof_ports, int nof_symbols) { +int predecoding_diversity_zf(cf_t *y, cf_t *ce[MAX_PORTS], cf_t *x[MAX_LAYERS], + int nof_ports, int nof_symbols) { int i; cf_t h0, h1, h2, h3, r0, r1, r2, r3; float hh, hh02, hh13; if (nof_ports == 2) { /* TODO: Use VOLK here */ - for (i=0;i MAX_PORTS) { - fprintf(stderr, "Maximum number of ports is %d (nof_ports=%d)\n", MAX_PORTS, nof_ports); + fprintf(stderr, "Maximum number of ports is %d (nof_ports=%d)\n", MAX_PORTS, + nof_ports); return -1; } if (nof_layers > MAX_LAYERS) { - fprintf(stderr, "Maximum number of layers is %d (nof_layers=%d)\n", MAX_LAYERS, nof_layers); + fprintf(stderr, "Maximum number of layers is %d (nof_layers=%d)\n", + MAX_LAYERS, nof_layers); return -1; } - - switch(type) { + switch (type) { case SINGLE_ANTENNA: if (nof_ports == 1 && nof_layers == 1) { - return predecoding_single_zf(y[0], 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 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; } break; @@ -202,7 +206,8 @@ int predecoding_type(cf_t *y[MAX_PORTS], cf_t *ce[MAX_PORTS], if (nof_ports == nof_layers) { return predecoding_diversity_zf(y, ce, x, nof_ports, nof_symbols); } else { - fprintf(stderr, "Error number of layers must equal number of ports in transmit diversity\n"); + fprintf(stderr, + "Error number of layers must equal number of ports in transmit diversity\n"); return -1; } break; diff --git a/lte/lib/mimo/test/precoding_test.c b/lte/lib/mimo/test/precoding_test.c index 67d8dcdf2..4a39db9c5 100644 --- a/lte/lib/mimo/test/precoding_test.c +++ b/lte/lib/mimo/test/precoding_test.c @@ -36,14 +36,16 @@ #include "lte.h" -#define MSE_THRESHOLD 0.00001 +#define MSE_THRESHOLD 0.00001 int nof_symbols = 1000; int nof_layers = 1, nof_ports = 1; char *mimo_type_name = NULL; void usage(char *prog) { - printf("Usage: %s -m [single|diversity|multiplex] -l [nof_layers] -p [nof_ports]\n", prog); + printf( + "Usage: %s -m [single|diversity|multiplex] -l [nof_layers] -p [nof_ports]\n", + prog); printf("\t-n num_symbols [Default %d]\n", nof_symbols); } @@ -77,7 +79,8 @@ void parse_args(int argc, char **argv) { int main(int argc, char **argv) { int i, j; float mse; - cf_t *x[MAX_LAYERS], *r[MAX_PORTS], *y[MAX_PORTS], *h[MAX_PORTS], *xr[MAX_LAYERS]; + cf_t *x[MAX_LAYERS], *r[MAX_PORTS], *y[MAX_PORTS], *h[MAX_PORTS], + *xr[MAX_LAYERS]; lte_mimo_type_t type; parse_args(argc, argv); @@ -92,7 +95,7 @@ int main(int argc, char **argv) { exit(-1); } - for (i=0;i #include #include @@ -59,12 +58,12 @@ void dci_free(dci_t *q) { } void dci_candidate_fprint(FILE *f, dci_candidate_t *q) { - fprintf(f, "L: %d, nCCE: %d, RNTI: 0x%x, nBits: %d\n", - q->L, q->ncce, q->rnti, q->nof_bits); + fprintf(f, "L: %d, nCCE: %d, RNTI: 0x%x, nBits: %d\n", q->L, q->ncce, q->rnti, + q->nof_bits); } int dci_msg_candidate_set(dci_msg_t *msg, int L, int nCCE, unsigned short rnti) { - if (L >= 0 && L <=3) { + if (L >= 0 && L <= 3) { msg->location.L = (unsigned char) L; } else { fprintf(stderr, "Invalid L %d\n", L); @@ -81,14 +80,14 @@ int dci_msg_candidate_set(dci_msg_t *msg, int L, int nCCE, unsigned short rnti) } int riv_nbits(int nof_prb) { - return (int) ceilf(log2f((float) nof_prb*((float) nof_prb+1)/2)); + return (int) ceilf(log2f((float) nof_prb * ((float) nof_prb + 1) / 2)); } -const int ambiguous_sizes[10] = {12, 14, 16, 20, 24, 26, 32, 40, 44, 56}; +const int ambiguous_sizes[10] = { 12, 14, 16, 20, 24, 26, 32, 40, 44, 56 }; bool is_ambiguous_size(int size) { int i; - for (i=0;i<10;i++) { + for (i = 0; i < 10; i++) { if (size == ambiguous_sizes[i]) { return true; } @@ -96,20 +95,17 @@ bool is_ambiguous_size(int size) { return false; } - - /********************************** * PAYLOAD sizeof functions * ********************************/ int dci_format0_sizeof_(int nof_prb) { - return 1+1+riv_nbits(nof_prb)+5+1+2+3+1; + return 1 + 1 + riv_nbits(nof_prb) + 5 + 1 + 2 + 3 + 1; } - int dci_format1A_sizeof(int nof_prb) { int n; - n = 1+1+riv_nbits(nof_prb)+5+3+1+2+2; - while(n < dci_format0_sizeof_(nof_prb)) { + n = 1 + 1 + riv_nbits(nof_prb) + 5 + 3 + 1 + 2 + 2; + while (n < dci_format0_sizeof_(nof_prb)) { n++; } if (is_ambiguous_size(n)) { @@ -118,7 +114,6 @@ int dci_format1A_sizeof(int nof_prb) { return n; } - int dci_format0_sizeof(int nof_prb) { int n = dci_format0_sizeof_(nof_prb); while (n < dci_format1A_sizeof(nof_prb)) { @@ -129,12 +124,12 @@ int dci_format0_sizeof(int nof_prb) { int dci_format1_sizeof(int nof_prb) { - int n = (int) ceilf((float) nof_prb/ra_type0_P(nof_prb))+5+3+1+2+2; + int n = (int) ceilf((float) nof_prb / ra_type0_P(nof_prb)) + 5 + 3 + 1 + 2 + + 2; if (nof_prb > 10) { n++; } - while(n == dci_format0_sizeof(nof_prb) - || n == dci_format1A_sizeof(nof_prb) + while (n == dci_format0_sizeof(nof_prb) || n == dci_format1A_sizeof(nof_prb) || is_ambiguous_size(n)) { n++; } @@ -144,7 +139,7 @@ int dci_format1_sizeof(int nof_prb) { int dci_format1C_sizeof(int nof_prb) { int n_vrb_dl_gap1 = ra_type2_n_vrb_dl(nof_prb, true); int n_step = ra_type2_n_rb_step(nof_prb); - int n = + riv_nbits((int) n_vrb_dl_gap1/n_step) + 5; + int n = +riv_nbits((int) n_vrb_dl_gap1 / n_step) + 5; if (nof_prb >= 50) { n++; } @@ -152,7 +147,7 @@ int dci_format1C_sizeof(int nof_prb) { } int dci_format_sizeof(dci_format_t format, int nof_prb) { - switch(format) { + switch (format) { case Format0: return dci_format0_sizeof(nof_prb); case Format1: @@ -166,13 +161,10 @@ int dci_format_sizeof(dci_format_t format, int nof_prb) { } } - - /********************************** * DCI Resource Allocation functions * ********************************/ - /* Packs DCI format 0 data to a sequence of bits and store them in msg according * to 36.212 5.3.3.1.1 * @@ -203,7 +195,8 @@ int dci_format0_pack(ra_pusch_t *data, dci_msg_t *msg, int nof_prb) { /* pack RIV according to 8.1 of 36.213 */ uint32_t riv; if (data->type2_alloc.L_crb) { - riv = ra_type2_to_riv(data->type2_alloc.L_crb, data->type2_alloc.RB_start, nof_prb); + riv = ra_type2_to_riv(data->type2_alloc.L_crb, data->type2_alloc.RB_start, + nof_prb); } else { riv = data->type2_alloc.riv; } @@ -222,7 +215,8 @@ int dci_format0_pack(ra_pusch_t *data, dci_msg_t *msg, int nof_prb) { } else { if (data->mcs.tbs) { if (data->mcs.tbs) { - data->mcs.tbs_idx = ra_tbs_to_table_idx(data->mcs.tbs, ra_nprb_ul(data, nof_prb)); + data->mcs.tbs_idx = ra_tbs_to_table_idx(data->mcs.tbs, + ra_nprb_ul(data, nof_prb)); } } mcs = ra_mcs_to_table_idx(&data->mcs); @@ -248,7 +242,7 @@ int dci_format0_pack(ra_pusch_t *data, dci_msg_t *msg, int nof_prb) { // Padding with zeros int n = dci_format0_sizeof(nof_prb); - while (y-msg->data < n) { + while (y - msg->data < n) { *y++ = 0; } msg->location.nof_bits = (y - msg->data); @@ -271,7 +265,8 @@ int dci_format0_unpack(dci_msg_t *msg, ra_pusch_t *data, int nof_prb) { return -1; } if (*y++ != 0) { - fprintf(stderr, "Invalid format differentiation field value. This is Format1A\n"); + fprintf(stderr, + "Invalid format differentiation field value. This is Format1A\n"); return -1; } if (*y++ == 0) { @@ -283,36 +278,38 @@ int dci_format0_unpack(dci_msg_t *msg, ra_pusch_t *data, int nof_prb) { data->freq_hop_fl = *y++; } else { n_ul_hop = 2; // Table 8.4-1 of 36.213 - data->freq_hop_fl = y[0]<<1 | y[1]; + data->freq_hop_fl = y[0] << 1 | y[1]; y += 2; } } /* unpack RIV according to 8.1 of 36.213 */ uint32_t riv = bit_unpack(&y, riv_nbits(nof_prb) - n_ul_hop); - ra_type2_from_riv(riv, &data->type2_alloc.L_crb, &data->type2_alloc.RB_start, nof_prb, nof_prb); + ra_type2_from_riv(riv, &data->type2_alloc.L_crb, &data->type2_alloc.RB_start, + nof_prb, nof_prb); bit_pack(riv, &y, riv_nbits(nof_prb) - n_ul_hop); data->type2_alloc.riv = riv; /* unpack MCS according to 8.6 of 36.213 */ uint32_t mcs = bit_unpack(&y, 5); - data->ndi = *y++?true:false; + data->ndi = *y++ ? true : false; // TCP and DM RS commands not implemented - y+= 5; + y += 5; // CQI request - data->cqi_request = *y++?true:false; + data->cqi_request = *y++ ? true : false; // 8.6.2 First paragraph if (mcs <= 28) { ra_mcs_from_idx_ul(mcs, &data->mcs); - data->mcs.tbs = ra_tbs_from_idx(data->mcs.tbs_idx, ra_nprb_ul(data, nof_prb)); + data->mcs.tbs = ra_tbs_from_idx(data->mcs.tbs_idx, + ra_nprb_ul(data, nof_prb)); } // 8.6.1 and 8.6.2 36.213 second paragraph if (mcs == 29 && data->cqi_request && ra_nprb_ul(data, nof_prb) <= 4) { - data->mcs.mod = QPSK; + data->mcs.mod = QPSK; } if (mcs > 29) { // Else leave MOD_NULL and use the previously used PUSCH modulation @@ -340,18 +337,20 @@ int dci_format1_pack(ra_pdsch_t *data, dci_msg_t *msg, int nof_prb) { /* Resource allocation: type0 or type 1 */ int P = ra_type0_P(nof_prb); - int alloc_size = (int) ceilf((float) nof_prb/P); - switch(data->alloc_type) { + int alloc_size = (int) ceilf((float) nof_prb / P); + switch (data->alloc_type) { case alloc_type0: bit_pack(data->type0_alloc.rbg_bitmask, &y, alloc_size); break; case alloc_type1: bit_pack(data->type1_alloc.rbg_subset, &y, (int) ceilf(log2f(P))); - *y++ = data->type1_alloc.shift?1:0; - bit_pack(data->type1_alloc.vrb_bitmask, &y, alloc_size - (int) ceilf(log2f(P)) - 1); + *y++ = data->type1_alloc.shift ? 1 : 0; + bit_pack(data->type1_alloc.vrb_bitmask, &y, + alloc_size - (int) ceilf(log2f(P)) - 1); break; default: - fprintf(stderr, "Format 1 accepts type0 or type1 resource allocation only\n"); + fprintf(stderr, + "Format 1 accepts type0 or type1 resource allocation only\n"); return -1; } @@ -361,7 +360,8 @@ int dci_format1_pack(ra_pdsch_t *data, dci_msg_t *msg, int nof_prb) { mcs = data->mcs.mcs_idx; } else { if (data->mcs.tbs) { - data->mcs.tbs_idx = ra_tbs_to_table_idx(data->mcs.tbs, ra_nprb_dl(data, nof_prb)); + data->mcs.tbs_idx = ra_tbs_to_table_idx(data->mcs.tbs, + ra_nprb_dl(data, nof_prb)); } mcs = ra_mcs_to_table_idx(&data->mcs); } @@ -381,7 +381,7 @@ int dci_format1_pack(ra_pdsch_t *data, dci_msg_t *msg, int nof_prb) { // Padding with zeros int n = dci_format1_sizeof(nof_prb); - while (y-msg->data < n) { + while (y - msg->data < n) { *y++ = 0; } msg->location.nof_bits = (y - msg->data); @@ -408,18 +408,20 @@ int dci_format1_unpack(dci_msg_t *msg, ra_pdsch_t *data, int nof_prb) { /* Resource allocation: type0 or type 1 */ int P = ra_type0_P(nof_prb); - int alloc_size = (int) ceilf((float) nof_prb/P); - switch(data->alloc_type) { + int alloc_size = (int) ceilf((float) nof_prb / P); + switch (data->alloc_type) { case alloc_type0: data->type0_alloc.rbg_bitmask = bit_unpack(&y, alloc_size); break; case alloc_type1: data->type1_alloc.rbg_subset = bit_unpack(&y, (int) ceilf(log2f(P))); - data->type1_alloc.shift = *y++?true:false; - data->type1_alloc.vrb_bitmask = bit_unpack(&y, alloc_size - (int) ceilf(log2f(P)) - 1); + data->type1_alloc.shift = *y++ ? true : false; + data->type1_alloc.vrb_bitmask = bit_unpack(&y, + alloc_size - (int) ceilf(log2f(P)) - 1); break; default: - fprintf(stderr, "Format 1 accepts type0 or type1 resource allocation only\n"); + fprintf(stderr, + "Format 1 accepts type0 or type1 resource allocation only\n"); return -1; } @@ -432,23 +434,22 @@ int dci_format1_unpack(dci_msg_t *msg, ra_pdsch_t *data, int nof_prb) { /* harq process number */ data->harq_process = bit_unpack(&y, 3); - data->ndi = *y++?true:false; + data->ndi = *y++ ? true : false; // rv version data->rv_idx = bit_unpack(&y, 2); // TPC not implemented - return 0; } - /* Packs DCI format 1A for compact scheduling of PDSCH words according to 36.212 5.3.3.1.3 * * TODO: RA procedure initiated by PDCCH, TPC commands */ -int dci_format1As_pack(ra_pdsch_t *data, dci_msg_t *msg, int nof_prb, bool crc_is_crnti) { +int dci_format1As_pack(ra_pdsch_t *data, dci_msg_t *msg, int nof_prb, + bool crc_is_crnti) { /* pack bits */ char *y = msg->data; @@ -464,7 +465,8 @@ int dci_format1As_pack(ra_pdsch_t *data, dci_msg_t *msg, int nof_prb, bool crc_i if (data->type2_alloc.mode == t2_loc) { if (data->type2_alloc.L_crb > nof_prb) { - fprintf(stderr, "L_CRB=%d can not exceed system BW for localized type2\n", data->type2_alloc.L_crb); + fprintf(stderr, "L_CRB=%d can not exceed system BW for localized type2\n", + data->type2_alloc.L_crb); return -1; } } else { @@ -472,17 +474,20 @@ int dci_format1As_pack(ra_pdsch_t *data, dci_msg_t *msg, int nof_prb, bool crc_i if (crc_is_crnti && nof_prb > 50) { n_vrb_dl = 16; } else { - n_vrb_dl = ra_type2_n_vrb_dl(nof_prb, data->type2_alloc.n_gap==t2_ng1); + n_vrb_dl = ra_type2_n_vrb_dl(nof_prb, data->type2_alloc.n_gap == t2_ng1); } if (data->type2_alloc.L_crb > n_vrb_dl) { - fprintf(stderr, "L_CRB=%d can not exceed N_vrb_dl=%d for distributed type2\n", data->type2_alloc.L_crb, n_vrb_dl); + fprintf(stderr, + "L_CRB=%d can not exceed N_vrb_dl=%d for distributed type2\n", + data->type2_alloc.L_crb, n_vrb_dl); return -1; } } /* pack RIV according to 7.1.6.3 of 36.213 */ uint32_t riv; if (data->type2_alloc.L_crb) { - riv = ra_type2_to_riv(data->type2_alloc.L_crb, data->type2_alloc.RB_start, nof_prb); + riv = ra_type2_to_riv(data->type2_alloc.L_crb, data->type2_alloc.RB_start, + nof_prb); } else { riv = data->type2_alloc.riv; } @@ -491,7 +496,7 @@ int dci_format1As_pack(ra_pdsch_t *data, dci_msg_t *msg, int nof_prb, bool crc_i nb_gap = 1; *y++ = data->type2_alloc.n_gap; } - bit_pack(riv, &y, riv_nbits(nof_prb)-nb_gap); + bit_pack(riv, &y, riv_nbits(nof_prb) - nb_gap); // in format1A, MCS = TBS according to 7.1.7.2 of 36.213 uint32_t mcs; @@ -504,7 +509,7 @@ int dci_format1As_pack(ra_pdsch_t *data, dci_msg_t *msg, int nof_prb, bool crc_i if (!crc_is_crnti) { n_prb = ra_nprb_dl(data, nof_prb); } else { - n_prb = data->type2_alloc.n_prb1a==nprb1a_2?2:3; + n_prb = data->type2_alloc.n_prb1a == nprb1a_2 ? 2 : 3; } data->mcs.tbs_idx = ra_tbs_to_table_idx(data->mcs.tbs, n_prb); } @@ -534,7 +539,7 @@ int dci_format1As_pack(ra_pdsch_t *data, dci_msg_t *msg, int nof_prb, bool crc_i // Padding with zeros int n = dci_format1A_sizeof(nof_prb); - while (y-msg->data < n) { + while (y - msg->data < n) { *y++ = 0; } msg->location.nof_bits = (y - msg->data); @@ -545,7 +550,8 @@ int dci_format1As_pack(ra_pdsch_t *data, dci_msg_t *msg, int nof_prb, bool crc_i /* Unpacks DCI format 1A for compact scheduling of PDSCH words according to 36.212 5.3.3.1.3 * */ -int dci_format1As_unpack(dci_msg_t *msg, ra_pdsch_t *data, int nof_prb, bool crc_is_crnti) { +int dci_format1As_unpack(dci_msg_t *msg, ra_pdsch_t *data, int nof_prb, + bool crc_is_crnti) { /* pack bits */ char *y = msg->data; @@ -555,8 +561,10 @@ 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"); + fprintf(stderr, + "Invalid format differentiation field value. This is Format0\n"); return -1; } @@ -579,7 +587,8 @@ int dci_format1As_unpack(dci_msg_t *msg, ra_pdsch_t *data, int nof_prb, bool crc nof_vrb = ra_type2_n_vrb_dl(nof_prb, data->type2_alloc.n_gap == t2_ng1); } uint32_t riv = bit_unpack(&y, riv_nbits(nof_prb) - nb_gap); - ra_type2_from_riv(riv, &data->type2_alloc.L_crb, &data->type2_alloc.RB_start, nof_prb, nof_vrb); + ra_type2_from_riv(riv, &data->type2_alloc.L_crb, &data->type2_alloc.RB_start, + nof_prb, nof_vrb); data->type2_alloc.riv = riv; // unpack MCS @@ -602,14 +611,14 @@ 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; if (crc_is_crnti) { n_prb = ra_nprb_dl(data, nof_prb); } else { - n_prb = data->type2_alloc.n_prb1a==nprb1a_2?2:3; + n_prb = data->type2_alloc.n_prb1a == nprb1a_2 ? 2 : 3; } data->mcs.tbs = ra_tbs_from_idx(data->mcs.tbs_idx, n_prb); data->mcs.mod = QPSK; @@ -626,7 +635,8 @@ int dci_format1Cs_pack(ra_pdsch_t *data, dci_msg_t *msg, int nof_prb) { char *y = msg->data; if (data->alloc_type != alloc_type2 || data->type2_alloc.mode != t2_dist) { - fprintf(stderr, "Format 1C accepts distributed type2 resource allocation only\n"); + fprintf(stderr, + "Format 1C accepts distributed type2 resource allocation only\n"); return -1; } @@ -634,11 +644,12 @@ int dci_format1Cs_pack(ra_pdsch_t *data, dci_msg_t *msg, int nof_prb) { *y++ = data->type2_alloc.n_gap; } int n_step = ra_type2_n_rb_step(nof_prb); - int n_vrb_dl = ra_type2_n_vrb_dl(nof_prb, data->type2_alloc.n_gap==t2_ng1); + int n_vrb_dl = ra_type2_n_vrb_dl(nof_prb, data->type2_alloc.n_gap == t2_ng1); - if (data->type2_alloc.L_crb > ((int) n_vrb_dl/n_step)*n_step) { - fprintf(stderr, "L_CRB=%d can not exceed N_vrb_dl=%d for distributed type2\n", data->type2_alloc.L_crb, - ((int) n_vrb_dl/n_step)*n_step); + if (data->type2_alloc.L_crb > ((int) n_vrb_dl / n_step) * n_step) { + fprintf(stderr, + "L_CRB=%d can not exceed N_vrb_dl=%d for distributed type2\n", + data->type2_alloc.L_crb, ((int) n_vrb_dl / n_step) * n_step); return -1; } if (data->type2_alloc.L_crb % n_step) { @@ -649,8 +660,8 @@ int dci_format1Cs_pack(ra_pdsch_t *data, dci_msg_t *msg, int nof_prb) { fprintf(stderr, "RB_start must be multiple of n_step\n"); return -1; } - int L_p = data->type2_alloc.L_crb/n_step; - int RB_p = data->type2_alloc.RB_start/n_step; + int L_p = data->type2_alloc.L_crb / n_step; + int RB_p = data->type2_alloc.RB_start / n_step; int n_vrb_p = (int) n_vrb_dl / n_step; uint32_t riv; @@ -659,7 +670,7 @@ int dci_format1Cs_pack(ra_pdsch_t *data, dci_msg_t *msg, int nof_prb) { } else { riv = data->type2_alloc.riv; } - bit_pack(riv, &y, riv_nbits((int) n_vrb_dl/n_step)); + bit_pack(riv, &y, riv_nbits((int) n_vrb_dl / n_step)); // in format1C, MCS = TBS according to 7.1.7.2 of 36.213 uint32_t mcs; @@ -694,9 +705,9 @@ int dci_format1Cs_unpack(dci_msg_t *msg, ra_pdsch_t *data, int nof_prb) { data->type2_alloc.n_gap = *y++; } int n_step = ra_type2_n_rb_step(nof_prb); - int n_vrb_dl = ra_type2_n_vrb_dl(nof_prb, data->type2_alloc.n_gap==t2_ng1); + int n_vrb_dl = ra_type2_n_vrb_dl(nof_prb, data->type2_alloc.n_gap == t2_ng1); - uint32_t riv = bit_unpack(&y, riv_nbits((int) n_vrb_dl/n_step)); + uint32_t riv = bit_unpack(&y, riv_nbits((int) n_vrb_dl / n_step)); int n_vrb_p = (int) n_vrb_dl / n_step; ra_type2_from_riv(riv, &L_p, &RB_p, n_vrb_p, n_vrb_p); @@ -714,8 +725,9 @@ int dci_format1Cs_unpack(dci_msg_t *msg, ra_pdsch_t *data, int nof_prb) { return 0; } -int dci_msg_pack_pdsch(ra_pdsch_t *data, dci_msg_t *msg, dci_format_t format, int nof_prb, bool crc_is_crnti) { - switch(format) { +int dci_msg_pack_pdsch(ra_pdsch_t *data, dci_msg_t *msg, dci_format_t format, + int nof_prb, bool crc_is_crnti) { + switch (format) { case Format1: return dci_format1_pack(data, msg, nof_prb); case Format1A: @@ -723,12 +735,14 @@ int dci_msg_pack_pdsch(ra_pdsch_t *data, dci_msg_t *msg, dci_format_t format, in case Format1C: return dci_format1Cs_pack(data, msg, nof_prb); default: - fprintf(stderr, "Invalid DCI format %s for PDSCH resource allocation\n", dci_format_string(format)); + fprintf(stderr, "Invalid DCI format %s for PDSCH resource allocation\n", + dci_format_string(format)); return -1; } } -int dci_msg_unpack_pdsch(dci_msg_t *msg, ra_pdsch_t *data, int nof_prb, bool crc_is_crnti) { +int dci_msg_unpack_pdsch(dci_msg_t *msg, ra_pdsch_t *data, int nof_prb, + bool crc_is_crnti) { if (msg->location.nof_bits == dci_format_sizeof(Format1, nof_prb)) { return dci_format1_unpack(msg, data, nof_prb); } else if (msg->location.nof_bits == dci_format_sizeof(Format1A, nof_prb)) { @@ -749,7 +763,7 @@ int dci_msg_unpack_pusch(dci_msg_t *msg, ra_pusch_t *data, int nof_prb) { } char* dci_format_string(dci_format_t format) { - switch(format) { + switch (format) { case Format0: return "Format0"; case Format1: @@ -764,26 +778,28 @@ char* dci_format_string(dci_format_t format) { } void dci_msg_type_fprint(FILE *f, dci_msg_type_t type) { - switch(type.type) { + switch (type.type) { case PUSCH_SCHED: - fprintf(f,"%s PUSCH Scheduling\n", dci_format_string(type.format)); + fprintf(f, "%s PUSCH Scheduling\n", dci_format_string(type.format)); break; case PDSCH_SCHED: - fprintf(f,"%s PDSCH Scheduling\n", dci_format_string(type.format)); + fprintf(f, "%s PDSCH Scheduling\n", dci_format_string(type.format)); break; case RA_PROC_PDCCH: - fprintf(f,"%s Random access initiated by PDCCH\n", dci_format_string(type.format)); + fprintf(f, "%s Random access initiated by PDCCH\n", + dci_format_string(type.format)); break; case MCCH_CHANGE: - fprintf(f,"%s MCCH change notification\n", dci_format_string(type.format)); + fprintf(f, "%s MCCH change notification\n", dci_format_string(type.format)); break; case TPC_COMMAND: - fprintf(f,"%s TPC command\n", dci_format_string(type.format)); + fprintf(f, "%s TPC command\n", dci_format_string(type.format)); break; } } -int dci_msg_get_type(dci_msg_t *msg, dci_msg_type_t *type, int nof_prb, unsigned short crnti) { +int dci_msg_get_type(dci_msg_t *msg, dci_msg_type_t *type, int nof_prb, + unsigned short crnti) { if (msg->location.nof_bits == dci_format_sizeof(Format0, nof_prb) && !msg->data[0]) { type->type = PUSCH_SCHED; diff --git a/lte/lib/phch/src/pbch.c b/lte/lib/phch/src/pbch.c index 4b1671b7d..ba3059e6c 100644 --- a/lte/lib/phch/src/pbch.c +++ b/lte/lib/phch/src/pbch.c @@ -25,7 +25,6 @@ * */ - #include #include #include @@ -43,18 +42,16 @@ #include "lte/utils/debug.h" const char crc_mask[4][16] = { - {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, - {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}, - {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, - {0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1} -}; - + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0 }, { 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1 } }; bool pbch_exists(int nframe, int nslot) { return (!(nframe % 5) && nslot == 1); } -int pbch_cp(cf_t *input, cf_t *output, int nof_prb, lte_cp_t cp, int cell_id, bool put) { +int pbch_cp(cf_t *input, cf_t *output, int nof_prb, lte_cp_t cp, int cell_id, + bool put) { int i; cf_t *ptr; assert(cell_id >= 0); @@ -67,17 +64,17 @@ int pbch_cp(cf_t *input, cf_t *output, int nof_prb, lte_cp_t cp, int cell_id, bo } /* symbol 0 & 1 */ - for (i=0;i<2;i++) { - prb_cp_ref(&input, &output, cell_id%3, 4, 6, put); + for (i = 0; i < 2; i++) { + prb_cp_ref(&input, &output, cell_id % 3, 4, 6, put); } /* symbols 2 & 3 */ if (CP_ISNORM(cp)) { - for (i=0;i<2;i++) { + for (i = 0; i < 2; i++) { prb_cp(&input, &output, 6); } } else { prb_cp(&input, &output, 6); - prb_cp_ref(&input, &output, cell_id%3, 4, 6, put); + prb_cp_ref(&input, &output, cell_id % 3, 4, 6, put); } if (put) { return input - ptr; @@ -93,7 +90,8 @@ int pbch_cp(cf_t *input, cf_t *output, int nof_prb, lte_cp_t cp, int cell_id, bo * * 36.211 10.3 section 6.6.4 */ -int pbch_put(cf_t *pbch, cf_t *slot1_data, int nof_prb, lte_cp_t cp, int cell_id) { +int pbch_put(cf_t *pbch, cf_t *slot1_data, int nof_prb, lte_cp_t cp, + int cell_id) { return pbch_cp(pbch, slot1_data, nof_prb, cp, cell_id, true); } @@ -104,7 +102,8 @@ int pbch_put(cf_t *pbch, cf_t *slot1_data, int nof_prb, lte_cp_t cp, int cell_id * * 36.211 10.3 section 6.6.4 */ -int pbch_get(cf_t *slot1_data, cf_t *pbch, int nof_prb, lte_cp_t cp, int cell_id) { +int pbch_get(cf_t *slot1_data, cf_t *pbch, int nof_prb, lte_cp_t cp, + int cell_id) { return pbch_cp(slot1_data, pbch, nof_prb, cp, cell_id, false); } @@ -129,7 +128,7 @@ int pbch_init(pbch_t *q, int nof_prb, int cell_id, lte_cp_t cp) { goto clean; } - int poly[3] = {0x6D, 0x4F, 0x57}; + int poly[3] = { 0x6D, 0x4F, 0x57 }; if (viterbi_init(&q->decoder, viterbi_37, poly, 40, true)) { goto clean; } @@ -141,14 +140,14 @@ int pbch_init(pbch_t *q, int nof_prb, int cell_id, lte_cp_t cp) { q->encoder.tail_biting = true; memcpy(q->encoder.poly, poly, 3 * sizeof(int)); - q->nof_symbols = (CP_ISNORM(q->cp)) ? PBCH_RE_CPNORM: PBCH_RE_CPEXT; + q->nof_symbols = (CP_ISNORM(q->cp)) ? PBCH_RE_CPNORM : PBCH_RE_CPEXT; q->pbch_d = malloc(sizeof(cf_t) * q->nof_symbols); if (!q->pbch_d) { goto clean; } int i; - for (i=0;ice[i] = malloc(sizeof(cf_t) * q->nof_symbols); if (!q->ce[i]) { goto clean; @@ -188,8 +187,7 @@ int pbch_init(pbch_t *q, int nof_prb, int cell_id, lte_cp_t cp) { } ret = 0; -clean: - if (ret == -1) { + clean: if (ret == -1) { pbch_free(q); } return ret; @@ -200,7 +198,7 @@ void pbch_free(pbch_t *q) { free(q->pbch_d); } int i; - for (i=0;ice[i]) { free(q->ce[i]); } @@ -241,7 +239,7 @@ void pbch_mib_unpack(char *msg, pbch_mib_t *mib) { int bw, phich_res; bw = bit_unpack(&msg, 3); - switch(bw) { + switch (bw) { case 0: mib->nof_prb = 6; break; @@ -249,7 +247,7 @@ void pbch_mib_unpack(char *msg, pbch_mib_t *mib) { mib->nof_prb = 15; break; default: - mib->nof_prb = (bw-1)*25; + mib->nof_prb = (bw - 1) * 25; break; } if (*msg) { @@ -260,7 +258,7 @@ void pbch_mib_unpack(char *msg, pbch_mib_t *mib) { msg++; phich_res = bit_unpack(&msg, 2); - switch(phich_res) { + switch (phich_res) { case 0: mib->phich_resources = R_1_6; break; @@ -277,28 +275,27 @@ void pbch_mib_unpack(char *msg, pbch_mib_t *mib) { mib->sfn = bit_unpack(&msg, 8) << 2; } - /** Unpacks MIB from PBCH message. * msg buffer must be 24 byte length at least */ void pbch_mib_pack(pbch_mib_t *mib, char *msg) { - int bw, phich_res=0; + int bw, phich_res = 0; bzero(msg, 24); - if (mib->nof_prb<=6) { + if (mib->nof_prb <= 6) { bw = 0; } else if (mib->nof_prb <= 15) { bw = 1; } else { - bw = 1 + mib->nof_prb/25; + bw = 1 + mib->nof_prb / 25; } bit_pack(bw, &msg, 3); *msg = mib->phich_length == PHICH_EXT; msg++; - switch(mib->phich_resources) { + switch (mib->phich_resources) { case R_1_6: phich_res = 0; break; @@ -319,9 +316,10 @@ void pbch_mib_pack(pbch_mib_t *mib, char *msg) { void pbch_mib_fprint(FILE *stream, pbch_mib_t *mib) { printf(" - Nof ports: %d\n", mib->nof_ports); printf(" - PRB: %d\n", mib->nof_prb); - printf(" - PHICH Length: %s\n", mib->phich_length==PHICH_EXT?"Extended":"Normal"); + printf(" - PHICH Length: %s\n", + mib->phich_length == PHICH_EXT ? "Extended" : "Normal"); printf(" - PHICH Resources: "); - switch(mib->phich_resources) { + switch (mib->phich_resources) { case R_1_6: printf("1/6"); break; @@ -343,16 +341,14 @@ void pbch_decode_reset(pbch_t *q) { q->frame_idx = 0; } - void crc_set_mask(char *data, int nof_ports) { int i; - for (i=0;i<16;i++) { - data[24+i] = (data[24+i] + crc_mask[nof_ports-1][i]) % 2; + for (i = 0; i < 16; i++) { + data[24 + i] = (data[24 + i] + crc_mask[nof_ports - 1][i]) % 2; } } - /* Checks CRC after applying the mask for the given number of ports. * * The bits buffer size must be at least 40 bytes. @@ -366,18 +362,21 @@ int pbch_crc_check(pbch_t *q, char *bits, int nof_ports) { return crc_checksum(&q->crc, data, 40); } -int pbch_decode_frame(pbch_t *q, pbch_mib_t *mib, int src, int dst, int n, int nof_bits, int nof_ports) { +int pbch_decode_frame(pbch_t *q, pbch_mib_t *mib, int src, int dst, int n, + int nof_bits, int nof_ports) { int j; - memcpy(&q->temp[dst*nof_bits], &q->pbch_llr[src*nof_bits], n*nof_bits*sizeof(float)); + memcpy(&q->temp[dst * nof_bits], &q->pbch_llr[src * nof_bits], + n * nof_bits * sizeof(float)); /* descramble */ - scrambling_f_offset(&q->seq_pbch, &q->temp[dst*nof_bits], dst*nof_bits, n*nof_bits); + scrambling_f_offset(&q->seq_pbch, &q->temp[dst * nof_bits], dst * nof_bits, + n * nof_bits); - for (j=0;jtemp[j] = RX_NULL; } - for (j=(dst+n)*nof_bits;j<4*nof_bits;j++) { + for (j = (dst + n) * nof_bits; j < 4 * nof_bits; j++) { q->temp[j] = RX_NULL; } @@ -385,7 +384,7 @@ int pbch_decode_frame(pbch_t *q, pbch_mib_t *mib, int src, int dst, int n, int n rm_conv_rx(q->temp, 4 * nof_bits, q->pbch_rm_f, 120); /* FIXME: If channel estimates are zero, received LLR are NaN. Check and return error */ - for (j=0;j<120;j++) { + for (j = 0; j < 120; j++) { if (isnan(q->pbch_rm_f[j]) || isinf(q->pbch_rm_f[j])) { return 0; } @@ -394,12 +393,12 @@ int pbch_decode_frame(pbch_t *q, pbch_mib_t *mib, int src, int dst, int n, int n /* decode */ viterbi_decode_f(&q->decoder, q->pbch_rm_f, q->data, 40); - int c=0; - for (j=0;j<40;j++) { - c+=q->data[j]; + int c = 0; + for (j = 0; j < 40; j++) { + c += q->data[j]; } if (!c) { - c=1; + c = 1; } if (!pbch_crc_check(q, q->data, nof_ports)) { @@ -407,7 +406,7 @@ int pbch_decode_frame(pbch_t *q, pbch_mib_t *mib, int src, int dst, int n, int n pbch_mib_unpack(q->data, mib); mib->nof_ports = nof_ports; - mib->sfn += dst-src; + mib->sfn += dst - src; return 1; } else { @@ -423,9 +422,10 @@ int pbch_decode_frame(pbch_t *q, pbch_mib_t *mib, int src, int dst, int n, int n * * Returns 1 if successfully decoded MIB, 0 if not and -1 on error */ -int pbch_decode(pbch_t *q, cf_t *slot1_symbols, cf_t *ce[MAX_PORTS_CTRL], float ebno, pbch_mib_t *mib) { +int pbch_decode(pbch_t *q, cf_t *slot1_symbols, cf_t *ce[MAX_PORTS_CTRL], + float ebno, pbch_mib_t *mib) { int src, dst, res, nb; - int nant_[3] = {1, 2, 4}; + int nant_[3] = { 1, 2, 4 }; int na, nant; /* Set pointers for layermapping & precoding */ @@ -434,22 +434,23 @@ int pbch_decode(pbch_t *q, cf_t *slot1_symbols, cf_t *ce[MAX_PORTS_CTRL], float cf_t *x[MAX_LAYERS]; /* number of layers equals number of ports */ - for (i=0;ipbch_x[i]; } memset(&x[MAX_PORTS_CTRL], 0, sizeof(cf_t*) * (MAX_LAYERS - MAX_PORTS_CTRL)); /* extract symbols */ - if (q->nof_symbols != pbch_get(slot1_symbols, q->pbch_symbols[0], q->nof_prb, - q->cp, q->cell_id)) { + if (q->nof_symbols + != pbch_get(slot1_symbols, q->pbch_symbols[0], q->nof_prb, q->cp, + q->cell_id)) { fprintf(stderr, "There was an error getting the PBCH symbols\n"); return -1; } /* extract channel estimates */ - for (i=0;inof_symbols != pbch_get(ce[i], q->ce[i], q->nof_prb, - q->cp, q->cell_id)) { + for (i = 0; i < MAX_PORTS_CTRL; i++) { + if (q->nof_symbols + != pbch_get(ce[i], q->ce[i], q->nof_prb, q->cp, q->cell_id)) { fprintf(stderr, "There was an error getting the PBCH symbols\n"); return -1; } @@ -459,7 +460,7 @@ int pbch_decode(pbch_t *q, cf_t *slot1_symbols, cf_t *ce[MAX_PORTS_CTRL], float res = 0; /* Try decoding for 1 to 4 antennas */ - for (na=0;na<3 && !res;na++) { + for (na = 0; na < 3 && !res; na++) { nant = nant_[na]; INFO("Trying %d TX antennas with %d frames\n", nant, q->frame_idx); @@ -467,10 +468,12 @@ int pbch_decode(pbch_t *q, cf_t *slot1_symbols, cf_t *ce[MAX_PORTS_CTRL], float /* in conctrol channels, only diversity is supported */ if (nant == 1) { /* no need for layer demapping */ - predecoding_single_zf(q->pbch_symbols[0], q->ce[0], q->pbch_d, q->nof_symbols); + 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); - layerdemap_diversity(x, q->pbch_d, nant, q->nof_symbols/nant); + 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); } /* demodulate symbols */ @@ -485,11 +488,12 @@ int pbch_decode(pbch_t *q, cf_t *slot1_symbols, cf_t *ce[MAX_PORTS_CTRL], float * FIXME: There are unnecessary checks because 2,3,4 have already been processed in the previous * calls. */ - for (nb=0;nbframe_idx && !res;nb++) { - for (dst=0;(dst<4-nb) && !res;dst++) { - for (src=0;srcframe_idx-nb && !res;src++) { - DEBUG("Trying %d blocks at offset %d as subframe mod4 number %d\n", nb+1, src, dst); - res = pbch_decode_frame(q, mib, src, dst, nb+1, nof_bits, nant); + for (nb = 0; nb < q->frame_idx && !res; nb++) { + for (dst = 0; (dst < 4 - nb) && !res; dst++) { + for (src = 0; src < q->frame_idx - nb && !res; src++) { + DEBUG("Trying %d blocks at offset %d as subframe mod4 number %d\n", + nb + 1, src, dst); + res = pbch_decode_frame(q, mib, src, dst, nb + 1, nof_bits, nant); } } } @@ -503,10 +507,10 @@ int pbch_decode(pbch_t *q, cf_t *slot1_symbols, cf_t *ce[MAX_PORTS_CTRL], float return res; } - /** Converts the MIB message to symbols mapped to SLOT #1 ready for transmission */ -void pbch_encode(pbch_t *q, pbch_mib_t *mib, cf_t *slot1_symbols[MAX_PORTS_CTRL], int nof_ports) { +void pbch_encode(pbch_t *q, pbch_mib_t *mib, + cf_t *slot1_symbols[MAX_PORTS_CTRL], int nof_ports) { int i; int nof_bits = 2 * q->nof_symbols; @@ -516,7 +520,7 @@ void pbch_encode(pbch_t *q, pbch_mib_t *mib, cf_t *slot1_symbols[MAX_PORTS_CTRL] cf_t *x[MAX_LAYERS]; /* number of layers equals number of ports */ - for (i=0;ipbch_x[i]; } memset(&x[nof_ports], 0, sizeof(cf_t*) * (MAX_LAYERS - nof_ports)); @@ -537,21 +541,22 @@ void pbch_encode(pbch_t *q, pbch_mib_t *mib, cf_t *slot1_symbols[MAX_PORTS_CTRL] scrambling_b_offset(&q->seq_pbch, &q->pbch_rm_b[q->frame_idx * nof_bits], q->frame_idx * nof_bits, nof_bits); - mod_modulate(&q->mod, &q->pbch_rm_b[q->frame_idx * nof_bits], q->pbch_d, nof_bits); - + mod_modulate(&q->mod, &q->pbch_rm_b[q->frame_idx * nof_bits], q->pbch_d, + nof_bits); /* layer mapping & precoding */ if (nof_ports > 1) { layermap_diversity(q->pbch_d, x, nof_ports, q->nof_symbols); - precoding_diversity(x, q->pbch_symbols, nof_ports, q->nof_symbols/nof_ports); + precoding_diversity(x, q->pbch_symbols, nof_ports, + q->nof_symbols / nof_ports); } else { memcpy(q->pbch_symbols[0], q->pbch_d, q->nof_symbols * sizeof(cf_t)); } - /* mapping to resource elements */ - for (i=0;ipbch_symbols[i], slot1_symbols[i], q->nof_prb, q->cp, q->cell_id); + for (i = 0; i < nof_ports; i++) { + pbch_put(q->pbch_symbols[i], slot1_symbols[i], q->nof_prb, q->cp, + q->cell_id); } q->frame_idx++; if (q->frame_idx == 4) { @@ -559,5 +564,3 @@ void pbch_encode(pbch_t *q, pbch_mib_t *mib, cf_t *slot1_symbols[MAX_PORTS_CTRL] } } - - diff --git a/lte/lib/phch/src/pcfich.c b/lte/lib/phch/src/pcfich.c index 4afd56f6b..ad554e49b 100644 --- a/lte/lib/phch/src/pcfich.c +++ b/lte/lib/phch/src/pcfich.c @@ -25,7 +25,6 @@ * */ - #include #include #include @@ -42,23 +41,22 @@ #include "lte/utils/vector.h" #include "lte/utils/debug.h" - // Table 5.3.4-1 -static char cfi_table[4][PCFICH_CFI_LEN] = { - {0,1,1,0,1,1,0,1,1,0,1,1,0,1,1,0,1,1,0,1,1,0,1,1,0,1,1,0,1,1,0,1}, - {1,0,1,1,0,1,1,0,1,1,0,1,1,0,1,1,0,1,1,0,1,1,0,1,1,0,1,1,0,1,1,0}, - {1,1,0,1,1,0,1,1,0,1,1,0,1,1,0,1,1,0,1,1,0,1,1,0,1,1,0,1,1,0,1,1}, - {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} // reserved +static char cfi_table[4][PCFICH_CFI_LEN] = { { 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, + 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1 }, { 1, 0, 1, + 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, + 0, 1, 1, 0 }, { 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, + 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } // reserved }; - - bool pcfich_exists(int nframe, int nslot) { return true; } /** 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 +66,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; @@ -77,8 +75,8 @@ int pcfich_init(pcfich_t *q, regs_t *regs, int cell_id, int nof_prb, int nof_tx_ demod_hard_init(&q->demod); demod_hard_table_set(&q->demod, LTE_QPSK); - for (int nsf=0;nsfseq_pcfich[nsf], 2*nsf, q->cell_id)) { + for (int nsf = 0; nsf < NSUBFRAMES_X_FRAME; nsf++) { + if (sequence_pcfich(&q->seq_pcfich[nsf], 2 * nsf, q->cell_id)) { goto clean; } } @@ -86,15 +84,14 @@ int pcfich_init(pcfich_t *q, regs_t *regs, int cell_id, int nof_prb, int nof_tx_ q->nof_symbols = PCFICH_RE; ret = 0; -clean: - if (ret == -1) { + clean: if (ret == -1) { pcfich_free(q); } return ret; } void pcfich_free(pcfich_t *q) { - for (int ns=0;nsseq_pcfich[ns]); } modem_table_free(&q->mod); @@ -105,12 +102,12 @@ void pcfich_free(pcfich_t *q) { */ int pcfich_cfi_decode(char bits[PCFICH_CFI_LEN], int *cfi) { int i, j; - int distance, index=-1; + int distance, index = -1; int min = 32; - for (i=0;i<3;i++) { + for (i = 0; i < 3; i++) { distance = 0; - for (j=0;j NSUBFRAMES_X_FRAME) { fprintf(stderr, "Invalid nslot %d\n", nsubframe); @@ -159,22 +154,22 @@ int pcfich_decode(pcfich_t *q, cf_t *slot_symbols, cf_t *ce[MAX_PORTS_CTRL], int } /* number of layers equals number of ports */ - for (i=0;ipcfich_x[i]; } - for (i=0;ice[i]; - symbols_precoding[i] = q->pcfich_symbols[i]; } /* extract symbols */ - if (q->nof_symbols != regs_pcfich_get(q->regs, slot_symbols, q->pcfich_symbols[0])) { + if (q->nof_symbols + != regs_pcfich_get(q->regs, slot_symbols, q->pcfich_symbols[0])) { fprintf(stderr, "There was an error getting the PCFICH symbols\n"); return -1; } /* extract channel estimates */ - for (i=0;inof_tx_ports;i++) { + for (i = 0; i < q->nof_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 +177,15 @@ 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); + 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 */ @@ -208,10 +206,10 @@ int pcfich_decode(pcfich_t *q, cf_t *slot_symbols, cf_t *ce[MAX_PORTS_CTRL], int } } - /** Encodes CFI and maps symbols to the slot */ -int pcfich_encode(pcfich_t *q, int cfi, cf_t *slot_symbols[MAX_PORTS_CTRL], int nsubframe) { +int pcfich_encode(pcfich_t *q, int cfi, cf_t *slot_symbols[MAX_PORTS_CTRL], + int nsubframe) { int i; if (nsubframe < 0 || nsubframe > NSUBFRAMES_X_FRAME) { @@ -224,10 +222,10 @@ 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; i < q->nof_ports; i++) { x[i] = q->pcfich_x[i]; } - for (i=0;ipcfich_symbols[i]; } @@ -240,15 +238,16 @@ int pcfich_encode(pcfich_t *q, int cfi, cf_t *slot_symbols[MAX_PORTS_CTRL], int mod_modulate(&q->mod, 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; i < q->nof_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; @@ -258,4 +257,3 @@ int pcfich_encode(pcfich_t *q, int cfi, cf_t *slot_symbols[MAX_PORTS_CTRL], int return 0; } - diff --git a/lte/lib/phch/src/pdcch.c b/lte/lib/phch/src/pdcch.c index 700b5f8a7..ab55d6311 100644 --- a/lte/lib/phch/src/pdcch.c +++ b/lte/lib/phch/src/pdcch.c @@ -42,23 +42,24 @@ #include "lte/utils/vector.h" #include "lte/utils/debug.h" -#define PDCCH_NOF_FORMATS 4 -#define PDCCH_FORMAT_NOF_CCE(i) (1<b)?b:a) /** * 36.213 9.1 */ -int gen_common_search(dci_candidate_t *c, int nof_cce, int nof_bits, unsigned short rnti) { +int gen_common_search(dci_candidate_t *c, int nof_cce, int nof_bits, + unsigned short rnti) { int i, l, L, k; k = 0; for (l = 3; l > 1; l--) { @@ -79,7 +80,8 @@ int gen_common_search(dci_candidate_t *c, int nof_cce, int nof_bits, unsigned sh /** * 36.213 9.1 */ -int gen_ue_search(dci_candidate_t *c, int nof_cce, int nof_bits, unsigned short rnti, int subframe) { +int gen_ue_search(dci_candidate_t *c, int nof_cce, int nof_bits, + unsigned short rnti, int subframe) { int i, l, L, k, m; unsigned int Yk; const int S[4] = { 6, 12, 8, 16 }; @@ -87,11 +89,12 @@ int gen_ue_search(dci_candidate_t *c, int nof_cce, int nof_bits, unsigned short if (!subframe) { INFO("UE-specific candidates for RNTI: 0x%x, NofBits: %d, NofCCE: %d\n", rnti, nof_bits, nof_cce); - if (VERBOSE_ISINFO()) printf("[INFO]: "); + if (VERBOSE_ISINFO()) + printf("[INFO]: "); } for (l = 3; l >= 0; l--) { L = (1 << l); - for (i = 0; i < MIN(nof_cce/L,16/S[l]); i++) { + for (i = 0; i < MIN(nof_cce / L, 16 / S[l]); i++) { c[k].L = l; c[k].nof_bits = nof_bits; c[k].rnti = rnti; @@ -109,14 +112,16 @@ int gen_ue_search(dci_candidate_t *c, int nof_cce, int nof_bits, unsigned short } } if (!subframe) { - if (VERBOSE_ISINFO()) printf("\n"); + if (VERBOSE_ISINFO()) + printf("\n"); } return k; } void pdcch_init_common(pdcch_t *q, pdcch_search_t *s, unsigned short rnti) { int k, i; - s->nof_candidates = NOF_COMMON_FORMATS*(MIN(q->nof_cce,16) / 4 + MIN(q->nof_cce,16) / 8); + s->nof_candidates = NOF_COMMON_FORMATS + * (MIN(q->nof_cce,16) / 4 + MIN(q->nof_cce,16) / 8); if (s->nof_candidates) { s->candidates[0] = malloc(sizeof(dci_candidate_t) * s->nof_candidates); dci_candidate_t *c = s->candidates[0]; @@ -124,7 +129,7 @@ void pdcch_init_common(pdcch_t *q, pdcch_search_t *s, unsigned short rnti) { if (c) { // Format 1A and 1C L=4 and L=8, 4 and 2 candidates, only if nof_cce > 16 k = 0; - for(i=0;inof_cce, dci_format_sizeof(common_formats[i], q->nof_prb), SIRNTI); s->nof_candidates++; @@ -149,19 +154,21 @@ void pdcch_init_search_ue(pdcch_t *q, unsigned short c_rnti) { int l, n, k, i; pdcch_search_t *s = &q->search_mode[SEARCH_UE]; s->nof_candidates = 0; - for (l=0;l<3;l++) { - s->nof_candidates += NOF_UE_FORMATS*(MIN(q->nof_cce,16) / (1<nof_candidates += NOF_UE_FORMATS * (MIN(q->nof_cce,16) / (1 << l)); } - INFO("Initiating %d candidate(s) in the UE-specific search space for C-RNTI: 0x%x\n", s->nof_candidates, c_rnti); + INFO( + "Initiating %d candidate(s) in the UE-specific search space for C-RNTI: 0x%x\n", + s->nof_candidates, c_rnti); if (s->nof_candidates) { - for (n=0;ncandidates[n] = malloc(sizeof(dci_candidate_t) * s->nof_candidates); dci_candidate_t *c = s->candidates[n]; if (c) { // Expect Formats 1, 1A, 0 k = 0; - for(i=0;inof_cce, dci_format_sizeof(ue_formats[i], q->nof_prb), c_rnti, n); } @@ -210,13 +217,13 @@ int pdcch_init(pdcch_t *q, regs_t *regs, int nof_prb, int nof_ports, q->nof_prb = nof_prb; q->current_search_mode = SEARCH_NONE; - q->nof_regs = (regs_pdcch_nregs(q->regs)/9)*9; + q->nof_regs = (regs_pdcch_nregs(q->regs) / 9) * 9; q->nof_cce = q->nof_regs / 9; q->nof_symbols = 4 * q->nof_regs; q->nof_bits = 2 * q->nof_symbols; - INFO("Init PDCCH: %d CCEs (%d REGs), %d bits, %d symbols, %d ports\n", q->nof_cce, - q->nof_regs, q->nof_bits, q->nof_symbols, q->nof_ports); + INFO("Init PDCCH: %d CCEs (%d REGs), %d bits, %d symbols, %d ports\n", + q->nof_cce, q->nof_regs, q->nof_bits, q->nof_symbols, q->nof_ports); if (modem_table_std(&q->mod, LTE_QPSK, true)) { goto clean; @@ -279,7 +286,7 @@ int pdcch_init(pdcch_t *q, regs_t *regs, int nof_prb, int nof_ports, void pdcch_free(pdcch_t *q) { int i, j; - for (i=0;isearch_mode[i].candidates[j]) { free(q->search_mode[i].candidates[j]); @@ -321,8 +328,7 @@ void pdcch_free(pdcch_t *q) { * * TODO: UE transmit antenna selection CRC mask */ -unsigned short dci_decode(pdcch_t *q, float *e, char *data, int E, - int nof_bits) { +unsigned short dci_decode(pdcch_t *q, float *e, char *data, int E, int nof_bits) { float tmp[3 * (DCI_MAX_BITS + 16)]; unsigned short p_bits, crc_res; @@ -330,13 +336,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;idecoder, tmp, data, nof_bits + 16); if (VERBOSE_ISDEBUG()) { - bit_fprint(stdout, data, nof_bits+16); + bit_fprint(stdout, data, nof_bits + 16); } x = &data[nof_bits]; p_bits = (unsigned short) bit_unpack(&x, 16); crc_res = ((unsigned short) crc_checksum(&q->crc, data, nof_bits) & 0xffff); - DEBUG("p_bits: 0x%x, crc_res: 0x%x, tot: 0x%x\n", p_bits, crc_res, p_bits ^ crc_res); + DEBUG("p_bits: 0x%x, crc_res: 0x%x, tot: 0x%x\n", p_bits, crc_res, + p_bits ^ crc_res); return (p_bits ^ crc_res); } @@ -363,23 +363,20 @@ int pdcch_decode_candidate(pdcch_t *q, float *llr, dci_candidate_t *c, dci_msg_t *msg) { unsigned short crc_res; DEBUG("Trying Candidate: Nbits: %d, E: %d, nCCE: %d, L: %d, RNTI: 0x%x\n", - c->nof_bits, PDCCH_FORMAT_NOF_BITS(c->L), c->ncce, c->L, - c->rnti); + c->nof_bits, PDCCH_FORMAT_NOF_BITS(c->L), c->ncce, c->L, c->rnti); crc_res = dci_decode(q, &llr[72 * c->ncce], msg->data, PDCCH_FORMAT_NOF_BITS(c->L), c->nof_bits); if (c->rnti == crc_res) { memcpy(&msg->location, c, sizeof(dci_candidate_t)); - INFO( - "FOUND Candidate: Nbits: %d, E: %d, nCCE: %d, L: %d, RNTI: 0x%x\n", - c->nof_bits, PDCCH_FORMAT_NOF_BITS(c->L), c->ncce, c->L, - c->rnti); + INFO("FOUND Candidate: Nbits: %d, E: %d, nCCE: %d, L: %d, RNTI: 0x%x\n", + c->nof_bits, PDCCH_FORMAT_NOF_BITS(c->L), c->ncce, c->L, c->rnti); return 1; } return 0; } -int pdcch_extract_llr(pdcch_t *q, cf_t *slot1_symbols, cf_t *ce[MAX_PORTS_CTRL], +int pdcch_extract_llr(pdcch_t *q, cf_t *slot_symbols, cf_t *ce[MAX_PORTS_CTRL], float *llr, int nsubframe, float ebno) { /* Set pointers for layermapping & precoding */ @@ -403,9 +400,10 @@ int pdcch_extract_llr(pdcch_t *q, cf_t *slot1_symbols, cf_t *ce[MAX_PORTS_CTRL], memset(&x[q->nof_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); + fprintf(stderr, "Expected %d PDCCH symbols but got %d symbols\n", + q->nof_symbols, n); return -1; } @@ -413,7 +411,8 @@ int pdcch_extract_llr(pdcch_t *q, cf_t *slot1_symbols, cf_t *ce[MAX_PORTS_CTRL], for (i = 0; i < q->nof_ports; i++) { n = regs_pdcch_get(q->regs, ce[i], q->ce[i]); if (q->nof_symbols != n) { - fprintf(stderr, "Expected %d PDCCH symbols but got %d symbols\n", q->nof_symbols, n); + fprintf(stderr, "Expected %d PDCCH symbols but got %d symbols\n", + q->nof_symbols, n); return -1; } } @@ -424,7 +423,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); @@ -459,7 +458,8 @@ int pdcch_decode_current_mode(pdcch_t *q, float *llr, dci_t *dci, int subframe) k = 0; } - for (i = 0; i < q->search_mode[q->current_search_mode].nof_candidates + for (i = 0; + i < q->search_mode[q->current_search_mode].nof_candidates && dci->nof_dcis < dci->max_dcis; i++) { if (pdcch_decode_candidate(q, q->pdcch_llr, &q->search_mode[q->current_search_mode].candidates[k][i], @@ -483,18 +483,16 @@ int pdcch_decode_ue(pdcch_t *q, float *llr, dci_t *dci, int nsubframe) { return pdcch_decode_current_mode(q, llr, dci, nsubframe); } - /* Decodes PDCCH channels * * dci->nof_dcis is the size of the dci->msg buffer (ie max number of messages) * * 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, - ebno)) { + if (pdcch_extract_llr(q, slot_symbols, ce, q->pdcch_llr, nsubframe, ebno)) { return -1; } @@ -521,7 +519,8 @@ void crc_set_mask_rnti(char *crc, unsigned short rnti) { /** 36.212 5.3.3.2 to 5.3.3.4 * TODO: UE transmit antenna selection CRC mask */ -void dci_encode(pdcch_t *q, char *data, char *e, int nof_bits, int E, unsigned short rnti) { +void dci_encode(pdcch_t *q, char *data, char *e, int nof_bits, int E, + unsigned short rnti) { convcoder_t encoder; char tmp[3 * (DCI_MAX_BITS + 16)]; @@ -546,9 +545,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 */ @@ -571,18 +570,21 @@ int pdcch_encode(pdcch_t *q, dci_t *dci, cf_t *slot1_symbols[MAX_PORTS_CTRL], /* Encode DCIs */ for (i = 0; i < dci->nof_dcis; i++) { /* do some sanity checks */ - if (dci->msg[i].location.ncce + PDCCH_FORMAT_NOF_CCE(dci->msg[i].location.L) > q->nof_cce - || dci->msg[i].location.L > 3 + if (dci->msg[i].location.ncce + PDCCH_FORMAT_NOF_CCE(dci->msg[i].location.L) + > q->nof_cce || dci->msg[i].location.L > 3 || dci->msg[i].location.nof_bits > DCI_MAX_BITS) { fprintf(stderr, "Illegal DCI message %d\n", i); return -1; } - INFO("Encoding DCI %d: Nbits: %d, E: %d, nCCE: %d, L: %d, RNTI: 0x%x\n", - i, dci->msg[i].location.nof_bits, PDCCH_FORMAT_NOF_BITS(dci->msg[i].location.L), - dci->msg[i].location.ncce, dci->msg[i].location.L, dci->msg[i].location.rnti); + INFO("Encoding DCI %d: Nbits: %d, E: %d, nCCE: %d, L: %d, RNTI: 0x%x\n", i, + dci->msg[i].location.nof_bits, + PDCCH_FORMAT_NOF_BITS(dci->msg[i].location.L), + dci->msg[i].location.ncce, dci->msg[i].location.L, + dci->msg[i].location.rnti); dci_encode(q, dci->msg[i].data, &q->pdcch_e[72 * dci->msg[i].location.ncce], - dci->msg[i].location.nof_bits, PDCCH_FORMAT_NOF_BITS(dci->msg[i].location.L), + dci->msg[i].location.nof_bits, + PDCCH_FORMAT_NOF_BITS(dci->msg[i].location.L), dci->msg[i].location.rnti); } @@ -601,7 +603,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..c97bacb5a --- /dev/null +++ b/lte/lib/phch/src/pdsch.c @@ -0,0 +1,698 @@ +/** + * + * \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 28166dbbe..62b8f8824 100644 --- a/lte/lib/phch/src/phich.c +++ b/lte/lib/phch/src/phich.c @@ -59,7 +59,7 @@ int phich_ngroups(phich_t *q) { void phich_reset(phich_t *q, cf_t *slot_symbols[MAX_PORTS_CTRL]) { int i; - for (i=0;iregs, slot_symbols[i]); } } @@ -114,7 +114,7 @@ char phich_ack_decode(char bits[PHICH_NBITS], int *distance) { INFO("PHICH decoder: %d, %d, %d\n", bits[0], bits[1], bits[2]); if (n >= 2) { if (distance) { - *distance = 3-n; + *distance = 3 - n; } return 1; } else { @@ -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,21 +173,18 @@ 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 */ if (PHICH_MAX_NSYMB - != regs_phich_get(q->regs, slot_symbols, q->phich_symbols[0], - ngroup)) { + != regs_phich_get(q->regs, slot_symbols, q->phich_symbols[0], ngroup)) { fprintf(stderr, "There was an error getting the phich symbols\n"); return -1; } /* extract channel estimates */ for (i = 0; i < q->nof_tx_ports; i++) { - if (PHICH_MAX_NSYMB - != regs_phich_get(q->regs, ce[i], q->ce[i], ngroup)) { + if (PHICH_MAX_NSYMB != regs_phich_get(q->regs, ce[i], q->ce[i], ngroup)) { fprintf(stderr, "There was an error getting the phich symbols\n"); return -1; } @@ -200,14 +196,15 @@ 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); } - DEBUG("Recv!!: \n",0); - DEBUG("d0: ",0); - if (VERBOSE_ISDEBUG()) vec_fprint_c(stdout, q->phich_d0, PHICH_MAX_NSYMB); + DEBUG("Recv!!: \n", 0); + DEBUG("d0: ", 0); + if (VERBOSE_ISDEBUG()) + vec_fprint_c(stdout, q->phich_d0, PHICH_MAX_NSYMB); if (CP_ISEXT(q->cp)) { if (ngroup % 2) { @@ -225,32 +222,34 @@ int phich_decode(phich_t *q, cf_t *slot_symbols, cf_t *ce[MAX_PORTS_CTRL], memcpy(q->phich_d, q->phich_d0, PHICH_MAX_NSYMB * sizeof(cf_t)); } - DEBUG("d: ",0); - if (VERBOSE_ISDEBUG()) vec_fprint_c(stdout, q->phich_d, PHICH_EXT_MSYMB); + DEBUG("d: ", 0); + if (VERBOSE_ISDEBUG()) + vec_fprint_c(stdout, q->phich_d, PHICH_EXT_MSYMB); scrambling_c(&q->seq_phich[nsubframe], q->phich_d); /* De-spreading */ if (CP_ISEXT(q->cp)) { - for (i=0;iphich_z[i] = 0; - for (j=0;jphich_z[i] += conjf(w_ext[nseq][j]) * - q->phich_d[i*PHICH_EXT_NSF+j]/PHICH_EXT_NSF; + for (j = 0; j < PHICH_EXT_NSF; j++) { + q->phich_z[i] += conjf(w_ext[nseq][j]) + * q->phich_d[i * PHICH_EXT_NSF + j] / PHICH_EXT_NSF; } } } else { - for (i=0;iphich_z[i] = 0; - for (j=0;jphich_z[i] += conjf(w_normal[nseq][j]) * - q->phich_d[i*PHICH_NORM_NSF+j]/PHICH_NORM_NSF; + for (j = 0; j < PHICH_NORM_NSF; j++) { + q->phich_z[i] += conjf(w_normal[nseq][j]) + * q->phich_d[i * PHICH_NORM_NSF + j] / PHICH_NORM_NSF; } } } - DEBUG("z: ",0); - if (VERBOSE_ISDEBUG()) vec_fprint_c(stdout, q->phich_z, PHICH_NBITS); + DEBUG("z: ", 0); + if (VERBOSE_ISDEBUG()) + vec_fprint_c(stdout, q->phich_z, PHICH_NBITS); demod_hard_demodulate(&q->demod, q->phich_z, q->data, PHICH_NBITS); @@ -306,8 +305,9 @@ int phich_encode(phich_t *q, char ack, int ngroup, int nseq, int nsubframe, mod_modulate(&q->mod, q->data, q->phich_z, PHICH_NBITS); - DEBUG("data: ",0); - if (VERBOSE_ISDEBUG()) vec_fprint_c(stdout, q->phich_z, PHICH_NBITS); + DEBUG("data: ", 0); + if (VERBOSE_ISDEBUG()) + vec_fprint_c(stdout, q->phich_z, PHICH_NBITS); /* Spread with w */ if (CP_ISEXT(q->cp)) { @@ -322,8 +322,9 @@ int phich_encode(phich_t *q, char ack, int ngroup, int nseq, int nsubframe, } } - DEBUG("d: ",0); - if (VERBOSE_ISDEBUG()) vec_fprint_c(stdout, q->phich_d, PHICH_EXT_MSYMB); + DEBUG("d: ", 0); + if (VERBOSE_ISDEBUG()) + vec_fprint_c(stdout, q->phich_d, PHICH_EXT_MSYMB); scrambling_c(&q->seq_phich[nsubframe], q->phich_d); @@ -348,9 +349,9 @@ int phich_encode(phich_t *q, char ack, int ngroup, int nseq, int nsubframe, memcpy(q->phich_d0, q->phich_d, PHICH_MAX_NSYMB * sizeof(cf_t)); } - DEBUG("d0: ",0); - if (VERBOSE_ISDEBUG()) vec_fprint_c(stdout, q->phich_d0, PHICH_MAX_NSYMB); - + DEBUG("d0: ", 0); + if (VERBOSE_ISDEBUG()) + vec_fprint_c(stdout, q->phich_d0, PHICH_MAX_NSYMB); /* layer mapping & precoding */ if (q->nof_tx_ports > 1) { @@ -364,8 +365,8 @@ int phich_encode(phich_t *q, char ack, int ngroup, int nseq, int nsubframe, /* mapping to resource elements */ for (i = 0; i < q->nof_tx_ports; i++) { - if (regs_phich_add(q->regs, q->phich_symbols[i], ngroup, - slot_symbols[i]) < 0) { + if (regs_phich_add(q->regs, q->phich_symbols[i], ngroup, slot_symbols[i]) + < 0) { fprintf(stderr, "Error putting PCHICH resource elements\n"); return -1; } diff --git a/lte/lib/phch/src/prb.c b/lte/lib/phch/src/prb.c index a51b9d9df..9c740fcba 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 328a2e389..9df8f1bf5 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 65c3bea4f..3e5c1ba6d 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,13 +40,98 @@ #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; i < NSUBFRAMES_X_FRAME; i++) { + for (s = 0; s < 2; s++) { + for (j = 0; j < prb_dist->slot[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; - nrows = (prb->nof_prb - 1)/ 25 + 1; - for (j=0;jnof_prb-j*25);i++) { - fprintf(f, "%3d, ", prb->prb_idx[j*25+i]); + nrows = (prb->nof_prb - 1) / 25 + 1; + for (j = 0; j < nrows; j++) { + for (i = 0; i < min(25, prb->nof_prb - j * 25); i++) { + fprintf(f, "%3d, ", prb->prb_idx[j * 25 + i]); } fprintf(f, "\n"); } @@ -58,8 +144,8 @@ int ra_prb_get_ul(ra_prb_slot_t *prb, ra_pusch_t *ra, int nof_prb) { fprintf(stderr, "Uplink only accepts type2 localized scheduling\n"); return -1; } - for (i=0;itype2_alloc.L_crb;i++) { - prb->prb_idx[i] = i+ra->type2_alloc.RB_start; + for (i = 0; i < ra->type2_alloc.L_crb; i++) { + prb->prb_idx[i] = i + ra->type2_alloc.RB_start; prb->nof_prb++; } return 0; @@ -70,105 +156,110 @@ 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) { + 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++; + int nb = (int) ceilf((float) nof_prb / P); + for (i = 0; i < nb; i++) { + if (bitmask & (1 << (nb - i - 1))) { + for (j = 0; j < P; j++) { + 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; - 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)) { - n_rb_rbg_subset = ((nof_prb-1)/(P*P)) * P + ((nof_prb-1)%P)+1; + 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)) { + n_rb_rbg_subset = ((nof_prb - 1) / (P * P)) * P + ((nof_prb - 1) % P) + 1; } else { - n_rb_rbg_subset = ((nof_prb-1)/(P*P)) * P; + n_rb_rbg_subset = ((nof_prb - 1) / (P * P)) * P; } - int shift = ra->type1_alloc.shift?(n_rb_rbg_subset-n_rb_type1):0; + int shift = ra->type1_alloc.shift ? (n_rb_rbg_subset - n_rb_type1) : 0; bitmask = ra->type1_alloc.vrb_bitmask; - for (i=0;iprb_idx[prb->nof_prb] = ((i+shift)/P)*P*P+ - ra->type1_alloc.rbg_subset*P+(i+shift)%P; - prb->nof_prb++; + for (i = 0; i < n_rb_type1; i++) { + if (bitmask & (1 << (n_rb_type1 - i - 1))) { + 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_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++; + for (i = 0; i < ra->type2_alloc.L_crb; i++) { + 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_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) { N_tilde_vrb = nof_prb; N_gap = ra_type2_ngap(nof_prb, true); } else { - N_tilde_vrb = 2*nof_prb; + N_tilde_vrb = 2 * nof_prb; N_gap = ra_type2_ngap(nof_prb, false); } - N_row = (int) ceilf((float) N_tilde_vrb/(4*P))*P; - N_null = 4*N_row-N_tilde_vrb; - for (i=0;itype2_alloc.L_crb;i++) { - n_vrb = i+ra->type2_alloc.RB_start; - n_tilde_vrb = n_vrb%N_tilde_vrb; - n_tilde_prb = 2*N_row*(n_tilde_vrb % 2)+n_tilde_vrb/2+N_tilde_vrb*(n_vrb/N_tilde_vrb); - n_tilde2_prb = N_row*(n_tilde_vrb % 4)+n_tilde_vrb/4+N_tilde_vrb*(n_vrb/N_tilde_vrb); + N_row = (int) ceilf((float) N_tilde_vrb / (4 * P)) * P; + N_null = 4 * N_row - N_tilde_vrb; + for (i = 0; i < ra->type2_alloc.L_crb; i++) { + n_vrb = i + ra->type2_alloc.RB_start; + n_tilde_vrb = n_vrb % N_tilde_vrb; + n_tilde_prb = 2 * N_row * (n_tilde_vrb % 2) + n_tilde_vrb / 2 + + N_tilde_vrb * (n_vrb / N_tilde_vrb); + n_tilde2_prb = N_row * (n_tilde_vrb % 4) + n_tilde_vrb / 4 + + N_tilde_vrb * (n_vrb / N_tilde_vrb); - if (N_null != 0 && n_tilde_vrb >= (N_tilde_vrb - N_null) && (n_tilde_vrb%2) == 1) { - n_tilde_prb_odd = n_tilde_prb-N_row; - } else if (N_null != 0 && n_tilde_vrb >= (N_tilde_vrb - N_null) && (n_tilde_vrb%2) == 0) { - n_tilde_prb_odd = n_tilde_prb-N_row+N_null/2; - } else if (N_null != 0 && n_tilde_vrb < (N_tilde_vrb - N_null) && (n_tilde_vrb%4) >= 2) { - n_tilde_prb_odd = n_tilde2_prb-N_null/2; + if (N_null != 0 && n_tilde_vrb >= (N_tilde_vrb - N_null) + && (n_tilde_vrb % 2) == 1) { + n_tilde_prb_odd = n_tilde_prb - N_row; + } else if (N_null != 0 && n_tilde_vrb >= (N_tilde_vrb - N_null) + && (n_tilde_vrb % 2) == 0) { + n_tilde_prb_odd = n_tilde_prb - N_row + N_null / 2; + } else if (N_null != 0 && n_tilde_vrb < (N_tilde_vrb - N_null) + && (n_tilde_vrb % 4) >= 2) { + n_tilde_prb_odd = n_tilde2_prb - N_null / 2; } else { n_tilde_prb_odd = n_tilde2_prb; } - n_tilde_prb_even = (n_tilde_prb_odd+N_tilde_vrb/2)%N_tilde_vrb+N_tilde_vrb*(n_vrb/N_tilde_vrb); + 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; + if (n_tilde_prb_odd < N_tilde_vrb / 2) { + 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++; - if (n_tilde_prb_even < N_tilde_vrb/2) { - prb_dist->slot2.prb_idx[i] = n_tilde_prb_even; + prb_dist->slot[0].nof_prb++; + if (n_tilde_prb_even < N_tilde_vrb / 2) { + 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; } @@ -181,22 +272,23 @@ int ra_nprb_ul(ra_pusch_t *ra, int nof_prb) { int ra_nprb_dl(ra_pdsch_t *ra, int nof_prb) { int nprb; int nof_rbg, P; - switch(ra->alloc_type) { + switch (ra->alloc_type) { case alloc_type0: // Get the number of allocated RBG except the last RBG nof_rbg = bit_count(ra->type0_alloc.rbg_bitmask & 0xFFFFFFFE); P = ra_type0_P(nof_prb); - if (nof_rbg > (int) ceilf((float)nof_prb/P)) { + if (nof_rbg > (int) ceilf((float) nof_prb / P)) { fprintf(stderr, "Number of RGB (%d) can not exceed %d\n", nof_prb, - (int) ceilf((float)nof_prb/P)); + (int) ceilf((float) nof_prb / P)); return -1; } nprb = nof_rbg * P; // last RBG may have smaller size. Add if set - int P_last = (nof_prb%P); - if (!P_last) P_last = P; - nprb += P_last*(ra->type0_alloc.rbg_bitmask&1); + int P_last = (nof_prb % P); + if (!P_last) + P_last = P; + nprb += P_last * (ra->type0_alloc.rbg_bitmask & 1); break; case alloc_type1: nprb = bit_count(ra->type1_alloc.vrb_bitmask); @@ -231,35 +323,35 @@ int ra_type0_P(int nof_prb) { /* Returns N_rb_type1 according to section 7.1.6.2 */ int ra_type1_N_rb(int nof_prb) { int P = ra_type0_P(nof_prb); - return (int) ceilf((float) nof_prb/P) - (int) ceilf(log2f((float) P)) - 1; + return (int) ceilf((float) nof_prb / P) - (int) ceilf(log2f((float) P)) - 1; } /* Convert Type2 scheduling L_crb and RB_start to RIV value */ uint32_t ra_type2_to_riv(uint16_t L_crb, uint16_t RB_start, int nof_prb) { uint32_t riv; - if (L_crb <= (int) nof_prb/2) { - riv = nof_prb*(L_crb-1) + RB_start; + if (L_crb <= (int) nof_prb / 2) { + riv = nof_prb * (L_crb - 1) + RB_start; } else { - riv = nof_prb*(nof_prb-L_crb+1) + nof_prb - 1 - RB_start; + riv = nof_prb * (nof_prb - L_crb + 1) + nof_prb - 1 - RB_start; } return riv; } /* Convert Type2 scheduling RIV value to L_crb and RB_start values */ -void ra_type2_from_riv(uint32_t riv, uint16_t *L_crb, uint16_t *RB_start, int nof_prb, int nof_vrb) { - *L_crb = (int) (riv/nof_prb) + 1; - *RB_start = riv%nof_prb; +void ra_type2_from_riv(uint32_t riv, uint16_t *L_crb, uint16_t *RB_start, + int nof_prb, int nof_vrb) { + *L_crb = (int) (riv / nof_prb) + 1; + *RB_start = riv % nof_prb; if (*L_crb > nof_vrb - *RB_start) { - *L_crb = nof_prb - (int) (riv/nof_prb) + 1; - *RB_start = nof_prb - riv%nof_prb - 1; + *L_crb = nof_prb - (int) (riv / nof_prb) + 1; + *RB_start = nof_prb - riv % nof_prb - 1; } } - /* Table 6.2.3.2-1 in 36.211 */ int ra_type2_ngap(int nof_prb, bool ngap_is_1) { if (nof_prb <= 10) { - return nof_prb/2; + return nof_prb / 2; } else if (nof_prb == 11) { return 4; } else if (nof_prb <= 19) { @@ -271,15 +363,14 @@ int ra_type2_ngap(int nof_prb, bool ngap_is_1) { } else if (nof_prb <= 49) { return 27; } else if (nof_prb <= 63) { - return ngap_is_1?27:9; + return ngap_is_1 ? 27 : 9; } else if (nof_prb <= 79) { - return ngap_is_1?32:16; + return ngap_is_1 ? 32 : 16; } else { - return ngap_is_1?48:16; + return ngap_is_1 ? 48 : 16; } } - /* Table 7.1.6.3-1 in 36.213 */ int ra_type2_n_rb_step(int nof_prb) { if (nof_prb < 50) { @@ -289,14 +380,13 @@ int ra_type2_n_rb_step(int nof_prb) { } } - /* as defined in 6.2.3.2 of 36.211 */ int ra_type2_n_vrb_dl(int nof_prb, bool ngap_is_1) { int ngap = ra_type2_ngap(nof_prb, ngap_is_1); if (ngap_is_1) { - return 2*(ngap<(nof_prb-ngap)?ngap:nof_prb-ngap); + return 2 * (ngap < (nof_prb - ngap) ? ngap : nof_prb - ngap); } else { - return ((int) nof_prb/ngap)*2*ngap; + return ((int) nof_prb / ngap) * 2 * ngap; } } @@ -321,10 +411,10 @@ int ra_mcs_from_idx_dl(uint8_t idx, ra_mcs_t *mcs) { mcs->tbs_idx = idx; } else if (idx < 17) { mcs->mod = QAM16; - mcs->tbs_idx = idx-1; + mcs->tbs_idx = idx - 1; } else if (idx < 29) { mcs->mod = QAM64; - mcs->tbs_idx = idx-2; + mcs->tbs_idx = idx - 2; } else if (idx == 29) { mcs->mod = QPSK; mcs->tbs_idx = 0; @@ -342,7 +432,6 @@ int ra_mcs_from_idx_dl(uint8_t idx, ra_mcs_t *mcs) { return 0; } - /* Converts MCS index to ra_mcs_t structure for Uplink as defined in Table 8.6.1-1 on 36.213 */ int ra_mcs_from_idx_ul(uint8_t idx, ra_mcs_t *mcs) { if (idx < 11) { @@ -350,10 +439,10 @@ int ra_mcs_from_idx_ul(uint8_t idx, ra_mcs_t *mcs) { mcs->tbs_idx = idx; } else if (idx < 21) { mcs->mod = QAM16; - mcs->tbs_idx = idx-1; + mcs->tbs_idx = idx - 1; } else if (idx < 29) { mcs->mod = QAM64; - mcs->tbs_idx = idx-2; + mcs->tbs_idx = idx - 2; } else { mcs->mod = MOD_NULL; mcs->tbs_idx = 0; @@ -379,9 +468,8 @@ int ra_tbs_to_table_idx_format1c(int tbs) { if (tbs < tbs_format1c_table[0]) { return -1; } - for (idx=1;idx<32;idx++) { - if (tbs_format1c_table[idx-1] <= tbs && - tbs_format1c_table[idx] >= tbs) { + for (idx = 1; idx < 32; idx++) { + if (tbs_format1c_table[idx - 1] <= tbs && tbs_format1c_table[idx] >= tbs) { return idx; } } @@ -389,9 +477,9 @@ int ra_tbs_to_table_idx_format1c(int tbs) { } /* Downlink Transport Block size determination as defined in 7.1.7.2 on 36.213 */ -int ra_tbs_from_idx(uint8_t tbs_idx, int n_prb ) { +int ra_tbs_from_idx(uint8_t tbs_idx, int n_prb) { if (tbs_idx < 27 && n_prb > 0 && n_prb <= 110) { - return tbs_table[tbs_idx][n_prb-1]; + return tbs_table[tbs_idx][n_prb - 1]; } else { return -1; } @@ -408,9 +496,8 @@ int ra_tbs_to_table_idx(int tbs, int n_prb) { if (tbs < tbs_table[0][n_prb]) { return -1; } - for (idx=1;idx<28;idx++) { - if (tbs_table[idx-1][n_prb] <= tbs && - tbs_table[idx][n_prb] >= tbs) { + for (idx = 1; idx < 28; idx++) { + if (tbs_table[idx - 1][n_prb] <= tbs && tbs_table[idx][n_prb] >= tbs) { return idx; } } @@ -441,7 +528,7 @@ void ra_pusch_fprint(FILE *f, ra_pusch_t *ra, int nof_prb) { } char *ra_type_string(ra_type_t alloc_type) { - switch(alloc_type) { + switch (alloc_type) { case alloc_type0: return "Type 0"; case alloc_type1: @@ -462,32 +549,33 @@ void ra_pdsch_set_mcs(ra_pdsch_t *ra, ra_mod_t mod, uint8_t tbs_idx) { ra->mcs.tbs_idx = tbs_idx; } - void ra_pdsch_fprint(FILE *f, ra_pdsch_t *ra, int nof_prb) { - fprintf(f, " - Resource Allocation Type:\t\t%s\n",ra_type_string(ra->alloc_type)); - switch(ra->alloc_type) { + fprintf(f, " - Resource Allocation Type:\t\t%s\n", + ra_type_string(ra->alloc_type)); + switch (ra->alloc_type) { case alloc_type0: - fprintf(f, " + Resource Block Group Size:\t\t%d\n",ra_type0_P(nof_prb)); - fprintf(f, " + RBG Bitmap:\t\t\t0x%x\n",ra->type0_alloc.rbg_bitmask); + fprintf(f, " + Resource Block Group Size:\t\t%d\n", ra_type0_P(nof_prb)); + fprintf(f, " + RBG Bitmap:\t\t\t0x%x\n", ra->type0_alloc.rbg_bitmask); break; case alloc_type1: - fprintf(f, " + Resource Block Group Size:\t\t%d\n",ra_type0_P(nof_prb)); - fprintf(f, " + RBG Bitmap:\t\t\t0x%x\n",ra->type1_alloc.vrb_bitmask); - fprintf(f, " + RBG Subset:\t\t\t%d\n",ra->type1_alloc.rbg_subset); - fprintf(f, " + RBG Shift:\t\t\t\t%s\n",ra->type1_alloc.shift?"Yes":"No"); + fprintf(f, " + Resource Block Group Size:\t\t%d\n", ra_type0_P(nof_prb)); + fprintf(f, " + RBG Bitmap:\t\t\t0x%x\n", ra->type1_alloc.vrb_bitmask); + fprintf(f, " + RBG Subset:\t\t\t%d\n", ra->type1_alloc.rbg_subset); + fprintf(f, " + RBG Shift:\t\t\t\t%s\n", + ra->type1_alloc.shift ? "Yes" : "No"); break; case alloc_type2: fprintf(f, " + Type:\t\t\t\t%s\n", - ra->type2_alloc.mode==t2_loc?"Localized":"Distributed"); - fprintf(f, " + Resource Indicator Value:\t\t%d\n",ra->type2_alloc.riv); + ra->type2_alloc.mode == t2_loc ? "Localized" : "Distributed"); + fprintf(f, " + Resource Indicator Value:\t\t%d\n", ra->type2_alloc.riv); if (ra->type2_alloc.mode == t2_loc) { fprintf(f, " + VRB Assignment:\t\t\t%d VRB starting with VRB %d\n", - ra->type2_alloc.L_crb, ra->type2_alloc.RB_start); + ra->type2_alloc.L_crb, ra->type2_alloc.RB_start); } else { fprintf(f, " + VRB Assignment:\t\t\t%d VRB starting with VRB %d\n", - ra->type2_alloc.L_crb, ra->type2_alloc.RB_start); + ra->type2_alloc.L_crb, ra->type2_alloc.RB_start); fprintf(f, " + VRB gap selection:\t\t\tGap %d\n", - ra->type2_alloc.n_gap == t2_ng1?1:2); + ra->type2_alloc.n_gap == t2_ng1 ? 1 : 2); fprintf(f, " + VRB gap:\t\t\t\t%d\n", ra_type2_ngap(nof_prb, ra->type2_alloc.n_gap == t2_ng1)); } @@ -496,14 +584,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)); @@ -511,7 +594,7 @@ void ra_pdsch_fprint(FILE *f, ra_pdsch_t *ra, int nof_prb) { fprintf(f, " - Modulation type:\t\t\t%s\n", ra_mod_string(ra->mcs.mod)); fprintf(f, " - Transport block size:\t\t%d\n", ra->mcs.tbs); fprintf(f, " - HARQ process:\t\t\t%d\n", ra->harq_process); - fprintf(f, " - New data indicator:\t\t\t%s\n", ra->ndi?"Yes":"No"); + fprintf(f, " - New data indicator:\t\t\t%s\n", ra->ndi ? "Yes" : "No"); fprintf(f, " - Redundancy version:\t\t\t%d\n", ra->rv_idx); fprintf(f, " - TPC command for PUCCH:\t\t--\n"); } diff --git a/lte/lib/phch/src/sequences.c b/lte/lib/phch/src/sequences.c index b6ddb8fe4..13ab21c4f 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 49ca02293..93d4475b3 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; @@ -55,7 +54,7 @@ int main(int argc, char **argv) { nof_prb = atoi(argv[1]); len = atoi(argv[2]); - nwords = (len-1)/32+1; + nwords = (len - 1) / 32 + 1; if (argc < 3 + nwords) { usage(argv[0]); @@ -65,9 +64,9 @@ int main(int argc, char **argv) { y = msg.data; rlen = 0; unsigned int x; - for (i=0;i +#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;i #include #include @@ -41,7 +40,7 @@ void scrambling_f_offset(sequence_t *s, float *data, int offset, int len) { assert (len + offset <= s->len); for (i = 0; i < len; i++) { - data[i] = data[i]*(1-2*s->c[i+offset]); + data[i] = data[i] * (1 - 2 * s->c[i + offset]); } } @@ -54,7 +53,7 @@ void scrambling_c_offset(sequence_t *s, cf_t *data, int offset, int len) { assert (len + offset <= s->len); for (i = 0; i < len; i++) { - data[i] = data[i]*(1-2*s->c[i+offset]); + data[i] = data[i] * (1 - 2 * s->c[i + offset]); } } @@ -70,7 +69,7 @@ void scrambling_b_offset(sequence_t *s, char *data, int offset, int len) { int i; assert (len + offset <= s->len); for (i = 0; i < len; i++) { - data[i] = (data[i] + s->c[i+offset]) % 2; + data[i] = (data[i] + s->c[i + offset]) % 2; } } @@ -80,15 +79,24 @@ int compute_sequences(scrambling_hl* h) { switch (h->init.channel) { case SCRAMBLING_PBCH: - return sequence_pbch(&h->obj.seq[0], h->init.nof_symbols == CPNORM_NSYMB?CPNORM:CPEXT, - h->init.cell_id); + return sequence_pbch(&h->obj.seq[0], + h->init.nof_symbols == CPNORM_NSYMB ? CPNORM : CPEXT, h->init.cell_id); case SCRAMBLING_PDSCH: + for (int ns = 0; ns < NSUBFRAMES_X_FRAME; ns++) { + sequence_pdsch(&h->obj.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); + for (int ns = 0; ns < NSUBFRAMES_X_FRAME; ns++) { + sequence_pcfich(&h->obj.seq[ns], 2 * ns, h->init.cell_id); } return 0; case SCRAMBLING_PDCCH: + for (int ns = 0; ns < NSUBFRAMES_X_FRAME; ns++) { + sequence_pdcch(&h->obj.seq[ns], 2 * ns, h->init.cell_id, LTE_NSOFT_BITS); + } + return 0; case SCRAMBLING_PMCH: case SCRAMBLING_PUCCH: fprintf(stderr, "Not implemented\n"); @@ -129,7 +137,7 @@ int scrambling_work(scrambling_hl* hl) { int scrambling_stop(scrambling_hl* hl) { int i; - for (i=0;iobj.seq[i]); } return 0;