From a08cdaecfceba2d042f708e61f66baf953b6ddbb Mon Sep 17 00:00:00 2001 From: ismagom Date: Fri, 27 Jun 2014 18:36:25 +0200 Subject: [PATCH 01/14] Fixed PDSCH not working with odd number of PRB. Fixed PBCH resource allocation for PRB greater than 6. Other minor issues --- lte/phy/examples/CMakeLists.txt | 46 +- lte/phy/examples/pbch_enodeb.c | 26 +- lte/phy/examples/pbch_ue.c | 159 ++--- lte/phy/examples/pdsch_enodeb.c | 367 ++++++++++ lte/phy/examples/pdsch_ue.c | 643 ++++++++++++++++++ lte/phy/examples/scan_mib.c | 51 +- lte/phy/examples/scan_pss.c | 6 +- .../include/liblte/phy/ch_estimation/chest.h | 5 +- lte/phy/include/liblte/phy/common/base.h | 15 +- lte/phy/include/liblte/phy/common/fft.h | 9 +- lte/phy/include/liblte/phy/phch/pbch.h | 13 +- lte/phy/include/liblte/phy/phch/pcfich.h | 10 +- lte/phy/include/liblte/phy/phch/pdcch.h | 23 +- lte/phy/include/liblte/phy/phch/pdsch.h | 63 +- lte/phy/include/liblte/phy/phch/phich.h | 12 +- lte/phy/include/liblte/phy/phch/regs.h | 2 +- lte/phy/include/liblte/phy/phy.h | 3 + lte/phy/include/liblte/phy/resampling/decim.h | 39 ++ .../include/liblte/phy/resampling/interp.h | 2 +- lte/phy/include/liblte/phy/sync/cfo.h | 1 + lte/phy/include/liblte/phy/sync/pss.h | 23 +- lte/phy/include/liblte/phy/sync/sss.h | 4 +- lte/phy/include/liblte/phy/sync/sync.h | 38 +- lte/phy/include/liblte/phy/sync/sync_frame.h | 106 +++ lte/phy/include/liblte/phy/utils/debug.h | 1 + lte/phy/lib/ch_estimation/src/chest.c | 34 +- lte/phy/lib/common/src/fft.c | 41 +- lte/phy/lib/common/src/lte.c | 3 + lte/phy/lib/common/test/fft_test.c | 4 +- lte/phy/lib/fec/src/viterbi.c | 4 +- lte/phy/lib/phch/src/dci.c | 3 +- lte/phy/lib/phch/src/pbch.c | 41 +- lte/phy/lib/phch/src/pcfich.c | 8 +- lte/phy/lib/phch/src/pdcch.c | 151 ++-- lte/phy/lib/phch/src/pdsch.c | 95 ++- lte/phy/lib/phch/src/phich.c | 10 +- lte/phy/lib/phch/src/prb.c | 18 +- lte/phy/lib/phch/src/prb.h | 6 +- lte/phy/lib/phch/src/ra.c | 12 +- lte/phy/lib/phch/src/regs.c | 24 +- lte/phy/lib/phch/test/pbch_file_test.c | 10 +- lte/phy/lib/phch/test/pbch_test.c | 10 +- lte/phy/lib/phch/test/pcfich_file_test.c | 8 +- lte/phy/lib/phch/test/pcfich_test.c | 8 +- lte/phy/lib/phch/test/pdcch_file_test.c | 16 +- lte/phy/lib/phch/test/pdcch_test.c | 15 +- lte/phy/lib/phch/test/pdsch_file_test.c | 527 +++++++------- lte/phy/lib/phch/test/pdsch_re_test.c | 112 +-- lte/phy/lib/phch/test/pdsch_test.c | 311 ++++----- lte/phy/lib/phch/test/phich_file_test.c | 8 +- lte/phy/lib/phch/test/phich_test.c | 8 +- lte/phy/lib/resampling/src/decim.c | 49 ++ lte/phy/lib/resampling/src/interp.c | 2 +- lte/phy/lib/sync/src/find_sss.c | 10 +- lte/phy/lib/sync/src/gen_sss.c | 1 - lte/phy/lib/sync/src/pss.c | 183 ++--- lte/phy/lib/sync/src/sss.c | 19 +- lte/phy/lib/sync/src/sync.c | 250 +++---- lte/phy/lib/sync/src/sync_frame.c | 236 +++++++ lte/phy/lib/sync/test/sync_test.c | 5 +- 60 files changed, 2753 insertions(+), 1156 deletions(-) create mode 100644 lte/phy/examples/pdsch_enodeb.c create mode 100644 lte/phy/examples/pdsch_ue.c create mode 100644 lte/phy/include/liblte/phy/resampling/decim.h create mode 100644 lte/phy/include/liblte/phy/sync/sync_frame.h create mode 100644 lte/phy/lib/resampling/src/decim.c create mode 100644 lte/phy/lib/sync/src/sync_frame.c diff --git a/lte/phy/examples/CMakeLists.txt b/lte/phy/examples/CMakeLists.txt index 78a02353a..5238328c8 100644 --- a/lte/phy/examples/CMakeLists.txt +++ b/lte/phy/examples/CMakeLists.txt @@ -57,20 +57,34 @@ target_link_libraries(pbch_ue lte_phy) add_executable(pbch_enodeb pbch_enodeb.c) target_link_libraries(pbch_enodeb lte_phy) +add_executable(pdsch_ue pdsch_ue.c) +target_link_libraries(pdsch_ue lte_phy) + +add_executable(pdsch_enodeb pdsch_enodeb.c) +target_link_libraries(pdsch_enodeb lte_phy) + IF(${CUHD_FIND} EQUAL -1) - SET_TARGET_PROPERTIES(pbch_ue PROPERTIES COMPILE_DEFINITIONS "DISABLE_UHD") - SET_TARGET_PROPERTIES(pbch_enodeb PROPERTIES COMPILE_DEFINITIONS "DISABLE_UHD") + SET_TARGET_PROPERTIES(pbch_ue PROPERTIES COMPILE_DEFINITIONS "DISABLE_UHD") + SET_TARGET_PROPERTIES(pbch_enodeb PROPERTIES COMPILE_DEFINITIONS "DISABLE_UHD") + SET_TARGET_PROPERTIES(pdsch_ue PROPERTIES COMPILE_DEFINITIONS "DISABLE_UHD") + SET_TARGET_PROPERTIES(pdsch_enodeb PROPERTIES COMPILE_DEFINITIONS "DISABLE_UHD") ELSE(${CUHD_FIND} EQUAL -1) - target_link_libraries(pbch_ue cuhd) - target_link_libraries(pbch_enodeb cuhd) + target_link_libraries(pbch_ue cuhd) + target_link_libraries(pbch_enodeb cuhd) + target_link_libraries(pdsch_ue cuhd) + target_link_libraries(pdsch_enodeb cuhd) ENDIF(${CUHD_FIND} EQUAL -1) IF(${GRAPHICS_FIND} EQUAL -1) - SET_TARGET_PROPERTIES(pbch_ue PROPERTIES COMPILE_DEFINITIONS "DISABLE_GRAPHICS") - SET_TARGET_PROPERTIES(pbch_enodeb PROPERTIES COMPILE_DEFINITIONS "DISABLE_GRAPHICS") + SET_TARGET_PROPERTIES(pbch_ue PROPERTIES COMPILE_DEFINITIONS "DISABLE_GRAPHICS") + SET_TARGET_PROPERTIES(pbch_enodeb PROPERTIES COMPILE_DEFINITIONS "DISABLE_GRAPHICS") + SET_TARGET_PROPERTIES(pdsch_ue PROPERTIES COMPILE_DEFINITIONS "DISABLE_GRAPHICS") + SET_TARGET_PROPERTIES(pdsch_enodeb PROPERTIES COMPILE_DEFINITIONS "DISABLE_GRAPHICS") ELSE(${GRAPHICS_FIND} EQUAL -1) - target_link_libraries(pbch_ue graphics) - target_link_libraries(pbch_enodeb graphics) + target_link_libraries(pbch_ue graphics) + target_link_libraries(pbch_enodeb graphics) + target_link_libraries(pdsch_ue graphics) + target_link_libraries(pdsch_enodeb graphics) ENDIF(${GRAPHICS_FIND} EQUAL -1) @@ -81,17 +95,17 @@ ENDIF(${GRAPHICS_FIND} EQUAL -1) IF(${CUHD_FIND} GREATER -1) - add_executable(scan_rssi scan_rssi.c) - target_link_libraries(scan_rssi lte_phy cuhd ) + add_executable(scan_rssi scan_rssi.c) + target_link_libraries(scan_rssi lte_phy cuhd ) - add_executable(scan_pss scan_pss.c) - target_link_libraries(scan_pss lte_phy cuhd ) + add_executable(scan_pss scan_pss.c) + target_link_libraries(scan_pss lte_phy cuhd ) - add_executable(scan_mib scan_mib.c) - target_link_libraries(scan_mib lte_phy cuhd ) + add_executable(scan_mib scan_mib.c) + target_link_libraries(scan_mib lte_phy cuhd ) - MESSAGE(STATUS " UHD examples will be installed.") + MESSAGE(STATUS " UHD examples will be installed.") ELSE(${CUHD_FIND} GREATER -1) - MESSAGE(STATUS " UHD examples NOT INSTALLED: CUHD library not compiled.") + MESSAGE(STATUS " UHD examples NOT INSTALLED: CUHD library not compiled.") ENDIF(${CUHD_FIND} GREATER -1) diff --git a/lte/phy/examples/pbch_enodeb.c b/lte/phy/examples/pbch_enodeb.c index 5a0f9c583..1d7a62801 100644 --- a/lte/phy/examples/pbch_enodeb.c +++ b/lte/phy/examples/pbch_enodeb.c @@ -50,7 +50,7 @@ filesink_t fsink; lte_fft_t ifft; pbch_t pbch; -cf_t *slot_buffer = NULL, *output_buffer = NULL; +cf_t *sf_buffer = NULL, *output_buffer = NULL; int slot_n_re, slot_n_samples; #define UHD_SAMP_FREQ 1920000 @@ -118,8 +118,8 @@ void parse_args(int argc, char **argv) { void base_init() { /* init memory */ - slot_buffer = malloc(sizeof(cf_t) * slot_n_re); - if (!slot_buffer) { + sf_buffer = malloc(sizeof(cf_t) * slot_n_re); + if (!sf_buffer) { perror("malloc"); exit(-1); } @@ -164,8 +164,8 @@ void base_free() { lte_ifft_free(&ifft); - if (slot_buffer) { - free(slot_buffer); + if (sf_buffer) { + free(sf_buffer); } if (output_buffer) { free(output_buffer); @@ -187,7 +187,7 @@ int main(int argc, char **argv) { pbch_mib_t mib; refsignal_t refs[NSLOTS_X_FRAME]; int i; - cf_t *slot1_symbols[MAX_PORTS_CTRL]; + cf_t *slot1_symbols[MAX_PORTS]; #ifdef DISABLE_UHD @@ -224,8 +224,8 @@ int main(int argc, char **argv) { mib.phich_resources = R_1; mib.sfn = 0; - for (i=0;i +#include +#include +#include +#include + +#include "liblte/phy/phy.h" + +#ifndef DISABLE_UHD +#include "liblte/cuhd/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 = ""; +int cfi=1; + +float uhd_amp = 0.25, uhd_gain = 10.0, uhd_freq = 2400000000; + +filesink_t fsink; +lte_fft_t ifft; +pbch_t pbch; +pcfich_t pcfich; +pdcch_t pdcch; +pdsch_t pdsch; +regs_t regs; + +cf_t *sf_buffer = NULL, *output_buffer = NULL; +int sf_n_re, sf_n_samples; + +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 */ + sf_buffer = malloc(sizeof(cf_t) * sf_n_re); + if (!sf_buffer) { + perror("malloc"); + exit(-1); + } + output_buffer = malloc(sizeof(cf_t) * sf_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, nof_prb, cell_id, CPNORM)) { + fprintf(stderr, "Error creating PBCH object\n"); + exit(-1); + } + + if (regs_init(®s, cell_id, nof_prb, 1, R_1, PHICH_NORM, CPNORM)) { + fprintf(stderr, "Error initiating regs\n"); + exit(-1); + } + + if (pcfich_init(&pcfich, ®s, cell_id, nof_prb, 1, CPNORM)) { + fprintf(stderr, "Error creating PBCH object\n"); + exit(-1); + } + + if (regs_set_cfi(®s, cfi)) { + fprintf(stderr, "Error setting CFI\n"); + exit(-1); + } + + if (pdcch_init(&pdcch, ®s, nof_prb, 1, cell_id, CPNORM)) { + fprintf(stderr, "Error creating PDCCH object\n"); + exit(-1); + } + + if (pdsch_init(&pdsch, 1234, nof_prb, 1, cell_id, CPNORM)) { + fprintf(stderr, "Error creating PDSCH object\n"); + exit(-1); + } +} + +void base_free() { + + pdsch_free(&pdsch); + pdcch_free(&pdcch); + regs_free(®s); + pbch_free(&pbch); + + lte_ifft_free(&ifft); + + if (sf_buffer) { + free(sf_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, sf_idx, 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; + ra_pdsch_t ra_dl; + ra_prb_t prb_alloc; + refsignal_t refs[NSLOTS_X_FRAME]; + int i, n; + char *data; + cf_t *sf_symbols[MAX_PORTS]; + cf_t *slot1_symbols[MAX_PORTS]; + dci_t dci_tx; + +#ifdef DISABLE_UHD + if (argc < 3) { + usage(argv[0]); + exit(-1); + } +#endif + + parse_args(argc, argv); + + N_id_2 = cell_id % 3; + sf_n_re = 2 * CPNORM_NSYMB * nof_prb * RE_X_RB; + sf_n_samples = 2 * 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 < NSLOTS_X_FRAME; i++) { + if (refsignal_init_LTEDL(&refs[i], 0, i, cell_id, CPNORM, nof_prb)) { + fprintf(stderr, "Error initiating CRS slot=%d\n", i); + return -1; + } + } + + mib.nof_ports = 1; + mib.nof_prb = nof_prb; + mib.phich_length = PHICH_NORM; + mib.phich_resources = R_1; + mib.sfn = 0; + + for (i = 0; i < MAX_PORTS; i++) { // now there's only 1 port + sf_symbols[i] = sf_buffer; + slot1_symbols[i] = &sf_buffer[sf_n_re/2]; + } + +#ifndef DISABLE_UHD + if (!output_file_name) { + printf("Set TX rate: %.2f MHz\n", + cuhd_set_tx_srate(uhd, lte_sampling_freq_hz(nof_prb)) / 1000000); + printf("Set TX gain: %.1f dB\n", cuhd_set_tx_gain(uhd, uhd_gain)); + printf("Set TX freq: %.2f MHz\n", + cuhd_set_tx_freq(uhd, uhd_freq) / 1000000); + } +#endif + + dci_init(&dci_tx, 1); + bzero(&ra_dl, sizeof(ra_pdsch_t)); + ra_dl.harq_process = 0; + ra_pdsch_set_mcs(&ra_dl, QPSK, 5); + ra_dl.ndi = 0; + ra_dl.rv_idx = 0; + ra_dl.alloc_type = alloc_type0; + ra_dl.type0_alloc.rbg_bitmask = 0xffffffff; + + dci_msg_pack_pdsch(&ra_dl, &dci_tx.msg[0], Format1, nof_prb, false); + dci_tx.nof_dcis++; + + if (pdcch_set_cfi(&pdcch, cfi)) { + fprintf(stderr, "Error setting CFI\n"); + return -1; + } + + pdcch_init_search_ue(&pdcch, 1234); + + ra_prb_get_dl(&prb_alloc, &ra_dl, nof_prb); + ra_prb_get_re(&prb_alloc, nof_prb, 1, nof_prb<10?(cfi+1):cfi, CPNORM); + ra_dl.mcs.tbs = ra_tbs_from_idx(ra_dl.mcs.tbs_idx, nof_prb); + + ra_pdsch_fprint(stdout, &ra_dl, nof_prb); + + data = malloc(sizeof(char) * ra_dl.mcs.tbs); + if (!data) { + perror("malloc"); + exit(-1); + } + + nf = 0; + + while (nf < nof_frames || nof_frames == -1) { + for (sf_idx = 0; sf_idx < NSUBFRAMES_X_FRAME; sf_idx++) { + bzero(sf_buffer, sizeof(cf_t) * sf_n_re); + + if (sf_idx == 0 || sf_idx == 5) { + pss_put_slot(pss_signal, sf_buffer, nof_prb, CPNORM); + sss_put_slot(sf_idx ? sss_signal5 : sss_signal0, sf_buffer, nof_prb, + CPNORM); + } + + if (sf_idx == 0) { + pbch_encode(&pbch, &mib, slot1_symbols, 1); + } + + for (n=0;n<2;n++) { + refsignal_put(&refs[2*sf_idx+n], &sf_buffer[n*sf_n_re/2]); + } + + pcfich_encode(&pcfich, cfi, sf_symbols, sf_idx); + + INFO("SF: %d, Generating %d random bits\n", sf_idx, ra_dl.mcs.tbs); + for (i=0;i +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "liblte/phy/phy.h" + +#ifndef DISABLE_UHD +#include "liblte/cuhd/cuhd.h" +void *uhd; +#endif + +#ifndef DISABLE_GRAPHICS +#include "liblte/graphics/plot.h" +plot_real_t poutfft; +plot_complex_t pce; +plot_scatter_t pscatrecv, pscatequal; +#endif + +#define MHZ 1000000 +#define SAMP_FREQ 1920000 + +#define NOF_PORTS 2 + +float find_threshold = 10.0; +int nof_frames = -1; +int pdsch_errors = 0, pdsch_total = 0; +int frame_cnt; +char *input_file_name = NULL; +int disable_plots = 0; + +/* These are the number of PRBs used during the SYNC procedure */ +int sampling_nof_prb = 6; + +/* Number of samples in a subframe */ +int sf_n_samples; + +int cell_id_initated = 0, mib_initiated = 0; + +int go_exit = 0; + +float uhd_freq = 2600000000.0, uhd_gain = 20.0; +char *uhd_args = ""; + +filesource_t fsrc; +cf_t *input_buffer, *sf_buffer, *fft_buffer, *input_decim_buffer, *ce[MAX_PORTS]; +float *tmp_plot; +pbch_t pbch; +pbch_mib_t mib; +pcfich_t pcfich; +pdcch_t pdcch; +dci_t dci_set; +pdsch_t pdsch; +regs_t regs; +lte_fft_t fft; +chest_t chest; +sync_frame_t sframe; + +#define CLRSTDOUT printf("\r\n"); fflush(stdout); printf("\r\n") + +#define DOWNSAMPLE_FACTOR(x, y) lte_symbol_sz(x) / lte_symbol_sz(y) + +void usage(char *prog) { + printf("Usage: %s [iagfndvtp]\n", prog); + printf("\t-i input_file [Default use USRP]\n"); +#ifndef DISABLE_UHD + printf("\t-a UHD args [Default %s]\n", uhd_args); + printf("\t-g UHD RX gain [Default %.2f dB]\n", uhd_gain); + printf("\t-f UHD RX frequency [Default %.1f MHz]\n", uhd_freq / 1000000); +#else + printf("\t UHD is disabled. CUHD library not available\n"); +#endif + printf("\t-p sampling_nof_prb [Default %d]\n", sampling_nof_prb); + printf("\t-n nof_frames [Default %d]\n", nof_frames); + printf("\t-t PSS threshold [Default %f]\n", find_threshold); +#ifndef DISABLE_GRAPHICS + printf("\t-d disable plots [Default enabled]\n"); +#else + printf("\t plots are disabled. Graphics library not available\n"); +#endif + printf("\t-v [set verbose to debug, default none]\n"); +} + +void parse_args(int argc, char **argv) { + int opt; + while ((opt = getopt(argc, argv, "iagfndvtp")) != -1) { + switch (opt) { + case 'i': + input_file_name = argv[optind]; + break; + case 'a': + uhd_args = argv[optind]; + break; + case 'g': + uhd_gain = atof(argv[optind]); + break; + case 'f': + uhd_freq = atof(argv[optind]); + break; + case 't': + find_threshold = atof(argv[optind]); + break; + case 'p': + sampling_nof_prb = atof(argv[optind]); + break; + case 'n': + nof_frames = atoi(argv[optind]); + break; + case 'd': + disable_plots = 1; + break; + case 'v': + verbose++; + break; + default: + usage(argv[0]); + exit(-1); + } + } +} + +#ifndef DISABLE_GRAPHICS + +void init_plots() { + plot_init(); + plot_real_init(&poutfft); + plot_real_setTitle(&poutfft, "Output FFT - Magnitude"); + plot_real_setLabels(&poutfft, "Index", "dB"); + plot_real_setYAxisScale(&poutfft, -60, 0); + plot_real_setXAxisScale(&poutfft, 1, 504); + + plot_complex_init(&pce); + plot_complex_setTitle(&pce, "Channel Estimates"); + plot_complex_setYAxisScale(&pce, Ip, -0.01, 0.01); + plot_complex_setYAxisScale(&pce, Q, -0.01, 0.01); + plot_complex_setYAxisScale(&pce, Magnitude, 0, 0.01); + plot_complex_setYAxisScale(&pce, Phase, -M_PI, M_PI); + + plot_scatter_init(&pscatrecv); + plot_scatter_setTitle(&pscatrecv, "Received Symbols"); + plot_scatter_setXAxisScale(&pscatrecv, -0.01, 0.01); + plot_scatter_setYAxisScale(&pscatrecv, -0.01, 0.01); + + plot_scatter_init(&pscatequal); + plot_scatter_setTitle(&pscatequal, "Equalized Symbols"); + plot_scatter_setXAxisScale(&pscatequal, -1, 1); + plot_scatter_setYAxisScale(&pscatequal, -1, 1); +} + +#endif + + +/* This function initializes the objects defined as global variables */ +int base_init(int nof_prb) { + int i; + + int sf_n_re = 2 * CPNORM_NSYMB * nof_prb * RE_X_RB; + int sf_n_samples = 2 * SLOT_LEN_CPNORM(lte_symbol_sz(nof_prb)); + + +#ifndef DISABLE_GRAPHICS + if (!disable_plots) { + tmp_plot = malloc(sizeof(cf_t) * sf_n_re); + if (!tmp_plot) { + perror("malloc"); + return -1; + } + init_plots(); + } +#else + printf("-- PLOTS are disabled. Graphics library not available --\n\n"); +#endif + + if (input_file_name) { + if (filesource_init(&fsrc, input_file_name, COMPLEX_FLOAT_BIN)) { + return -1; + } + } else { + /* open UHD device */ +#ifndef DISABLE_UHD + printf("Opening UHD device...\n"); + if (cuhd_open(uhd_args, &uhd)) { + fprintf(stderr, "Error opening uhd\n"); + return -1; + } +#else + printf("Error UHD not available. Select an input file\n"); + return -1; +#endif + } + + /* For the input buffer, we allocate space for 1 ms of samples */ + input_buffer = (cf_t*) malloc(sf_n_samples * sizeof(cf_t)); + if (!input_buffer) { + perror("malloc"); + return -1; + } + input_decim_buffer = (cf_t*) malloc(sf_n_samples * sizeof(cf_t)); + if (!input_decim_buffer) { + perror("malloc"); + return -1; + } + + + /* This buffer is the aligned version of input_buffer */ + sf_buffer = (cf_t*) malloc(sf_n_samples * sizeof(cf_t)); + if (!sf_buffer) { + perror("malloc"); + return -1; + } + + /* For the rest of the buffers, we allocate for the number of RE in one subframe */ + fft_buffer = (cf_t*) malloc(sf_n_re * sizeof(cf_t)); + if (!fft_buffer) { + perror("malloc"); + return -1; + } + + for (i = 0; i < MAX_PORTS; i++) { + ce[i] = (cf_t*) malloc(sf_n_re * sizeof(cf_t)); + if (!ce[i]) { + perror("malloc"); + return -1; + } + } + + bzero(&mib, sizeof(pbch_mib_t)); + + if (sync_frame_init(&sframe, DOWNSAMPLE_FACTOR(nof_prb,6))) { + fprintf(stderr, "Error initiating PSS/SSS\n"); + return -1; + } + + if (chest_init(&chest, LINEAR, CPNORM, nof_prb, NOF_PORTS)) { + fprintf(stderr, "Error initializing equalizer\n"); + return -1; + } + + if (lte_fft_init(&fft, CPNORM, nof_prb)) { + fprintf(stderr, "Error initializing FFT\n"); + return -1; + } + + dci_init(&dci_set, 10); + + return 0; +} + +void base_free() { + int i; + + if (input_file_name) { + filesource_free(&fsrc); + } else { +#ifndef DISABLE_UHD + cuhd_close(uhd); +#endif + } + +#ifndef DISABLE_GRAPHICS + if (!disable_plots) { + if (tmp_plot) { + free(tmp_plot); + } + plot_exit(); + } +#endif + + pbch_free(&pbch); + pdsch_free(&pdsch); + pdcch_free(&pdcch); + regs_free(®s); + sync_frame_free(&sframe); + lte_fft_free(&fft); + chest_free(&chest); + + free(input_buffer); + free(input_decim_buffer); + free(fft_buffer); + for (i = 0; i < MAX_PORTS; i++) { + free(ce[i]); + } +} + +int mib_init(int cell_id) { + + if (mib.nof_prb > sampling_nof_prb) { + fprintf(stderr, "Error sampling frequency is %.2f Mhz but captured signal has %d PRB\n", + (float) lte_sampling_freq_hz(sampling_nof_prb)/MHZ, mib.nof_prb); + return -1; + } + if (regs_init(®s, cell_id, mib.nof_prb, mib.nof_ports, + mib.phich_resources, mib.phich_length, CPNORM)) { + fprintf(stderr, "Error initiating regs\n"); + return -1; + } + + if (pcfich_init(&pcfich, ®s, cell_id, mib.nof_prb, mib.nof_ports, CPNORM)) { + fprintf(stderr, "Error creating PCFICH object\n"); + return -1; + } + + if (pdcch_init(&pdcch, ®s, mib.nof_prb, mib.nof_ports, cell_id, CPNORM)) { + fprintf(stderr, "Error creating PDCCH object\n"); + return -1; + } + + if (pdsch_init(&pdsch, 1234, mib.nof_prb, mib.nof_ports, cell_id, CPNORM)) { + fprintf(stderr, "Error creating PDSCH object\n"); + return -1; + } + + chest_set_nof_ports(&chest, mib.nof_ports); + + mib_initiated = 1; + + DEBUG("Receiver initiated cell_id=%d nof_prb=%d\n", cell_id, mib.nof_prb); + + return 0; +} + +int cell_id_init(int nof_prb, int cell_id) { + + if (chest_ref_LTEDL(&chest, cell_id)) { + fprintf(stderr, "Error initializing reference signal\n"); + return -1; + } + + if (pbch_init(&pbch, nof_prb, cell_id, CPNORM)) { + fprintf(stderr, "Error initiating PBCH\n"); + return -1; + } + + cell_id_initated = 1; + DEBUG("PBCH initiated cell_id=%d\n", cell_id); + + return 0; +} + +char data[10000]; + +int rx_run(cf_t *input, int sf_idx) { + int cfi, i, cfi_distance, nof_dcis; + cf_t *input_decim; + ra_pdsch_t ra_dl; + ra_prb_t prb_alloc; + + /* Downsample if the signal bandwith is shorter */ + if (sampling_nof_prb > mib.nof_prb) { + decim_c(input, input_decim_buffer, sf_n_samples, DOWNSAMPLE_FACTOR(sampling_nof_prb, mib.nof_prb)); + input_decim = input_decim_buffer; + } else { + input_decim = input; + } + + lte_fft_run_sf(&fft, input_decim, fft_buffer); + + /* Get channel estimates for each port */ + chest_ce_sf(&chest, fft_buffer, ce, sf_idx); + + /* First decode PCFICH and obtain CFI */ + if (pcfich_decode(&pcfich, fft_buffer, ce, sf_idx, &cfi, &cfi_distance)<0) { + return -1; + } + + INFO("Decoded CFI=%d with distance %d\n", cfi, cfi_distance); + + if (regs_set_cfi(®s, cfi)) { + fprintf(stderr, "Error setting CFI\n"); + return -1; + } + if (pdcch_set_cfi(&pdcch, cfi)) { + fprintf(stderr, "Error setting CFI\n"); + return -1; + } + pdcch_init_search_ue(&pdcch, 1234); + + dci_set.nof_dcis = 0; + nof_dcis = pdcch_decode(&pdcch, fft_buffer, ce, &dci_set, sf_idx); + INFO("Received %d DCIs\n", nof_dcis); + for (i=0;i 0) { + int n_re = 2 * RE_X_RB * CPNORM_NSYMB * mib.nof_prb; + for (i = 0; i < n_re; i++) { + tmp_plot[i] = 10 * log10f(cabsf(fft_buffer[i])); + if (isinf(tmp_plot[i])) { + tmp_plot[i] = -80; + } + } + plot_real_setNewData(&poutfft, tmp_plot, n_re); + plot_complex_setNewData(&pce, ce[0], n_re); + plot_scatter_setNewData(&pscatrecv, pdsch.pdsch_symbols[0], prb_alloc.re_sf[sf_idx]); + plot_scatter_setNewData(&pscatequal, pdsch.pdsch_d, prb_alloc.re_sf[sf_idx]); + } +#endif + + return 0; +} + +int mib_decoder_run(cf_t *input) { + int i, n; + + lte_fft_run_slot(&fft, input, fft_buffer); + + /* Get channel estimates for each port */ + for (i = 0; i < NOF_PORTS; i++) { + chest_ce_slot_port(&chest, fft_buffer, ce[i], 1, i); + } + + DEBUG("Decoding PBCH\n", 0); + n = pbch_decode(&pbch, fft_buffer, ce, &mib); + + return n; +} + +int run_receiver(cf_t *input, int cell_id, int sf_idx) { + + if (!cell_id_initated) { + cell_id_init(sampling_nof_prb, cell_id); + } + if (!mib.nof_prb) { + + if (!sf_idx) { + if (mib_decoder_run(&input[sf_n_samples/2])) { + INFO("MIB decoded!\n", 0); + if (!mib_initiated) { + if (mib_init(cell_id)) { + return -1; + } + } + if (VERBOSE_ISINFO() || !frame_cnt) { + CLRSTDOUT; + printf(" - Phy. CellId:\t %d\n", cell_id); + pbch_mib_fprint(stdout, &mib); + } + } + } + } + if (mib.nof_prb) { + if (rx_run(input, sf_idx)) { + return -1; + } + } + return 0; +} + +void sigintHandler(int sig_num) { + go_exit = 1; +} + +void setup_uhd() { + double samp_freq; + +#ifndef DISABLE_UHD + /* Get the sampling rate from the number of PRB */ + samp_freq = lte_sampling_freq_hz(sampling_nof_prb); + + INFO("Setting sampling frequency %.2f MHz\n", (float) samp_freq/MHZ); + cuhd_set_rx_srate(uhd, samp_freq); + cuhd_set_rx_gain(uhd, uhd_gain); + + /* set uhd_freq */ + cuhd_set_rx_freq(uhd, (double) uhd_freq); + cuhd_rx_wait_lo_locked(uhd); + DEBUG("Set uhd_freq to %.3f MHz\n", (double ) uhd_freq); + + DEBUG("Starting receiver...\n", 0); + cuhd_start_rx_stream(uhd); +#endif +} + +void read_io(cf_t *buffer, int nsamples) { + int n; + DEBUG(" ----- RECEIVING %d SAMPLES ---- \n", nsamples); + if (input_file_name) { + n = filesource_read(&fsrc, buffer, nsamples); + if (n == -1) { + fprintf(stderr, "Error reading file\n"); + exit(-1); + /* wrap file if arrive to end */ + } else if (n < nsamples) { + DEBUG("Read %d from file. Seeking to 0\n",n); + filesource_seek(&fsrc, 0); + filesource_read(&fsrc, buffer, nsamples); + } + } else { +#ifndef DISABLE_UHD + cuhd_recv(uhd, buffer, nsamples, 1); +#endif + } +} + +int main(int argc, char **argv) { + +#ifdef DISABLE_UHD + if (argc < 3) { + usage(argv[0]); + exit(-1); + } +#endif + + parse_args(argc, argv); + + if (base_init(sampling_nof_prb)) { + fprintf(stderr, "Error initializing memory\n"); + exit(-1); + } + + /* If input_file_name is NULL, we read from the USRP */ + if (!input_file_name) { + setup_uhd(); + } + + printf("\n --- Press Ctrl+C to exit --- \n"); + signal(SIGINT, sigintHandler); + + /* Initialize variables */ + mib.sfn = -1; + frame_cnt = 0; + + /* The number of samples read from the USRP or file corresponds to 1 ms (subframe) */ + sf_n_samples = 1920 * lte_symbol_sz(sampling_nof_prb)/128; + + sync_frame_set_threshold(&sframe, find_threshold); + + while (!go_exit && (frame_cnt < nof_frames || nof_frames == -1)) { + + read_io(input_buffer, sf_n_samples); + + switch(sync_frame_push(&sframe, input_buffer, sf_buffer)) { + case 0: + /* not yet synched */ + break; + case 1: + if (!(frame_cnt%10)) { + mib.sfn++; + } + /* synch'd and tracking */ + if (run_receiver(sf_buffer, sync_frame_cell_id(&sframe), sync_frame_sfidx(&sframe))) { + exit(-1); + } + if (!(frame_cnt % 10)) { + printf( + "SFN: %4d, CFO: %+.4f KHz, SFO: %+.4f Khz, TimeOffset: %4d, Errors: %4d/%4d, BLER: %.1e\r", + mib.sfn, sframe.cur_cfo * 15, sframe.timeoffset / 5, sframe.peak_idx, + pdsch_errors, pdsch_total, + (float) pdsch_errors / pdsch_total); + fflush(stdout); + } + + break; + default: + fprintf(stderr, "Error running automatic synchronization\n"); + exit(-1); + } + + frame_cnt++; + if (input_file_name) { + usleep(5000); + } + } + + base_free(); + + printf("\nBye\n"); + exit(0); +} + diff --git a/lte/phy/examples/scan_mib.c b/lte/phy/examples/scan_mib.c index 9bdf883e6..600a635f7 100644 --- a/lte/phy/examples/scan_mib.c +++ b/lte/phy/examples/scan_mib.c @@ -53,7 +53,7 @@ #define IS_SIGNAL(i) (10*log10f(rssi[i]) + 30 > rssi_threshold) int band, earfcn=-1; -float find_threshold = 10.0, track_threshold = 8.0; +float find_threshold = 10.0; int earfcn_start=-1, earfcn_end = -1; float rssi_threshold = -45.0; int max_track_lost=9; @@ -64,7 +64,7 @@ cf_t *input_buffer, *fft_buffer, *ce[MAX_PORTS]; pbch_t pbch; lte_fft_t fft; chest_t chest; -sync_t sfind, strack; +sync_t ssync; cfo_t cfocorr; float *cfo_v; @@ -86,7 +86,7 @@ enum sync_state {INIT, FIND, TRACK, MIB, DONE}; void usage(char *prog) { - printf("Usage: %s [seRrFfTtgv] -b band\n", prog); + printf("Usage: %s [seRrFfTgv] -b band\n", prog); printf("\t-s earfcn_start [Default All]\n"); printf("\t-e earfcn_end [Default All]\n"); printf("\t-R rssi_nof_samples [Default %d]\n", nof_samples_rssi); @@ -94,7 +94,6 @@ void usage(char *prog) { printf("\t-F pss_find_nof_frames [Default %d]\n", nof_frames_find); printf("\t-f pss_find_threshold [Default %.2f]\n", find_threshold); printf("\t-T pss_track_nof_frames [Default %d]\n", nof_frames_track); - printf("\t-t pss_track_threshold [Default %.2f]\n", track_threshold); printf("\t-l pss_track_len [Default %d]\n", track_len); printf("\t-g gain [Default %.2f dB]\n", uhd_gain); printf("\t-v [set verbose to debug, default none]\n"); @@ -102,7 +101,7 @@ void usage(char *prog) { void parse_args(int argc, char **argv) { int opt; - while ((opt = getopt(argc, argv, "bseRrFfTtgv")) != -1) { + while ((opt = getopt(argc, argv, "bseRrFfTgv")) != -1) { switch(opt) { case 'b': band = atoi(argv[optind]); @@ -128,9 +127,6 @@ void parse_args(int argc, char **argv) { case 'T': nof_frames_track = atoi(argv[optind]); break; - case 't': - track_threshold = atof(argv[optind]); - break; case 'g': uhd_gain = atof(argv[optind]); break; @@ -166,11 +162,7 @@ int base_init(int frame_length) { return -1; } } - if (sync_init(&sfind, FLEN)) { - fprintf(stderr, "Error initiating PSS/SSS\n"); - return -1; - } - if (sync_init(&strack, track_len)) { + if (sync_init(&ssync, FLEN)) { fprintf(stderr, "Error initiating PSS/SSS\n"); return -1; } @@ -235,8 +227,7 @@ void base_free() { cuhd_close(uhd); #endif - sync_free(&sfind); - sync_free(&strack); + sync_free(&ssync); lte_fft_free(&fft); chest_free(&chest); cfo_free(&cfocorr); @@ -335,7 +326,7 @@ int mib_decoder_init(int cell_id) { int mib_decoder_run(cf_t *input, pbch_mib_t *mib) { int i; - lte_fft_run(&fft, input, fft_buffer); + lte_fft_run_slot(&fft, input, fft_buffer); /* Get channel estimates for each port */ for (i=0;i= nof_frames_find) { state = INIT; @@ -469,20 +456,20 @@ int main(int argc, char **argv) { case TRACK: INFO("Tracking PSS find_idx %d offset %d\n", find_idx, find_idx - track_len); - track_idx = sync_run(&strack, &input_buffer[FLEN + find_idx - track_len]); - p2a_v[frame_cnt] = sync_get_peak_to_avg(&strack); + track_idx = sync_track(&ssync, &input_buffer[FLEN + find_idx - track_len]); + p2a_v[frame_cnt] = sync_get_peak_to_avg(&ssync); /* save cell id for the best peak-to-avg */ if (p2a_v[frame_cnt] > max_peak_to_avg) { max_peak_to_avg = p2a_v[frame_cnt]; - cell_id = sync_get_cell_id(&strack); + cell_id = sync_get_cell_id(&ssync); } if (track_idx != -1) { - cfo_v[frame_cnt] = sync_get_cfo(&strack); + cfo_v[frame_cnt] = sync_get_cfo(&ssync); last_found = frame_cnt; find_idx += track_idx - track_len; idx_v[frame_cnt] = find_idx; - nslot = sync_get_slot_id(&strack); + nslot = sync_get_slot_id(&ssync); } else { idx_v[frame_cnt] = -1; cfo_v[frame_cnt] = 0.0; diff --git a/lte/phy/examples/scan_pss.c b/lte/phy/examples/scan_pss.c index 7f86b9f30..7ba271498 100644 --- a/lte/phy/examples/scan_pss.c +++ b/lte/phy/examples/scan_pss.c @@ -348,19 +348,17 @@ int main(int argc, char **argv) { /* set find_threshold and go to FIND state */ sync_set_threshold(&sfind, find_threshold); - sync_force_N_id_2(&sfind, -1); state = FIND; break; case FIND: /* find peak in all frame */ - find_idx = sync_run(&sfind, &input_buffer[FLEN]); + find_idx = sync_find(&sfind, &input_buffer[FLEN]); DEBUG("[%3d/%d]: PAR=%.2f\n", freq, nof_bands, sync_get_peak_to_avg(&sfind)); if (find_idx != -1) { /* if found peak, go to track and set lower threshold */ frame_cnt = -1; last_found = 0; sync_set_threshold(&strack, track_threshold); - sync_force_N_id_2(&strack, sync_get_N_id_2(&sfind)); state = TRACK; INFO("[%3d/%d]: EARFCN %d Freq. %.2f MHz PSS found PAR %.2f dB\n", freq, nof_bands, channels[freq].id, channels[freq].fd, @@ -382,7 +380,7 @@ int main(int argc, char **argv) { filesink_write(&fs, &input_buffer[FLEN+find_idx+track_len], track_len); - track_idx = sync_run(&strack, &input_buffer[FLEN + find_idx - track_len]); + track_idx = sync_find(&strack, &input_buffer[FLEN + find_idx - track_len]); p2a_v[frame_cnt] = sync_get_peak_to_avg(&strack); /* save cell id for the best peak-to-avg */ diff --git a/lte/phy/include/liblte/phy/ch_estimation/chest.h b/lte/phy/include/liblte/phy/ch_estimation/chest.h index 8335e917a..93c121df7 100644 --- a/lte/phy/include/liblte/phy/ch_estimation/chest.h +++ b/lte/phy/include/liblte/phy/ch_estimation/chest.h @@ -61,6 +61,7 @@ typedef struct LIBLTE_API{ LIBLTE_API int chest_init(chest_t *q, chest_interp_t interp, lte_cp_t cp, int nof_prb, int nof_ports); LIBLTE_API void chest_free(chest_t *q); +LIBLTE_API void chest_set_nof_ports(chest_t *q, int nof_ports); LIBLTE_API int chest_ref_LTEDL_slot_port(chest_t *q, int port, int nslot, int cell_id); LIBLTE_API int chest_ref_LTEDL_slot(chest_t *q, int nslot, int cell_id); @@ -68,7 +69,9 @@ LIBLTE_API int chest_ref_LTEDL(chest_t *q, int cell_id); LIBLTE_API void chest_ce_ref(chest_t *q, cf_t *input, int nslot, int port_id, int nref); LIBLTE_API void chest_ce_slot_port(chest_t *q, cf_t *input, cf_t *ce, int nslot, int port_id); -LIBLTE_API void chest_ce_slot(chest_t *q, cf_t *input, cf_t **ce, int nslot); +LIBLTE_API void chest_ce_sf_port(chest_t *q, cf_t *input, cf_t *ce, int sf_idx, int port_id); +LIBLTE_API void chest_ce_slot(chest_t *q, cf_t *input, cf_t *ce[MAX_PORTS], int nslot); +LIBLTE_API void chest_ce_sf(chest_t *q, cf_t *input, cf_t *ce[MAX_PORTS], int sf_idx); LIBLTE_API void chest_fprint(chest_t *q, FILE *stream, int nslot, int port_id); LIBLTE_API void chest_ref_fprint(chest_t *q, FILE *stream, int nslot, int port_id); diff --git a/lte/phy/include/liblte/phy/common/base.h b/lte/phy/include/liblte/phy/common/base.h index 3449449c8..c553a7c51 100644 --- a/lte/phy/include/liblte/phy/common/base.h +++ b/lte/phy/include/liblte/phy/common/base.h @@ -41,7 +41,6 @@ #define LTE_NIL_SYMBOL 2 #define MAX_PORTS 4 -#define MAX_PORTS_CTRL 4 #define MAX_LAYERS 8 #define MAX_CODEWORDS 2 @@ -82,7 +81,7 @@ typedef enum {CPNORM, CPEXT} lte_cp_t; #define SF_LEN_CPNORM(symbol_sz) 2*SLOT_LEN_CPNORM(symbol_sz) #define SF_LEN_CPEXT(symbol_sz) 2*SLOT_LEN_CPEXT(symbol_sz) -#define SF_LEN(symbol_sz, cp) 2*SLOT_LEN(cp, symbol_sz) +#define SF_LEN(symbol_sz, cp) (2*SLOT_LEN(symbol_sz, cp)) #define SLOT_IDX_CPNORM(idx, symbol_sz) (idx==0?(CP(symbol_sz, CPNORM_0_LEN)):(CP(symbol_sz, CPNORM_0_LEN)+idx*(symbol_sz+CP(symbol_sz, CPNORM_LEN)))) #define SLOT_IDX_CPEXT(idx, symbol_sz) (idx*(symbol_sz+CP(symbol_sz, CPEXT_LEN))) @@ -96,8 +95,13 @@ typedef enum {CPNORM, CPEXT} lte_cp_t; #define GUARD_RE(nof_prb) ((lte_symbol_sz(nof_prb)-nof_prb*RE_X_RB)/2) +#define SYMBOL_HAS_REF(l, cp, nof_ports) ((l == 1 && nof_ports == 4) \ + || l == 0 \ + || l == CP_NSYMB(cp) - 3) + LIBLTE_API const int lte_symbol_sz(int nof_prb); +LIBLTE_API const int lte_sampling_freq_hz(int nof_prb); LIBLTE_API int lte_re_x_prb(int ns, int symbol, int nof_ports, int nof_symbols); LIBLTE_API int lte_voffset(int symbol_id, int cell_id, int nof_ports); @@ -105,6 +109,13 @@ LIBLTE_API int lte_voffset(int symbol_id, int cell_id, int nof_ports); #define NOF_TC_CB_SIZES 188 +typedef struct LIBLTE_API { + int nof_prb; + int nof_ports; + int cell_id; + lte_cp_t cp; +}lte_cell_t; + typedef enum LIBLTE_API { SINGLE_ANTENNA,TX_DIVERSITY, SPATIAL_MULTIPLEX diff --git a/lte/phy/include/liblte/phy/common/fft.h b/lte/phy/include/liblte/phy/common/fft.h index 881c64387..46c439e53 100644 --- a/lte/phy/include/liblte/phy/common/fft.h +++ b/lte/phy/include/liblte/phy/common/fft.h @@ -46,16 +46,19 @@ typedef struct LIBLTE_API{ int symbol_sz; int nof_guards; int nof_re; - lte_cp_t cp_type; + int slot_sz; + lte_cp_t cp; cf_t *tmp; // for removing zero padding }lte_fft_t; LIBLTE_API int lte_fft_init(lte_fft_t *q, lte_cp_t cp_type, int nof_prb); LIBLTE_API void lte_fft_free(lte_fft_t *q); -LIBLTE_API void lte_fft_run(lte_fft_t *q, cf_t *input, cf_t *output); +LIBLTE_API void lte_fft_run_slot(lte_fft_t *q, cf_t *input, cf_t *output); +LIBLTE_API void lte_fft_run_sf(lte_fft_t *q, cf_t *input, cf_t *output); LIBLTE_API int lte_ifft_init(lte_fft_t *q, lte_cp_t cp_type, int nof_prb); LIBLTE_API void lte_ifft_free(lte_fft_t *q); -LIBLTE_API void lte_ifft_run(lte_fft_t *q, cf_t *input, cf_t *output); +LIBLTE_API void lte_ifft_run_slot(lte_fft_t *q, cf_t *input, cf_t *output); +LIBLTE_API void lte_ifft_run_sf(lte_fft_t *q, cf_t *input, cf_t *output); #endif diff --git a/lte/phy/include/liblte/phy/phch/pbch.h b/lte/phy/include/liblte/phy/phch/pbch.h index 6583aca9d..568e8ead4 100644 --- a/lte/phy/include/liblte/phy/phch/pbch.h +++ b/lte/phy/include/liblte/phy/phch/pbch.h @@ -62,9 +62,9 @@ typedef struct LIBLTE_API { int nof_symbols; /* buffers */ - cf_t *ce[MAX_PORTS_CTRL]; - cf_t *pbch_symbols[MAX_PORTS_CTRL]; - cf_t *pbch_x[MAX_PORTS_CTRL]; + cf_t *ce[MAX_PORTS]; + cf_t *pbch_symbols[MAX_PORTS]; + cf_t *pbch_x[MAX_PORTS]; cf_t *pbch_d; float *pbch_llr; float *temp; @@ -87,13 +87,10 @@ typedef struct LIBLTE_API { LIBLTE_API int pbch_init(pbch_t *q, int nof_prb, int cell_id, lte_cp_t cp); LIBLTE_API void pbch_free(pbch_t *q); -LIBLTE_API int pbch_decode(pbch_t *q, cf_t *slot1_symbols, cf_t *ce[MAX_PORTS_CTRL], float ebno, pbch_mib_t *mib); -LIBLTE_API void pbch_encode(pbch_t *q, pbch_mib_t *mib, cf_t *slot1_symbols[MAX_PORTS_CTRL], int nof_ports); +LIBLTE_API int pbch_decode(pbch_t *q, cf_t *slot1_symbols, cf_t *ce[MAX_PORTS], pbch_mib_t *mib); +LIBLTE_API void pbch_encode(pbch_t *q, pbch_mib_t *mib, cf_t *slot1_symbols[MAX_PORTS], int nof_ports); LIBLTE_API void pbch_decode_reset(pbch_t *q); LIBLTE_API void pbch_mib_fprint(FILE *stream, pbch_mib_t *mib); -LIBLTE_API bool pbch_exists(int nframe, int nslot); -LIBLTE_API int pbch_put(cf_t *pbch, cf_t *slot1_data, int nof_prb, lte_cp_t cp, int cell_id); -LIBLTE_API int pbch_get(cf_t *pbch, cf_t *slot1_data, int nof_prb, lte_cp_t cp, int cell_id); #endif // PBCH_ diff --git a/lte/phy/include/liblte/phy/phch/pcfich.h b/lte/phy/include/liblte/phy/phch/pcfich.h index 1e9c63724..167756e6d 100644 --- a/lte/phy/include/liblte/phy/phch/pcfich.h +++ b/lte/phy/include/liblte/phy/phch/pcfich.h @@ -55,9 +55,9 @@ typedef struct LIBLTE_API { regs_t *regs; /* buffers */ - cf_t ce[MAX_PORTS_CTRL][PCFICH_RE]; - cf_t pcfich_symbols[MAX_PORTS_CTRL][PCFICH_RE]; - cf_t pcfich_x[MAX_PORTS_CTRL][PCFICH_RE]; + cf_t ce[MAX_PORTS][PCFICH_RE]; + cf_t pcfich_symbols[MAX_PORTS][PCFICH_RE]; + cf_t pcfich_x[MAX_PORTS][PCFICH_RE]; cf_t pcfich_d[PCFICH_RE]; /* bit message */ @@ -73,9 +73,9 @@ typedef struct LIBLTE_API { LIBLTE_API int pcfich_init(pcfich_t *q, regs_t *regs, int cell_id, int nof_prb, int nof_tx_ports, lte_cp_t cp); LIBLTE_API void pcfich_free(pcfich_t *q); -LIBLTE_API int pcfich_decode(pcfich_t *q, cf_t *slot_symbols, cf_t *ce[MAX_PORTS_CTRL], +LIBLTE_API int pcfich_decode(pcfich_t *q, cf_t *slot_symbols, cf_t *ce[MAX_PORTS], int nsubframe, int *cfi, int *distance); -LIBLTE_API int pcfich_encode(pcfich_t *q, int cfi, cf_t *slot_symbols[MAX_PORTS_CTRL], +LIBLTE_API int pcfich_encode(pcfich_t *q, int cfi, cf_t *slot_symbols[MAX_PORTS], int nsubframe); LIBLTE_API bool pcfich_exists(int nframe, int nslot); diff --git a/lte/phy/include/liblte/phy/phch/pdcch.h b/lte/phy/include/liblte/phy/phch/pdcch.h index 5b4948ac1..78c29d970 100644 --- a/lte/phy/include/liblte/phy/phch/pdcch.h +++ b/lte/phy/include/liblte/phy/phch/pdcch.h @@ -44,7 +44,8 @@ typedef _Complex float cf_t; -#define PDCCH_NOF_SEARCH_MODES 3 +#define PDCCH_NOF_SEARCH_MODES 3 +#define MAX_CANDIDATES 32 typedef enum LIBLTE_API { SEARCH_NONE = 3, SEARCH_SI = 0, SEARCH_RA = 1, SEARCH_UE = 2 @@ -56,7 +57,7 @@ typedef enum LIBLTE_API { */ typedef struct LIBLTE_API { int nof_candidates; - dci_candidate_t *candidates[NSUBFRAMES_X_FRAME]; + dci_candidate_t candidates[NSUBFRAMES_X_FRAME][MAX_CANDIDATES]; } pdcch_search_t; /* PDCCH object */ @@ -76,9 +77,9 @@ typedef struct LIBLTE_API { regs_t *regs; /* buffers */ - cf_t *ce[MAX_PORTS_CTRL]; - cf_t *pdcch_symbols[MAX_PORTS_CTRL]; - cf_t *pdcch_x[MAX_PORTS_CTRL]; + cf_t *ce[MAX_PORTS]; + cf_t *pdcch_symbols[MAX_PORTS]; + cf_t *pdcch_x[MAX_PORTS]; cf_t *pdcch_d; char *pdcch_e; float *pdcch_llr; @@ -95,8 +96,10 @@ LIBLTE_API int pdcch_init(pdcch_t *q, regs_t *regs, int nof_prb, int nof_ports, int cell_id, lte_cp_t cp); LIBLTE_API void pdcch_free(pdcch_t *q); +LIBLTE_API int pdcch_set_cfi(pdcch_t *q, int cfi); + /* Encoding functions */ -LIBLTE_API int pdcch_encode(pdcch_t *q, dci_t *dci, cf_t *slot_symbols[MAX_PORTS_CTRL], +LIBLTE_API int pdcch_encode(pdcch_t *q, dci_t *dci, cf_t *slot_symbols[MAX_PORTS], int nsubframe); /* Decoding functions */ @@ -106,10 +109,10 @@ LIBLTE_API int pdcch_encode(pdcch_t *q, dci_t *dci, cf_t *slot_symbols[MAX_PORTS * b) call pdcch_extract_llr() and then call pdcch_decode_si/ue/ra */ -LIBLTE_API int pdcch_decode(pdcch_t *q, cf_t *slot_symbols, cf_t *ce[MAX_PORTS_CTRL], - dci_t *dci, int nsubframe, float ebno); -LIBLTE_API int pdcch_extract_llr(pdcch_t *q, cf_t *slot_symbols, cf_t *ce[MAX_PORTS_CTRL], - float *llr, int nsubframe, float ebno); +LIBLTE_API int pdcch_decode(pdcch_t *q, cf_t *slot_symbols, cf_t *ce[MAX_PORTS], + dci_t *dci, int nsubframe); +LIBLTE_API int pdcch_extract_llr(pdcch_t *q, cf_t *slot_symbols, cf_t *ce[MAX_PORTS], + float *llr, int nsubframe); LIBLTE_API void pdcch_init_search_si(pdcch_t *q); LIBLTE_API void pdcch_set_search_si(pdcch_t *q); diff --git a/lte/phy/include/liblte/phy/phch/pdsch.h b/lte/phy/include/liblte/phy/phch/pdsch.h index a17a3ac2e..8e46aef37 100644 --- a/lte/phy/include/liblte/phy/phch/pdsch.h +++ b/lte/phy/include/liblte/phy/phch/pdsch.h @@ -49,43 +49,46 @@ typedef _Complex float cf_t; /* PDSCH object */ typedef struct LIBLTE_API { - int cell_id; - lte_cp_t cp; - int nof_prb; - int nof_ports; - int max_symbols; - unsigned short rnti; + int cell_id; + lte_cp_t cp; + int nof_prb; + int nof_ports; + int max_symbols; + unsigned short rnti; - /* buffers */ - cf_t *ce[MAX_PORTS]; - cf_t *pdsch_symbols[MAX_PORTS]; - cf_t *pdsch_x[MAX_PORTS]; - cf_t *pdsch_d; - char *pdsch_e_bits; - char *cb_in_b; - char *cb_out_b; - float *pdsch_llr; - float *pdsch_rm_f; + /* buffers */ + cf_t *ce[MAX_PORTS]; + cf_t *pdsch_symbols[MAX_PORTS]; + cf_t *pdsch_x[MAX_PORTS]; + cf_t *pdsch_d; + char *pdsch_e_bits; + char *cb_in_b; + char *cb_out_b; + float *pdsch_llr; + float *pdsch_rm_f; - /* tx & rx objects */ - modem_table_t mod[4]; - demod_soft_t demod; - sequence_t seq_pdsch[NSUBFRAMES_X_FRAME]; - tcod_t encoder; - tdec_t decoder; - rm_turbo_t rm_turbo; - crc_t crc_tb; - crc_t crc_cb; + /* tx & rx objects */ + modem_table_t mod[4]; + demod_soft_t demod; + sequence_t seq_pdsch[NSUBFRAMES_X_FRAME]; + tcod_t encoder; + tdec_t decoder; + rm_turbo_t rm_turbo; + crc_t crc_tb; + crc_t crc_cb; }pdsch_t; -LIBLTE_API int pdsch_init(pdsch_t *q, unsigned short user_rnti, int nof_prb, - int nof_ports, int cell_id, lte_cp_t cp); +LIBLTE_API int pdsch_init(pdsch_t *q, unsigned short user_rnti, int nof_prb, + int nof_ports, int cell_id, lte_cp_t cp); LIBLTE_API void pdsch_free(pdsch_t *q); LIBLTE_API 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 nsubframe, ra_mcs_t mcs, ra_prb_t *prb_alloc); LIBLTE_API 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); - + char *data, int nsubframe, ra_mcs_t mcs, ra_prb_t *prb_alloc); +LIBLTE_API int pdsch_get(pdsch_t *q, cf_t *sf_symbols, cf_t *pdsch_symbols, + ra_prb_t *prb_alloc, int nsubframe); +LIBLTE_API int pdsch_put(pdsch_t *q, cf_t *pdsch_symbols, cf_t *sf_symbols, + ra_prb_t *prb_alloc, int nsubframe); #endif diff --git a/lte/phy/include/liblte/phy/phch/phich.h b/lte/phy/include/liblte/phy/phch/phich.h index eec569c96..29a299796 100644 --- a/lte/phy/include/liblte/phy/phch/phich.h +++ b/lte/phy/include/liblte/phy/phch/phich.h @@ -63,9 +63,9 @@ typedef struct LIBLTE_API { regs_t *regs; /* buffers */ - cf_t ce[MAX_PORTS_CTRL][PHICH_MAX_NSYMB]; - cf_t phich_symbols[MAX_PORTS_CTRL][PHICH_MAX_NSYMB]; - cf_t phich_x[MAX_PORTS_CTRL][PHICH_MAX_NSYMB]; + cf_t ce[MAX_PORTS][PHICH_MAX_NSYMB]; + cf_t phich_symbols[MAX_PORTS][PHICH_MAX_NSYMB]; + cf_t phich_x[MAX_PORTS][PHICH_MAX_NSYMB]; cf_t phich_d[PHICH_MAX_NSYMB]; cf_t phich_d0[PHICH_MAX_NSYMB]; cf_t phich_z[PHICH_NBITS]; @@ -82,13 +82,13 @@ typedef struct LIBLTE_API { LIBLTE_API int phich_init(phich_t *q, regs_t *regs, int cell_id, int nof_prb, int nof_tx_ports, lte_cp_t cp); LIBLTE_API void phich_free(phich_t *q); -LIBLTE_API int phich_decode(phich_t *q, cf_t *slot_symbols, cf_t *ce[MAX_PORTS_CTRL], +LIBLTE_API int phich_decode(phich_t *q, cf_t *slot_symbols, cf_t *ce[MAX_PORTS], int ngroup, int nseq, int nsubframe, char *ack, int *distance); LIBLTE_API int phich_encode(phich_t *q, char ack, int ngroup, int nseq, int nsubframe, - cf_t *slot_symbols[MAX_PORTS_CTRL]); + cf_t *slot_symbols[MAX_PORTS]); -LIBLTE_API void phich_reset(phich_t *q, cf_t *slot_symbols[MAX_PORTS_CTRL]); +LIBLTE_API void phich_reset(phich_t *q, cf_t *slot_symbols[MAX_PORTS]); LIBLTE_API int phich_ngroups(phich_t *q); LIBLTE_API bool phich_exists(int nframe, int nslot); LIBLTE_API int phich_put(regs_t *h, cf_t *phich, cf_t *slot_data); diff --git a/lte/phy/include/liblte/phy/phch/regs.h b/lte/phy/include/liblte/phy/phch/regs.h index 496444e0a..fa5175317 100644 --- a/lte/phy/include/liblte/phy/phch/regs.h +++ b/lte/phy/include/liblte/phy/phch/regs.h @@ -94,7 +94,7 @@ LIBLTE_API int regs_phich_get(regs_t *h, cf_t *slot_symbols, cf_t phich_symbols[ LIBLTE_API int regs_phich_ngroups(regs_t *h); LIBLTE_API int regs_phich_reset(regs_t *h, cf_t *slot_symbols); -LIBLTE_API int regs_pdcch_nregs(regs_t *h); +LIBLTE_API int regs_pdcch_nregs(regs_t *h, int cfi); LIBLTE_API int regs_pdcch_put(regs_t *h, cf_t *pdcch_symbols, cf_t *slot_symbols); LIBLTE_API int regs_pdcch_get(regs_t *h, cf_t *slot_symbols, cf_t *pdcch_symbols); diff --git a/lte/phy/include/liblte/phy/phy.h b/lte/phy/include/liblte/phy/phy.h index c8dfb1cc6..39243164b 100644 --- a/lte/phy/include/liblte/phy/phy.h +++ b/lte/phy/include/liblte/phy/phy.h @@ -93,11 +93,14 @@ #include "liblte/phy/scrambling/scrambling.h" #include "liblte/phy/resampling/interp.h" +#include "liblte/phy/resampling/decim.h" +#include "liblte/phy/resampling/resample_arb.h" #include "liblte/phy/sync/pss.h" #include "liblte/phy/sync/sfo.h" #include "liblte/phy/sync/sss.h" #include "liblte/phy/sync/sync.h" +#include "liblte/phy/sync/sync_frame.h" #include "liblte/phy/sync/cfo.h" #ifdef __cplusplus diff --git a/lte/phy/include/liblte/phy/resampling/decim.h b/lte/phy/include/liblte/phy/resampling/decim.h new file mode 100644 index 000000000..4d3036784 --- /dev/null +++ b/lte/phy/include/liblte/phy/resampling/decim.h @@ -0,0 +1,39 @@ +/** + * + * \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/. + * + */ + +#ifndef DECIM_H +#define DECIM_H_ + +#include "liblte/config.h" + +typedef _Complex float cf_t; + + +LIBLTE_API void decim_c(cf_t *input, cf_t *output, int M, int len); +LIBLTE_API void decim_f(float *input, float *output, int M, int len); + +#endif // DECIM_H diff --git a/lte/phy/include/liblte/phy/resampling/interp.h b/lte/phy/include/liblte/phy/resampling/interp.h index ef7e87205..3c0a652e7 100644 --- a/lte/phy/include/liblte/phy/resampling/interp.h +++ b/lte/phy/include/liblte/phy/resampling/interp.h @@ -34,7 +34,7 @@ typedef _Complex float cf_t; LIBLTE_API void interp_linear_offset(cf_t *input, cf_t *output, int M, int len, int off_st, int off_end); -LIBLTE_API void interp_linear(cf_t *input, cf_t *output, int M, int len); +LIBLTE_API void interp_linear_c(cf_t *input, cf_t *output, int M, int len); LIBLTE_API void interp_linear_f(float *input, float *output, int M, int len); #endif // INTERP_H diff --git a/lte/phy/include/liblte/phy/sync/cfo.h b/lte/phy/include/liblte/phy/sync/cfo.h index c2adb9a04..b3f282fe0 100644 --- a/lte/phy/include/liblte/phy/sync/cfo.h +++ b/lte/phy/include/liblte/phy/sync/cfo.h @@ -32,6 +32,7 @@ #include #include "liblte/config.h" +#include "liblte/phy/utils/cexptab.h" typedef _Complex float cf_t; diff --git a/lte/phy/include/liblte/phy/sync/pss.h b/lte/phy/include/liblte/phy/sync/pss.h index 884470ee1..30161e135 100644 --- a/lte/phy/include/liblte/phy/sync/pss.h +++ b/lte/phy/include/liblte/phy/sync/pss.h @@ -69,20 +69,25 @@ typedef struct LIBLTE_API { int frame_size; int N_id_2; - float current_cfo; - bool cfo_auto; // default true - int nof_nosync_frames; - int nosync_timeout_frames; // default 5 - float correlation_threshold; // default 10000 - int frame_start_idx; - int fb_wp; - cf_t *pss_signal_freq; + cf_t *pss_signal_freq[3]; // One sequence for each N_id_2 cf_t *tmp_input; float *conv_abs; - cf_t *frame_buffer; cf_t *conv_output; + +#ifdef ENABLE_HL + cf_t *frame_buffer; cf_t *tmp_nco; + float current_cfo; + bool cfo_auto; + int nof_nosync_frames; + int nosync_timeout_frames; + float correlation_threshold; + int frame_start_idx; + int fb_wp; +#endif + + }pss_synch_t; typedef enum { PSS_TX, PSS_RX } pss_direction_t; diff --git a/lte/phy/include/liblte/phy/sync/sss.h b/lte/phy/include/liblte/phy/sync/sss.h index ce5b502ec..2ee839e14 100644 --- a/lte/phy/include/liblte/phy/sync/sss.h +++ b/lte/phy/include/liblte/phy/sync/sss.h @@ -53,7 +53,6 @@ struct sss_tables{ int z1[N_SSS][N_SSS]; int c[2][N_SSS]; int s[N_SSS][N_SSS]; - int N_id_2; }; /* Allocate 32 complex to make it multiple of 32-byte AVX instructions alignment requirement. @@ -74,9 +73,10 @@ typedef struct LIBLTE_API { float corr_peak_threshold; int symbol_sz; int subframe_sz; + int N_id_2; int N_id_1_table[30][30]; - struct fc_tables fc_tables; + struct fc_tables fc_tables[3]; // one for each N_id_2 }sss_synch_t; diff --git a/lte/phy/include/liblte/phy/sync/sync.h b/lte/phy/include/liblte/phy/sync/sync.h index b1602a117..0288b29d6 100644 --- a/lte/phy/include/liblte/phy/sync/sync.h +++ b/lte/phy/include/liblte/phy/sync/sync.h @@ -32,13 +32,13 @@ #include #include "liblte/config.h" -#include "pss.h" -#include "sss.h" -#include "sfo.h" +#include "liblte/phy/sync/pss.h" +#include "liblte/phy/sync/sss.h" /** * * This object performs time and frequency synchronization using the PSS and SSS signals. + * * The object is designed to work with signals sampled at 1.92 Mhz centered at the carrier frequency. * Thus, downsampling is required if the signal is sampled at higher frequencies. * @@ -49,28 +49,36 @@ enum sync_pss_det { ABSOLUTE, PEAK_MEAN}; +#define TRACK_THRESHOLD 10.0 +#define TRACK_LEN 300 + typedef struct LIBLTE_API { - pss_synch_t pss[3]; // One for each N_id_2 - sss_synch_t sss[3]; // One for each N_id_2 + pss_synch_t pss; + pss_synch_t pss_track; + sss_synch_t sss; enum sync_pss_det pss_mode; float threshold; float peak_to_avg; - int force_N_id_2; int N_id_2; int N_id_1; int slot_id; float cfo; - lte_cp_t cp; bool detect_cp; bool sss_en; + lte_cp_t cp; }sync_t; LIBLTE_API int sync_init(sync_t *q, int frame_size); LIBLTE_API void sync_free(sync_t *q); -/* Runs the synchronization algorithm. input signal must be sampled at 1.92 MHz and should be frame_size long at least */ -LIBLTE_API int sync_run(sync_t *q, cf_t *input); +/* Finds a correlation peak in the input signal. The signal must be sampled at 1.92 MHz and should be + subframe_size long at least */ +LIBLTE_API int sync_find(sync_t *q, cf_t *input); + +/* Tracks the correlation peak in the input signal. The signal must be sampled at 1.92 MHz and should be + TRACK_LEN long at least */ +LIBLTE_API int sync_track(sync_t *q, cf_t *input); /* Sets the threshold for peak comparison */ LIBLTE_API void sync_set_threshold(sync_t *q, float threshold); @@ -79,14 +87,6 @@ LIBLTE_API void sync_pss_det_absolute(sync_t *q); /* Set peak comparison to relative to the mean */ LIBLTE_API void sync_pss_det_peak_to_avg(sync_t *q); -/* Forces the synchronizer to check one N_id_2 PSS sequence only (useful for tracking mode) */ -LIBLTE_API void sync_force_N_id_2(sync_t *q, int force_N_id_2); -/* Forces the synchronizer to skip CP detection (useful for tracking mode) */ -LIBLTE_API void sync_force_cp(sync_t *q, lte_cp_t cp); -/* Enables/Disables SSS detection (useful for tracking mode) */ -LIBLTE_API void sync_sss_en(sync_t *q, bool enabled); - - /* Gets the slot id (0 or 10) */ LIBLTE_API int sync_get_slot_id(sync_t *q); /* Gets the last peak-to-average ratio */ @@ -101,6 +101,10 @@ LIBLTE_API int sync_get_cell_id(sync_t *q); LIBLTE_API float sync_get_cfo(sync_t *q); /* Gets the CP length estimation from the last call to synch_run() */ LIBLTE_API lte_cp_t sync_get_cp(sync_t *q); +/* Enables/Disables SSS detection */ +LIBLTE_API void sync_sss_en(sync_t *q, bool enabled); +/* Enables/Disables CP detection */ +LIBLTE_API void sync_cp_en(sync_t *q, bool enabled); #endif // SYNC_ diff --git a/lte/phy/include/liblte/phy/sync/sync_frame.h b/lte/phy/include/liblte/phy/sync/sync_frame.h new file mode 100644 index 000000000..9ed2335f0 --- /dev/null +++ b/lte/phy/include/liblte/phy/sync/sync_frame.h @@ -0,0 +1,106 @@ +/** + * + * \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/. + * + */ + +#ifndef SYNC_FRAME_ +#define SYNC_FRAME_ + +#include + +#include "liblte/config.h" +#include "liblte/phy/sync/sync.h" +#include "liblte/phy/sync/cfo.h" + +/** + * + * Uses sync object to automatically manage the FIND and TRACKING states. + * It is suposed to work on a subframe basis. The input signal must be sampled at + * a frequency integer multiple of 1.92 MHz. The signal is internally downsampled + * and fed to the sync object. + * + * This object also deals with frame alignment and CFO correction, returning an + * output signal aligned both in time and frequency. + */ + +enum sync_frame_state { SF_FIND, SF_TRACK }; + +#define SYNC_SF_LEN 1920 // 1ms at 1.92 MHz + +#define TRACK_MAX_LOST 10 + + +typedef struct LIBLTE_API { + sync_t s; + enum sync_frame_state state; + int downsampling; + unsigned long frame_cnt; + bool fb_wp; + int frame_size; + cf_t *input_buffer; + cf_t *input_downsampled; + cfo_t cfocorr; + float cur_cfo; + int peak_idx; + int cell_id; + float timeoffset; + int last_found; + int sf_idx; +}sync_frame_t; + + +/* Initializes the automatic tracker, setting the downsampling ratio for the input signal. + * upsampled is the ratio of the provided signal sampling frequency to 1.92 Mhz. E.g. if input is sampled at 3.84 Mhz, + * upsampled should be 2. +*/ +LIBLTE_API int sync_frame_init(sync_frame_t *q, int upsampled); + +LIBLTE_API void sync_frame_free(sync_frame_t *q); + +LIBLTE_API void sync_frame_set_threshold(sync_frame_t *q, float threshold); + +LIBLTE_API int sync_frame_cell_id(sync_frame_t *q); + +LIBLTE_API int sync_frame_sfidx(sync_frame_t *q); + +/* Automatically time/freq synchronizes the input signal. Returns 1 if the signal is synched and locked, + * and fills the output buffer with the time and frequency aligned version of the signal. + * If 0 is returned, the PSS was not found. -1 is returned in case of error. + * + * The provided signal can be sampled at an integer multiple of 1.92 Mhz. + * The sampling ratio is provided when calling the sync_auto_reset() function. + * + * The buffer input must have subframe_size samples (used in sync_init) + */ +LIBLTE_API int sync_frame_push(sync_frame_t *q, cf_t *input, cf_t *output); + +/* Resets the automatic tracker */ +LIBLTE_API void sync_frame_reset(sync_frame_t *q); + + + + +#endif // SYNC_FRAME_ + diff --git a/lte/phy/include/liblte/phy/utils/debug.h b/lte/phy/include/liblte/phy/utils/debug.h index 06b03079c..78bba353a 100644 --- a/lte/phy/include/liblte/phy/utils/debug.h +++ b/lte/phy/include/liblte/phy/utils/debug.h @@ -44,6 +44,7 @@ LIBLTE_API extern int verbose; #define VERBOSE_ISINFO() (verbose>=VERBOSE_INFO) #define VERBOSE_ISDEBUG() (verbose>=VERBOSE_DEBUG) +#define VERBOSE_ISNONE() (verbose==VERBOSE_NONE) #define PRINT_DEBUG verbose=VERBOSE_DEBUG #define PRINT_INFO verbose=VERBOSE_INFO diff --git a/lte/phy/lib/ch_estimation/src/chest.c b/lte/phy/lib/ch_estimation/src/chest.c index a953153d9..ae855cfdc 100644 --- a/lte/phy/lib/ch_estimation/src/chest.c +++ b/lte/phy/lib/ch_estimation/src/chest.c @@ -46,6 +46,15 @@ void chest_fprint(chest_t *q, FILE *stream, int nslot, int port_id) { chest_ce_fprint(q, stream, nslot, port_id); } +/* Sets the number of ports to estimate. nof_ports must be smaler than nof_ports + * used during the call to chest_init(). + */ +void chest_set_nof_ports(chest_t *q, int nof_ports) { + if (nof_ports < q->nof_ports && nof_ports > 0) { + q->nof_ports = nof_ports; + } +} + void chest_ref_fprint(chest_t *q, FILE *stream, int nslot, int port_id) { int i; fprintf(stream, "refs%d=[",port_id); @@ -149,8 +158,18 @@ void chest_ce_slot_port(chest_t *q, cf_t *input, cf_t *ce, int nslot, int port_i } } -/* Computes channel estimates for each reference in a slot. - * Saves the result for the p-th port to the pointer ce[p] + +/* Computes channel estimates for each reference in a subframe and port id. + */ +void chest_ce_sf_port(chest_t *q, cf_t *input, cf_t *ce, int sf_idx, int port_id) { + int n, slotsz; + slotsz = CP_NSYMB(q->cp)*q->nof_prb*RE_X_RB; + for (n=0;n<2;n++) { + chest_ce_slot_port(q, &input[n*slotsz], &ce[n*slotsz], 2*sf_idx+n, port_id); + } +} + +/* Computes channel estimates for each reference in a slot for all ports. */ void chest_ce_slot(chest_t *q, cf_t *input, cf_t **ce, int nslot) { int p; @@ -159,6 +178,17 @@ void chest_ce_slot(chest_t *q, cf_t *input, cf_t **ce, int nslot) { } } +/* Computes channel estimates for each reference in a subframe for all ports. + */ +void chest_ce_sf(chest_t *q, cf_t *input, cf_t *ce[MAX_PORTS], int sf_idx) { + int p, n, slotsz; + slotsz = CP_NSYMB(q->cp)*q->nof_prb*RE_X_RB; + for (p=0;pnof_ports;p++) { + for (n=0;n<2;n++) { + chest_ce_slot_port(q, &input[n*slotsz], &ce[p][n*slotsz], 2*sf_idx+n, p); + } + } +} int chest_init(chest_t *q, chest_interp_t interp, lte_cp_t cp, int nof_prb, int nof_ports) { if (nof_ports > MAX_PORTS) { diff --git a/lte/phy/lib/common/src/fft.c b/lte/phy/lib/common/src/fft.c index 508c63264..990cd7840 100644 --- a/lte/phy/lib/common/src/fft.c +++ b/lte/phy/lib/common/src/fft.c @@ -35,7 +35,7 @@ #include "liblte/phy/utils/debug.h" #include "liblte/phy/utils/vector.h" -int lte_fft_init_(lte_fft_t *q, lte_cp_t cp_type, int nof_prb, dft_dir_t dir) { +int lte_fft_init_(lte_fft_t *q, lte_cp_t cp, int nof_prb, dft_dir_t dir) { int symbol_sz = lte_symbol_sz(nof_prb); if (symbol_sz == -1) { @@ -57,13 +57,15 @@ int lte_fft_init_(lte_fft_t *q, lte_cp_t cp_type, int nof_prb, dft_dir_t dir) { dft_plan_set_dc(&q->fft_plan, true); q->symbol_sz = symbol_sz; - q->nof_symbols = CP_NSYMB(cp_type); - q->cp_type = cp_type; + q->nof_symbols = CP_NSYMB(cp); + q->cp = cp; q->nof_re = nof_prb * RE_X_RB; q->nof_guards = ((symbol_sz - q->nof_re) / 2); - DEBUG("Init %s symbol_sz=%d, nof_symbols=%d, cp_type=%s, nof_re=%d, nof_guards=%d\n", + q->slot_sz = SLOT_LEN(symbol_sz, cp); + + DEBUG("Init %s symbol_sz=%d, nof_symbols=%d, cp=%s, nof_re=%d, nof_guards=%d\n", dir==FORWARD?"FFT":"iFFT", q->symbol_sz, q->nof_symbols, - q->cp_type==CPNORM?"Normal":"Extended", q->nof_re, q->nof_guards); + q->cp==CPNORM?"Normal":"Extended", q->nof_re, q->nof_guards); return 0; } @@ -75,17 +77,17 @@ void lte_fft_free_(lte_fft_t *q) { bzero(q, sizeof(lte_fft_t)); } -int lte_fft_init(lte_fft_t *q, lte_cp_t cp_type, int nof_prb) { - return lte_fft_init_(q, cp_type, nof_prb, FORWARD); +int lte_fft_init(lte_fft_t *q, lte_cp_t cp, int nof_prb) { + return lte_fft_init_(q, cp, nof_prb, FORWARD); } void lte_fft_free(lte_fft_t *q) { lte_fft_free_(q); } -int lte_ifft_init(lte_fft_t *q, lte_cp_t cp_type, int nof_prb) { +int lte_ifft_init(lte_fft_t *q, lte_cp_t cp, int nof_prb) { int i; - if (lte_fft_init_(q, cp_type, nof_prb, BACKWARD)) { + if (lte_fft_init_(q, cp, nof_prb, BACKWARD)) { return -1; } /* set now zeros at CP */ @@ -103,10 +105,10 @@ void lte_ifft_free(lte_fft_t *q) { /* Transforms input samples into output OFDM symbols. * Performs FFT on a each symbol and removes CP. */ -void lte_fft_run(lte_fft_t *q, cf_t *input, cf_t *output) { +void lte_fft_run_slot(lte_fft_t *q, cf_t *input, cf_t *output) { int i; for (i=0;inof_symbols;i++) { - input += CP_ISNORM(q->cp_type)?CP_NORM(i, q->symbol_sz):CP_EXT(q->symbol_sz); + input += CP_ISNORM(q->cp)?CP_NORM(i, q->symbol_sz):CP_EXT(q->symbol_sz); dft_run_c(&q->fft_plan, input, q->tmp); memcpy(output, &q->tmp[q->nof_guards], q->nof_re * sizeof(cf_t)); input += q->symbol_sz; @@ -114,13 +116,20 @@ void lte_fft_run(lte_fft_t *q, cf_t *input, cf_t *output) { } } +void lte_fft_run_sf(lte_fft_t *q, cf_t *input, cf_t *output) { + int n; + for (n=0;n<2;n++) { + lte_fft_run_slot(q, &input[n*q->slot_sz], &output[n*q->nof_re*q->nof_symbols]); + } +} + /* Transforms input OFDM symbols into output samples. * Performs FFT on a each symbol and adds CP. */ -void lte_ifft_run(lte_fft_t *q, cf_t *input, cf_t *output) { +void lte_ifft_run_slot(lte_fft_t *q, cf_t *input, cf_t *output) { int i, cp_len; for (i=0;inof_symbols;i++) { - cp_len = CP_ISNORM(q->cp_type)?CP_NORM(i, q->symbol_sz):CP_EXT(q->symbol_sz); + cp_len = CP_ISNORM(q->cp)?CP_NORM(i, q->symbol_sz):CP_EXT(q->symbol_sz); memcpy(&q->tmp[q->nof_guards], input, q->nof_re * sizeof(cf_t)); dft_run_c(&q->fft_plan, q->tmp, &output[cp_len]); input += q->nof_re; @@ -130,3 +139,9 @@ void lte_ifft_run(lte_fft_t *q, cf_t *input, cf_t *output) { } } +void lte_ifft_run_sf(lte_fft_t *q, cf_t *input, cf_t *output) { + int n; + for (n=0;n<2;n++) { + lte_ifft_run_slot(q, &input[n*q->nof_re*q->nof_symbols], &output[n*q->slot_sz]); + } +} diff --git a/lte/phy/lib/common/src/lte.c b/lte/phy/lib/common/src/lte.c index 063c4494c..d85a79afb 100644 --- a/lte/phy/lib/common/src/lte.c +++ b/lte/phy/lib/common/src/lte.c @@ -77,6 +77,9 @@ int lte_find_cb_index(int long_cb) { } } +const int lte_sampling_freq_hz(int nof_prb) { + return 15000 * lte_symbol_sz(nof_prb); +} const int lte_symbol_sz(int nof_prb) { if (nof_prb<=0) { return -1; diff --git a/lte/phy/lib/common/test/fft_test.c b/lte/phy/lib/common/test/fft_test.c index a5e1e3662..8d6f883bf 100644 --- a/lte/phy/lib/common/test/fft_test.c +++ b/lte/phy/lib/common/test/fft_test.c @@ -111,8 +111,8 @@ int main(int argc, char **argv) { input[i] = 100 * ((float) rand()/RAND_MAX + (float) I*rand()/RAND_MAX); } - lte_ifft_run(&ifft, input, outfft); - lte_fft_run(&fft, outfft, outifft); + lte_ifft_run_slot(&ifft, input, outfft); + lte_fft_run_slot(&fft, outfft, outifft); /* compute MSE */ diff --git a/lte/phy/lib/fec/src/viterbi.c b/lte/phy/lib/fec/src/viterbi.c index 4b79ea983..aa17e176a 100644 --- a/lte/phy/lib/fec/src/viterbi.c +++ b/lte/phy/lib/fec/src/viterbi.c @@ -185,7 +185,9 @@ int viterbi_init(viterbi_t *q, viterbi_type_t type, int poly[3], } void viterbi_free(viterbi_t *q) { - q->free(q); + if (q->free) { + q->free(q); + } } /* symbols are real-valued */ diff --git a/lte/phy/lib/phch/src/dci.c b/lte/phy/lib/phch/src/dci.c index 42d9d41fc..a2dff2dcd 100644 --- a/lte/phy/lib/phch/src/dci.c +++ b/lte/phy/lib/phch/src/dci.c @@ -364,6 +364,7 @@ int dci_format1_pack(ra_pdsch_t *data, dci_msg_t *msg, int nof_prb) { ra_nprb_dl(data, nof_prb)); } mcs = ra_mcs_to_table_idx(&data->mcs); + data->mcs.mcs_idx = mcs; } bit_pack(mcs, &y, 5); @@ -425,7 +426,7 @@ int dci_format1_unpack(dci_msg_t *msg, ra_pdsch_t *data, int nof_prb) { return -1; } - /* pack MCS according to 7.1.7 of 36.213 */ + /* unpack MCS according to 7.1.7 of 36.213 */ uint32_t mcs = bit_unpack(&y, 5); data->mcs.mcs_idx = mcs; ra_mcs_from_idx_dl(mcs, &data->mcs); diff --git a/lte/phy/lib/phch/src/pbch.c b/lte/phy/lib/phch/src/pbch.c index 2e8a47c39..c1f6b2297 100644 --- a/lte/phy/lib/phch/src/pbch.c +++ b/lte/phy/lib/phch/src/pbch.c @@ -55,6 +55,7 @@ int pbch_cp(cf_t *input, cf_t *output, int nof_prb, lte_cp_t cp, int cell_id, int i; cf_t *ptr; assert(cell_id >= 0); + if (put) { ptr = input; output += nof_prb * RE_X_RB / 2 - 36; @@ -62,19 +63,34 @@ int pbch_cp(cf_t *input, cf_t *output, int nof_prb, lte_cp_t cp, int cell_id, ptr = output; input += nof_prb * RE_X_RB / 2 - 36; } - + /* symbol 0 & 1 */ for (i = 0; i < 2; i++) { - prb_cp_ref(&input, &output, cell_id % 3, 4, 6, put); + prb_cp_ref(&input, &output, cell_id % 3, 4, 4*6, put); + if (put) { + output += nof_prb * RE_X_RB - 2*36; + } else { + input += nof_prb * RE_X_RB - 2*36; + } } /* symbols 2 & 3 */ if (CP_ISNORM(cp)) { for (i = 0; i < 2; i++) { prb_cp(&input, &output, 6); + if (put) { + output += nof_prb * RE_X_RB - 2*36; + } else { + input += nof_prb * RE_X_RB - 2*36; + } } } else { prb_cp(&input, &output, 6); - prb_cp_ref(&input, &output, cell_id % 3, 4, 6, put); + if (put) { + output += nof_prb * RE_X_RB - 2*36; + } else { + input += nof_prb * RE_X_RB - 2*36; + } + prb_cp_ref(&input, &output, cell_id % 3, 4, 4*6, put); } if (put) { return input - ptr; @@ -147,7 +163,7 @@ int pbch_init(pbch_t *q, int nof_prb, int cell_id, lte_cp_t cp) { goto clean; } int i; - for (i = 0; i < MAX_PORTS_CTRL; i++) { + for (i = 0; i < MAX_PORTS; i++) { q->ce[i] = malloc(sizeof(cf_t) * q->nof_symbols); if (!q->ce[i]) { goto clean; @@ -198,7 +214,7 @@ void pbch_free(pbch_t *q) { free(q->pbch_d); } int i; - for (i = 0; i < MAX_PORTS_CTRL; i++) { + for (i = 0; i < MAX_PORTS; i++) { if (q->ce[i]) { free(q->ce[i]); } @@ -422,8 +438,7 @@ int pbch_decode_frame(pbch_t *q, pbch_mib_t *mib, int src, int dst, 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], pbch_mib_t *mib) { int src, dst, res, nb; int nant_[3] = { 1, 2, 4 }; int na, nant; @@ -434,10 +449,10 @@ int pbch_decode(pbch_t *q, cf_t *slot1_symbols, cf_t *ce[MAX_PORTS_CTRL], cf_t *x[MAX_LAYERS]; /* number of layers equals number of ports */ - for (i = 0; i < MAX_PORTS_CTRL; i++) { + for (i = 0; i < MAX_PORTS; i++) { x[i] = q->pbch_x[i]; } - memset(&x[MAX_PORTS_CTRL], 0, sizeof(cf_t*) * (MAX_LAYERS - MAX_PORTS_CTRL)); + memset(&x[MAX_PORTS], 0, sizeof(cf_t*) * (MAX_LAYERS - MAX_PORTS)); /* extract symbols */ if (q->nof_symbols @@ -448,7 +463,7 @@ int pbch_decode(pbch_t *q, cf_t *slot1_symbols, cf_t *ce[MAX_PORTS_CTRL], } /* extract channel estimates */ - for (i = 0; i < MAX_PORTS_CTRL; i++) { + for (i = 0; i < MAX_PORTS; 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"); @@ -477,7 +492,7 @@ int pbch_decode(pbch_t *q, cf_t *slot1_symbols, cf_t *ce[MAX_PORTS_CTRL], } /* demodulate symbols */ - demod_soft_sigma_set(&q->demod, ebno); + demod_soft_sigma_set(&q->demod, 1.0); demod_soft_demodulate(&q->demod, q->pbch_d, &q->pbch_llr[nof_bits * (q->frame_idx - 1)], q->nof_symbols); @@ -510,11 +525,11 @@ int pbch_decode(pbch_t *q, cf_t *slot1_symbols, cf_t *ce[MAX_PORTS_CTRL], /** 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) { + cf_t *slot1_symbols[MAX_PORTS], int nof_ports) { int i; int nof_bits = 2 * q->nof_symbols; - assert(nof_ports <= MAX_PORTS_CTRL); + assert(nof_ports <= MAX_PORTS); /* Set pointers for layermapping & precoding */ cf_t *x[MAX_LAYERS]; diff --git a/lte/phy/lib/phch/src/pcfich.c b/lte/phy/lib/phch/src/pcfich.c index 58ad0bfc9..05224f695 100644 --- a/lte/phy/lib/phch/src/pcfich.c +++ b/lte/phy/lib/phch/src/pcfich.c @@ -139,7 +139,7 @@ int pcfich_cfi_encode(int cfi, char bits[PCFICH_CFI_LEN]) { * * Returns 1 if successfully decoded the CFI, 0 if not and -1 on error */ -int pcfich_decode(pcfich_t *q, cf_t *slot_symbols, cf_t *ce[MAX_PORTS_CTRL], +int pcfich_decode(pcfich_t *q, cf_t *slot_symbols, cf_t *ce[MAX_PORTS], int nsubframe, int *cfi, int *distance) { int dist; @@ -154,7 +154,7 @@ int pcfich_decode(pcfich_t *q, cf_t *slot_symbols, cf_t *ce[MAX_PORTS_CTRL], } /* number of layers equals number of ports */ - for (i = 0; i < MAX_PORTS_CTRL; i++) { + for (i = 0; i < MAX_PORTS; i++) { x[i] = q->pcfich_x[i]; } for (i = 0; i < MAX_PORTS; i++) { @@ -208,7 +208,7 @@ int pcfich_decode(pcfich_t *q, cf_t *slot_symbols, cf_t *ce[MAX_PORTS_CTRL], /** Encodes CFI and maps symbols to the slot */ -int pcfich_encode(pcfich_t *q, int cfi, cf_t *slot_symbols[MAX_PORTS_CTRL], +int pcfich_encode(pcfich_t *q, int cfi, cf_t *slot_symbols[MAX_PORTS], int nsubframe) { int i; @@ -229,7 +229,7 @@ int pcfich_encode(pcfich_t *q, int cfi, cf_t *slot_symbols[MAX_PORTS_CTRL], symbols_precoding[i] = q->pcfich_symbols[i]; } - /* pack MIB */ + /* pack CFI */ pcfich_cfi_encode(cfi, q->data); /* scramble for slot sequence nslot */ diff --git a/lte/phy/lib/phch/src/pdcch.c b/lte/phy/lib/phch/src/pdcch.c index d3f37b71c..0b37faaab 100644 --- a/lte/phy/lib/phch/src/pdcch.c +++ b/lte/phy/lib/phch/src/pdcch.c @@ -89,8 +89,6 @@ int gen_ue_search(dci_candidate_t *c, int nof_cce, int nof_bits, 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]: "); } for (l = 3; l >= 0; l--) { L = (1 << l); @@ -103,39 +101,31 @@ int gen_ue_search(dci_candidate_t *c, int nof_cce, int nof_bits, Yk = (39827 * Yk) % 65537; } c[k].ncce = L * ((Yk + i) % (nof_cce / L)); - if (!subframe) { - if (VERBOSE_ISINFO()) { - printf("(%d, %d), ", c[k].ncce, c[k].L); - } + if (VERBOSE_ISDEBUG()) { + printf("sf %d - (%d, %d), ", subframe, c[k].ncce, c[k].L); } k++; } } - if (!subframe) { - if (VERBOSE_ISINFO()) - printf("\n"); + if (VERBOSE_ISDEBUG()) { + 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); - if (s->nof_candidates) { - s->candidates[0] = malloc(sizeof(dci_candidate_t) * s->nof_candidates); - dci_candidate_t *c = s->candidates[0]; - s->nof_candidates = 0; - 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; i < NOF_COMMON_FORMATS; i++) { - k += gen_common_search(&c[k], q->nof_cce, - dci_format_sizeof(common_formats[i], q->nof_prb), SIRNTI); - s->nof_candidates++; - } - } + dci_candidate_t *c = s->candidates[0]; + s->nof_candidates = 0; + // Format 1A and 1C L=4 and L=8, 4 and 2 candidates, only if nof_cce > 16 + k = 0; + for (i = 0; i < NOF_COMMON_FORMATS && k < MAX_CANDIDATES; i++) { + k += gen_common_search(&c[k], q->nof_cce, + dci_format_sizeof(common_formats[i], q->nof_prb), SIRNTI); } + s->nof_candidates=k; + INFO("Initiated %d candidate(s) in the Common search space for RNTI: 0x%x\n", + s->nof_candidates, rnti); } /** 36.213 v9.3 Table 7.1-1: System Information DCI messages @@ -151,30 +141,23 @@ void pdcch_init_search_si(pdcch_t *q) { * DCI Format 1A and 1 + PUSCH scheduling format 0 */ void pdcch_init_search_ue(pdcch_t *q, unsigned short c_rnti) { - int l, n, k, i; + int 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 << l)); - } - 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; n < NSUBFRAMES_X_FRAME; n++) { - s->candidates[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; i < NOF_UE_FORMATS; i++) { - k += gen_ue_search(&c[k], q->nof_cce, - dci_format_sizeof(ue_formats[i], q->nof_prb), c_rnti, n); - } - } + for (n = 0; n < NSUBFRAMES_X_FRAME; n++) { + dci_candidate_t *c = s->candidates[n]; + + if (!n) s->nof_candidates = 0; + + // Expect Formats 1, 1A, 0 + k = 0; + for (i = 0; i < NOF_UE_FORMATS && k < MAX_CANDIDATES; i++) { + k += gen_ue_search(&c[k], q->nof_cce, + dci_format_sizeof(ue_formats[i], q->nof_prb), c_rnti, n); } + s->nof_candidates = k; } + INFO("Initiated %d candidate(s) in the UE-specific search space for C-RNTI: 0x%x\n", + s->nof_candidates, c_rnti); q->current_search_mode = SEARCH_UE; } @@ -196,6 +179,24 @@ void pdcch_set_search_ra(pdcch_t *q) { q->current_search_mode = SEARCH_RA; } +int pdcch_set_cfi(pdcch_t *q, int cfi) { + if (cfi == -1) { + q->nof_bits = -1; + q->nof_symbols = -1; + q->nof_cce = -1; + q->nof_regs = -1; + return 0; + } else if (cfi < 4 && cfi > 0) { + q->nof_regs = (regs_pdcch_nregs(q->regs, cfi) / 9) * 9; + q->nof_cce = q->nof_regs / 9; + q->nof_symbols = 4 * q->nof_regs; + q->nof_bits = 2 * q->nof_symbols; + return 0; + } else { + return -1; + } +} + /** Initializes the PDCCH transmitter and receiver */ int pdcch_init(pdcch_t *q, regs_t *regs, int nof_prb, int nof_ports, int cell_id, lte_cp_t cp) { @@ -205,7 +206,7 @@ int pdcch_init(pdcch_t *q, regs_t *regs, int nof_prb, int nof_ports, if (cell_id < 0) { return -1; } - if (nof_ports > MAX_PORTS_CTRL) { + if (nof_ports > MAX_PORTS) { fprintf(stderr, "Invalid number of ports %d\n", nof_ports); return -1; } @@ -217,10 +218,10 @@ 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_cce = q->nof_regs / 9; - q->nof_symbols = 4 * q->nof_regs; - q->nof_bits = 2 * q->nof_symbols; + /* Now allocate memory for the maximum number of REGs (CFI=2), then can + * be changed at runtime + */ + pdcch_set_cfi(q, 3); 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); @@ -262,7 +263,7 @@ int pdcch_init(pdcch_t *q, regs_t *regs, int nof_prb, int nof_ports, goto clean; } - for (i = 0; i < MAX_PORTS_CTRL; i++) { + for (i = 0; i < MAX_PORTS; i++) { q->ce[i] = malloc(sizeof(cf_t) * q->nof_symbols); if (!q->ce[i]) { goto clean; @@ -276,6 +277,10 @@ int pdcch_init(pdcch_t *q, regs_t *regs, int nof_prb, int nof_ports, goto clean; } } + + /* Reset CFI to make sure we return error if new CFI is not set */ + pdcch_set_cfi(q, -1); + ret = 0; clean: if (ret == -1) { pdcch_free(q); @@ -284,15 +289,8 @@ int pdcch_init(pdcch_t *q, regs_t *regs, int nof_prb, int nof_ports, } void pdcch_free(pdcch_t *q) { - int i, j; + int i; - for (i = 0; i < PDCCH_NOF_SEARCH_MODES; i++) { - for (j = 0; j < NSUBFRAMES_X_FRAME; j++) { - if (q->search_mode[i].candidates[j]) { - free(q->search_mode[i].candidates[j]); - } - } - } if (q->pdcch_e) { free(q->pdcch_e); } @@ -302,7 +300,7 @@ void pdcch_free(pdcch_t *q) { if (q->pdcch_d) { free(q->pdcch_d); } - for (i = 0; i < MAX_PORTS_CTRL; i++) { + for (i = 0; i < MAX_PORTS; i++) { if (q->ce[i]) { free(q->ce[i]); } @@ -362,7 +360,7 @@ unsigned short dci_decode(pdcch_t *q, float *e, char *data, int E, int nof_bits) 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", + INFO("Trying Candidate: Nbits: %d, E: %3d, nCCE: %d, L: %d, RNTI: 0x%x\n", 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); @@ -376,20 +374,20 @@ int pdcch_decode_candidate(pdcch_t *q, float *llr, dci_candidate_t *c, return 0; } -int pdcch_extract_llr(pdcch_t *q, cf_t *slot_symbols, cf_t *ce[MAX_PORTS_CTRL], - float *llr, int nsubframe, float ebno) { +int pdcch_extract_llr(pdcch_t *q, cf_t *slot_symbols, cf_t *ce[MAX_PORTS], + float *llr, int nsubframe) { /* Set pointers for layermapping & precoding */ int i; cf_t *x[MAX_LAYERS]; - if (nsubframe < 0 || nsubframe > NSUBFRAMES_X_FRAME) { - fprintf(stderr, "Invalid subframe %d\n", nsubframe); + if (q->nof_bits == -1 || q->nof_cce == -1 || q->nof_regs == -1) { + fprintf(stderr, "Must call pdcch_set_cfi() first to set the CFI\n"); return -1; } - if (ebno == 0.0) { - fprintf(stderr, "EbNo is Zero\n"); + if (nsubframe < 0 || nsubframe > NSUBFRAMES_X_FRAME) { + fprintf(stderr, "Invalid subframe %d\n", nsubframe); return -1; } @@ -435,7 +433,7 @@ int pdcch_extract_llr(pdcch_t *q, cf_t *slot_symbols, cf_t *ce[MAX_PORTS_CTRL], } /* demodulate symbols */ - demod_soft_sigma_set(&q->demod, ebno); + demod_soft_sigma_set(&q->demod, 1.0); demod_soft_demodulate(&q->demod, q->pdcch_d, q->pdcch_llr, q->nof_symbols); DEBUG("llr: ", 0); @@ -489,10 +487,15 @@ int pdcch_decode_ue(pdcch_t *q, float *llr, dci_t *dci, int nsubframe) { * * Returns number of messages stored in dci */ -int pdcch_decode(pdcch_t *q, cf_t *slot_symbols, cf_t *ce[MAX_PORTS_CTRL], - dci_t *dci, int nsubframe, float ebno) { +int pdcch_decode(pdcch_t *q, cf_t *slot_symbols, cf_t *ce[MAX_PORTS], + dci_t *dci, int nsubframe) { + + if (q->nof_bits == -1 || q->nof_cce == -1 || q->nof_regs == -1) { + fprintf(stderr, "Must call pdcch_set_cfi() first to set the CFI\n"); + return -1; + } - if (pdcch_extract_llr(q, slot_symbols, ce, q->pdcch_llr, nsubframe, ebno)) { + if (pdcch_extract_llr(q, slot_symbols, ce, q->pdcch_llr, nsubframe)) { return -1; } @@ -547,12 +550,16 @@ void dci_encode(pdcch_t *q, char *data, char *e, int nof_bits, int E, /** 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 *slot_symbols[MAX_PORTS_CTRL], +int pdcch_encode(pdcch_t *q, dci_t *dci, cf_t *slot_symbols[MAX_PORTS], int nsubframe) { int i; /* Set pointers for layermapping & precoding */ cf_t *x[MAX_LAYERS]; + if (q->nof_bits == -1 || q->nof_cce == -1 || q->nof_regs == -1) { + fprintf(stderr, "Must call pdcch_set_cfi() first to set the CFI\n"); + return -1; + } if (nsubframe < 0 || nsubframe > NSUBFRAMES_X_FRAME) { fprintf(stderr, "Invalid subframe %d\n", nsubframe); return -1; diff --git a/lte/phy/lib/phch/src/pdsch.c b/lte/phy/lib/phch/src/pdsch.c index e3a44287e..fd2b237a9 100644 --- a/lte/phy/lib/phch/src/pdsch.c +++ b/lte/phy/lib/phch/src/pdsch.c @@ -44,10 +44,7 @@ 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) +#define MAX_PDSCH_RE(cp) (2 * CP_NSYMB(cp) * 12) int pdsch_cp(pdsch_t *q, cf_t *input, cf_t *output, ra_prb_t *prb_alloc, int nsubframe, bool put) { @@ -56,9 +53,9 @@ int pdsch_cp(pdsch_t *q, cf_t *input, cf_t *output, ra_prb_t *prb_alloc, cf_t *in_ptr = input, *out_ptr = output; int offset; -assert(q->cell_id >= 0); + assert(q->cell_id >= 0); - INFO("%s %d RE from %d PRB\n", put ? "Putting" : "Getting", + 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) { @@ -68,14 +65,14 @@ assert(q->cell_id >= 0); } 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 (l = 0; l < CP_NSYMB(q->cp); l++) { for (n = 0; n < prb_alloc->slot[s].nof_prb; n++) { + if (s == 0) { + lstart = prb_alloc->lstart; + } else { + lstart = 0; + } lend = CP_NSYMB(q->cp); is_pbch = is_sss = false; @@ -103,31 +100,36 @@ assert(q->cell_id >= 0); 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 (SYMBOL_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); + prb_cp_ref(&in_ptr, &out_ptr, offset, nof_refs, nof_refs, 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 ((q->nof_prb % 2) && ((is_pbch && l < lstart) || (is_sss && l >= lend))) { + if (prb_alloc->slot[s].prb_idx[n] == q->nof_prb / 2 - 3) { + if (SYMBOL_HAS_REF(l, q->cp, q->nof_ports)) { + prb_cp_ref(&in_ptr, &out_ptr, offset, nof_refs, nof_refs/2, put); + } else { + prb_cp_half(&in_ptr, &out_ptr, 1); + } + } else if (prb_alloc->slot[s].prb_idx[n] == q->nof_prb / 2 + 3) { + if (put) { + out_ptr += 6; + } else { + in_ptr += 6; + } + if (SYMBOL_HAS_REF(l, q->cp, q->nof_ports)) { + prb_cp_ref(&in_ptr, &out_ptr, offset, nof_refs, nof_refs/2, put); + } else { + prb_cp_half(&in_ptr, &out_ptr, 1); + } } } } @@ -135,9 +137,9 @@ assert(q->cell_id >= 0); } if (put) { - return (int) (input - in_ptr); + return abs((int) (input - in_ptr)); } else { - return (int) (output - out_ptr); + return abs((int) (output - out_ptr)); } } @@ -421,11 +423,6 @@ int pdsch_decode_tb(pdsch_t *q, char *data, int tbs, int nb_e, int rv_idx) { //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)); @@ -450,13 +447,6 @@ int pdsch_decode_tb(pdsch_t *q, char *data, int tbs, int nb_e, int rv_idx) { // 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"); } @@ -470,7 +460,7 @@ 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; + int i, n; cf_t *x[MAX_LAYERS]; int nof_symbols, nof_bits, nof_bits_e; @@ -490,8 +480,7 @@ int pdsch_decode(pdsch_t *q, cf_t *sf_symbols, cf_t *ce[MAX_PORTS], char *data, return -1; } - INFO( - "Decoding PDSCH SF: %d, Mod %d, NofBits: %d, NofSymbols: %d, NofBitsE: %d\n", + 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) { @@ -504,15 +493,23 @@ int pdsch_decode(pdsch_t *q, cf_t *sf_symbols, cf_t *ce[MAX_PORTS], char *data, 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); + n = pdsch_get(q, sf_symbols, q->pdsch_symbols[0], prb_alloc, nsubframe); + if (n != nof_symbols) { + fprintf(stderr, "Error expecting %d symbols but got %d\n", nof_symbols, n); + return -1; + } /* extract channel estimates */ for (i = 0; i < q->nof_ports; i++) { - pdsch_get(q, ce[i], q->ce[i], prb_alloc, nsubframe); + n = pdsch_get(q, ce[i], q->ce[i], prb_alloc, nsubframe); + if (n != nof_symbols) { + fprintf(stderr, "Error expecting %d symbols but got %d\n", nof_symbols, n); + return -1; + } } - + /* TODO: only diversity is supported */ if (q->nof_ports == 1) { /* no need for layer demapping */ @@ -524,7 +521,7 @@ int pdsch_decode(pdsch_t *q, cf_t *sf_symbols, cf_t *ce[MAX_PORTS], char *data, 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]); diff --git a/lte/phy/lib/phch/src/phich.c b/lte/phy/lib/phch/src/phich.c index b17ff7150..bb214d8d7 100644 --- a/lte/phy/lib/phch/src/phich.c +++ b/lte/phy/lib/phch/src/phich.c @@ -57,9 +57,9 @@ int phich_ngroups(phich_t *q) { return regs_phich_ngroups(q->regs); } -void phich_reset(phich_t *q, cf_t *slot_symbols[MAX_PORTS_CTRL]) { +void phich_reset(phich_t *q, cf_t *slot_symbols[MAX_PORTS]) { int i; - for (i = 0; i < MAX_PORTS_CTRL; i++) { + for (i = 0; i < MAX_PORTS; i++) { regs_phich_reset(q->regs, slot_symbols[i]); } } @@ -136,7 +136,7 @@ void phich_ack_encode(char ack, char bits[PHICH_NBITS]) { * * Returns 1 if successfully decoded the CFI, 0 if not and -1 on error */ -int phich_decode(phich_t *q, cf_t *slot_symbols, cf_t *ce[MAX_PORTS_CTRL], +int phich_decode(phich_t *q, cf_t *slot_symbols, cf_t *ce[MAX_PORTS], int ngroup, int nseq, int nsubframe, char *ack, int *distance) { /* Set pointers for layermapping & precoding */ @@ -168,7 +168,7 @@ int phich_decode(phich_t *q, cf_t *slot_symbols, cf_t *ce[MAX_PORTS_CTRL], } /* number of layers equals number of ports */ - for (i = 0; i < MAX_PORTS_CTRL; i++) { + for (i = 0; i < MAX_PORTS; i++) { x[i] = q->phich_x[i]; } for (i = 0; i < MAX_PORTS; i++) { @@ -264,7 +264,7 @@ int phich_decode(phich_t *q, cf_t *slot_symbols, cf_t *ce[MAX_PORTS_CTRL], * The parameter ack is an array of phich_ngroups() pointers to buffers of nof_sequences chars */ int phich_encode(phich_t *q, char ack, int ngroup, int nseq, int nsubframe, - cf_t *slot_symbols[MAX_PORTS_CTRL]) { + cf_t *slot_symbols[MAX_PORTS]) { int i; if (nsubframe < 0 || nsubframe > NSUBFRAMES_X_FRAME) { diff --git a/lte/phy/lib/phch/src/prb.c b/lte/phy/lib/phch/src/prb.c index e680af15f..4d8c1cb11 100644 --- a/lte/phy/lib/phch/src/prb.c +++ b/lte/phy/lib/phch/src/prb.c @@ -33,14 +33,14 @@ #include "liblte/phy/common/base.h" void prb_cp_ref(cf_t **input, cf_t **output, int offset, int nof_refs, - int nof_prb, bool advance_output) { + int nof_intervals, bool advance_output) { int i; int ref_interval = ((RE_X_RB / nof_refs) - 1); memcpy(*output, *input, offset * sizeof(cf_t)); *input += offset; *output += offset; - for (i = 0; i < nof_refs * nof_prb - 1; i++) { + for (i = 0; i < nof_intervals - 1; i++) { if (advance_output) { (*output)++; } else { @@ -70,18 +70,18 @@ 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) { - 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; + 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); + int nof_intervals) { + prb_cp_ref(input, output, offset, nof_refs, nof_intervals, false); } void prb_get_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, true); + int nof_intervals) { + prb_cp_ref(input, output, offset, nof_refs, nof_intervals, true); } diff --git a/lte/phy/lib/phch/src/prb.h b/lte/phy/lib/phch/src/prb.h index 9df8f1bf5..0ca10fd5a 100644 --- a/lte/phy/lib/phch/src/prb.h +++ b/lte/phy/lib/phch/src/prb.h @@ -29,10 +29,10 @@ 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); + int nof_intervals, 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); + int nof_intervals); void phch_get_prb_ref(cf_t **input, cf_t **output, int offset, int nof_refs, - int nof_prb); + int nof_intervals); diff --git a/lte/phy/lib/phch/src/ra.c b/lte/phy/lib/phch/src/ra.c index 861f0d8d6..e328a4efb 100644 --- a/lte/phy/lib/phch/src/ra.c +++ b/lte/phy/lib/phch/src/ra.c @@ -117,6 +117,7 @@ void ra_prb_get_re(ra_prb_t *prb_dist, int nof_prb, int nof_ports, prb_dist->lstart = nof_ctrl_symbols; // Compute number of RE per subframe for (i = 0; i < NSUBFRAMES_X_FRAME; i++) { + prb_dist->re_sf[i] = 0; 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], @@ -166,8 +167,10 @@ int ra_prb_get_dl(ra_prb_t *prb_dist, ra_pdsch_t *ra, int nof_prb) { 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++; + if (i*P+j < nof_prb) { + prb_dist->slot[0].prb_idx[prb_dist->slot[0].nof_prb] = i * P + j; + prb_dist->slot[0].nof_prb++; + } } } } @@ -278,9 +281,7 @@ int ra_nprb_dl(ra_pdsch_t *ra, int nof_prb) { 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)) { - fprintf(stderr, "Number of RGB (%d) can not exceed %d\n", nof_prb, - (int) ceilf((float) nof_prb / P)); - return -1; + nof_rbg = (int) ceilf((float) nof_prb / P) - 1; } nprb = nof_rbg * P; @@ -547,6 +548,7 @@ void ra_pdsch_set_mcs_index(ra_pdsch_t *ra, uint8_t mcs_idx) { void ra_pdsch_set_mcs(ra_pdsch_t *ra, ra_mod_t mod, uint8_t tbs_idx) { ra->mcs.mod = mod; ra->mcs.tbs_idx = tbs_idx; + ra->mcs.tbs = 0; } void ra_pdsch_fprint(FILE *f, ra_pdsch_t *ra, int nof_prb) { diff --git a/lte/phy/lib/phch/src/regs.c b/lte/phy/lib/phch/src/regs.c index 57ffe2f4d..a2149e1ca 100644 --- a/lte/phy/lib/phch/src/regs.c +++ b/lte/phy/lib/phch/src/regs.c @@ -122,12 +122,6 @@ int regs_pdcch_init(regs_t *h) { h->pdcch[cfi].nof_regs = (h->pdcch[cfi].nof_regs/9)*9; free(tmp); tmp = NULL; - if (VERBOSE_ISINFO() && cfi == 1) { - for (i=0;ipdcch[cfi].nof_regs;i++) { - INFO("Logical PDCCH REG#%d:%d (%d,%d)\n", i%9,i/9, - h->pdcch[cfi].regs[i]->k0, h->pdcch[cfi].regs[i]->l); - } - } } ret = 0; @@ -141,12 +135,12 @@ clean_and_exit: return ret; } -int regs_pdcch_nregs(regs_t *h) { - if (h->cfi == -1) { - fprintf(stderr, "Must call regs_set_cfi() first\n"); +int regs_pdcch_nregs(regs_t *h, int cfi) { + if (cfi < 1 || cfi > 3) { + fprintf(stderr, "Invalid CFI=%d\n", cfi); return -1; } else { - return h->pdcch[h->cfi].nof_regs; + return h->pdcch[cfi-1].nof_regs; } } @@ -671,8 +665,9 @@ int regs_init(regs_t *h, int cell_id, int nof_prb, int nof_ports, fprintf(stderr, "Error initializing REGs\n"); goto clean_and_exit; } - DEBUG("Available REG #%3d: l=%d, prb=%d, nreg=%d (k0=%d)\n", k, i, prb, j[i], + /*DEBUG("Available REG #%3d: l=%d, prb=%d, nreg=%d (k0=%d)\n", k, i, prb, j[i], h->regs[k].k0); + */ j[i]++; k++; } @@ -718,7 +713,6 @@ clean_and_exit: int regs_put_reg(regs_reg_t *reg, cf_t *reg_data, cf_t *slot_symbols, int nof_prb) { int i; for (i = 0; i < REGS_RE_X_REG; i++) { - DEBUG("PUT REG: i=%d, (k=%d,l=%d)\n", i, REG_IDX(reg, i, nof_prb),reg->l); slot_symbols[REG_IDX(reg, i, nof_prb)] = reg_data[i]; } return REGS_RE_X_REG; @@ -732,9 +726,6 @@ int regs_add_reg(regs_reg_t *reg, cf_t *reg_data, cf_t *slot_symbols, int nof_pr int i; for (i = 0; i < REGS_RE_X_REG; i++) { slot_symbols[REG_IDX(reg, i, nof_prb)] += reg_data[i]; - DEBUG("ADD REG: i=%d, (k=%d,l=%d): %.1f+%.1fi\n", i, REG_IDX(reg, i, nof_prb),reg->l, - __real__ slot_symbols[REG_IDX(reg, i, nof_prb)], - __imag__ slot_symbols[REG_IDX(reg, i, nof_prb)]); } return REGS_RE_X_REG; } @@ -746,7 +737,6 @@ int regs_add_reg(regs_reg_t *reg, cf_t *reg_data, cf_t *slot_symbols, int nof_pr int regs_reset_reg(regs_reg_t *reg, cf_t *slot_symbols, int nof_prb) { int i; for (i = 0; i < REGS_RE_X_REG; i++) { - DEBUG("RESET REG: i=%d, (k=%d,l=%d)\n", i, REG_IDX(reg, i, nof_prb),reg->l); slot_symbols[REG_IDX(reg, i, nof_prb)] = 0; } return REGS_RE_X_REG; @@ -759,8 +749,6 @@ int regs_get_reg(regs_reg_t *reg, cf_t *slot_symbols, cf_t *reg_data, int nof_pr int i; for (i = 0; i < REGS_RE_X_REG; i++) { reg_data[i] = slot_symbols[REG_IDX(reg, i, nof_prb)]; - //DEBUG("GET REG: i=%d, (k=%d,l=%d): %.1f+%.1fi\n", i, REG_IDX(reg, i, nof_prb),reg->l, - // __real__ reg_data[i], __imag__ reg_data[i]); } return REGS_RE_X_REG; } diff --git a/lte/phy/lib/phch/test/pbch_file_test.c b/lte/phy/lib/phch/test/pbch_file_test.c index c356620cf..a3fab332e 100644 --- a/lte/phy/lib/phch/test/pbch_file_test.c +++ b/lte/phy/lib/phch/test/pbch_file_test.c @@ -45,7 +45,7 @@ FILE *fmatlab = NULL; #define FLEN 9600 filesource_t fsrc; -cf_t *input_buffer, *fft_buffer, *ce[MAX_PORTS_CTRL]; +cf_t *input_buffer, *fft_buffer, *ce[MAX_PORTS]; pbch_t pbch; lte_fft_t fft; chest_t chest; @@ -118,7 +118,7 @@ int base_init() { return -1; } - 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; + pdsch_t pdsch; + int i, j; + char *data = NULL; + cf_t *ce[MAX_PORTS]; + int nof_re; + cf_t *slot_symbols[MAX_PORTS]; + 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 "liblte/phy/resampling/decim.h" +#include "liblte/phy/utils/debug.h" + + +/* Performs integer linear decimation by a factor of M */ +void decim_c(cf_t *input, cf_t *output, int M, int len) { + int i; + for (i=0;ifc_tables.c[0], z, N_SSS); + vec_prod_ccc(y[0], q->fc_tables[q->N_id_2].c[0], z, N_SSS); memcpy(zdelay, &z[1], (N_SSS - 1) * sizeof(cf_t)); vec_conj_cc(z, zconj, N_SSS - 1); vec_prod_ccc(zdelay, zconj, zprod, N_SSS - 1); - corr_all_zs(zprod, q->fc_tables.s, tmp); + corr_all_zs(zprod, q->fc_tables[q->N_id_2].s, tmp); vec_abs_cf(tmp, tmp_real, N_SSS); *m0 = vec_max_fi(tmp_real, N_SSS); if (m0_value) { *m0_value = tmp_real[*m0]; } - vec_prod_ccc(y[1], q->fc_tables.c[1], tmp, N_SSS); - vec_prod_ccc(tmp, q->fc_tables.z1[*m0], z, N_SSS); + vec_prod_ccc(y[1], q->fc_tables[q->N_id_2].c[1], tmp, N_SSS); + vec_prod_ccc(tmp, q->fc_tables[q->N_id_2].z1[*m0], z, N_SSS); memcpy(zdelay, &z[1], (N_SSS - 1) * sizeof(cf_t)); vec_conj_cc(z, zconj, N_SSS - 1); vec_prod_ccc(zdelay, zconj, zprod, N_SSS - 1); - corr_all_zs(zprod, q->fc_tables.s, tmp); + corr_all_zs(zprod, q->fc_tables[q->N_id_2].s, tmp); vec_abs_cf(tmp, tmp_real, N_SSS); *m1 = vec_max_fi(tmp_real, N_SSS); if (m1_value) { diff --git a/lte/phy/lib/sync/src/gen_sss.c b/lte/phy/lib/sync/src/gen_sss.c index 89279cda3..e68407f45 100644 --- a/lte/phy/lib/sync/src/gen_sss.c +++ b/lte/phy/lib/sync/src/gen_sss.c @@ -123,7 +123,6 @@ void generate_sss_all_tables(struct sss_tables *tables, int N_id_2) { for (i = 0; i < 2; i++) { generate_c(tables->c[i], c_t, N_id_2, i); } - tables->N_id_2 = N_id_2; } void sss_generate(float *signal0, float *signal5, int cell_id) { diff --git a/lte/phy/lib/sync/src/pss.c b/lte/phy/lib/sync/src/pss.c index 6d17a93ff..fd5f6c522 100644 --- a/lte/phy/lib/sync/src/pss.c +++ b/lte/phy/lib/sync/src/pss.c @@ -39,18 +39,50 @@ #define NOT_SYNC 0xF0F0F0F0 + +int pss_synch_init_N_id_2(pss_synch_t *q, int N_id_2) { + q->N_id_2 = N_id_2; + + dft_plan_t plan; + cf_t pss_signal_pad[PSS_LEN_FREQ]; + cf_t pss_signal_time[PSS_LEN]; + + if (N_id_2 < 0 || N_id_2 > 2) { + fprintf(stderr, "Invalid N_id_2 %d\n", N_id_2); + return -1; + } + + pss_generate(pss_signal_time, N_id_2); + + memset(pss_signal_pad, 0, PSS_LEN_FREQ * sizeof(cf_t)); + memset(q->pss_signal_freq[N_id_2], 0, PSS_LEN_FREQ * sizeof(cf_t)); + memcpy(&pss_signal_pad[33], pss_signal_time, PSS_LEN * sizeof(cf_t)); + + if (dft_plan(&plan, PSS_LEN_FREQ - 1, BACKWARD, COMPLEX)) { + return -1; + } + dft_plan_set_mirror(&plan, true); + dft_plan_set_dc(&plan, true); + dft_run_c(&plan, pss_signal_pad, q->pss_signal_freq[q->N_id_2]); + + vec_sc_prod_cfc(q->pss_signal_freq[q->N_id_2], (float) 1 / (PSS_LEN_FREQ - 1), + pss_signal_pad, PSS_LEN_FREQ); + + vec_conj_cc(pss_signal_pad, q->pss_signal_freq[q->N_id_2], PSS_LEN_FREQ); + + dft_plan_free(&plan); + + return 0; +} + /* Initializes the object. subframe_size is the size, in samples, of the 1ms subframe * */ int pss_synch_init(pss_synch_t *q, int frame_size) { int ret = -1; + int N_id_2; bzero(q, sizeof(pss_synch_t)); - q->pss_signal_freq = vec_malloc((PSS_LEN_FREQ + frame_size) * sizeof(cf_t)); - if (!q->pss_signal_freq) { - fprintf(stderr, "Error allocating memory\n"); - goto clean_and_exit; - } q->conv_abs = vec_malloc((PSS_LEN_FREQ + frame_size) * sizeof(float)); if (!q->conv_abs) { fprintf(stderr, "Error allocating memory\n"); @@ -61,16 +93,35 @@ int pss_synch_init(pss_synch_t *q, int frame_size) { fprintf(stderr, "Error allocating memory\n"); goto clean_and_exit; } - q->frame_buffer = vec_malloc(4 * frame_size * sizeof(cf_t)); - if (!q->frame_buffer) { + q->conv_output = vec_malloc((PSS_LEN_FREQ + frame_size) * sizeof(cf_t)); + if (!q->conv_output) { fprintf(stderr, "Error allocating memory\n"); goto clean_and_exit; } - q->conv_output = vec_malloc((PSS_LEN_FREQ + frame_size) * sizeof(cf_t)); - if (!q->conv_output) { + for (N_id_2=0;N_id_2<3;N_id_2++) { + q->pss_signal_freq[N_id_2] = vec_malloc((PSS_LEN_FREQ + frame_size) * sizeof(cf_t)); + if (!q->pss_signal_freq[N_id_2]) { + fprintf(stderr, "Error allocating memory\n"); + goto clean_and_exit; + } + if (pss_synch_init_N_id_2(q, N_id_2)) { + fprintf(stderr, "Error initiating PSS detector for N_id_2=%d\n", N_id_2); + goto clean_and_exit; + } + } + +#ifdef ENABLE_SF + q->frame_buffer = vec_malloc(4 * frame_size * sizeof(cf_t)); + if (!q->frame_buffer) { fprintf(stderr, "Error allocating memory\n"); goto clean_and_exit; } + q->correlation_threshold = DEFAULT_CORRELATION_TH; + q->nosync_timeout_frames = DEFAULT_NOSYNC_TIMEOUT; + q->cfo_auto = true; + q->frame_start_idx = NOT_SYNC; + q->fb_wp = 0; +#endif #ifdef CONVOLUTION_FFT if (conv_fft_cc_init(&q->conv_fft, frame_size, PSS_LEN_FREQ)) { @@ -79,13 +130,8 @@ int pss_synch_init(pss_synch_t *q, int frame_size) { } #endif - q->correlation_threshold = DEFAULT_CORRELATION_TH; - q->nosync_timeout_frames = DEFAULT_NOSYNC_TIMEOUT; - q->cfo_auto = true; q->N_id_2 = -1; q->frame_size = frame_size; - q->frame_start_idx = NOT_SYNC; - q->fb_wp = 0; ret = 0; clean_and_exit: if (ret == -1) { @@ -95,8 +141,11 @@ int pss_synch_init(pss_synch_t *q, int frame_size) { } void pss_synch_free(pss_synch_t *q) { - if (q->pss_signal_freq) { - free(q->pss_signal_freq); + int i; + for (i=0;i<3;i++) { + if (q->pss_signal_freq[i]) { + free(q->pss_signal_freq[i]); + } } if (q->conv_abs) { free(q->conv_abs); @@ -104,13 +153,16 @@ void pss_synch_free(pss_synch_t *q) { if (q->tmp_input) { free(q->tmp_input); } - if (q->frame_buffer) { - free(q->frame_buffer); - } if (q->conv_output) { free(q->conv_output); } +#ifdef ENABLE_SF + if (q->frame_buffer) { + free(q->frame_buffer); + } +#endif + #ifdef CONVOLUTION_FFT conv_fft_cc_free(&q->conv_fft); #endif @@ -162,47 +214,20 @@ void pss_put_slot(cf_t *pss_signal, cf_t *slot, int nof_prb, lte_cp_t cp) { memset(&slot[k + PSS_LEN], 0, 5 * sizeof(cf_t)); } -/** Sets the current N_id_2 value. Initializes the object for this PSS sequence - * Returns -1 on error, 0 otherwise + +/** Sets the current N_id_2 value. Returns -1 on error, 0 otherwise */ int pss_synch_set_N_id_2(pss_synch_t *q, int N_id_2) { - q->N_id_2 = N_id_2; - - dft_plan_t plan; - cf_t pss_signal_pad[PSS_LEN_FREQ]; - cf_t pss_signal_time[PSS_LEN]; - - if (N_id_2 < 0 || N_id_2 > 2) { + if (N_id_2 < 0 || N_id_2 > 2) { fprintf(stderr, "Invalid N_id_2 %d\n", N_id_2); return -1; + } else { + q->N_id_2 = N_id_2; + return 0; } - - pss_generate(pss_signal_time, N_id_2); - - memset(pss_signal_pad, 0, PSS_LEN_FREQ * sizeof(cf_t)); - memset(q->pss_signal_freq, 0, PSS_LEN_FREQ * sizeof(cf_t)); - memcpy(&pss_signal_pad[33], pss_signal_time, PSS_LEN * sizeof(cf_t)); - - if (dft_plan(&plan, PSS_LEN_FREQ - 1, BACKWARD, COMPLEX)) { - return -1; - } - dft_plan_set_mirror(&plan, true); - dft_plan_set_dc(&plan, true); - - dft_run_c(&plan, pss_signal_pad, q->pss_signal_freq); - - vec_sc_prod_cfc(q->pss_signal_freq, (float) 1 / (PSS_LEN_FREQ - 1), - pss_signal_pad, PSS_LEN_FREQ); - - vec_conj_cc(pss_signal_pad, q->pss_signal_freq, PSS_LEN_FREQ); - - q->N_id_2 = N_id_2; - - dft_plan_free(&plan); - - return 0; } + /** Returns the index of the PSS correlation peak in a subframe. * The frame starts at corr_peak_pos-subframe_size/2. * The value of the correlation is stored in corr_peak_value. @@ -214,15 +239,15 @@ int pss_synch_find_pss(pss_synch_t *q, cf_t *input, float *corr_peak_value, int corr_peak_pos; int conv_output_len; - memset(&q->pss_signal_freq[PSS_LEN_FREQ], 0, q->frame_size * sizeof(cf_t)); + memset(&q->pss_signal_freq[q->N_id_2][PSS_LEN_FREQ], 0, q->frame_size * sizeof(cf_t)); memcpy(q->tmp_input, input, q->frame_size * sizeof(cf_t)); memset(&q->tmp_input[q->frame_size], 0, PSS_LEN_FREQ * sizeof(cf_t)); #ifdef CONVOLUTION_FFT conv_output_len = conv_fft_cc_run(&q->conv_fft, q->tmp_input, - q->pss_signal_freq, q->conv_output); + q->pss_signal_freq[q->N_id_2], q->conv_output); #else - conv_output_len = conv_cc(input, q->pss_signal_freq, q->conv_output, q->frame_size, PSS_LEN_FREQ); + conv_output_len = conv_cc(input, q->pss_signal_freq[q->N_id_2], q->conv_output, q->frame_size, PSS_LEN_FREQ); #endif vec_abs_cf(q->conv_output, q->conv_abs, conv_output_len); @@ -247,7 +272,7 @@ float pss_synch_cfo_compute(pss_synch_t* q, cf_t *pss_recv) { cf_t y0, y1, yr; cf_t y[PSS_LEN_FREQ - 1]; - vec_prod_ccc_unalign(q->pss_signal_freq, pss_recv, y, PSS_LEN_FREQ - 1); + vec_prod_ccc_unalign(q->pss_signal_freq[q->N_id_2], pss_recv, y, PSS_LEN_FREQ - 1); y0 = vec_acc_cc(y, (PSS_LEN_FREQ - 1) / 2); y1 = vec_acc_cc(&y[(PSS_LEN_FREQ - 1) / 2], (PSS_LEN_FREQ - 1) / 2); @@ -256,6 +281,28 @@ float pss_synch_cfo_compute(pss_synch_t* q, cf_t *pss_recv) { return atan2f(__imag__ yr, __real__ yr) / M_PI; } +#ifdef ENABLE_SF + +void pss_synch_set_timeout(pss_synch_t *q, int nof_frames) { + q->nosync_timeout_frames = nof_frames; +} + +void pss_synch_set_threshold(pss_synch_t *q, float threshold) { + q->correlation_threshold = threshold; +} + +void pss_synch_set_cfo_mode(pss_synch_t *q, bool cfo_auto) { + q->cfo_auto = cfo_auto; +} + +float pss_synch_get_cfo(pss_synch_t *q) { + return q->current_cfo; +} + +int pss_synch_get_frame_start_idx(pss_synch_t *q) { + return q->frame_start_idx; +} + /** This function is designed to be called periodically on a subframe basis. * The function finds the PSS correlation peak and computes (does not adjust) CFO automatically as defined by * pss_synch_set_cfo_mode(). @@ -338,26 +385,6 @@ int pss_synch_frame(pss_synch_t *q, cf_t *input, cf_t *output, int nsamples) { return retval; } -void pss_synch_set_timeout(pss_synch_t *q, int nof_frames) { - q->nosync_timeout_frames = nof_frames; -} - -void pss_synch_set_threshold(pss_synch_t *q, float threshold) { - q->correlation_threshold = threshold; -} - -void pss_synch_set_cfo_mode(pss_synch_t *q, bool cfo_auto) { - q->cfo_auto = cfo_auto; -} - -float pss_synch_get_cfo(pss_synch_t *q) { - return q->current_cfo; -} - -int pss_synch_get_frame_start_idx(pss_synch_t *q) { - return q->frame_start_idx; -} - /** High-level API */ int pss_synch_initialize(pss_synch_hl* h) { @@ -397,3 +424,5 @@ int pss_synch_stop(pss_synch_hl* hl) { return 0; } +#endif + diff --git a/lte/phy/lib/sync/src/sss.c b/lte/phy/lib/sync/src/sss.c index f3b4bb62a..9d4525e83 100644 --- a/lte/phy/lib/sync/src/sss.c +++ b/lte/phy/lib/sync/src/sss.c @@ -41,6 +41,9 @@ void convert_tables(struct fc_tables *fc_tables, struct sss_tables *in); void generate_N_id_1_table(int table[30][30]); int sss_synch_init(sss_synch_t *q) { + int N_id_2; + struct sss_tables sss_tables; + bzero(q, sizeof(sss_synch_t)); if (dft_plan(&q->dftp_input, SSS_DFT_LEN, FORWARD, COMPLEX)) { @@ -49,6 +52,11 @@ int sss_synch_init(sss_synch_t *q) { generate_N_id_1_table(q->N_id_1_table); dft_plan_set_mirror(&q->dftp_input, true); dft_plan_set_dc(&q->dftp_input, true); + for (N_id_2=0;N_id_2<3;N_id_2++) { + generate_sss_all_tables(&sss_tables, N_id_2); + convert_tables(&q->fc_tables[N_id_2], &sss_tables); + } + q->N_id_2 = 0; return 0; } @@ -57,18 +65,15 @@ void sss_synch_free(sss_synch_t *q) { bzero(q, sizeof(sss_synch_t)); } -/** Initializes the SSS sequences for the given N_id_2 */ +/** Sets the N_id_2 to search for */ int sss_synch_set_N_id_2(sss_synch_t *q, int N_id_2) { if (N_id_2 < 0 || N_id_2 > 2) { fprintf(stderr, "Invalid N_id_2 %d\n", N_id_2); return -1; + } else { + q->N_id_2 = N_id_2; + return 0; } - - struct sss_tables sss_tables; - generate_sss_all_tables(&sss_tables, N_id_2); - convert_tables(&q->fc_tables, &sss_tables); - - return 0; } /** 36.211 10.3 section 6.11.2.2 diff --git a/lte/phy/lib/sync/src/sync.c b/lte/phy/lib/sync/src/sync.c index 5b0e28dd7..6d0b8c8e9 100644 --- a/lte/phy/lib/sync/src/sync.c +++ b/lte/phy/lib/sync/src/sync.c @@ -34,45 +34,34 @@ #include "liblte/phy/sync/sync.h" int sync_init(sync_t *q, int frame_size) { - int N_id_2; bzero(q, sizeof(sync_t)); - q->force_N_id_2 = -1; q->threshold = 1.5; q->pss_mode = PEAK_MEAN; q->detect_cp = true; q->sss_en = true; - for (N_id_2=0;N_id_2<3;N_id_2++) { - if (pss_synch_init(&q->pss[N_id_2], frame_size)) { - fprintf(stderr, "Error initializing PSS object\n"); - return -1; - } - if (pss_synch_set_N_id_2(&q->pss[N_id_2], N_id_2)) { - fprintf(stderr, "Error initializing N_id_2\n"); - return -1; - } - if (sss_synch_init(&q->sss[N_id_2])) { - fprintf(stderr, "Error initializing SSS object\n"); - return -1; - } - if (sss_synch_set_N_id_2(&q->sss[N_id_2], N_id_2)) { - fprintf(stderr, "Error initializing N_id_2\n"); - return -1; - } - DEBUG("PSS and SSS initiated N_id_2=%d\n", N_id_2); + if (pss_synch_init(&q->pss, frame_size)) { + fprintf(stderr, "Error initializing PSS object\n"); + return -1; } - + if (pss_synch_init(&q->pss_track, TRACK_LEN)) { + fprintf(stderr, "Error initializing PSS track object\n"); + return -1; + } + if (sss_synch_init(&q->sss)) { + fprintf(stderr, "Error initializing SSS object\n"); + return -1; + } + DEBUG("PSS and SSS initiated\n",0); + return 0; } void sync_free(sync_t *q) { - int N_id_2; - - for (N_id_2=0;N_id_2<3;N_id_2++) { - pss_synch_free(&q->pss[N_id_2]); - sss_synch_free(&q->sss[N_id_2]); - } + pss_synch_free(&q->pss); + pss_synch_free(&q->pss_track); + sss_synch_free(&q->sss); } void sync_pss_det_absolute(sync_t *q) { @@ -86,15 +75,6 @@ void sync_set_threshold(sync_t *q, float threshold) { q->threshold = threshold; } -void sync_force_N_id_2(sync_t *q, int force_N_id_2) { - q->force_N_id_2 = force_N_id_2; -} - -void sync_force_cp(sync_t *q, lte_cp_t cp) { - q->cp = cp; - q->detect_cp = false; -} - void sync_sss_en(sync_t *q, bool enabled) { q->sss_en = enabled; } @@ -127,36 +107,129 @@ float sync_get_peak_to_avg(sync_t *q) { return q->peak_to_avg; } +void sync_cp_en(sync_t *q, bool enabled) { + q->detect_cp = enabled; +} + lte_cp_t sync_get_cp(sync_t *q) { return q->cp; } -int sync_run(sync_t *q, cf_t *input) { - int N_id_2, peak_pos[3], sss_idx_n, sss_idx_e; - int m0, m1; +int sync_sss(sync_t *q, cf_t *input, int N_id_2, int peak_pos, bool en_cp) { + int m0, m1, sss_idx_n, sss_idx_e; float m0_value_e, m1_value_e,m0_value_n, m1_value_n; int slot_id_e, N_id_1_e, slot_id_n, N_id_1_n; + + sss_synch_set_N_id_2(&q->sss, N_id_2); + + /* Make sure we have enough room to find SSS sequence */ + sss_idx_n = peak_pos-2*(128+CP(128,CPNORM_LEN)); + sss_idx_e = peak_pos-2*(128+CP(128,CPEXT_LEN)); + + if (en_cp) { + if (sss_idx_n < 0 || sss_idx_e < 0) { + INFO("Not enough room to decode SSS (%d, %d)\n", sss_idx_n, sss_idx_e); + return -1; + } + } else { + if (CP_ISNORM(q->cp)) { + if (sss_idx_n < 0) { + INFO("Not enough room to decode SSS (%d)\n", sss_idx_n); + return -1; + } + } else { + if (sss_idx_e < 0) { + INFO("Not enough room to decode SSS (%d)\n", sss_idx_e); + return -1; + } + } + } + + N_id_1_e = -1; + N_id_1_n = -1; + slot_id_e = -1; + slot_id_n = -1; + + /* try Normal CP length */ + if (en_cp || CP_ISNORM(q->cp)) { + sss_synch_m0m1(&q->sss, &input[sss_idx_n], + &m0, &m0_value_n, &m1, &m1_value_n); + + slot_id_n = 2 * sss_synch_subframe(m0, m1); + N_id_1_n = sss_synch_N_id_1(&q->sss, m0, m1); + } + + if (en_cp || CP_ISEXT(q->cp)) { + /* Now try Extended CP length */ + sss_synch_m0m1(&q->sss, &input[sss_idx_e], + &m0, &m0_value_e, &m1, &m1_value_e); + + slot_id_e = 2 * sss_synch_subframe(m0, m1); + N_id_1_e = sss_synch_N_id_1(&q->sss, m0, m1); + } + + /* Correlation with extended CP hypoteshis is greater than with normal? */ + if ((en_cp && m0_value_e * m1_value_e > m0_value_n * m1_value_n) + || CP_ISEXT(q->cp)) { + q->cp = CPEXT; + q->slot_id = slot_id_e; + q->N_id_1 = N_id_1_e; + /* then is normal CP */ + } else { + q->cp = CPNORM; + q->slot_id = slot_id_n; + q->N_id_1 = N_id_1_n; + } + + INFO("SSS detected N_id_1=%d, slot_idx=%d, %s CP\n", + q->N_id_1, q->slot_id, CP_ISNORM(q->cp)?"Normal":"Extended"); + + return 0; +} + +int sync_track(sync_t *q, cf_t *input) { + float peak_value, mean_value; + int peak_detected = 0; + pss_synch_set_N_id_2(&q->pss_track, q->N_id_2); + + int peak_pos = pss_synch_find_pss(&q->pss, input, &peak_value, &mean_value); + + if (q->peak_to_avg > TRACK_THRESHOLD) { + peak_detected = 1; + } + if (peak_detected) { + + q->cfo = pss_synch_cfo_compute(&q->pss, &input[peak_pos-128]); + + if (q->sss_en) { + if (sync_sss(q, input, q->N_id_2, peak_pos, false)) { + return -1; + } + } + + return peak_pos; + } else { + return -1; + } +} + +int sync_find(sync_t *q, cf_t *input) { + int N_id_2, peak_pos[3]; float peak_value[3]; float mean_value[3]; float max=-999; int i; int peak_detected; - if (q->force_N_id_2 == -1) { - for (N_id_2=0;N_id_2<3;N_id_2++) { - peak_pos[N_id_2] = pss_synch_find_pss(&q->pss[N_id_2], input, - &peak_value[N_id_2], &mean_value[N_id_2]); - } - for (i=0;i<3;i++) { - if (peak_value[i] > max) { - max = peak_value[i]; - N_id_2 = i; - } + for (N_id_2=0;N_id_2<3;N_id_2++) { + pss_synch_set_N_id_2(&q->pss, N_id_2); + peak_pos[N_id_2] = pss_synch_find_pss(&q->pss, input, &peak_value[N_id_2], &mean_value[N_id_2]); + } + for (i=0;i<3;i++) { + if (peak_value[i] > max) { + max = peak_value[i]; + N_id_2 = i; } - } else { - N_id_2 = q->force_N_id_2; - peak_pos[N_id_2] = pss_synch_find_pss(&q->pss[N_id_2], input, - &peak_value[N_id_2], &mean_value[N_id_2]); } q->peak_to_avg = peak_value[N_id_2] / mean_value[N_id_2]; @@ -178,74 +251,17 @@ int sync_run(sync_t *q, cf_t *input) { } } if (peak_detected) { - - q->cfo = pss_synch_cfo_compute(&q->pss[N_id_2], &input[peak_pos[N_id_2]-128]); - + q->N_id_2 = N_id_2; + pss_synch_set_N_id_2(&q->pss, q->N_id_2); + q->cfo = pss_synch_cfo_compute(&q->pss, &input[peak_pos[q->N_id_2]-128]); + INFO("PSS peak detected N_id_2=%d, pos=%d peak=%.2f par=%.2f th=%.2f cfo=%.4f\n", N_id_2, peak_pos[N_id_2], peak_value[N_id_2], q->peak_to_avg, q->threshold, q->cfo); - if (q->sss_en) { - - /* Make sure we have enough room to find SSS sequence */ - sss_idx_n = peak_pos[N_id_2]-2*(128+CP(128,CPNORM_LEN)); - sss_idx_e = peak_pos[N_id_2]-2*(128+CP(128,CPEXT_LEN)); - - if (q->detect_cp) { - if (sss_idx_n < 0 || sss_idx_e < 0) { - INFO("Not enough room to decode SSS (%d, %d)\n", sss_idx_n, sss_idx_e); - return -1; - } - } else { - if (CP_ISNORM(q->cp)) { - if (sss_idx_n < 0) { - INFO("Not enough room to decode SSS (%d)\n", sss_idx_n); - return -1; - } - } else { - if (sss_idx_e < 0) { - INFO("Not enough room to decode SSS (%d)\n", sss_idx_e); - return -1; - } - } - } - N_id_1_e = -1; - N_id_1_n = -1; - slot_id_e = -1; - slot_id_n = -1; - /* try Normal CP length */ - if (q->detect_cp || CP_ISNORM(q->cp)) { - sss_synch_m0m1(&q->sss[N_id_2], &input[sss_idx_n], - &m0, &m0_value_n, &m1, &m1_value_n); - - slot_id_n = 2 * sss_synch_subframe(m0, m1); - N_id_1_n = sss_synch_N_id_1(&q->sss[N_id_2], m0, m1); + if (q->sss_en) { + if (sync_sss(q, input, q->N_id_2, peak_pos[q->N_id_2], q->detect_cp)) { + return -1; } - - if (q->detect_cp || CP_ISEXT(q->cp)) { - /* Now try Extended CP length */ - sss_synch_m0m1(&q->sss[N_id_2], &input[sss_idx_e], - &m0, &m0_value_e, &m1, &m1_value_e); - - slot_id_e = 2 * sss_synch_subframe(m0, m1); - N_id_1_e = sss_synch_N_id_1(&q->sss[N_id_2], m0, m1); - } - - /* Correlation with extended CP hypoteshis is greater than with normal? */ - if ((q->detect_cp && m0_value_e * m1_value_e > m0_value_n * m1_value_n) - || CP_ISEXT(q->cp)) { - q->cp = CPEXT; - q->slot_id = slot_id_e; - q->N_id_1 = N_id_1_e; - /* then is normal CP */ - } else { - q->cp = CPNORM; - q->slot_id = slot_id_n; - q->N_id_1 = N_id_1_n; - } - q->N_id_2 = N_id_2; - - INFO("SSS detected N_id_1=%d, slot_idx=%d, %s CP\n", - q->N_id_1, q->slot_id, CP_ISNORM(q->cp)?"Normal":"Extended"); } return peak_pos[N_id_2]; diff --git a/lte/phy/lib/sync/src/sync_frame.c b/lte/phy/lib/sync/src/sync_frame.c new file mode 100644 index 000000000..7ffdc3f8a --- /dev/null +++ b/lte/phy/lib/sync/src/sync_frame.c @@ -0,0 +1,236 @@ +/** + * + * \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 "liblte/phy/resampling/decim.h" +#include "liblte/phy/utils/debug.h" +#include "liblte/phy/sync/sync_frame.h" + + +int sync_frame_init(sync_frame_t *q, int downsampling) { + int ret = -1; + bzero(q, sizeof(sync_frame_t)); + + if(sync_init(&q->s, SYNC_SF_LEN)) { + goto clean_exit; + } + sync_pss_det_peak_to_avg(&q->s); + + if (cfo_init(&q->cfocorr, SYNC_SF_LEN * downsampling)) { + fprintf(stderr, "Error initiating CFO\n"); + goto clean_exit; + } + + q->input_buffer = malloc(2 * SYNC_SF_LEN * downsampling * sizeof(cf_t)); + if (!q->input_buffer) { + perror("malloc"); + goto clean_exit; + } + + q->input_downsampled = malloc(SYNC_SF_LEN * sizeof(cf_t)); + if (!q->input_downsampled) { + perror("malloc"); + goto clean_exit; + } + + q->downsampling = downsampling; + sync_frame_reset(q); + ret = 0; + +clean_exit: + if (ret == -1) { + sync_frame_free(q); + } + return ret; +} + +void sync_frame_free(sync_frame_t *q) { + if (q->input_buffer) { + free(q->input_buffer); + } + if (q->input_downsampled) { + free(q->input_downsampled); + } + cfo_free(&q->cfocorr); + sync_free(&q->s); +} + +void sync_frame_run(sync_frame_t *q, cf_t *input) { + int track_idx; + + switch (q->state) { + + case SF_FIND: + q->peak_idx = sync_find(&q->s, input); + q->cell_id = sync_get_cell_id(&q->s); + + INFO("FIND %3d:\tPAR=%.2f\n", (int) q->frame_cnt, sync_get_peak_to_avg(&q->s)); + + if (q->peak_idx != -1 && q->cell_id != -1) { + + /* Get the subframe index (0 or 5) */ + q->sf_idx = sync_get_slot_id(&q->s)/2; + + /* Reset variables */ + q->last_found = 0; + q->timeoffset = 0; + q->frame_cnt = 0; + + /* Goto Tracking state */ + q->state = SF_TRACK; + } + break; + case SF_TRACK: + + q->sf_idx = (q->sf_idx + 1) % 10; + + /* Every SF idx 0 and 5, find peak around known position q->peak_idx */ + if (q->sf_idx != 0 && q->sf_idx != 5) { + break; + } + + track_idx = sync_track(&q->s, &input[q->peak_idx - TRACK_LEN]); + + INFO("TRACK %3d: SF=%d. Previous idx is %d New Offset is %d\n", + (int) q->frame_cnt, q->sf_idx, q->peak_idx, track_idx - TRACK_LEN); + + if (track_idx != -1) { + INFO("Expected SF idx %d but got %d. Going back to FIND\n", q->sf_idx, + sync_get_slot_id(&q->s)/2); + + /* Make sure subframe idx is what we expect */ + if (q->sf_idx != sync_get_slot_id(&q->s)/2) { + INFO("Expected SF idx %d but got %d. Going back to FIND\n", q->sf_idx, + sync_get_slot_id(&q->s)/2); + q->state = SF_FIND; + } + + /* compute cumulative moving average CFO */ + q->cur_cfo = (sync_get_cfo(&q->s) + q->frame_cnt * q->cur_cfo) / (q->frame_cnt + 1); + + /* compute cumulative moving average time offset */ + q->timeoffset = (float) (track_idx - TRACK_LEN + q->timeoffset * q->frame_cnt) + / (q->frame_cnt + 1); + + q->last_found = q->frame_cnt; + q->peak_idx = (q->peak_idx + track_idx - TRACK_LEN) % SYNC_SF_LEN; + + if (q->peak_idx < 0) { + INFO("PSS lost (peak_idx=%d). Going back to FIND\n", q->peak_idx); + q->state = SF_FIND; + } + } else { + /* if sync not found, adjust time offset with the averaged value */ + q->peak_idx = (q->peak_idx + (int) q->timeoffset) % SYNC_SF_LEN; + + /* if we missed too many PSS go back to FIND */ + if (q->frame_cnt - q->last_found > TRACK_MAX_LOST) { + INFO("%d frames lost. Going back to FIND", (int) q->frame_cnt - q->last_found); + q->state = SF_FIND; + } + } + q->frame_cnt++; + break; + } +} + +void sync_frame_set_threshold(sync_frame_t *q, float threshold) { + sync_set_threshold(&q->s, threshold); +} + +int sync_frame_cell_id(sync_frame_t *q) { + return q->cell_id; +} + +int sync_frame_sfidx(sync_frame_t *q) { + return q->sf_idx; +} + + +int sync_frame_push(sync_frame_t *q, cf_t *input, cf_t *output) { + int retval = 0; + int frame_start; + cf_t *input_ds; + int sf_len; + + if (q->downsampling == 1) { + input_ds = input; + } else { + decim_c(input, q->input_downsampled, q->downsampling, SYNC_SF_LEN * q->downsampling); + input_ds = q->input_downsampled; + } + + sync_frame_run(q, input_ds); + + sf_len = q->downsampling * SYNC_SF_LEN; + + if (q->state == SF_FIND) { + memcpy(q->input_buffer, input, sf_len * sizeof(cf_t)); + } else { + frame_start = q->downsampling * q->peak_idx - sf_len/2; + + DEBUG("Peak_idx=%d, frame_start=%d cfo=%.3f\n",q->peak_idx, + frame_start, q->cur_cfo); + + if (frame_start > 0) { + if (q->fb_wp) { + memcpy(&q->input_buffer[(sf_len - frame_start)], input, frame_start * sizeof(cf_t)); + memcpy(output, q->input_buffer, sf_len * sizeof(cf_t)); + retval = 1; + } + memcpy(q->input_buffer, &input[frame_start], (sf_len - frame_start) * sizeof(cf_t)); + q->fb_wp = true; + } else { + memcpy(output, &q->input_buffer[sf_len + frame_start], (-frame_start) * sizeof(cf_t)); + memcpy(&output[-frame_start], input, (sf_len + frame_start) * sizeof(cf_t)); + memcpy(&q->input_buffer[sf_len + frame_start], &input[sf_len + frame_start], (-frame_start) * sizeof(cf_t)); + retval = 1; + } + } + + /* Frequency Synchronization */ + if (retval) { + cfo_correct(&q->cfocorr, output, -q->cur_cfo / 128); + } + + if (!retval) { + DEBUG("Frame Buffered\n",0); + } + + return retval; +} + +void sync_frame_reset(sync_frame_t *q) { + q->state = SF_FIND; + q->frame_cnt = 0; + q->fb_wp = false; + q->cur_cfo = 0; +} + diff --git a/lte/phy/lib/sync/test/sync_test.c b/lte/phy/lib/sync/test/sync_test.c index f1641c9eb..79d19636c 100644 --- a/lte/phy/lib/sync/test/sync_test.c +++ b/lte/phy/lib/sync/test/sync_test.c @@ -107,7 +107,6 @@ int main(int argc, char **argv) { } sync_set_threshold(&sync, 20); - sync_force_N_id_2(&sync, -1); if (cell_id == -1) { cid = 0; @@ -130,9 +129,9 @@ int main(int argc, char **argv) { /* Transform to OFDM symbols */ memset(fft_buffer, 0, sizeof(cf_t) * 2 * FLEN); - lte_ifft_run(&ifft, buffer, &fft_buffer[offset]); + lte_ifft_run_slot(&ifft, buffer, &fft_buffer[offset]); - find_idx = sync_run(&sync, fft_buffer); + find_idx = sync_find(&sync, fft_buffer); find_ns = sync_get_slot_id(&sync); printf("cell_id: %d find: %d, offset: %d, ns=%d find_ns=%d\n", cid, find_idx, offset, ns, find_ns); From 5eab57670b95cc4cedd9ad54de5a6c03211e3f2e Mon Sep 17 00:00:00 2001 From: ismagom Date: Sun, 29 Jun 2014 19:51:25 +0200 Subject: [PATCH 02/14] Changed nof_prb, nof_ports, cell_id, etc. by lte_cell_t structure. Fixed PBCH/PDSCH resource mapping with odd number PRB. PDSCH examles not working with more than 6 PRB due to downsampling problem. --- CMakeLists.txt | 2 +- lte/phy/examples/pbch_enodeb.c | 8 +- lte/phy/examples/pbch_ue.c | 9 +- lte/phy/examples/pdsch_enodeb.c | 35 +- lte/phy/examples/pdsch_ue.c | 102 ++- lte/phy/examples/scan_mib.c | 8 +- .../include/liblte/phy/ch_estimation/chest.h | 122 ++- .../liblte/phy/ch_estimation/refsignal.h | 24 +- lte/phy/include/liblte/phy/channel/ch_awgn.h | 12 +- lte/phy/include/liblte/phy/common/fft.h | 30 +- .../include/liblte/phy/common/phy_common.h | 52 +- lte/phy/include/liblte/phy/common/sequence.h | 38 +- lte/phy/include/liblte/phy/phch/dci.h | 61 +- lte/phy/include/liblte/phy/phch/pbch.h | 21 +- lte/phy/include/liblte/phy/phch/pcfich.h | 29 +- lte/phy/include/liblte/phy/phch/pdcch.h | 77 +- lte/phy/include/liblte/phy/phch/pdsch.h | 44 +- lte/phy/include/liblte/phy/phch/phich.h | 41 +- lte/phy/include/liblte/phy/phch/prach.h | 2 +- lte/phy/include/liblte/phy/phch/regs.h | 82 +- lte/phy/include/liblte/phy/phy.h | 1 - lte/phy/include/liblte/phy/sync/sync_frame.h | 1 + lte/phy/lib/ch_estimation/src/chest.c | 305 +++---- lte/phy/lib/ch_estimation/src/refsignal.c | 159 ++-- lte/phy/lib/ch_estimation/test/chest_test.c | 58 +- lte/phy/lib/common/src/phy_common.c | 15 + lte/phy/lib/common/src/sequence.c | 21 +- lte/phy/lib/phch/src/dci.c | 132 +-- lte/phy/lib/phch/src/pcfich.c | 242 +++--- lte/phy/lib/phch/src/pdcch.c | 646 ++++++++------- lte/phy/lib/phch/src/pdsch.c | 753 +++++++++--------- lte/phy/lib/phch/src/phich.c | 150 ++-- lte/phy/lib/phch/src/regs.c | 301 +++---- lte/phy/lib/phch/src/sequences.c | 14 +- lte/phy/lib/phch/test/pbch_file_test.c | 47 +- lte/phy/lib/phch/test/pcfich_file_test.c | 64 +- lte/phy/lib/phch/test/pcfich_test.c | 39 +- lte/phy/lib/phch/test/pdcch_file_test.c | 74 +- lte/phy/lib/phch/test/pdcch_test.c | 51 +- lte/phy/lib/phch/test/pdsch_file_test.c | 90 +-- lte/phy/lib/phch/test/pdsch_re_test.c | 12 +- lte/phy/lib/phch/test/pdsch_test.c | 46 +- lte/phy/lib/phch/test/phich_file_test.c | 55 +- lte/phy/lib/phch/test/phich_test.c | 49 +- lte/phy/lib/sync/src/sync_frame.c | 5 + 45 files changed, 2327 insertions(+), 1802 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c8f92b065..73195b1d5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -77,7 +77,7 @@ IF(CMAKE_COMPILER_IS_GNUCXX) ENDIF(CMAKE_COMPILER_IS_GNUCXX) IF(CMAKE_COMPILER_IS_GNUCC) - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wno-format-extra-args -Winline -Wno-unused-result -Wno-format -std=c99 -D_GNU_SOURCE") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror -Wall -Wno-format-extra-args -Winline -Wno-unused-result -Wno-format -std=c99 -D_GNU_SOURCE") IF(NOT WIN32) ADD_CXX_COMPILER_FLAG_IF_AVAILABLE(-fvisibility=hidden HAVE_VISIBILITY_HIDDEN) ENDIF(NOT WIN32) diff --git a/lte/phy/examples/pbch_enodeb.c b/lte/phy/examples/pbch_enodeb.c index 1d7a62801..7be23a2b7 100644 --- a/lte/phy/examples/pbch_enodeb.c +++ b/lte/phy/examples/pbch_enodeb.c @@ -211,8 +211,14 @@ int main(int argc, char **argv) { sss_generate(sss_signal0, sss_signal5, cell_id); /* Generate CRS signals */ + lte_cell_t cell; + cell.id = cell_id; + cell.nof_prb = 6; + cell.cp = CPNORM; + cell.nof_ports = 1; + for (i=0;i sampling_nof_prb) { + if (!lte_cell_isvalid(&cell)) { + fprintf(stderr, "Invalid cell properties: Id=%d, Ports=%d, PRBs=%d\n", + cell.id, cell.nof_ports, cell.nof_prb); + return -1; + } + if (cell.nof_prb > sampling_nof_prb) { fprintf(stderr, "Error sampling frequency is %.2f Mhz but captured signal has %d PRB\n", - (float) lte_sampling_freq_hz(sampling_nof_prb)/MHZ, mib.nof_prb); + (float) lte_sampling_freq_hz(sampling_nof_prb)/MHZ, cell.nof_prb); return -1; } - if (regs_init(®s, cell_id, mib.nof_prb, mib.nof_ports, - mib.phich_resources, mib.phich_length, CPNORM)) { - fprintf(stderr, "Error initiating regs\n"); + if (regs_init(®s, phich_resources, phich_length, cell)) { + fprintf(stderr, "Error initiating REGs\n"); return -1; } - if (pcfich_init(&pcfich, ®s, cell_id, mib.nof_prb, mib.nof_ports, CPNORM)) { + if (pcfich_init(&pcfich, ®s, cell)) { fprintf(stderr, "Error creating PCFICH object\n"); return -1; } - if (pdcch_init(&pdcch, ®s, mib.nof_prb, mib.nof_ports, cell_id, CPNORM)) { + if (pdcch_init(&pdcch, ®s, cell)) { fprintf(stderr, "Error creating PDCCH object\n"); return -1; } - if (pdsch_init(&pdsch, 1234, mib.nof_prb, mib.nof_ports, cell_id, CPNORM)) { + if (pdsch_init(&pdsch, 1234, cell)) { fprintf(stderr, "Error creating PDSCH object\n"); return -1; } - chest_set_nof_ports(&chest, mib.nof_ports); + chest_set_nof_ports(&chest, cell.nof_ports); mib_initiated = 1; - DEBUG("Receiver initiated cell_id=%d nof_prb=%d\n", cell_id, mib.nof_prb); + DEBUG("Receiver initiated cell.id=%d nof_prb=%d\n", cell.id, cell.nof_prb); return 0; } int cell_id_init(int nof_prb, int cell_id) { - if (chest_ref_LTEDL(&chest, cell_id)) { + lte_cell_t cell; + + cell.id = cell_id; + cell.nof_prb = 6; + cell.nof_ports = MAX_PORTS; + cell.cp = CPNORM; + + if (chest_ref_LTEDL(&chest, cell)) { fprintf(stderr, "Error initializing reference signal\n"); return -1; } @@ -373,14 +384,15 @@ int cell_id_init(int nof_prb, int cell_id) { char data[10000]; int rx_run(cf_t *input, int sf_idx) { - int cfi, i, cfi_distance, nof_dcis; + uint8_t cfi, cfi_distance; + int i, nof_dcis; cf_t *input_decim; ra_pdsch_t ra_dl; ra_prb_t prb_alloc; /* Downsample if the signal bandwith is shorter */ - if (sampling_nof_prb > mib.nof_prb) { - decim_c(input, input_decim_buffer, sf_n_samples, DOWNSAMPLE_FACTOR(sampling_nof_prb, mib.nof_prb)); + if (sampling_nof_prb > cell.nof_prb) { + decim_c(input, input_decim_buffer, sf_n_samples, DOWNSAMPLE_FACTOR(sampling_nof_prb, cell.nof_prb)); input_decim = input_decim_buffer; } else { input_decim = input; @@ -402,18 +414,15 @@ int rx_run(cf_t *input, int sf_idx) { fprintf(stderr, "Error setting CFI\n"); return -1; } - if (pdcch_set_cfi(&pdcch, cfi)) { - fprintf(stderr, "Error setting CFI\n"); - return -1; - } - pdcch_init_search_ue(&pdcch, 1234); + + pdcch_init_search_ue(&pdcch, 1234, cfi); dci_set.nof_dcis = 0; - nof_dcis = pdcch_decode(&pdcch, fft_buffer, ce, &dci_set, sf_idx); + nof_dcis = pdcch_decode(&pdcch, fft_buffer, ce, &dci_set, sf_idx, cfi); INFO("Received %d DCIs\n", nof_dcis); for (i=0;i 0) { - int n_re = 2 * RE_X_RB * CPNORM_NSYMB * mib.nof_prb; + int n_re = 2 * RE_X_RB * CPNORM_NSYMB * cell.nof_prb; for (i = 0; i < n_re; i++) { tmp_plot[i] = 10 * log10f(cabsf(fft_buffer[i])); if (isinf(tmp_plot[i])) { @@ -472,7 +481,7 @@ int rx_run(cf_t *input, int sf_idx) { return 0; } -int mib_decoder_run(cf_t *input) { +int mib_decoder_run(cf_t *input, pbch_mib_t *mib) { int i, n; lte_fft_run_slot(&fft, input, fft_buffer); @@ -483,23 +492,30 @@ int mib_decoder_run(cf_t *input) { } DEBUG("Decoding PBCH\n", 0); - n = pbch_decode(&pbch, fft_buffer, ce, &mib); + n = pbch_decode(&pbch, fft_buffer, ce, mib); return n; } int run_receiver(cf_t *input, int cell_id, int sf_idx) { - + pbch_mib_t mib; + if (!cell_id_initated) { cell_id_init(sampling_nof_prb, cell_id); } - if (!mib.nof_prb) { + if (!cell.nof_prb) { if (!sf_idx) { - if (mib_decoder_run(&input[sf_n_samples/2])) { + if (mib_decoder_run(&input[sf_n_samples/2], &mib)) { INFO("MIB decoded!\n", 0); + cell.id = cell_id; + cell.cp = CPNORM; + cell.nof_ports = mib.nof_ports; + cell.nof_prb = mib.nof_prb; + subframe_number = mib.sfn; + if (!mib_initiated) { - if (mib_init(cell_id)) { + if (mib_init(mib.phich_resources, mib.phich_length)) { return -1; } } @@ -511,7 +527,7 @@ int run_receiver(cf_t *input, int cell_id, int sf_idx) { } } } - if (mib.nof_prb) { + if (cell.nof_prb) { if (rx_run(input, sf_idx)) { return -1; } @@ -566,7 +582,7 @@ void read_io(cf_t *buffer, int nsamples) { } int main(int argc, char **argv) { - + #ifdef DISABLE_UHD if (argc < 3) { usage(argv[0]); @@ -590,8 +606,8 @@ int main(int argc, char **argv) { signal(SIGINT, sigintHandler); /* Initialize variables */ - mib.sfn = -1; frame_cnt = 0; + subframe_number = -1; /* The number of samples read from the USRP or file corresponds to 1 ms (subframe) */ sf_n_samples = 1920 * lte_symbol_sz(sampling_nof_prb)/128; @@ -608,7 +624,7 @@ int main(int argc, char **argv) { break; case 1: if (!(frame_cnt%10)) { - mib.sfn++; + subframe_number++; } /* synch'd and tracking */ if (run_receiver(sf_buffer, sync_frame_cell_id(&sframe), sync_frame_sfidx(&sframe))) { @@ -617,7 +633,7 @@ int main(int argc, char **argv) { if (!(frame_cnt % 10)) { printf( "SFN: %4d, CFO: %+.4f KHz, SFO: %+.4f Khz, TimeOffset: %4d, Errors: %4d/%4d, BLER: %.1e\r", - mib.sfn, sframe.cur_cfo * 15, sframe.timeoffset / 5, sframe.peak_idx, + subframe_number, sframe.cur_cfo * 15, sframe.timeoffset / 5, sframe.peak_idx, pdsch_errors, pdsch_total, (float) pdsch_errors / pdsch_total); fflush(stdout); diff --git a/lte/phy/examples/scan_mib.c b/lte/phy/examples/scan_mib.c index 600a635f7..b22dcde49 100644 --- a/lte/phy/examples/scan_mib.c +++ b/lte/phy/examples/scan_mib.c @@ -311,7 +311,13 @@ int rssi_scan() { int mib_decoder_init(int cell_id) { - if (chest_ref_LTEDL(&chest, cell_id)) { + lte_cell_t cell; + cell.id = cell_id; + cell.nof_prb = 6; + cell.nof_ports = MAX_PORTS; + cell.cp = CPNORM; + + if (chest_ref_LTEDL(&chest, cell)) { fprintf(stderr, "Error initializing reference signal\n"); return -1; } diff --git a/lte/phy/include/liblte/phy/ch_estimation/chest.h b/lte/phy/include/liblte/phy/ch_estimation/chest.h index db99dacbf..2d4707870 100644 --- a/lte/phy/include/liblte/phy/ch_estimation/chest.h +++ b/lte/phy/include/liblte/phy/ch_estimation/chest.h @@ -40,7 +40,12 @@ typedef _Complex float cf_t; /* this is only a shortcut */ typedef enum {LINEAR} chest_interp_t; -typedef void (*interpolate_fnc_t) (cf_t *input, cf_t *output, int M, int len, int off_st, int off_end); +typedef void (*interpolate_fnc_t) (cf_t *input, + cf_t *output, + int M, + int len, + int off_st, + int off_end); /** This is an OFDM channel estimator. * It works with any reference signal pattern, provided by the object @@ -50,34 +55,94 @@ typedef void (*interpolate_fnc_t) (cf_t *input, cf_t *output, int M, int len, in */ /* Low-level API */ -typedef struct LIBLTE_API{ - int nof_ports; - int nof_symbols; - int nof_prb; - lte_cp_t cp; +typedef struct LIBLTE_API { + uint8_t nof_ports; + uint16_t nof_re; + uint8_t nof_symbols; + refsignal_t refsignal[MAX_PORTS][NSLOTS_X_FRAME]; interpolate_fnc_t interp; }chest_t; -LIBLTE_API int chest_init(chest_t *q, chest_interp_t interp, lte_cp_t cp, int nof_prb, int nof_ports); -LIBLTE_API void chest_free(chest_t *q); -LIBLTE_API void chest_set_nof_ports(chest_t *q, int nof_ports); - -LIBLTE_API int chest_ref_LTEDL_slot_port(chest_t *q, int port, int nslot, int cell_id); -LIBLTE_API int chest_ref_LTEDL_slot(chest_t *q, int nslot, int cell_id); -LIBLTE_API int chest_ref_LTEDL(chest_t *q, int cell_id); +LIBLTE_API int chest_init(chest_t *q, + chest_interp_t interp, + uint16_t nof_re, + uint8_t nof_symbols, + uint8_t nof_ports); -LIBLTE_API void chest_ce_ref(chest_t *q, cf_t *input, int nslot, int port_id, int nref); -LIBLTE_API void chest_ce_slot_port(chest_t *q, cf_t *input, cf_t *ce, int nslot, int port_id); -LIBLTE_API void chest_ce_sf_port(chest_t *q, cf_t *input, cf_t *ce, int sf_idx, int port_id); -LIBLTE_API void chest_ce_slot(chest_t *q, cf_t *input, cf_t *ce[MAX_PORTS], int nslot); -LIBLTE_API void chest_ce_sf(chest_t *q, cf_t *input, cf_t *ce[MAX_PORTS], int sf_idx); +LIBLTE_API void chest_free(chest_t *q); -LIBLTE_API void chest_fprint(chest_t *q, FILE *stream, int nslot, int port_id); -LIBLTE_API void chest_ref_fprint(chest_t *q, FILE *stream, int nslot, int port_id); -LIBLTE_API void chest_recvsig_fprint(chest_t *q, FILE *stream, int nslot, int port_id); -LIBLTE_API void chest_ce_fprint(chest_t *q, FILE *stream, int nslot, int port_id); -LIBLTE_API int chest_ref_symbols(chest_t *q, int port_id, int nslot, int l[2]); +LIBLTE_API int chest_set_nof_ports(chest_t *q, + uint8_t nof_ports); + +LIBLTE_API int chest_init_LTEDL(chest_t *q, + chest_interp_t interp, + lte_cell_t cell); + +LIBLTE_API int chest_ref_LTEDL_slot_port(chest_t *q, + uint8_t nslot, + uint8_t port_id, + lte_cell_t cell); + +LIBLTE_API int chest_ref_LTEDL_slot(chest_t *q, + uint8_t nslot, + lte_cell_t cell); + +LIBLTE_API int chest_ref_LTEDL(chest_t *q, + lte_cell_t cell); + +LIBLTE_API int chest_ce_ref(chest_t *q, + cf_t *input, + uint8_t nslot, + uint8_t port_id, + uint16_t nref); + +LIBLTE_API int chest_ce_slot_port(chest_t *q, + cf_t *input, + cf_t *ce, + uint8_t nslot, + uint8_t port_id); + +LIBLTE_API int chest_ce_sf_port(chest_t *q, + cf_t *input, + cf_t *ce, + uint8_t sf_idx, + uint8_t port_id); + +LIBLTE_API int chest_ce_slot(chest_t *q, + cf_t *input, + cf_t *ce[MAX_PORTS], + uint8_t nslot); + +LIBLTE_API int chest_ce_sf(chest_t *q, + cf_t *input, + cf_t *ce[MAX_PORTS], + uint8_t sf_idx); + +LIBLTE_API void chest_fprint(chest_t *q, + FILE *stream, + uint8_t nslot, + uint8_t port_id); + +LIBLTE_API void chest_ref_fprint(chest_t *q, + FILE *stream, + uint8_t nslot, + uint8_t port_id); + +LIBLTE_API void chest_recvsig_fprint(chest_t *q, + FILE *stream, + uint8_t nslot, + uint8_t port_id); + +LIBLTE_API void chest_ce_fprint(chest_t *q, + FILE *stream, + uint8_t nslot, + uint8_t port_id); + +LIBLTE_API int chest_ref_symbols(chest_t *q, + uint8_t port_id, + uint8_t nslot, + uint8_t l[2]); /* High-level API */ @@ -94,8 +159,7 @@ typedef struct LIBLTE_API{ cf_t *input; int in_len; struct chest_ctrl_in { - int slot_id; // slot id in the 10ms frame - int cell_id; + int sf_idx; // subframe id in the 10ms frame } ctrl_in; cf_t *output[MAX_PORTS]; int out_len[MAX_PORTS]; @@ -108,3 +172,11 @@ LIBLTE_API int chest_work(chest_hl* hl); LIBLTE_API int chest_stop(chest_hl* hl); #endif + + + + + + + + diff --git a/lte/phy/include/liblte/phy/ch_estimation/refsignal.h b/lte/phy/include/liblte/phy/ch_estimation/refsignal.h index 7b1f6518a..c6ef8d859 100644 --- a/lte/phy/include/liblte/phy/ch_estimation/refsignal.h +++ b/lte/phy/include/liblte/phy/ch_estimation/refsignal.h @@ -43,26 +43,30 @@ typedef _Complex float cf_t; typedef struct LIBLTE_API{ - int time_idx; - int freq_idx; + uint8_t time_idx; + uint16_t freq_idx; cf_t simbol; cf_t recv_simbol; }ref_t; typedef struct LIBLTE_API{ - int nof_refs; // number of reference signals - int *symbols_ref; // symbols with at least one reference - int nsymbols; // number of symbols with at least one reference - int voffset; // offset of the first reference in the freq domain - int nof_prb; + uint16_t nof_refs; // number of reference signals + uint8_t *symbols_ref; // symbols with at least one reference + uint8_t nsymbols; // number of symbols with at least one reference + uint8_t voffset; // offset of the first reference in the freq domain + uint16_t nof_prb; ref_t *refs; cf_t *ch_est; } refsignal_t; -LIBLTE_API int refsignal_init_LTEDL(refsignal_t *q, int port_id, int nslot, - int cell_id, lte_cp_t cp, int nof_prb); +LIBLTE_API int refsignal_init_LTEDL(refsignal_t *q, + uint8_t port_id, + uint8_t nslot, + lte_cell_t cell); + LIBLTE_API void refsignal_free(refsignal_t *q); -LIBLTE_API void refsignal_put(refsignal_t *q, cf_t *slot_symbols); +LIBLTE_API int refsignal_put(refsignal_t *q, + cf_t *slot_symbols); #endif diff --git a/lte/phy/include/liblte/phy/channel/ch_awgn.h b/lte/phy/include/liblte/phy/channel/ch_awgn.h index 19a452cb1..fa209dfe3 100644 --- a/lte/phy/include/liblte/phy/channel/ch_awgn.h +++ b/lte/phy/include/liblte/phy/channel/ch_awgn.h @@ -34,8 +34,16 @@ typedef _Complex float cf_t; -LIBLTE_API void ch_awgn_c(const cf_t* input, cf_t* output, float variance, int buff_sz); -LIBLTE_API void ch_awgn_f(const float* x, float* y, float variance, int buff_sz); +LIBLTE_API void ch_awgn_c(const cf_t* input, + cf_t* output, + float variance, + int buff_sz); + +LIBLTE_API void ch_awgn_f(const float* x, + float* y, + float variance, + int buff_sz); + /* High-level API */ diff --git a/lte/phy/include/liblte/phy/common/fft.h b/lte/phy/include/liblte/phy/common/fft.h index 1c89ae09b..048bd37dc 100644 --- a/lte/phy/include/liblte/phy/common/fft.h +++ b/lte/phy/include/liblte/phy/common/fft.h @@ -51,14 +51,32 @@ typedef struct LIBLTE_API{ cf_t *tmp; // for removing zero padding }lte_fft_t; -LIBLTE_API int lte_fft_init(lte_fft_t *q, lte_cp_t cp_type, int nof_prb); +LIBLTE_API int lte_fft_init(lte_fft_t *q, + lte_cp_t cp_type, + int nof_prb); + LIBLTE_API void lte_fft_free(lte_fft_t *q); -LIBLTE_API void lte_fft_run_slot(lte_fft_t *q, cf_t *input, cf_t *output); -LIBLTE_API void lte_fft_run_sf(lte_fft_t *q, cf_t *input, cf_t *output); -LIBLTE_API int lte_ifft_init(lte_fft_t *q, lte_cp_t cp_type, int nof_prb); +LIBLTE_API void lte_fft_run_slot(lte_fft_t *q, + cf_t *input, + cf_t *output); + +LIBLTE_API void lte_fft_run_sf(lte_fft_t *q, + cf_t *input, + cf_t *output); + +LIBLTE_API int lte_ifft_init(lte_fft_t *q, + lte_cp_t cp_type, + int nof_prb); + LIBLTE_API void lte_ifft_free(lte_fft_t *q); -LIBLTE_API void lte_ifft_run_slot(lte_fft_t *q, cf_t *input, cf_t *output); -LIBLTE_API void lte_ifft_run_sf(lte_fft_t *q, cf_t *input, cf_t *output); + +LIBLTE_API void lte_ifft_run_slot(lte_fft_t *q, + cf_t *input, + cf_t *output); + +LIBLTE_API void lte_ifft_run_sf(lte_fft_t *q, + cf_t *input, + cf_t *output); #endif diff --git a/lte/phy/include/liblte/phy/common/phy_common.h b/lte/phy/include/liblte/phy/common/phy_common.h index c553a7c51..5fcdbb176 100644 --- a/lte/phy/include/liblte/phy/common/phy_common.h +++ b/lte/phy/include/liblte/phy/common/phy_common.h @@ -29,6 +29,8 @@ #ifndef _LTEBASE_ #define _LTEBASE_ +#include +#include #include "liblte/config.h" #define NSUBFRAMES_X_FRAME 10 @@ -100,23 +102,17 @@ typedef enum {CPNORM, CPEXT} lte_cp_t; || l == CP_NSYMB(cp) - 3) -LIBLTE_API const int lte_symbol_sz(int nof_prb); -LIBLTE_API const int lte_sampling_freq_hz(int nof_prb); -LIBLTE_API int lte_re_x_prb(int ns, int symbol, int nof_ports, int nof_symbols); -LIBLTE_API int lte_voffset(int symbol_id, int cell_id, int nof_ports); - #define NOF_LTE_BANDS 29 #define NOF_TC_CB_SIZES 188 typedef struct LIBLTE_API { - int nof_prb; - int nof_ports; - int cell_id; + uint8_t nof_prb; + uint8_t nof_ports; + uint16_t id; lte_cp_t cp; }lte_cell_t; - typedef enum LIBLTE_API { SINGLE_ANTENNA,TX_DIVERSITY, SPATIAL_MULTIPLEX } lte_mimo_type_t; @@ -134,16 +130,46 @@ LIBLTE_API enum band_geographical_area { ALL, NAR, APAC, EMEA, JAPAN, CALA, NA }; +LIBLTE_API bool lte_cell_isvalid(lte_cell_t *cell); + +LIBLTE_API const int lte_symbol_sz(int nof_prb); + +LIBLTE_API const int lte_sampling_freq_hz(int nof_prb); + +LIBLTE_API int lte_re_x_prb(int ns, + int symbol, + int nof_ports, + int nof_symbols); + +LIBLTE_API int lte_voffset(int symbol_id, + int cell_id, + int nof_ports); + LIBLTE_API int lte_cb_size(int index); + LIBLTE_API int lte_find_cb_index(int long_cb); LIBLTE_API float lte_band_fd(int earfcn); -LIBLTE_API int lte_band_get_fd_band(int band, lte_earfcn_t *earfcn, int earfcn_start, int earfcn_end, int max_elems); -LIBLTE_API int lte_band_get_fd_band_all(int band, lte_earfcn_t *earfcn, int max_nelems); -LIBLTE_API int lte_band_get_fd_region(enum band_geographical_area region, lte_earfcn_t *earfcn, int max_elems); -LIBLTE_API int lte_str2mimotype(char *mimo_type_str, lte_mimo_type_t *type); +LIBLTE_API int lte_band_get_fd_band(int band, + lte_earfcn_t *earfcn, + int earfcn_start, + int earfcn_end, + int max_elems); + +LIBLTE_API int lte_band_get_fd_band_all(int band, + lte_earfcn_t *earfcn, + int max_nelems); + +LIBLTE_API int lte_band_get_fd_region(enum band_geographical_area region, + lte_earfcn_t *earfcn, + int max_elems); + +LIBLTE_API int lte_str2mimotype(char *mimo_type_str, + lte_mimo_type_t *type); + LIBLTE_API char *lte_mimotype2str(lte_mimo_type_t type); + #endif diff --git a/lte/phy/include/liblte/phy/common/sequence.h b/lte/phy/include/liblte/phy/common/sequence.h index 0fb52df2f..f237ac20c 100644 --- a/lte/phy/include/liblte/phy/common/sequence.h +++ b/lte/phy/include/liblte/phy/common/sequence.h @@ -33,19 +33,39 @@ typedef struct LIBLTE_API { char *c; - int len; + uint32_t len; } sequence_t; -LIBLTE_API int sequence_init(sequence_t *q, int len); +LIBLTE_API int sequence_init(sequence_t *q, uint32_t len); + LIBLTE_API void sequence_free(sequence_t *q); -LIBLTE_API int sequence_LTEPRS(sequence_t *q, int len, int seed); +LIBLTE_API int sequence_LTEPRS(sequence_t *q, + uint32_t len, + uint32_t seed); + +LIBLTE_API int sequence_pbch(sequence_t *seq, + lte_cp_t cp, + uint16_t cell_id); + +LIBLTE_API int sequence_pcfich(sequence_t *seq, + uint8_t nslot, + uint16_t cell_id); + +LIBLTE_API int sequence_phich(sequence_t *seq, + uint8_t nslot, + uint16_t cell_id); + +LIBLTE_API int sequence_pdcch(sequence_t *seq, + uint8_t nslot, + uint16_t cell_id, + uint32_t len); -LIBLTE_API int sequence_pbch(sequence_t *seq, lte_cp_t cp, int cell_id); -LIBLTE_API int sequence_pcfich(sequence_t *seq, int nslot, int cell_id); -LIBLTE_API int sequence_phich(sequence_t *seq, int nslot, int cell_id); -LIBLTE_API int sequence_pdcch(sequence_t *seq, int nslot, int cell_id, int len); -LIBLTE_API int sequence_pdsch(sequence_t *seq, unsigned short rnti, int q, - int nslot, int cell_id, int len); +LIBLTE_API int sequence_pdsch(sequence_t *seq, + unsigned short rnti, + int q, + uint8_t nslot, + uint16_t cell_id, + uint32_t len); #endif diff --git a/lte/phy/include/liblte/phy/phch/dci.h b/lte/phy/include/liblte/phy/phch/dci.h index eb6b8afd3..23137e214 100644 --- a/lte/phy/include/liblte/phy/phch/dci.h +++ b/lte/phy/include/liblte/phy/phch/dci.h @@ -62,10 +62,10 @@ typedef enum { } dci_spec_t; typedef struct LIBLTE_API { - unsigned char nof_bits; - unsigned char L; // Aggregation level - unsigned char ncce; // Position of first CCE of the dci - unsigned short rnti; + uint8_t nof_bits; + uint8_t L; // Aggregation level + uint8_t ncce; // Position of first CCE of the dci + uint16_t rnti; } dci_candidate_t; typedef struct LIBLTE_API { @@ -75,28 +75,55 @@ typedef struct LIBLTE_API { typedef struct LIBLTE_API { dci_msg_t *msg; - int nof_dcis; - int max_dcis; + uint8_t nof_dcis; + uint8_t max_dcis; } dci_t; -LIBLTE_API int dci_init(dci_t *q, int max_dci); +LIBLTE_API int dci_init(dci_t *q, + uint8_t max_dci); + LIBLTE_API void dci_free(dci_t *q); + LIBLTE_API char* dci_format_string(dci_format_t format); -LIBLTE_API int dci_msg_candidate_set(dci_msg_t *msg, int L, int nCCE, unsigned short rnti); -LIBLTE_API void dci_candidate_fprint(FILE *f, dci_candidate_t *q); +LIBLTE_API int dci_msg_candidate_set(dci_msg_t *msg, + uint8_t L, + uint8_t nCCE, + uint16_t rnti); + +LIBLTE_API void dci_candidate_fprint(FILE *f, + dci_candidate_t *q); -LIBLTE_API int dci_msg_get_type(dci_msg_t *msg, dci_msg_type_t *type, int nof_prb, unsigned short crnti); -LIBLTE_API void dci_msg_type_fprint(FILE *f, dci_msg_type_t type); +LIBLTE_API int dci_msg_get_type(dci_msg_t *msg, + dci_msg_type_t *type, + uint8_t nof_prb, + uint16_t crnti); + +LIBLTE_API void dci_msg_type_fprint(FILE *f, + dci_msg_type_t type); // For dci_msg_type_t = PUSCH_SCHED -LIBLTE_API int dci_msg_pack_pusch(ra_pusch_t *data, dci_msg_t *msg, int nof_prb); -LIBLTE_API int dci_msg_unpack_pusch(dci_msg_t *msg, ra_pusch_t *data, int nof_prb); +LIBLTE_API int dci_msg_pack_pusch(ra_pusch_t *data, + dci_msg_t *msg, + uint8_t nof_prb); -// For dci_msg_type_t = PDSCH_SCHED -LIBLTE_API int dci_msg_pack_pdsch(ra_pdsch_t *data, dci_msg_t *msg, dci_format_t format, int nof_prb, bool crc_is_crnti); -LIBLTE_API int dci_msg_unpack_pdsch(dci_msg_t *msg, ra_pdsch_t *data, int nof_prb, bool crc_is_crnti); +LIBLTE_API int dci_msg_unpack_pusch(dci_msg_t *msg, + ra_pusch_t *data, + uint8_t nof_prb); -LIBLTE_API int dci_format_sizeof(dci_format_t format, int nof_prb); +// For dci_msg_type_t = PDSCH_SCHED +LIBLTE_API int dci_msg_pack_pdsch(ra_pdsch_t *data, + dci_msg_t *msg, + dci_format_t format, + uint8_t nof_prb, + bool crc_is_crnti); + +LIBLTE_API int dci_msg_unpack_pdsch(dci_msg_t *msg, + ra_pdsch_t *data, + uint8_t nof_prb, + bool crc_is_crnti); + +LIBLTE_API uint8_t dci_format_sizeof(dci_format_t format, + uint8_t nof_prb); #endif // DCI_ diff --git a/lte/phy/include/liblte/phy/phch/pbch.h b/lte/phy/include/liblte/phy/phch/pbch.h index b3b146d4c..ac96c2174 100644 --- a/lte/phy/include/liblte/phy/phch/pbch.h +++ b/lte/phy/include/liblte/phy/phch/pbch.h @@ -85,12 +85,25 @@ typedef struct LIBLTE_API { }pbch_t; -LIBLTE_API int pbch_init(pbch_t *q, int nof_prb, int cell_id, lte_cp_t cp); +LIBLTE_API int pbch_init(pbch_t *q, + int nof_prb, + int cell_id, + lte_cp_t cp); + LIBLTE_API void pbch_free(pbch_t *q); -LIBLTE_API int pbch_decode(pbch_t *q, cf_t *slot1_symbols, cf_t *ce[MAX_PORTS], pbch_mib_t *mib); -LIBLTE_API void pbch_encode(pbch_t *q, pbch_mib_t *mib, cf_t *slot1_symbols[MAX_PORTS], int nof_ports); +LIBLTE_API int pbch_decode(pbch_t *q, + cf_t *slot1_symbols, + cf_t *ce[MAX_PORTS], + pbch_mib_t *mib); + +LIBLTE_API void pbch_encode(pbch_t *q, + pbch_mib_t *mib, + cf_t *slot1_symbols[MAX_PORTS], + int nof_ports); + LIBLTE_API void pbch_decode_reset(pbch_t *q); -LIBLTE_API void pbch_mib_fprint(FILE *stream, pbch_mib_t *mib); +LIBLTE_API void pbch_mib_fprint(FILE *stream, + pbch_mib_t *mib); #endif // PBCH_ diff --git a/lte/phy/include/liblte/phy/phch/pcfich.h b/lte/phy/include/liblte/phy/phch/pcfich.h index 68b487719..7e04267a0 100644 --- a/lte/phy/include/liblte/phy/phch/pcfich.h +++ b/lte/phy/include/liblte/phy/phch/pcfich.h @@ -45,11 +45,8 @@ typedef _Complex float cf_t; /* PCFICH object */ typedef struct LIBLTE_API { - int cell_id; - lte_cp_t cp; + lte_cell_t cell; int nof_symbols; - int nof_prb; - int nof_ports; /* handler to REGs resource mapper */ regs_t *regs; @@ -70,16 +67,22 @@ typedef struct LIBLTE_API { } pcfich_t; -LIBLTE_API int pcfich_init(pcfich_t *q, regs_t *regs, int cell_id, int nof_prb, - int nof_tx_ports, lte_cp_t cp); +LIBLTE_API int pcfich_init(pcfich_t *q, + regs_t *regs, + lte_cell_t cell); + LIBLTE_API void pcfich_free(pcfich_t *q); -LIBLTE_API int pcfich_decode(pcfich_t *q, cf_t *slot_symbols, cf_t *ce[MAX_PORTS], - int nsubframe, int *cfi, int *distance); -LIBLTE_API int pcfich_encode(pcfich_t *q, int cfi, cf_t *slot_symbols[MAX_PORTS], - int nsubframe); -LIBLTE_API bool pcfich_exists(int nframe, int nslot); -LIBLTE_API int pcfich_put(regs_t *h, cf_t *pcfich, cf_t *slot_data); -LIBLTE_API int pcfich_get(regs_t *h, cf_t *pcfich, cf_t *slot_data); +LIBLTE_API int pcfich_decode(pcfich_t *q, + cf_t *sf_symbols, + cf_t *ce[MAX_PORTS], + uint8_t subframe, + uint8_t *cfi, + uint8_t *distance); + +LIBLTE_API int pcfich_encode(pcfich_t *q, + uint8_t cfi, + cf_t *sf_symbols[MAX_PORTS], + uint8_t subframe); #endif diff --git a/lte/phy/include/liblte/phy/phch/pdcch.h b/lte/phy/include/liblte/phy/phch/pdcch.h index b44a00a56..cbcf7824c 100644 --- a/lte/phy/include/liblte/phy/phch/pdcch.h +++ b/lte/phy/include/liblte/phy/phch/pdcch.h @@ -56,20 +56,18 @@ typedef enum LIBLTE_API { * DCI messages as defined in Section 7.1 of 36.213 */ typedef struct LIBLTE_API { - int nof_candidates; + uint8_t nof_candidates; dci_candidate_t candidates[NSUBFRAMES_X_FRAME][MAX_CANDIDATES]; } pdcch_search_t; /* PDCCH object */ typedef struct LIBLTE_API { - int cell_id; - lte_cp_t cp; - int nof_prb; - int nof_bits; - int nof_symbols; - int nof_ports; - int nof_regs; - int nof_cce; + lte_cell_t cell; + uint16_t nof_bits; + uint16_t nof_symbols; + uint16_t nof_regs; + uint16_t nof_cce; + uint16_t max_bits; pdcch_search_t search_mode[PDCCH_NOF_SEARCH_MODES]; pdcch_search_mode_t current_search_mode; @@ -92,15 +90,19 @@ typedef struct LIBLTE_API { crc_t crc; } pdcch_t; -LIBLTE_API int pdcch_init(pdcch_t *q, regs_t *regs, int nof_prb, int nof_ports, - int cell_id, lte_cp_t cp); +LIBLTE_API int pdcch_init(pdcch_t *q, + regs_t *regs, + lte_cell_t cell); + LIBLTE_API void pdcch_free(pdcch_t *q); -LIBLTE_API int pdcch_set_cfi(pdcch_t *q, int cfi); /* Encoding functions */ -LIBLTE_API int pdcch_encode(pdcch_t *q, dci_t *dci, cf_t *slot_symbols[MAX_PORTS], - int nsubframe); +LIBLTE_API int pdcch_encode(pdcch_t *q, + dci_t *dci, + cf_t *slot_symbols[MAX_PORTS], + uint8_t nsubframe, + uint8_t cfi); /* Decoding functions */ @@ -109,21 +111,48 @@ LIBLTE_API int pdcch_encode(pdcch_t *q, dci_t *dci, cf_t *slot_symbols[MAX_PORTS * b) call pdcch_extract_llr() and then call pdcch_decode_si/ue/ra */ -LIBLTE_API int pdcch_decode(pdcch_t *q, cf_t *slot_symbols, cf_t *ce[MAX_PORTS], - dci_t *dci, int nsubframe); -LIBLTE_API int pdcch_extract_llr(pdcch_t *q, cf_t *slot_symbols, cf_t *ce[MAX_PORTS], - float *llr, int nsubframe); +LIBLTE_API int pdcch_decode(pdcch_t *q, + cf_t *slot_symbols, + cf_t *ce[MAX_PORTS], + dci_t *dci, + uint8_t nsubframe, + uint8_t cfi); + +LIBLTE_API int pdcch_extract_llr(pdcch_t *q, + cf_t *slot_symbols, + cf_t *ce[MAX_PORTS], + float *llr, + uint8_t nsubframe, + uint8_t cfi); + +LIBLTE_API int pdcch_init_search_si(pdcch_t *q, + uint8_t cfi); -LIBLTE_API void pdcch_init_search_si(pdcch_t *q); LIBLTE_API void pdcch_set_search_si(pdcch_t *q); -LIBLTE_API int pdcch_decode_si(pdcch_t *q, float *llr, dci_t *dci); -LIBLTE_API void pdcch_init_search_ue(pdcch_t *q, unsigned short c_rnti); +LIBLTE_API int pdcch_decode_si(pdcch_t *q, + float *llr, + dci_t *dci); + +LIBLTE_API int pdcch_init_search_ue(pdcch_t *q, + uint16_t c_rnti, + uint8_t cfi); + LIBLTE_API void pdcch_set_search_ue(pdcch_t *q); -LIBLTE_API int pdcch_decode_ue(pdcch_t *q, float *llr, dci_t *dci, int nsubframe); -LIBLTE_API void pdcch_init_search_ra(pdcch_t *q, unsigned short ra_rnti); +LIBLTE_API int pdcch_decode_ue(pdcch_t *q, + float *llr, + dci_t *dci, + uint8_t nsubframe); + +LIBLTE_API int pdcch_init_search_ra(pdcch_t *q, + uint16_t ra_rnti, + uint8_t cfi); + LIBLTE_API void pdcch_set_search_ra(pdcch_t *q); -LIBLTE_API int pdcch_decode_ra(pdcch_t *q, float *llr, dci_t *dci); + +LIBLTE_API int pdcch_decode_ra(pdcch_t *q, + float *llr, + dci_t *dci); #endif diff --git a/lte/phy/include/liblte/phy/phch/pdsch.h b/lte/phy/include/liblte/phy/phch/pdsch.h index 8f2ce7504..9f7ac40cc 100644 --- a/lte/phy/include/liblte/phy/phch/pdsch.h +++ b/lte/phy/include/liblte/phy/phch/pdsch.h @@ -49,12 +49,10 @@ typedef _Complex float cf_t; /* PDSCH object */ typedef struct LIBLTE_API { - int cell_id; - lte_cp_t cp; - int nof_prb; - int nof_ports; - int max_symbols; - unsigned short rnti; + lte_cell_t cell; + + uint16_t max_symbols; + uint16_t rnti; /* buffers */ cf_t *ce[MAX_PORTS]; @@ -78,17 +76,31 @@ typedef struct LIBLTE_API { crc_t crc_cb; }pdsch_t; -LIBLTE_API int pdsch_init(pdsch_t *q, unsigned short user_rnti, int nof_prb, - int nof_ports, int cell_id, lte_cp_t cp); +LIBLTE_API int pdsch_init(pdsch_t *q, + uint16_t user_rnti, + lte_cell_t cell); + LIBLTE_API void pdsch_free(pdsch_t *q); -LIBLTE_API 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); -LIBLTE_API 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); -LIBLTE_API int pdsch_get(pdsch_t *q, cf_t *sf_symbols, cf_t *pdsch_symbols, - ra_prb_t *prb_alloc, int nsubframe); -LIBLTE_API int pdsch_put(pdsch_t *q, cf_t *pdsch_symbols, cf_t *sf_symbols, - ra_prb_t *prb_alloc, int nsubframe); +LIBLTE_API int pdsch_encode(pdsch_t *q, + char *data, + cf_t *sf_symbols[MAX_PORTS], + uint8_t nsubframe, + ra_mcs_t mcs, + ra_prb_t *prb_alloc); + +LIBLTE_API int pdsch_decode(pdsch_t *q, + cf_t *sf_symbols, + cf_t *ce[MAX_PORTS], + char *data, + uint8_t nsubframe, + ra_mcs_t mcs, + ra_prb_t *prb_alloc); + +LIBLTE_API int pdsch_get(pdsch_t *q, + cf_t *sf_symbols, + cf_t *pdsch_symbols, + ra_prb_t *prb_alloc, + uint8_t subframe); #endif diff --git a/lte/phy/include/liblte/phy/phch/phich.h b/lte/phy/include/liblte/phy/phch/phich.h index 63b7a1b57..fad03467a 100644 --- a/lte/phy/include/liblte/phy/phch/phich.h +++ b/lte/phy/include/liblte/phy/phch/phich.h @@ -55,10 +55,8 @@ typedef _Complex float cf_t; /* phich object */ typedef struct LIBLTE_API { - lte_cp_t cp; - int nof_prb; - int nof_tx_ports; - + lte_cell_t cell; + /* handler to REGs resource mapper */ regs_t *regs; @@ -80,18 +78,31 @@ typedef struct LIBLTE_API { }phich_t; -LIBLTE_API int phich_init(phich_t *q, regs_t *regs, int cell_id, int nof_prb, int nof_tx_ports, lte_cp_t cp); -LIBLTE_API void phich_free(phich_t *q); -LIBLTE_API int phich_decode(phich_t *q, cf_t *slot_symbols, cf_t *ce[MAX_PORTS], - int ngroup, int nseq, int nsubframe, char *ack, int *distance); -LIBLTE_API int phich_encode(phich_t *q, char ack, int ngroup, int nseq, int nsubframe, - cf_t *slot_symbols[MAX_PORTS]); +LIBLTE_API int phich_init(phich_t *q, + regs_t *regs, + lte_cell_t cell); +LIBLTE_API void phich_free(phich_t *q); -LIBLTE_API void phich_reset(phich_t *q, cf_t *slot_symbols[MAX_PORTS]); -LIBLTE_API int phich_ngroups(phich_t *q); -LIBLTE_API bool phich_exists(int nframe, int nslot); -LIBLTE_API int phich_put(regs_t *h, cf_t *phich, cf_t *slot_data); -LIBLTE_API int phich_get(regs_t *h, cf_t *phich, cf_t *slot_data); +LIBLTE_API int phich_decode(phich_t *q, + cf_t *slot_symbols, + cf_t *ce[MAX_PORTS], + uint8_t ngroup, + uint8_t nseq, + uint8_t nsubframe, + char *ack, + uint8_t *distance); + +LIBLTE_API int phich_encode(phich_t *q, + char ack, + uint8_t ngroup, + uint8_t nseq, + uint8_t nsubframe, + cf_t *slot_symbols[MAX_PORTS]); + +LIBLTE_API void phich_reset(phich_t *q, + cf_t *slot_symbols[MAX_PORTS]); + +LIBLTE_API uint8_t phich_ngroups(phich_t *q); #endif // PHICH_ diff --git a/lte/phy/include/liblte/phy/phch/prach.h b/lte/phy/include/liblte/phy/phch/prach.h index b50e78b0d..4bdd08778 100644 --- a/lte/phy/include/liblte/phy/phch/prach.h +++ b/lte/phy/include/liblte/phy/phch/prach.h @@ -46,7 +46,7 @@ typedef _Complex float cf_t; * Based on 3GPP TS 36.211 version 10.7.0 Release 10. */ -typedef struct LIBLTE_API{ +typedef struct LIBLTE_API { // Parameters from higher layers (extracted from SIB2) uint32_t f; // preamble format uint32_t rsi; // rootSequenceIndex diff --git a/lte/phy/include/liblte/phy/phch/regs.h b/lte/phy/include/liblte/phy/phch/regs.h index 9a23474bc..61d289513 100644 --- a/lte/phy/include/liblte/phy/phch/regs.h +++ b/lte/phy/include/liblte/phy/phch/regs.h @@ -45,57 +45,79 @@ typedef _Complex float cf_t; typedef struct LIBLTE_API { - int k[4]; - int k0; - int l; + uint16_t k[4]; + uint16_t k0; + uint8_t l; bool assigned; }regs_reg_t; typedef struct LIBLTE_API { - int nof_regs; + uint16_t nof_regs; regs_reg_t **regs; }regs_ch_t; typedef struct LIBLTE_API { - int cell_id; - int nof_prb; - int max_ctrl_symbols; - int cfi; - int ngroups_phich; - int nof_ports; - lte_cp_t cp; + lte_cell_t cell; + uint8_t max_ctrl_symbols; + uint8_t cfi; + bool cfi_initiated; + uint8_t ngroups_phich; + phich_resources_t phich_res; phich_length_t phich_len; + regs_ch_t pcfich; regs_ch_t *phich; // there are several phich regs_ch_t pdcch[3]; /* PDCCH indexing, permutation and interleaving is computed for the three possible CFI value */ - int nof_regs; + + uint16_t nof_regs; regs_reg_t *regs; }regs_t; -LIBLTE_API int regs_init(regs_t *h, int cell_id, int nof_prb, int nof_ports, - phich_resources_t phich_res, phich_length_t phich_len, lte_cp_t cp); +LIBLTE_API int regs_init(regs_t *h, + phich_resources_t phich_res, + phich_length_t phich_len, + lte_cell_t cell); + LIBLTE_API void regs_free(regs_t *h); -LIBLTE_API int regs_set_cfi(regs_t *h, int nof_ctrl_symbols); +LIBLTE_API int regs_set_cfi(regs_t *h, + uint8_t nof_ctrl_symbols); + + +LIBLTE_API uint16_t regs_pcfich_nregs(regs_t *h); +LIBLTE_API int regs_pcfich_put(regs_t *h, + cf_t pcfich_symbols[REGS_PCFICH_NSYM], + cf_t *slot_symbols); + +LIBLTE_API int regs_pcfich_get(regs_t *h, + cf_t *slot_symbols, + cf_t pcfich_symbols[REGS_PCFICH_NSYM]); -LIBLTE_API int regs_put_reg(regs_reg_t *reg, cf_t *reg_data, cf_t *slot_symbols, int nof_prb); -LIBLTE_API int regs_add_reg(regs_reg_t *reg, cf_t *reg_data, cf_t *slot_symbols, int nof_prb); -LIBLTE_API int regs_get_reg(regs_reg_t *reg, cf_t *slot_symbols, cf_t *reg_data, int nof_prb); -LIBLTE_API int regs_reset_reg(regs_reg_t *reg, cf_t *slot_symbols, int nof_prb); +LIBLTE_API uint16_t regs_phich_nregs(regs_t *h); +LIBLTE_API int regs_phich_add(regs_t *h, + cf_t phich_symbols[REGS_PHICH_NSYM], + uint8_t ngroup, + cf_t *slot_symbols); -LIBLTE_API int regs_pcfich_nregs(regs_t *h); -LIBLTE_API int regs_pcfich_put(regs_t *h, cf_t pcfich_symbols[REGS_PCFICH_NSYM], cf_t *slot_symbols); -LIBLTE_API int regs_pcfich_get(regs_t *h, cf_t *slot_symbols, cf_t pcfich_symbols[REGS_PCFICH_NSYM]); +LIBLTE_API int regs_phich_get(regs_t *h, + cf_t *slot_symbols, + cf_t phich_symbols[REGS_PHICH_NSYM], + uint8_t ngroup); -LIBLTE_API int regs_phich_nregs(regs_t *h); -LIBLTE_API int regs_phich_add(regs_t *h, cf_t phich_symbols[REGS_PHICH_NSYM], int ngroup, cf_t *slot_symbols); -LIBLTE_API int regs_phich_get(regs_t *h, cf_t *slot_symbols, cf_t phich_symbols[REGS_PHICH_NSYM], int ngroup); -LIBLTE_API int regs_phich_ngroups(regs_t *h); -LIBLTE_API int regs_phich_reset(regs_t *h, cf_t *slot_symbols); +LIBLTE_API uint8_t regs_phich_ngroups(regs_t *h); +LIBLTE_API int regs_phich_reset(regs_t *h, + cf_t *slot_symbols); -LIBLTE_API int regs_pdcch_nregs(regs_t *h, int cfi); -LIBLTE_API int regs_pdcch_put(regs_t *h, cf_t *pdcch_symbols, cf_t *slot_symbols); -LIBLTE_API int regs_pdcch_get(regs_t *h, cf_t *slot_symbols, cf_t *pdcch_symbols); +LIBLTE_API int regs_pdcch_nregs(regs_t *h, uint8_t cfi); +LIBLTE_API int regs_pdcch_put(regs_t *h, + cf_t *pdcch_symbols, + cf_t *slot_symbols); + +LIBLTE_API int regs_pdcch_get(regs_t *h, + cf_t *slot_symbols, + cf_t *pdcch_symbols); #endif // REGS_H_ + + diff --git a/lte/phy/include/liblte/phy/phy.h b/lte/phy/include/liblte/phy/phy.h index 4839572e6..0b5ba19d2 100644 --- a/lte/phy/include/liblte/phy/phy.h +++ b/lte/phy/include/liblte/phy/phy.h @@ -50,7 +50,6 @@ #include "liblte/phy/common/phy_common.h" #include "liblte/phy/common/fft.h" -#include "liblte/phy/common/sequence.h" #include "liblte/phy/ch_estimation/chest.h" #include "liblte/phy/ch_estimation/refsignal.h" diff --git a/lte/phy/include/liblte/phy/sync/sync_frame.h b/lte/phy/include/liblte/phy/sync/sync_frame.h index 9ed2335f0..c4758a5db 100644 --- a/lte/phy/include/liblte/phy/sync/sync_frame.h +++ b/lte/phy/include/liblte/phy/sync/sync_frame.h @@ -56,6 +56,7 @@ typedef struct LIBLTE_API { sync_t s; enum sync_frame_state state; int downsampling; + resample_arb_t resample; unsigned long frame_cnt; bool fb_wp; int frame_size; diff --git a/lte/phy/lib/ch_estimation/src/chest.c b/lte/phy/lib/ch_estimation/src/chest.c index ae855cfdc..73d72906b 100644 --- a/lte/phy/lib/ch_estimation/src/chest.c +++ b/lte/phy/lib/ch_estimation/src/chest.c @@ -29,7 +29,6 @@ #include #include #include -#include #include #include "liblte/phy/ch_estimation/chest.h" @@ -40,7 +39,7 @@ #define SLOT_SZ(q) (q->nof_symbols * q->symbol_sz) #define SF_SZ(q) (2 * SLOT_SZ(q)) -void chest_fprint(chest_t *q, FILE *stream, int nslot, int port_id) { +void chest_fprint(chest_t *q, FILE *stream, uint8_t nslot, uint8_t port_id) { chest_ref_fprint(q, stream, nslot, port_id); chest_recvsig_fprint(q, stream, nslot, port_id); chest_ce_fprint(q, stream, nslot, port_id); @@ -49,13 +48,16 @@ void chest_fprint(chest_t *q, FILE *stream, int nslot, int port_id) { /* Sets the number of ports to estimate. nof_ports must be smaler than nof_ports * used during the call to chest_init(). */ -void chest_set_nof_ports(chest_t *q, int nof_ports) { - if (nof_ports < q->nof_ports && nof_ports > 0) { +int chest_set_nof_ports(chest_t *q, uint8_t nof_ports) { + if (nof_ports < q->nof_ports) { q->nof_ports = nof_ports; + return LIBLTE_SUCCESS; + } else { + return LIBLTE_ERROR_INVALID_INPUTS; } } -void chest_ref_fprint(chest_t *q, FILE *stream, int nslot, int port_id) { +void chest_ref_fprint(chest_t *q, FILE *stream, uint8_t nslot, uint8_t port_id) { int i; fprintf(stream, "refs%d=[",port_id); for (i=0;irefsignal[port_id][nslot].nof_refs;i++) { @@ -65,7 +67,7 @@ void chest_ref_fprint(chest_t *q, FILE *stream, int nslot, int port_id) { fprintf(stream, "];\n"); } -void chest_recvsig_fprint(chest_t *q, FILE *stream, int nslot, int port_id) { +void chest_recvsig_fprint(chest_t *q, FILE *stream, uint8_t nslot, uint8_t port_id) { int i; fprintf(stream, "recvsig%d=[",port_id); for (i=0;irefsignal[port_id][nslot].nof_refs;i++) { @@ -75,7 +77,7 @@ void chest_recvsig_fprint(chest_t *q, FILE *stream, int nslot, int port_id) { fprintf(stream, "];\n"); } -void chest_ce_fprint(chest_t *q, FILE *stream, int nslot, int port_id) { +void chest_ce_fprint(chest_t *q, FILE *stream, uint8_t nslot, uint8_t port_id) { int i; fprintf(stream, "mag%d=[",port_id); for (i=0;irefsignal[port_id][nslot].nof_refs;i++) { @@ -89,164 +91,206 @@ void chest_ce_fprint(chest_t *q, FILE *stream, int nslot, int port_id) { fprintf(stream, "];\n"); } -void chest_ce_ref(chest_t *q, cf_t *input, int nslot, int port_id, int nref) { +int chest_ce_ref(chest_t *q, cf_t *input, uint8_t nslot, uint8_t port_id, uint16_t nref) { int fidx, tidx; cf_t known_ref, channel_ref; - - fidx = q->refsignal[port_id][nslot].refs[nref].freq_idx; // reference frequency index - tidx = q->refsignal[port_id][nslot].refs[nref].time_idx; // reference time index - known_ref = q->refsignal[port_id][nslot].refs[nref].simbol; - channel_ref = input[SAMPLE_IDX(q->nof_prb, tidx, fidx)]; - q->refsignal[port_id][nslot].refs[nref].recv_simbol = channel_ref; - - DEBUG("Reference %2d pos (%2d,%2d)=%3d %.2f dB %.2f/%.2f=%.2f\n", nref, tidx, fidx, SAMPLE_IDX(q->nof_prb, tidx, fidx), - 10*log10f(cabsf(channel_ref/known_ref)), - cargf(channel_ref)/M_PI,cargf(known_ref)/M_PI,cargf(channel_ref/known_ref)/M_PI); - - /* FIXME: compare with threshold */ - if (channel_ref != 0) { - q->refsignal[port_id][nslot].ch_est[nref] = channel_ref/known_ref; - } else { - q->refsignal[port_id][nslot].ch_est[nref] = 0; + int ret = LIBLTE_ERROR_INVALID_INPUTS; + + if (q != NULL && + input != NULL && + nslot < NSLOTS_X_FRAME && + port_id < q->nof_ports) + { + if (nref < q->refsignal[port_id][nslot].nof_refs) { + fidx = q->refsignal[port_id][nslot].refs[nref].freq_idx; // reference frequency index + tidx = q->refsignal[port_id][nslot].refs[nref].time_idx; // reference time index + known_ref = q->refsignal[port_id][nslot].refs[nref].simbol; + channel_ref = input[tidx * q->nof_re + fidx]; + q->refsignal[port_id][nslot].refs[nref].recv_simbol = channel_ref; + + DEBUG("Reference %2d pos (%2d,%2d)=%3d %.2f dB %.2f/%.2f=%.2f\n", nref, tidx, fidx, tidx * q->nof_re + fidx, + 10*log10f(cabsf(channel_ref/known_ref)), + cargf(channel_ref)/M_PI,cargf(known_ref)/M_PI, + cargf(channel_ref/known_ref)/M_PI); + + /* FIXME: compare with threshold */ + if (channel_ref != 0) { + q->refsignal[port_id][nslot].ch_est[nref] = channel_ref/known_ref; + } else { + q->refsignal[port_id][nslot].ch_est[nref] = 0; + } + ret = LIBLTE_SUCCESS; + } } + return ret; } /* Computes channel estimates for each reference in a slot and port. * Saves the nof_prb * 12 * nof_symbols channel estimates in the array ce */ -void chest_ce_slot_port(chest_t *q, cf_t *input, cf_t *ce, int nslot, int port_id) { +int chest_ce_slot_port(chest_t *q, cf_t *input, cf_t *ce, uint8_t nslot, uint8_t port_id) { int i, j; cf_t x[2], y[MAX_NSYMB]; - assert(nslot >= 0 && nslot < NSLOTS_X_FRAME); - assert(port_id >= 0 && port_id < q->nof_ports); - assert(q->refsignal[port_id][nslot].nsymbols <= 2); - - refsignal_t *r = &q->refsignal[port_id][nslot]; - - INFO("Estimating channel slot=%d port=%d using %d reference signals\n", - nslot, port_id, r->nof_refs); - - for (i=0;inof_refs;i++) { - chest_ce_ref(q, input, nslot, port_id, i); - } + int ret = LIBLTE_ERROR_INVALID_INPUTS; + + if (q != NULL && + input != NULL && + nslot < NSLOTS_X_FRAME && + port_id < q->nof_ports) + { + if (q->refsignal[port_id][nslot].nsymbols <= 2) { + refsignal_t *r = &q->refsignal[port_id][nslot]; + + INFO("Estimating channel slot=%d port=%d using %d reference signals\n", + nslot, port_id, r->nof_refs); + + for (i=0;inof_refs;i++) { + chest_ce_ref(q, input, nslot, port_id, i); + } - /* interpolate the symbols with references - * in the freq domain */ - for (i=0;insymbols;i++) { - interp_linear_offset(&r->ch_est[i * r->nof_refs/2], - &ce[r->symbols_ref[i] * q->nof_prb * RE_X_RB], RE_X_RB/2, - r->nof_refs/2, r->voffset, RE_X_RB/2-r->voffset); + /* interpolate the symbols with references + * in the freq domain */ + for (i=0;insymbols;i++) { + interp_linear_offset(&r->ch_est[i * r->nof_refs/2], + &ce[r->symbols_ref[i] * q->nof_re], RE_X_RB/2, + r->nof_refs/2, r->voffset, RE_X_RB/2-r->voffset); - } - /* now interpolate in the time domain */ - for (i=0;inof_prb * RE_X_RB; i++) { - if (r->nsymbols > 1) { - for (j=0;jnsymbols;j++) { - x[j] = ce[r->symbols_ref[j] * q->nof_prb * RE_X_RB + i]; } - interp_linear_offset(x, y, r->symbols_ref[1]-r->symbols_ref[0], - 2, r->symbols_ref[0], 3); - } else { - for (j=0;jsymbols_ref[0] * q->nof_prb * RE_X_RB + i]; + /* now interpolate in the time domain */ + for (i=0;inof_re; i++) { + if (r->nsymbols > 1) { + for (j=0;jnsymbols;j++) { + x[j] = ce[r->symbols_ref[j] * q->nof_re + i]; + } + interp_linear_offset(x, y, r->symbols_ref[1]-r->symbols_ref[0], + 2, r->symbols_ref[0], 3); + } else { + for (j=0;jsymbols_ref[0] * q->nof_re + i]; + } + } + for (j=0;jnof_symbols;j++) { + ce[j * q->nof_re + i] = y[j]; + } } - } - for (j=0;jnof_symbols;j++) { - ce[j * q->nof_prb * RE_X_RB + i] = y[j]; + ret = LIBLTE_SUCCESS; } } + return ret; } /* Computes channel estimates for each reference in a subframe and port id. */ -void chest_ce_sf_port(chest_t *q, cf_t *input, cf_t *ce, int sf_idx, int port_id) { - int n, slotsz; - slotsz = CP_NSYMB(q->cp)*q->nof_prb*RE_X_RB; +int chest_ce_sf_port(chest_t *q, cf_t *input, cf_t *ce, uint8_t sf_idx, uint8_t port_id) { + int n, slotsz, ret; + slotsz = q->nof_symbols*q->nof_re; for (n=0;n<2;n++) { - chest_ce_slot_port(q, &input[n*slotsz], &ce[n*slotsz], 2*sf_idx+n, port_id); + ret = chest_ce_slot_port(q, &input[n*slotsz], &ce[n*slotsz], 2*sf_idx+n, port_id); + if (ret != LIBLTE_SUCCESS) { + return ret; + } } + return LIBLTE_SUCCESS; } /* Computes channel estimates for each reference in a slot for all ports. */ -void chest_ce_slot(chest_t *q, cf_t *input, cf_t **ce, int nslot) { - int p; +int chest_ce_slot(chest_t *q, cf_t *input, cf_t **ce, uint8_t nslot) { + int p, ret; for (p=0;pnof_ports;p++) { - chest_ce_slot_port(q, input, ce[p], nslot, p); + ret = chest_ce_slot_port(q, input, ce[p], nslot, p); + if (ret != LIBLTE_SUCCESS) { + return ret; + } } + return LIBLTE_SUCCESS; } /* Computes channel estimates for each reference in a subframe for all ports. */ -void chest_ce_sf(chest_t *q, cf_t *input, cf_t *ce[MAX_PORTS], int sf_idx) { - int p, n, slotsz; - slotsz = CP_NSYMB(q->cp)*q->nof_prb*RE_X_RB; +int chest_ce_sf(chest_t *q, cf_t *input, cf_t *ce[MAX_PORTS], uint8_t sf_idx) { + int p, n, slotsz, ret; + slotsz = q->nof_symbols*q->nof_re; for (p=0;pnof_ports;p++) { for (n=0;n<2;n++) { - chest_ce_slot_port(q, &input[n*slotsz], &ce[p][n*slotsz], 2*sf_idx+n, p); + ret = chest_ce_slot_port(q, &input[n*slotsz], &ce[p][n*slotsz], 2*sf_idx+n, p); + if (ret != LIBLTE_SUCCESS) { + return ret; + } } } + return LIBLTE_SUCCESS; } -int chest_init(chest_t *q, chest_interp_t interp, lte_cp_t cp, int nof_prb, int nof_ports) { - - if (nof_ports > MAX_PORTS) { - fprintf(stderr, "Error: Maximum ports %d\n", MAX_PORTS); - return -1; - } - bzero(q, sizeof(chest_t)); - q->nof_ports = nof_ports; - q->nof_symbols = CP_NSYMB(cp); - q->cp = cp; - q->nof_prb = nof_prb; +int chest_init(chest_t *q, chest_interp_t interp, uint16_t nof_re, uint8_t nof_symbols, uint8_t nof_ports) { + int ret = LIBLTE_ERROR_INVALID_INPUTS; + + if (q != NULL && + nof_ports < MAX_PORTS) + { + bzero(q, sizeof(chest_t)); - switch(interp) { - case LINEAR: - q->interp = interp_linear_offset; - } + q->nof_ports = nof_ports; + q->nof_symbols = nof_symbols; + q->nof_re = nof_re; + + switch(interp) { + case LINEAR: + q->interp = interp_linear_offset; + } - INFO("Initializing channel estimator size %dx%d, nof_ports=%d\n", - q->nof_symbols, nof_prb, nof_ports); + INFO("Initializing channel estimator size %dx%d, nof_ports=%d\n", + q->nof_symbols, q->nof_re, nof_ports); - return 0; + ret = LIBLTE_SUCCESS; + } + return ret; } -int chest_ref_LTEDL_slot_port(chest_t *q, int port, int nslot, int cell_id) { - if (port < 0 || port > q->nof_ports) { - return -1; - } - if (nslot < 0 || nslot > NSLOTS_X_FRAME) { - return -1; +int chest_init_LTEDL(chest_t *q, chest_interp_t interp, lte_cell_t cell) { + int ret; + ret = chest_init(q, interp, cell.nof_prb * RE_X_RB, CP_NSYMB(cell.cp), cell.nof_ports); + if (ret != LIBLTE_SUCCESS) { + return ret; + } else { + return chest_ref_LTEDL(q, cell); } +} - if (refsignal_init_LTEDL(&q->refsignal[port][nslot], port, nslot, cell_id, q->cp, q->nof_prb)) { - fprintf(stderr, "Error initiating CRS port=%d, slot=%d\n", port, nslot); - return -1; +int chest_ref_LTEDL_slot_port(chest_t *q, uint8_t nslot, uint8_t port_id, lte_cell_t cell) { + int ret = LIBLTE_ERROR_INVALID_INPUTS; + + if (q != NULL && + port_id < MAX_PORTS && + nslot < NSLOTS_X_FRAME) + { + ret = refsignal_init_LTEDL(&q->refsignal[port_id][nslot], port_id, nslot, cell); } - - return 0; + return ret; } -int chest_ref_LTEDL_slot(chest_t *q, int nslot, int cell_id) { - int p; +int chest_ref_LTEDL_slot(chest_t *q, uint8_t nslot, lte_cell_t cell) { + int p, ret; for (p=0;pnof_ports;p++) { - if (chest_ref_LTEDL_slot_port(q, p, nslot, cell_id)) { - return -1; + ret = chest_ref_LTEDL_slot_port(q, nslot, p, cell); + if (ret != LIBLTE_SUCCESS) { + return ret; } } - return 0; + return LIBLTE_SUCCESS; } -int chest_ref_LTEDL(chest_t *q, int cell_id) { - int n; +int chest_ref_LTEDL(chest_t *q, lte_cell_t cell) { + int n, ret; for (n=0;n NSLOTS_X_FRAME) { - return -1; +int chest_ref_symbols(chest_t *q, uint8_t port_id, uint8_t nslot, uint8_t l[2]) { + + if (q != NULL && + port_id < MAX_PORTS && + nslot < NSLOTS_X_FRAME) + { + memcpy(l, q->refsignal[port_id][nslot].symbols_ref, sizeof(uint8_t) * q->refsignal[port_id][nslot].nsymbols); + return q->refsignal[port_id][nslot].nsymbols; + } else { + return LIBLTE_ERROR_INVALID_INPUTS; } - memcpy(l, q->refsignal[port_id][nslot].symbols_ref, sizeof(int) * q->refsignal[port_id][nslot].nsymbols); - return q->refsignal[port_id][nslot].nsymbols; } @@ -275,6 +324,8 @@ int chest_ref_symbols(chest_t *q, int port_id, int nslot, int l[2]) { */ int chest_initialize(chest_hl* h) { + lte_cell_t cell; + if (!h->init.nof_symbols) { h->init.nof_symbols = CPNORM_NSYMB; // Normal CP } @@ -282,37 +333,23 @@ int chest_initialize(chest_hl* h) { h->init.nof_prb = 6; } - if (chest_init(&h->obj, LINEAR, (h->init.nof_symbols==CPNORM_NSYMB)?CPNORM:CPEXT, - h->init.nof_prb, h->init.nof_ports)) { + cell.id = h->init.cell_id; + cell.nof_ports = h->init.nof_ports; + cell.nof_prb = h->init.nof_prb; + cell.cp = h->init.nof_symbols == CPNORM_NSYMB ? CPNORM : CPEXT; + + if (chest_init_LTEDL(&h->obj, LINEAR, cell)) { fprintf(stderr, "Error initializing equalizer\n"); return -1; } - if (h->init.cell_id != -1) { - if (chest_ref_LTEDL(&h->obj, h->init.cell_id)) { - fprintf(stderr, "Error initializing reference signal\n"); - return -1; - } - } return 0; } -/** This function must be called in an slot basis (0.5ms) for LTE */ +/** This function must be called in an subframe basis (1ms) for LTE */ int chest_work(chest_hl* hl) { - int i; chest_t *q = &hl->obj; - - if (hl->init.cell_id != hl->ctrl_in.cell_id) { - if (chest_ref_LTEDL(q, hl->init.cell_id)) { - fprintf(stderr, "Error initializing reference signal\n"); - return -1; - } - } - - for (i=0;iinit.nof_ports;i++) { - chest_ce_slot_port(q, hl->input, hl->output[i], 1, 0); - hl->out_len[i] = hl->in_len; - } + chest_ce_sf(q, hl->input, hl->output, hl->ctrl_in.sf_idx); return 0; } diff --git a/lte/phy/lib/ch_estimation/src/refsignal.c b/lte/phy/lib/ch_estimation/src/refsignal.c index 3303899a9..f4eb0dfd8 100644 --- a/lte/phy/lib/ch_estimation/src/refsignal.c +++ b/lte/phy/lib/ch_estimation/src/refsignal.c @@ -40,7 +40,7 @@ #define idx(x, y) (l*nof_refs_x_symbol+i) -int refsignal_v(int port_id, int ns, int symbol_id) { +int refsignal_v(uint8_t port_id, uint8_t ns, uint8_t symbol_id) { int v=-1; switch(port_id) { case 0: @@ -67,108 +67,121 @@ int refsignal_v(int port_id, int ns, int symbol_id) { return v; } -int refsignal_k(int m, int v, int cell_id) { +int refsignal_k(int m, int v, uint16_t cell_id) { return 6*m+((v+(cell_id%6))%6); } -void refsignal_put(refsignal_t *q, cf_t *slot_symbols) { +int refsignal_put(refsignal_t *q, cf_t *slot_symbols) { int i; - int fidx, tidx; - for (i=0;inof_refs;i++) { - fidx = q->refs[i].freq_idx; // reference frequency index - tidx = q->refs[i].time_idx; // reference time index - slot_symbols[SAMPLE_IDX(q->nof_prb, tidx, fidx)] = q->refs[i].simbol; + uint16_t fidx, tidx; + if (q != NULL && + slot_symbols != NULL) + { + for (i=0;inof_refs;i++) { + fidx = q->refs[i].freq_idx; // reference frequency index + tidx = q->refs[i].time_idx; // reference time index + slot_symbols[SAMPLE_IDX(q->nof_prb, tidx, fidx)] = q->refs[i].simbol; + } + return LIBLTE_SUCCESS; + } else { + return LIBLTE_ERROR_INVALID_INPUTS; } } /** Initializes refsignal_t object according to 3GPP 36.211 6.10.1 * */ -int refsignal_init_LTEDL(refsignal_t *q, int port_id, int nslot, - int cell_id, lte_cp_t cp, int nof_prb) { +int refsignal_init_LTEDL(refsignal_t *q, uint8_t port_id, uint8_t nslot, + lte_cell_t cell) { - unsigned int c_init; - int ns, l, lp[2]; + uint32_t c_init; + uint8_t ns, l, lp[2]; int N_cp; int i; - int ret = -1; + int ret = LIBLTE_ERROR_INVALID_INPUTS; sequence_t seq; int v; int mp; - int nof_refs_x_symbol, nof_ref_symbols; - - bzero(q, sizeof(refsignal_t)); - bzero(&seq, sizeof(sequence_t)); - - if (CP_ISNORM(cp)) { - N_cp = 1; - } else { - N_cp = 0; - } - - if (port_id < 0 || port_id > (MAX_PORTS - 1)) { - fprintf(stderr, "Invalid port id %d\n", port_id); - return -1; - } + uint8_t nof_refs_x_symbol, nof_ref_symbols; + + if (q != NULL && + port_id < MAX_PORTS && + nslot < NSLOTS_X_FRAME && + lte_cell_isvalid(&cell)) + { + + bzero(q, sizeof(refsignal_t)); + bzero(&seq, sizeof(sequence_t)); + + if (CP_ISNORM(cell.cp)) { + N_cp = 1; + } else { + N_cp = 0; + } - if (port_id < 2) { - nof_ref_symbols = 2; - lp[0] = 0; - lp[1] = CP_NSYMB(cp) - 3; - } else { - nof_ref_symbols = 1; - lp[0] = 1; - } - nof_refs_x_symbol = 2 * nof_prb; - - q->nof_refs = nof_refs_x_symbol * nof_ref_symbols; - q->nsymbols = nof_ref_symbols; - q->symbols_ref = malloc(sizeof(int) * nof_ref_symbols); - q->voffset = cell_id%6; - q->nof_prb = nof_prb; - if (!q->symbols_ref) { - return -1; - } + if (port_id < 2) { + nof_ref_symbols = 2; + lp[0] = 0; + lp[1] = CP_NSYMB(cell.cp) - 3; + } else { + nof_ref_symbols = 1; + lp[0] = 1; + } + nof_refs_x_symbol = 2 * cell.nof_prb; - memcpy(q->symbols_ref, lp, sizeof(int) * nof_ref_symbols); + q->nof_refs = nof_refs_x_symbol * nof_ref_symbols; + q->nsymbols = nof_ref_symbols; + q->voffset = cell.id%6; + q->nof_prb = cell.nof_prb; - q->refs = vec_malloc(q->nof_refs * sizeof(ref_t)); - if (!q->refs) { - goto free_and_exit; - } - q->ch_est = vec_malloc(q->nof_refs * sizeof(cf_t)); - if (!q->ch_est) { - goto free_and_exit; - } + q->symbols_ref = malloc(sizeof(uint8_t) * nof_ref_symbols); + if (!q->symbols_ref) { + perror("malloc"); + goto free_and_exit; + } - ns = nslot; - for (l = 0; l < nof_ref_symbols; l++) { + memcpy(q->symbols_ref, lp, sizeof(uint8_t) * nof_ref_symbols); - c_init = 1024 * (7 * (ns + 1) + lp[l] + 1) * (2 * cell_id + 1) - + 2 * cell_id + N_cp; - if (sequence_LTEPRS(&seq, 2 * 2 * MAX_PRB, c_init)) { + q->refs = vec_malloc(q->nof_refs * sizeof(ref_t)); + if (!q->refs) { goto free_and_exit; } + q->ch_est = vec_malloc(q->nof_refs * sizeof(cf_t)); + if (!q->ch_est) { + goto free_and_exit; + } + + ns = nslot; + for (l = 0; l < nof_ref_symbols; l++) { - v = refsignal_v(port_id, ns, lp[l]); + c_init = 1024 * (7 * (ns + 1) + lp[l] + 1) * (2 * cell.id + 1) + + 2 * cell.id + N_cp; + ret = sequence_LTEPRS(&seq, 2 * 2 * MAX_PRB, c_init); + if (ret != LIBLTE_SUCCESS) { + goto free_and_exit; + } - for (i = 0; i < nof_refs_x_symbol; i++) { - mp = i + MAX_PRB - nof_prb; + v = refsignal_v(port_id, ns, lp[l]); - /* generate signal */ - __real__ q->refs[idx(l,i)].simbol = (1 - 2 * (float) seq.c[2 * mp]) / sqrt(2); - __imag__ q->refs[idx(l,i)].simbol = (1 - 2 * (float) seq.c[2 * mp + 1]) / sqrt(2); + for (i = 0; i < nof_refs_x_symbol; i++) { + mp = i + MAX_PRB - cell.nof_prb; - /* mapping to resource elements */ - q->refs[idx(l,i)].freq_idx = refsignal_k(i, v, cell_id); - q->refs[idx(l,i)].time_idx = lp[l]; + /* generate signal */ + __real__ q->refs[idx(l,i)].simbol = (1 - 2 * (float) seq.c[2 * mp]) / sqrt(2); + __imag__ q->refs[idx(l,i)].simbol = (1 - 2 * (float) seq.c[2 * mp + 1]) / sqrt(2); + + /* mapping to resource elements */ + q->refs[idx(l,i)].freq_idx = refsignal_k(i, v, cell.id); + q->refs[idx(l,i)].time_idx = lp[l]; + } } + ret = LIBLTE_SUCCESS; } - - ret = 0; free_and_exit: - sequence_free(&seq); - if (ret == -1) { + if (ret != LIBLTE_ERROR_INVALID_INPUTS) { + sequence_free(&seq); + } + if (ret == LIBLTE_ERROR) { refsignal_free(q); } return ret; diff --git a/lte/phy/lib/ch_estimation/test/chest_test.c b/lte/phy/lib/ch_estimation/test/chest_test.c index 5f5d6647e..3408ce553 100644 --- a/lte/phy/lib/ch_estimation/test/chest_test.c +++ b/lte/phy/lib/ch_estimation/test/chest_test.c @@ -33,19 +33,22 @@ #include "liblte/phy/phy.h" -int cell_id = -1; -int nof_prb = 6; -lte_cp_t cp = CPNORM; +lte_cell_t cell = { + 6, // nof_prb + MAX_PORTS, // nof_ports + 1000, // cell_id + CPNORM // cyclic prefix +}; char *output_matlab = NULL; void usage(char *prog) { printf("Usage: %s [recov]\n", prog); - printf("\t-r nof_prb [Default %d]\n", nof_prb); + printf("\t-r nof_prb [Default %d]\n", cell.nof_prb); printf("\t-e extended cyclic prefix [Default normal]\n"); - printf("\t-c cell_id (-1 tests all). [Default %d]\n", cell_id); + printf("\t-c cell_id (1000 tests all). [Default %d]\n", cell.id); printf("\t-o output matlab file [Default %s]\n",output_matlab?output_matlab:"None"); printf("\t-v increase verbosity\n"); @@ -56,13 +59,13 @@ void parse_args(int argc, char **argv) { while ((opt = getopt(argc, argv, "recov")) != -1) { switch(opt) { case 'r': - nof_prb = atoi(argv[optind]); + cell.nof_prb = atoi(argv[optind]); break; case 'e': - cp = CPEXT; + cell.cp = CPEXT; break; case 'c': - cell_id = atoi(argv[optind]); + cell.id = atoi(argv[optind]); break; case 'o': output_matlab = argv[optind]; @@ -120,7 +123,8 @@ int main(int argc, char **argv) { int max_cid; FILE *fmatlab = NULL; float mse_mag, mse_phase; - + lte_cell_t cell; + parse_args(argc,argv); if (output_matlab) { @@ -131,7 +135,7 @@ int main(int argc, char **argv) { } } - num_re = nof_prb * RE_X_RB * CP_NSYMB(cp); + num_re = cell.nof_prb * RE_X_RB * CP_NSYMB(cell.cp); input = malloc(num_re * sizeof(cf_t)); if (!input) { @@ -149,31 +153,23 @@ int main(int argc, char **argv) { goto do_exit; } - if (cell_id == -1) { + if (cell.id == 1000) { cid = 0; max_cid = 504; } else { - cid = cell_id; - max_cid = cell_id; + cid = cell.id; + max_cid = cell.id; } + while(cid <= max_cid) { - if (chest_init(&eq, LINEAR, cp, nof_prb, MAX_PORTS)) { + cell.id = cid; + if (chest_init_LTEDL(&eq, LINEAR, cell)) { fprintf(stderr, "Error initializing equalizer\n"); goto do_exit; } - if (chest_ref_LTEDL(&eq, cid)) { - fprintf(stderr, "Error initializing reference signal\n"); - goto do_exit; - } - for (n_slot=0;n_slotid < 504 && + cell->nof_ports > 0 && + cell->nof_ports < 5 && + cell->nof_prb > 5 && + cell->nof_prb < 111 + ) { + return true; + } else { + return false; + } +} + /* * Returns Turbo coder interleaver size for Table 5.1.3-3 (36.212) index */ diff --git a/lte/phy/lib/common/src/sequence.c b/lte/phy/lib/common/src/sequence.c index a659b0562..f4325ccd7 100644 --- a/lte/phy/lib/common/src/sequence.c +++ b/lte/phy/lib/common/src/sequence.c @@ -41,17 +41,16 @@ * It follows the 3GPP Release 8 (LTE) 36.211 * Section 7.2 */ -void generate_prs_c(sequence_t *q, unsigned int seed) { +void generate_prs_c(sequence_t *q, uint32_t seed) { int n; - unsigned int *x1; - unsigned int *x2; + uint32_t *x1, *x2; - x1 = calloc(Nc + q->len + 31, sizeof(unsigned int)); + x1 = calloc(Nc + q->len + 31, sizeof(uint32_t)); if (!x1) { perror("calloc"); return; } - x2 = calloc(Nc + q->len + 31, sizeof(unsigned int)); + x2 = calloc(Nc + q->len + 31, sizeof(uint32_t)); if (!x2) { free(x1); perror("calloc"); @@ -76,26 +75,26 @@ void generate_prs_c(sequence_t *q, unsigned int seed) { free(x2); } -int sequence_LTEPRS(sequence_t *q, int len, int seed) { +int sequence_LTEPRS(sequence_t *q, uint32_t len, uint32_t seed) { if (sequence_init(q, len)) { - return -1; + return LIBLTE_ERROR; } q->len = len; generate_prs_c(q, seed); - return 0; + return LIBLTE_SUCCESS; } -int sequence_init(sequence_t *q, int len) { +int sequence_init(sequence_t *q, uint32_t len) { if (q->c && (q->len != len)) { free(q->c); } if (!q->c) { q->c = malloc(len * sizeof(char)); if (!q->c) { - return -1; + return LIBLTE_ERROR; } } - return 0; + return LIBLTE_SUCCESS; } void sequence_free(sequence_t *q) { diff --git a/lte/phy/lib/phch/src/dci.c b/lte/phy/lib/phch/src/dci.c index 0b81a7076..d98426c64 100644 --- a/lte/phy/lib/phch/src/dci.c +++ b/lte/phy/lib/phch/src/dci.c @@ -40,15 +40,15 @@ #include "liblte/phy/utils/vector.h" #include "liblte/phy/utils/debug.h" -int dci_init(dci_t *q, int max_dcis) { +int dci_init(dci_t *q, uint8_t max_dcis) { q->msg = calloc(sizeof(dci_msg_t), max_dcis); if (!q->msg) { perror("malloc"); - return -1; + return LIBLTE_ERROR; } q->nof_dcis = 0; q->max_dcis = max_dcis; - return 0; + return LIBLTE_SUCCESS; } void dci_free(dci_t *q) { @@ -62,30 +62,30 @@ void dci_candidate_fprint(FILE *f, dci_candidate_t *q) { q->nof_bits); } -int dci_msg_candidate_set(dci_msg_t *msg, int L, int nCCE, unsigned short rnti) { +int dci_msg_candidate_set(dci_msg_t *msg, uint8_t L, uint8_t nCCE, uint16_t rnti) { if (L >= 0 && L <= 3) { - msg->location.L = (unsigned char) L; + msg->location.L = L; } else { fprintf(stderr, "Invalid L %d\n", L); - return -1; + return LIBLTE_ERROR; } if (nCCE >= 0 && nCCE <= 87) { - msg->location.ncce = (unsigned char) nCCE; + msg->location.ncce = nCCE; } else { fprintf(stderr, "Invalid nCCE %d\n", nCCE); - return -1; + return LIBLTE_ERROR; } msg->location.rnti = rnti; - return 0; + return LIBLTE_SUCCESS; } -int riv_nbits(int nof_prb) { - return (int) ceilf(log2f((float) nof_prb * ((float) nof_prb + 1) / 2)); +uint8_t riv_nbits(uint8_t nof_prb) { + return (uint8_t) 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 }; -bool is_ambiguous_size(int size) { +bool is_ambiguous_size(uint8_t size) { int i; for (i = 0; i < 10; i++) { if (size == ambiguous_sizes[i]) { @@ -98,12 +98,12 @@ bool is_ambiguous_size(int size) { /********************************** * PAYLOAD sizeof functions * ********************************/ -int dci_format0_sizeof_(int nof_prb) { +uint8_t dci_format0_sizeof_(uint8_t nof_prb) { return 1 + 1 + riv_nbits(nof_prb) + 5 + 1 + 2 + 3 + 1; } -int dci_format1A_sizeof(int nof_prb) { - int n; +uint8_t dci_format1A_sizeof(uint8_t nof_prb) { + uint8_t n; n = 1 + 1 + riv_nbits(nof_prb) + 5 + 3 + 1 + 2 + 2; while (n < dci_format0_sizeof_(nof_prb)) { n++; @@ -114,7 +114,7 @@ int dci_format1A_sizeof(int nof_prb) { return n; } -int dci_format0_sizeof(int nof_prb) { +uint8_t dci_format0_sizeof(uint8_t nof_prb) { int n = dci_format0_sizeof_(nof_prb); while (n < dci_format1A_sizeof(nof_prb)) { n++; @@ -122,9 +122,9 @@ int dci_format0_sizeof(int nof_prb) { return n; } -int dci_format1_sizeof(int nof_prb) { +uint8_t dci_format1_sizeof(uint8_t nof_prb) { - int n = (int) ceilf((float) nof_prb / ra_type0_P(nof_prb)) + 5 + 3 + 1 + 2 + uint8_t n = (uint8_t) ceilf((float) nof_prb / ra_type0_P(nof_prb)) + 5 + 3 + 1 + 2 + 2; if (nof_prb > 10) { n++; @@ -136,17 +136,17 @@ int dci_format1_sizeof(int nof_prb) { return n; } -int dci_format1C_sizeof(int nof_prb) { +uint8_t dci_format1C_sizeof(uint8_t 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; + uint8_t n = +riv_nbits((uint8_t) n_vrb_dl_gap1 / n_step) + 5; if (nof_prb >= 50) { n++; } return n; } -int dci_format_sizeof(dci_format_t format, int nof_prb) { +uint8_t dci_format_sizeof(dci_format_t format, uint8_t nof_prb) { switch (format) { case Format0: return dci_format0_sizeof(nof_prb); @@ -157,7 +157,7 @@ int dci_format_sizeof(dci_format_t format, int nof_prb) { case Format1C: return dci_format1C_sizeof(nof_prb); default: - return -1; + return LIBLTE_ERROR; } } @@ -170,7 +170,7 @@ int dci_format_sizeof(dci_format_t format, int nof_prb) { * * TODO: TPC and cyclic shift for DM RS not implemented */ -int dci_format0_pack(ra_pusch_t *data, dci_msg_t *msg, int nof_prb) { +int dci_format0_pack(ra_pusch_t *data, dci_msg_t *msg, uint8_t nof_prb) { /* pack bits */ char *y = msg->data; @@ -246,14 +246,14 @@ int dci_format0_pack(ra_pusch_t *data, dci_msg_t *msg, int nof_prb) { *y++ = 0; } msg->location.nof_bits = (y - msg->data); - return 0; + return LIBLTE_SUCCESS; } /* Unpacks DCI format 0 data and store result in msg according * to 36.212 5.3.3.1.1 * * TODO: TPC and cyclic shift for DM RS not implemented */ -int dci_format0_unpack(dci_msg_t *msg, ra_pusch_t *data, int nof_prb) { +int dci_format0_unpack(dci_msg_t *msg, ra_pusch_t *data, uint8_t nof_prb) { /* pack bits */ char *y = msg->data; @@ -262,12 +262,12 @@ int dci_format0_unpack(dci_msg_t *msg, ra_pusch_t *data, int nof_prb) { /* Make sure it's a Format0 message */ if (msg->location.nof_bits != dci_format_sizeof(Format0, nof_prb)) { fprintf(stderr, "Invalid message length for format 0\n"); - return -1; + return LIBLTE_ERROR; } if (*y++ != 0) { fprintf(stderr, "Invalid format differentiation field value. This is Format1A\n"); - return -1; + return LIBLTE_ERROR; } if (*y++ == 0) { data->freq_hop_fl = hop_disabled; @@ -317,7 +317,7 @@ int dci_format0_unpack(dci_msg_t *msg, ra_pusch_t *data, int nof_prb) { data->rv_idx = mcs - 28; } - return 0; + return LIBLTE_SUCCESS; } /* Packs DCI format 1 data to a sequence of bits and store them in msg according @@ -326,7 +326,7 @@ int dci_format0_unpack(dci_msg_t *msg, ra_pusch_t *data, int nof_prb) { * TODO: TPC commands */ -int dci_format1_pack(ra_pdsch_t *data, dci_msg_t *msg, int nof_prb) { +int dci_format1_pack(ra_pdsch_t *data, dci_msg_t *msg, uint8_t nof_prb) { /* pack bits */ char *y = msg->data; @@ -351,7 +351,7 @@ int dci_format1_pack(ra_pdsch_t *data, dci_msg_t *msg, int nof_prb) { default: fprintf(stderr, "Format 1 accepts type0 or type1 resource allocation only\n"); - return -1; + return LIBLTE_ERROR; } /* pack MCS according to 7.1.7 of 36.213 */ @@ -387,10 +387,10 @@ int dci_format1_pack(ra_pdsch_t *data, dci_msg_t *msg, int nof_prb) { } msg->location.nof_bits = (y - msg->data); - return 0; + return LIBLTE_SUCCESS; } -int dci_format1_unpack(dci_msg_t *msg, ra_pdsch_t *data, int nof_prb) { +int dci_format1_unpack(dci_msg_t *msg, ra_pdsch_t *data, uint8_t nof_prb) { /* pack bits */ char *y = msg->data; @@ -398,7 +398,7 @@ int dci_format1_unpack(dci_msg_t *msg, ra_pdsch_t *data, int nof_prb) { /* Make sure it's a Format1 message */ if (msg->location.nof_bits != dci_format_sizeof(Format1, nof_prb)) { fprintf(stderr, "Invalid message length for format 1\n"); - return -1; + return LIBLTE_ERROR; } if (nof_prb > 10) { @@ -408,7 +408,7 @@ 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); + uint8_t P = ra_type0_P(nof_prb); int alloc_size = (int) ceilf((float) nof_prb / P); switch (data->alloc_type) { case alloc_type0: @@ -423,7 +423,7 @@ int dci_format1_unpack(dci_msg_t *msg, ra_pdsch_t *data, int nof_prb) { default: fprintf(stderr, "Format 1 accepts type0 or type1 resource allocation only\n"); - return -1; + return LIBLTE_ERROR; } /* unpack MCS according to 7.1.7 of 36.213 */ @@ -442,14 +442,14 @@ int dci_format1_unpack(dci_msg_t *msg, ra_pdsch_t *data, int nof_prb) { // TPC not implemented - return 0; + return LIBLTE_SUCCESS; } /* 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, +int dci_format1As_pack(ra_pdsch_t *data, dci_msg_t *msg, uint8_t nof_prb, bool crc_is_crnti) { /* pack bits */ @@ -459,7 +459,7 @@ int dci_format1As_pack(ra_pdsch_t *data, dci_msg_t *msg, int nof_prb, if (data->alloc_type != alloc_type2) { fprintf(stderr, "Format 1A accepts type2 resource allocation only\n"); - return -1; + return LIBLTE_ERROR; } *y++ = data->type2_alloc.mode; // localized or distributed VRB assignment @@ -468,7 +468,7 @@ int dci_format1As_pack(ra_pdsch_t *data, dci_msg_t *msg, int nof_prb, 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); - return -1; + return LIBLTE_ERROR; } } else { int n_vrb_dl; @@ -481,7 +481,7 @@ int dci_format1As_pack(ra_pdsch_t *data, dci_msg_t *msg, int nof_prb, 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; + return LIBLTE_ERROR; } } /* pack RIV according to 7.1.6.3 of 36.213 */ @@ -545,13 +545,13 @@ int dci_format1As_pack(ra_pdsch_t *data, dci_msg_t *msg, int nof_prb, } msg->location.nof_bits = (y - msg->data); - return 0; + return LIBLTE_SUCCESS; } /* 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, +int dci_format1As_unpack(dci_msg_t *msg, ra_pdsch_t *data, uint8_t nof_prb, bool crc_is_crnti) { /* pack bits */ @@ -560,13 +560,13 @@ int dci_format1As_unpack(dci_msg_t *msg, ra_pdsch_t *data, int nof_prb, /* Make sure it's a Format0 message */ if (msg->location.nof_bits != dci_format_sizeof(Format1A, nof_prb)) { fprintf(stderr, "Invalid message length for format 1A\n"); - return -1; + return LIBLTE_ERROR; } if (*y++ != 1) { fprintf(stderr, "Invalid format differentiation field value. This is Format0\n"); - return -1; + return LIBLTE_ERROR; } data->alloc_type = alloc_type2; @@ -624,13 +624,13 @@ int dci_format1As_unpack(dci_msg_t *msg, ra_pdsch_t *data, int nof_prb, data->mcs.tbs = ra_tbs_from_idx(data->mcs.tbs_idx, n_prb); data->mcs.mod = QPSK; - return 0; + return LIBLTE_SUCCESS; } /* Format 1C for compact scheduling of PDSCH words * */ -int dci_format1Cs_pack(ra_pdsch_t *data, dci_msg_t *msg, int nof_prb) { +int dci_format1Cs_pack(ra_pdsch_t *data, dci_msg_t *msg, uint8_t nof_prb) { /* pack bits */ char *y = msg->data; @@ -638,7 +638,7 @@ int dci_format1Cs_pack(ra_pdsch_t *data, dci_msg_t *msg, int nof_prb) { if (data->alloc_type != alloc_type2 || data->type2_alloc.mode != t2_dist) { fprintf(stderr, "Format 1C accepts distributed type2 resource allocation only\n"); - return -1; + return LIBLTE_ERROR; } if (nof_prb >= 50) { @@ -651,15 +651,15 @@ int dci_format1Cs_pack(ra_pdsch_t *data, dci_msg_t *msg, int nof_prb) { 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; + return LIBLTE_ERROR; } if (data->type2_alloc.L_crb % n_step) { fprintf(stderr, "L_crb must be multiple of n_step\n"); - return -1; + return LIBLTE_ERROR; } if (data->type2_alloc.RB_start % n_step) { fprintf(stderr, "RB_start must be multiple of n_step\n"); - return -1; + return LIBLTE_ERROR; } int L_p = data->type2_alloc.L_crb / n_step; int RB_p = data->type2_alloc.RB_start / n_step; @@ -687,10 +687,10 @@ int dci_format1Cs_pack(ra_pdsch_t *data, dci_msg_t *msg, int nof_prb) { msg->location.nof_bits = (y - msg->data); - return 0; + return LIBLTE_SUCCESS; } -int dci_format1Cs_unpack(dci_msg_t *msg, ra_pdsch_t *data, int nof_prb) { +int dci_format1Cs_unpack(dci_msg_t *msg, ra_pdsch_t *data, uint8_t nof_prb) { uint16_t L_p, RB_p; /* pack bits */ @@ -698,7 +698,7 @@ int dci_format1Cs_unpack(dci_msg_t *msg, ra_pdsch_t *data, int nof_prb) { if (msg->location.nof_bits != dci_format_sizeof(Format1C, nof_prb)) { fprintf(stderr, "Invalid message length for format 1C\n"); - return -1; + return LIBLTE_ERROR; } data->alloc_type = alloc_type2; data->type2_alloc.mode = t2_dist; @@ -723,11 +723,11 @@ int dci_format1Cs_unpack(dci_msg_t *msg, ra_pdsch_t *data, int nof_prb) { msg->location.nof_bits = (y - msg->data); - return 0; + return LIBLTE_SUCCESS; } int dci_msg_pack_pdsch(ra_pdsch_t *data, dci_msg_t *msg, dci_format_t format, - int nof_prb, bool crc_is_crnti) { + uint8_t nof_prb, bool crc_is_crnti) { switch (format) { case Format1: return dci_format1_pack(data, msg, nof_prb); @@ -738,11 +738,11 @@ int dci_msg_pack_pdsch(ra_pdsch_t *data, dci_msg_t *msg, dci_format_t format, default: fprintf(stderr, "Invalid DCI format %s for PDSCH resource allocation\n", dci_format_string(format)); - return -1; + return LIBLTE_ERROR; } } -int dci_msg_unpack_pdsch(dci_msg_t *msg, ra_pdsch_t *data, int nof_prb, +int dci_msg_unpack_pdsch(dci_msg_t *msg, ra_pdsch_t *data, uint8_t 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); @@ -751,15 +751,15 @@ int dci_msg_unpack_pdsch(dci_msg_t *msg, ra_pdsch_t *data, int nof_prb, } else if (msg->location.nof_bits == dci_format_sizeof(Format1C, nof_prb)) { return dci_format1Cs_unpack(msg, data, nof_prb); } else { - return -1; + return LIBLTE_ERROR; } } -int dci_msg_pack_pusch(ra_pusch_t *data, dci_msg_t *msg, int nof_prb) { +int dci_msg_pack_pusch(ra_pusch_t *data, dci_msg_t *msg, uint8_t nof_prb) { return dci_format0_pack(data, msg, nof_prb); } -int dci_msg_unpack_pusch(dci_msg_t *msg, ra_pusch_t *data, int nof_prb) { +int dci_msg_unpack_pusch(dci_msg_t *msg, ra_pusch_t *data, uint8_t nof_prb) { return dci_format0_unpack(msg, data, nof_prb); } @@ -799,17 +799,17 @@ void dci_msg_type_fprint(FILE *f, dci_msg_type_t type) { } } -int dci_msg_get_type(dci_msg_t *msg, dci_msg_type_t *type, int nof_prb, +int dci_msg_get_type(dci_msg_t *msg, dci_msg_type_t *type, uint8_t nof_prb, unsigned short crnti) { if (msg->location.nof_bits == dci_format_sizeof(Format0, nof_prb) && !msg->data[0]) { type->type = PUSCH_SCHED; type->format = Format0; - return 0; + return LIBLTE_SUCCESS; } else if (msg->location.nof_bits == dci_format_sizeof(Format1, nof_prb)) { type->type = PDSCH_SCHED; // only these 2 types supported type->format = Format1; - return 0; + return LIBLTE_SUCCESS; } else if (msg->location.nof_bits == dci_format_sizeof(Format1A, nof_prb)) { if (msg->location.rnti == crnti) { type->type = RA_PROC_PDCCH; @@ -818,7 +818,7 @@ int dci_msg_get_type(dci_msg_t *msg, dci_msg_type_t *type, int nof_prb, type->type = PDSCH_SCHED; // only these 2 types supported type->format = Format1A; } - return 0; + return LIBLTE_SUCCESS; } else if (msg->location.nof_bits == dci_format_sizeof(Format1C, nof_prb)) { if (msg->location.rnti == MRNTI) { type->type = MCCH_CHANGE; @@ -827,8 +827,8 @@ int dci_msg_get_type(dci_msg_t *msg, dci_msg_type_t *type, int nof_prb, type->type = PDSCH_SCHED; // only these 2 types supported type->format = Format1C; } - return 0; + return LIBLTE_SUCCESS; } - return -1; + return LIBLTE_ERROR; } diff --git a/lte/phy/lib/phch/src/pcfich.c b/lte/phy/lib/phch/src/pcfich.c index af7da9feb..f342d6406 100644 --- a/lte/phy/lib/phch/src/pcfich.c +++ b/lte/phy/lib/phch/src/pcfich.c @@ -54,37 +54,42 @@ 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_ports, lte_cp_t cp) { - int ret = -1; - if (cell_id < 0) { - return -1; - } - bzero(q, sizeof(pcfich_t)); - q->cell_id = cell_id; - q->cp = cp; - q->regs = regs; - q->nof_prb = nof_prb; - q->nof_ports = nof_ports; - - if (modem_table_std(&q->mod, LTE_QPSK, false)) { - goto clean; - } +/** Initializes the pcfich channel receiver. + * On error, returns -1 and frees the structrure + */ +int pcfich_init(pcfich_t *q, regs_t *regs, lte_cell_t cell) { + int ret = LIBLTE_ERROR_INVALID_INPUTS; + + if (q != NULL && + regs != NULL && + lte_cell_isvalid(&cell)) + { + ret = LIBLTE_ERROR; + + bzero(q, sizeof(pcfich_t)); + q->cell = cell; + q->regs = regs; + + if (modem_table_std(&q->mod, LTE_QPSK, false)) { + goto clean; + } - demod_hard_init(&q->demod); - demod_hard_table_set(&q->demod, LTE_QPSK); + demod_hard_init(&q->demod); + demod_hard_table_set(&q->demod, LTE_QPSK); - for (int nsf = 0; nsf < NSUBFRAMES_X_FRAME; nsf++) { - if (sequence_pcfich(&q->seq_pcfich[nsf], 2 * nsf, q->cell_id)) { - goto clean; + for (int nsf = 0; nsf < NSUBFRAMES_X_FRAME; nsf++) { + if (sequence_pcfich(&q->seq_pcfich[nsf], 2 * nsf, q->cell.id)) { + goto clean; + } } - } - q->nof_symbols = PCFICH_RE; + q->nof_symbols = PCFICH_RE; - ret = 0; - clean: if (ret == -1) { + ret = LIBLTE_SUCCESS; + } + + clean: + if (ret == LIBLTE_ERROR) { pcfich_free(q); } return ret; @@ -100,7 +105,7 @@ void pcfich_free(pcfich_t *q) { /** Finds the CFI with minimum distance with the vector of received 32 bits. * Saves the CFI value in the cfi pointer and returns the distance. */ -int pcfich_cfi_decode(char bits[PCFICH_CFI_LEN], int *cfi) { +int pcfich_cfi_decode(char bits[PCFICH_CFI_LEN], uint8_t *cfi) { int i, j; int distance, index = -1; int min = 32; @@ -120,7 +125,6 @@ int pcfich_cfi_decode(char bits[PCFICH_CFI_LEN], int *cfi) { *cfi = index + 1; } return min; - } /** Encodes the CFI producing a vector of 32 bits. @@ -128,11 +132,11 @@ int pcfich_cfi_decode(char bits[PCFICH_CFI_LEN], int *cfi) { */ int pcfich_cfi_encode(int cfi, char bits[PCFICH_CFI_LEN]) { if (cfi < 1 || cfi > 3) { - fprintf(stderr, "Invalid CFI %d\n", cfi); - return -1; + return LIBLTE_ERROR_INVALID_INPUTS; + } else{ + memcpy(bits, cfi_table[cfi - 1], PCFICH_CFI_LEN * sizeof(char)); + return LIBLTE_SUCCESS; } - memcpy(bits, cfi_table[cfi - 1], PCFICH_CFI_LEN * sizeof(char)); - return 0; } /* Decodes the PCFICH channel and saves the CFI in the cfi pointer. @@ -140,7 +144,7 @@ int pcfich_cfi_encode(int cfi, char bits[PCFICH_CFI_LEN]) { * Returns 1 if successfully decoded the CFI, 0 if not and -1 on error */ int pcfich_decode(pcfich_t *q, cf_t *slot_symbols, cf_t *ce[MAX_PORTS], - int nsubframe, int *cfi, int *distance) { + uint8_t nsubframe, uint8_t *cfi, uint8_t *distance) { int dist; /* Set pointers for layermapping & precoding */ @@ -148,112 +152,120 @@ int pcfich_decode(pcfich_t *q, cf_t *slot_symbols, cf_t *ce[MAX_PORTS], cf_t *x[MAX_LAYERS]; cf_t *ce_precoding[MAX_PORTS]; - if (nsubframe < 0 || nsubframe > NSUBFRAMES_X_FRAME) { - fprintf(stderr, "Invalid nslot %d\n", nsubframe); - return -1; - } + if (q != NULL && + slot_symbols != NULL && + nsubframe < NSUBFRAMES_X_FRAME) + { - /* number of layers equals number of ports */ - for (i = 0; i < MAX_PORTS; i++) { - x[i] = q->pcfich_x[i]; - } - for (i = 0; i < MAX_PORTS; i++) { - ce_precoding[i] = q->ce[i]; - } - - /* extract symbols */ - 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; - } + /* number of layers equals number of ports */ + for (i = 0; i < MAX_PORTS; i++) { + x[i] = q->pcfich_x[i]; + } + for (i = 0; i < MAX_PORTS; i++) { + ce_precoding[i] = q->ce[i]; + } - /* extract channel estimates */ - for (i = 0; i < q->nof_ports; i++) { - if (q->nof_symbols != regs_pcfich_get(q->regs, ce[i], q->ce[i])) { + /* extract symbols */ + 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; + return LIBLTE_ERROR; } - } - /* in control channels, only diversity is supported */ - if (q->nof_ports == 1) { - /* no need for layer demapping */ - predecoding_single_zf(q->pcfich_symbols[0], q->ce[0], q->pcfich_d, - q->nof_symbols); - } else { - predecoding_diversity_zf(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); - } + /* extract channel estimates */ + for (i = 0; i < q->cell.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 LIBLTE_ERROR; + } + } - /* demodulate symbols */ - demod_hard_demodulate(&q->demod, q->pcfich_d, q->data, q->nof_symbols); + /* in control channels, only diversity is supported */ + if (q->cell.nof_ports == 1) { + /* no need for layer demapping */ + predecoding_single_zf(q->pcfich_symbols[0], q->ce[0], q->pcfich_d, + q->nof_symbols); + } else { + predecoding_diversity_zf(q->pcfich_symbols[0], ce_precoding, x, + q->cell.nof_ports, q->nof_symbols); + layerdemap_diversity(x, q->pcfich_d, q->cell.nof_ports, + q->nof_symbols / q->cell.nof_ports); + } - /* Scramble with the sequence for slot nslot */ - scrambling_b(&q->seq_pcfich[nsubframe], q->data); + /* demodulate symbols */ + demod_hard_demodulate(&q->demod, q->pcfich_d, q->data, q->nof_symbols); - /* decode CFI */ - dist = pcfich_cfi_decode(q->data, cfi); - if (distance) { - *distance = dist; - } - if (dist < PCFICH_MAX_DISTANCE) { - return 1; + /* Scramble with the sequence for slot nslot */ + scrambling_b(&q->seq_pcfich[nsubframe], q->data); + + /* decode CFI */ + dist = pcfich_cfi_decode(q->data, cfi); + if (distance) { + *distance = dist; + } + if (dist < PCFICH_MAX_DISTANCE) { + return 1; + } else { + return 0; + } } else { - return 0; + return LIBLTE_ERROR_INVALID_INPUTS; } + } /** Encodes CFI and maps symbols to the slot */ -int pcfich_encode(pcfich_t *q, int cfi, cf_t *slot_symbols[MAX_PORTS], - int nsubframe) { +int pcfich_encode(pcfich_t *q, uint8_t cfi, cf_t *slot_symbols[MAX_PORTS], + uint8_t subframe) { int i; - if (nsubframe < 0 || nsubframe > NSUBFRAMES_X_FRAME) { - fprintf(stderr, "Invalid nslot %d\n", nsubframe); - return -1; - } + if (q != NULL && + cfi < 3 && + slot_symbols != NULL && + subframe < NSUBFRAMES_X_FRAME) + { - /* Set pointers for layermapping & precoding */ - cf_t *x[MAX_LAYERS]; - cf_t *symbols_precoding[MAX_PORTS]; + /* Set pointers for layermapping & precoding */ + cf_t *x[MAX_LAYERS]; + cf_t *symbols_precoding[MAX_PORTS]; - /* number of layers equals number of ports */ - for (i = 0; i < q->nof_ports; i++) { - x[i] = q->pcfich_x[i]; - } - for (i = 0; i < MAX_PORTS; i++) { - symbols_precoding[i] = q->pcfich_symbols[i]; - } + /* number of layers equals number of ports */ + for (i = 0; i < q->cell.nof_ports; i++) { + x[i] = q->pcfich_x[i]; + } + for (i = 0; i < MAX_PORTS; i++) { + symbols_precoding[i] = q->pcfich_symbols[i]; + } - /* pack CFI */ - pcfich_cfi_encode(cfi, q->data); + /* pack CFI */ + pcfich_cfi_encode(cfi, q->data); - /* scramble for slot sequence nslot */ - scrambling_b(&q->seq_pcfich[nsubframe], q->data); + /* scramble for slot sequence nslot */ + scrambling_b(&q->seq_pcfich[subframe], q->data); - mod_modulate(&q->mod, q->data, q->pcfich_d, PCFICH_CFI_LEN); + mod_modulate(&q->mod, q->data, q->pcfich_d, PCFICH_CFI_LEN); - /* layer mapping & precoding */ - 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)); - } + /* layer mapping & precoding */ + if (q->cell.nof_ports > 1) { + layermap_diversity(q->pcfich_d, x, q->cell.nof_ports, q->nof_symbols); + precoding_diversity(x, symbols_precoding, q->cell.nof_ports, + q->nof_symbols / q->cell.nof_ports); + } else { + memcpy(q->pcfich_symbols[0], q->pcfich_d, q->nof_symbols * sizeof(cf_t)); + } - /* mapping to resource elements */ - 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; + /* mapping to resource elements */ + for (i = 0; i < q->cell.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 LIBLTE_ERROR; + } } + return LIBLTE_SUCCESS; + } else { + return LIBLTE_ERROR_INVALID_INPUTS; } - - return 0; } + diff --git a/lte/phy/lib/phch/src/pdcch.c b/lte/phy/lib/phch/src/pdcch.c index 512badb96..a239d9507 100644 --- a/lte/phy/lib/phch/src/pdcch.c +++ b/lte/phy/lib/phch/src/pdcch.c @@ -31,7 +31,6 @@ #include #include #include -#include #include #include "liblte/phy/phch/dci.h" @@ -42,24 +41,26 @@ #include "liblte/phy/utils/vector.h" #include "liblte/phy/utils/debug.h" -#define PDCCH_NOF_FORMATS 4 -#define PDCCH_FORMAT_NOF_CCE(i) (1<b)?b:a) +void set_cfi(pdcch_t *q, uint8_t cfi); + /** * 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, uint16_t nof_cce, uint16_t nof_bits, + uint16_t rnti) { int i, l, L, k; k = 0; for (l = 3; l > 1; l--) { @@ -80,15 +81,15 @@ int gen_common_search(dci_candidate_t *c, int nof_cce, int nof_bits, /** * 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, uint16_t nof_cce, uint8_t nof_bits, + uint16_t rnti, uint8_t subframe) { int i, l, L, k, m; unsigned int Yk; const int S[4] = { 6, 12, 8, 16 }; k = 0; - if (!subframe) { - INFO("UE-specific candidates for RNTI: 0x%x, NofBits: %d, NofCCE: %d\n", - rnti, nof_bits, nof_cce); + + if (VERBOSE_ISDEBUG()) { + printf("NofBits=%d, RNTI: 0x%x, SF=%d (n, L): ", nof_bits, rnti, subframe); } for (l = 3; l >= 0; l--) { L = (1 << l); @@ -102,7 +103,12 @@ int gen_ue_search(dci_candidate_t *c, int nof_cce, int nof_bits, } c[k].ncce = L * ((Yk + i) % (nof_cce / L)); if (VERBOSE_ISDEBUG()) { - printf("sf %d - (%d, %d), ", subframe, c[k].ncce, c[k].L); + printf("(%d, %d), ", c[k].ncce, c[k].L); + } + if (c[k].ncce + PDCCH_FORMAT_NOF_CCE(c[k].L) > nof_cce || + nof_bits > DCI_MAX_BITS) { + fprintf(stderr, "Illegal DCI message\n"); + return LIBLTE_ERROR; } k++; } @@ -113,35 +119,17 @@ int gen_ue_search(dci_candidate_t *c, int nof_cce, int nof_bits, return k; } -void pdcch_init_common(pdcch_t *q, pdcch_search_t *s, unsigned short rnti) { - int k, i; - dci_candidate_t *c = s->candidates[0]; - s->nof_candidates = 0; - // Format 1A and 1C L=4 and L=8, 4 and 2 candidates, only if nof_cce > 16 - k = 0; - for (i = 0; i < NOF_COMMON_FORMATS && k < MAX_CANDIDATES; i++) { - k += gen_common_search(&c[k], q->nof_cce, - dci_format_sizeof(common_formats[i], q->nof_prb), SIRNTI); - } - s->nof_candidates=k; - INFO("Initiated %d candidate(s) in the Common search space for RNTI: 0x%x\n", - s->nof_candidates, rnti); -} - -/** 36.213 v9.3 Table 7.1-1: System Information DCI messages - * Expect DCI formats 1C and 1A in the common search space - */ -void pdcch_init_search_si(pdcch_t *q) { - pdcch_init_common(q, &q->search_mode[SEARCH_SI], SIRNTI); - q->current_search_mode = SEARCH_SI; -} /** 36.213 v9.3 Table 7.1-5 * user-specific search space. Currently supported transmission Mode 1: * DCI Format 1A and 1 + PUSCH scheduling format 0 */ -void pdcch_init_search_ue(pdcch_t *q, unsigned short c_rnti) { - int n, k, i; +int pdcch_init_search_ue(pdcch_t *q, uint16_t c_rnti, uint8_t cfi) { + int k, i, r; + uint8_t n; + + set_cfi(q, cfi); + pdcch_search_t *s = &q->search_mode[SEARCH_UE]; for (n = 0; n < NSUBFRAMES_X_FRAME; n++) { dci_candidate_t *c = s->candidates[n]; @@ -151,22 +139,67 @@ void pdcch_init_search_ue(pdcch_t *q, unsigned short c_rnti) { // Expect Formats 1, 1A, 0 k = 0; for (i = 0; i < NOF_UE_FORMATS && k < MAX_CANDIDATES; i++) { - k += gen_ue_search(&c[k], q->nof_cce, - dci_format_sizeof(ue_formats[i], q->nof_prb), c_rnti, n); + r = gen_ue_search(&c[k], q->nof_cce, + dci_format_sizeof(ue_formats[i], q->cell.nof_prb), c_rnti, n); + if (r < 0) { + fprintf(stderr, "Error generating UE-specific search space\n"); + return r; + } + k += r; } s->nof_candidates = k; } INFO("Initiated %d candidate(s) in the UE-specific search space for C-RNTI: 0x%x\n", s->nof_candidates, c_rnti); q->current_search_mode = SEARCH_UE; + + return LIBLTE_SUCCESS; +} + + +int pdcch_init_common(pdcch_t *q, pdcch_search_t *s, uint16_t rnti) { + int k, r, i; + dci_candidate_t *c = s->candidates[0]; + s->nof_candidates = 0; + // Format 1A and 1C L=4 and L=8, 4 and 2 candidates, only if nof_cce > 16 + k = 0; + for (i = 0; i < NOF_COMMON_FORMATS && k < MAX_CANDIDATES; i++) { + r = gen_common_search(&c[k], q->nof_cce, + dci_format_sizeof(common_formats[i], q->cell.nof_prb), SIRNTI); + if (r < 0) { + return r; + } + k += r; + } + s->nof_candidates=k; + INFO("Initiated %d candidate(s) in the Common search space for RNTI: 0x%x\n", + s->nof_candidates, rnti); + + return LIBLTE_SUCCESS; +} + +/** 36.213 v9.3 Table 7.1-1: System Information DCI messages + * Expect DCI formats 1C and 1A in the common search space + */ +int pdcch_init_search_si(pdcch_t *q, uint8_t cfi) { + set_cfi(q, cfi); + int r = pdcch_init_common(q, &q->search_mode[SEARCH_SI], SIRNTI); + if (r >= 0) { + q->current_search_mode = SEARCH_SI; + } + return r; } /** 36.213 v9.3 Table 7.1-3 * Expect DCI formats 1C and 1A in the common search space */ -void pdcch_init_search_ra(pdcch_t *q, unsigned short ra_rnti) { - pdcch_init_common(q, &q->search_mode[SEARCH_RA], ra_rnti); - q->current_search_mode = SEARCH_RA; +int pdcch_init_search_ra(pdcch_t *q, uint16_t ra_rnti, uint8_t cfi) { + set_cfi(q, cfi); + int r = pdcch_init_common(q, &q->search_mode[SEARCH_RA], ra_rnti); + if (r >= 0) { + q->current_search_mode = SEARCH_RA; + } + return r; } void pdcch_set_search_si(pdcch_t *q) { @@ -179,110 +212,94 @@ void pdcch_set_search_ra(pdcch_t *q) { q->current_search_mode = SEARCH_RA; } -int pdcch_set_cfi(pdcch_t *q, int cfi) { - if (cfi == -1) { - q->nof_bits = -1; - q->nof_symbols = -1; - q->nof_cce = -1; - q->nof_regs = -1; - return 0; - } else if (cfi < 4 && cfi > 0) { +void set_cfi(pdcch_t *q, uint8_t cfi) { + if (cfi > 0 && cfi < 4) { q->nof_regs = (regs_pdcch_nregs(q->regs, cfi) / 9) * 9; q->nof_cce = q->nof_regs / 9; q->nof_symbols = 4 * q->nof_regs; q->nof_bits = 2 * q->nof_symbols; - return 0; - } else { - return -1; - } + } } /** Initializes the PDCCH transmitter and receiver */ -int pdcch_init(pdcch_t *q, regs_t *regs, int nof_prb, int nof_ports, - int cell_id, lte_cp_t cp) { - int ret = -1; +int pdcch_init(pdcch_t *q, regs_t *regs, lte_cell_t cell) { + int ret = LIBLTE_ERROR_INVALID_INPUTS; 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(pdcch_t)); - q->cell_id = cell_id; - q->cp = cp; - q->regs = regs; - q->nof_ports = nof_ports; - q->nof_prb = nof_prb; - q->current_search_mode = SEARCH_NONE; - - /* Now allocate memory for the maximum number of REGs (CFI=2), then can - * be changed at runtime - */ - pdcch_set_cfi(q, 3); - - 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; - } - if (crc_init(&q->crc, LTE_CRC16, 16)) { - goto clean; - } - - demod_soft_init(&q->demod); - demod_soft_table_set(&q->demod, &q->mod); - demod_soft_alg_set(&q->demod, APPROX); - - for (i = 0; i < NSUBFRAMES_X_FRAME; i++) { - if (sequence_pdcch(&q->seq_pdcch[i], 2 * i, q->cell_id, q->nof_bits)) { + if (q != NULL && + regs != NULL && + lte_cell_isvalid(&cell)) + { + ret = LIBLTE_ERROR; + bzero(q, sizeof(pdcch_t)); + q->cell = cell; + q->regs = regs; + q->current_search_mode = SEARCH_NONE; + + /* Now allocate memory for the maximum number of REGs (CFI=3) + */ + set_cfi(q, 3); + q->max_bits = q->nof_bits; + + 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->cell.nof_ports); + + if (modem_table_std(&q->mod, LTE_QPSK, true)) { + goto clean; + } + if (crc_init(&q->crc, LTE_CRC16, 16)) { goto clean; } - } - - int poly[3] = { 0x6D, 0x4F, 0x57 }; - if (viterbi_init(&q->decoder, viterbi_37, poly, DCI_MAX_BITS + 16, true)) { - goto clean; - } - q->pdcch_e = malloc(sizeof(char) * q->nof_bits); - if (!q->pdcch_e) { - goto clean; - } + demod_soft_init(&q->demod); + demod_soft_table_set(&q->demod, &q->mod); + demod_soft_alg_set(&q->demod, APPROX); - q->pdcch_llr = malloc(sizeof(float) * q->nof_bits); - if (!q->pdcch_llr) { - goto clean; - } + for (i = 0; i < NSUBFRAMES_X_FRAME; i++) { + if (sequence_pdcch(&q->seq_pdcch[i], 2 * i, q->cell.id, q->nof_bits)) { + goto clean; + } + } - q->pdcch_d = malloc(sizeof(cf_t) * q->nof_symbols); - if (!q->pdcch_d) { - goto clean; - } + int poly[3] = { 0x6D, 0x4F, 0x57 }; + if (viterbi_init(&q->decoder, viterbi_37, poly, DCI_MAX_BITS + 16, true)) { + goto clean; + } - for (i = 0; i < MAX_PORTS; i++) { - q->ce[i] = malloc(sizeof(cf_t) * q->nof_symbols); - if (!q->ce[i]) { + q->pdcch_e = malloc(sizeof(char) * q->nof_bits); + if (!q->pdcch_e) { goto clean; } - q->pdcch_x[i] = malloc(sizeof(cf_t) * q->nof_symbols); - if (!q->pdcch_x[i]) { + + q->pdcch_llr = malloc(sizeof(float) * q->nof_bits); + if (!q->pdcch_llr) { goto clean; } - q->pdcch_symbols[i] = malloc(sizeof(cf_t) * q->nof_symbols); - if (!q->pdcch_symbols[i]) { + + q->pdcch_d = malloc(sizeof(cf_t) * q->nof_symbols); + if (!q->pdcch_d) { goto clean; } - } - /* Reset CFI to make sure we return error if new CFI is not set */ - pdcch_set_cfi(q, -1); + for (i = 0; i < MAX_PORTS; i++) { + q->ce[i] = malloc(sizeof(cf_t) * q->nof_symbols); + if (!q->ce[i]) { + goto clean; + } + q->pdcch_x[i] = malloc(sizeof(cf_t) * q->nof_symbols); + if (!q->pdcch_x[i]) { + goto clean; + } + q->pdcch_symbols[i] = malloc(sizeof(cf_t) * q->nof_symbols); + if (!q->pdcch_symbols[i]) { + goto clean; + } + } - ret = 0; - clean: if (ret == -1) { + ret = LIBLTE_SUCCESS; + } + clean: + if (ret == LIBLTE_ERROR) { pdcch_free(q); } return ret; @@ -326,44 +343,58 @@ 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) { +int dci_decode(pdcch_t *q, float *e, char *data, uint16_t E, uint16_t nof_bits, uint16_t *crc) { float tmp[3 * (DCI_MAX_BITS + 16)]; - unsigned short p_bits, crc_res; + uint16_t p_bits, crc_res; char *x; - assert(nof_bits < DCI_MAX_BITS); + if (q != NULL && + data != NULL && + E < q->max_bits && + nof_bits < DCI_MAX_BITS) + { - /* unrate matching */ - rm_conv_rx(e, E, tmp, 3 * (nof_bits + 16)); + /* unrate matching */ + rm_conv_rx(e, E, tmp, 3 * (nof_bits + 16)); - DEBUG("Viterbi input: ", 0); - if (VERBOSE_ISDEBUG()) { - vec_fprint_f(stdout, tmp, 3 * (nof_bits + 16)); - } + DEBUG("Viterbi input: ", 0); + if (VERBOSE_ISDEBUG()) { + vec_fprint_f(stdout, tmp, 3 * (nof_bits + 16)); + } - /* viterbi decoder */ - viterbi_decode_f(&q->decoder, tmp, data, nof_bits + 16); + /* viterbi decoder */ + viterbi_decode_f(&q->decoder, tmp, data, nof_bits + 16); - if (VERBOSE_ISDEBUG()) { - bit_fprint(stdout, data, nof_bits + 16); - } + if (VERBOSE_ISDEBUG()) { + 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); - return (p_bits ^ crc_res); + x = &data[nof_bits]; + p_bits = (uint16_t) bit_unpack(&x, 16); + crc_res = ((uint16_t) 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); + + if (crc) { + *crc = p_bits ^ crc_res; + } + return LIBLTE_SUCCESS; + } else { + return LIBLTE_ERROR_INVALID_INPUTS; + } } int pdcch_decode_candidate(pdcch_t *q, float *llr, dci_candidate_t *c, dci_msg_t *msg) { - unsigned short crc_res; + uint16_t crc_res; INFO("Trying Candidate: Nbits: %d, E: %3d, nCCE: %d, L: %d, RNTI: 0x%x\n", 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 (dci_decode(q, &llr[72 * c->ncce], msg->data, + PDCCH_FORMAT_NOF_BITS(c->L), c->nof_bits, &crc_res)) { + return LIBLTE_ERROR; + } if (c->rnti == crc_res) { memcpy(&msg->location, c, sizeof(dci_candidate_t)); @@ -371,85 +402,88 @@ int pdcch_decode_candidate(pdcch_t *q, float *llr, dci_candidate_t *c, c->nof_bits, PDCCH_FORMAT_NOF_BITS(c->L), c->ncce, c->L, c->rnti); return 1; } - return 0; + return LIBLTE_SUCCESS; } int pdcch_extract_llr(pdcch_t *q, cf_t *slot_symbols, cf_t *ce[MAX_PORTS], - float *llr, int nsubframe) { + float *llr, uint8_t nsubframe, uint8_t cfi) { /* Set pointers for layermapping & precoding */ int i; cf_t *x[MAX_LAYERS]; - if (q->nof_bits == -1 || q->nof_cce == -1 || q->nof_regs == -1) { - fprintf(stderr, "Must call pdcch_set_cfi() first to set the CFI\n"); - return -1; - } - - 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->pdcch_x[i]; - } - memset(&x[q->nof_ports], 0, sizeof(cf_t*) * (MAX_LAYERS - q->nof_ports)); - - /* extract symbols */ - int n = regs_pdcch_get(q->regs, slot_symbols, q->pdcch_symbols[0]); - if (q->nof_symbols != n) { - fprintf(stderr, "Expected %d PDCCH symbols but got %d symbols\n", - q->nof_symbols, n); - return -1; - } + if (q != NULL && + llr != NULL && + slot_symbols != NULL && + nsubframe < 10 && + cfi > 0 && + cfi < 4) + { + set_cfi(q, cfi); + + /* number of layers equals number of ports */ + for (i = 0; i < q->cell.nof_ports; i++) { + x[i] = q->pdcch_x[i]; + } + memset(&x[q->cell.nof_ports], 0, sizeof(cf_t*) * (MAX_LAYERS - q->cell.nof_ports)); - /* extract channel estimates */ - for (i = 0; i < q->nof_ports; i++) { - n = regs_pdcch_get(q->regs, ce[i], q->ce[i]); + /* extract symbols */ + int n = regs_pdcch_get(q->regs, slot_symbols, q->pdcch_symbols[0]); if (q->nof_symbols != n) { fprintf(stderr, "Expected %d PDCCH symbols but got %d symbols\n", q->nof_symbols, n); - return -1; + return LIBLTE_ERROR; } - } - /* in control channels, only diversity is supported */ - if (q->nof_ports == 1) { - /* no need for layer demapping */ - predecoding_single_zf(q->pdcch_symbols[0], q->ce[0], q->pdcch_d, - q->nof_symbols); - } else { - 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); - } + /* extract channel estimates */ + for (i = 0; i < q->cell.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); + return LIBLTE_ERROR; + } + } - DEBUG("pdcch d symbols: ", 0); - if (VERBOSE_ISDEBUG()) { - vec_fprint_c(stdout, q->pdcch_d, q->nof_symbols); - } + /* in control channels, only diversity is supported */ + if (q->cell.nof_ports == 1) { + /* no need for layer demapping */ + predecoding_single_zf(q->pdcch_symbols[0], q->ce[0], q->pdcch_d, + q->nof_symbols); + } else { + predecoding_diversity_zf(q->pdcch_symbols[0], q->ce, x, q->cell.nof_ports, + q->nof_symbols); + layerdemap_diversity(x, q->pdcch_d, q->cell.nof_ports, + q->nof_symbols / q->cell.nof_ports); + } - /* demodulate symbols */ - demod_soft_sigma_set(&q->demod, 1.0); - demod_soft_demodulate(&q->demod, q->pdcch_d, q->pdcch_llr, q->nof_symbols); + DEBUG("pdcch d symbols: ", 0); + if (VERBOSE_ISDEBUG()) { + vec_fprint_c(stdout, q->pdcch_d, q->nof_symbols); + } - DEBUG("llr: ", 0); - if (VERBOSE_ISDEBUG()) { - vec_fprint_f(stdout, q->pdcch_llr, q->nof_bits); - } + /* demodulate symbols */ + demod_soft_sigma_set(&q->demod, 1.0); + demod_soft_demodulate(&q->demod, q->pdcch_d, q->pdcch_llr, q->nof_symbols); + + DEBUG("llr: ", 0); + if (VERBOSE_ISDEBUG()) { + vec_fprint_f(stdout, q->pdcch_llr, q->nof_bits); + } - /* descramble */ - scrambling_f_offset(&q->seq_pdcch[nsubframe], llr, 0, q->nof_bits); + /* descramble */ + scrambling_f_offset(&q->seq_pdcch[nsubframe], llr, 0, q->nof_bits); - return 0; + return LIBLTE_SUCCESS; + } else { + return LIBLTE_ERROR_INVALID_INPUTS; + } } -int pdcch_decode_current_mode(pdcch_t *q, float *llr, dci_t *dci, int subframe) { +int pdcch_decode_current_mode(pdcch_t *q, float *llr, dci_t *dci, uint8_t subframe) { int k, i; - + int ret; + if (q->current_search_mode == SEARCH_UE) { k = subframe; } else { @@ -459,10 +493,13 @@ int pdcch_decode_current_mode(pdcch_t *q, float *llr, dci_t *dci, int subframe) 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, + ret = pdcch_decode_candidate(q, q->pdcch_llr, &q->search_mode[q->current_search_mode].candidates[k][i], - &dci->msg[dci->nof_dcis])) { + &dci->msg[dci->nof_dcis]); + if (ret == 1) { dci->nof_dcis++; + } else if (ret == -1) { + return LIBLTE_ERROR; } } return dci->nof_dcis; @@ -476,7 +513,7 @@ int pdcch_decode_ra(pdcch_t *q, float *llr, dci_t *dci) { pdcch_set_search_ra(q); return pdcch_decode_current_mode(q, llr, dci, 0); } -int pdcch_decode_ue(pdcch_t *q, float *llr, dci_t *dci, int nsubframe) { +int pdcch_decode_ue(pdcch_t *q, float *llr, dci_t *dci, uint8_t nsubframe) { pdcch_set_search_ue(q); return pdcch_decode_current_mode(q, llr, dci, nsubframe); } @@ -488,25 +525,30 @@ int pdcch_decode_ue(pdcch_t *q, float *llr, dci_t *dci, int nsubframe) { * Returns number of messages stored in dci */ int pdcch_decode(pdcch_t *q, cf_t *slot_symbols, cf_t *ce[MAX_PORTS], - dci_t *dci, int nsubframe) { - - if (q->nof_bits == -1 || q->nof_cce == -1 || q->nof_regs == -1) { - fprintf(stderr, "Must call pdcch_set_cfi() first to set the CFI\n"); - return -1; - } + dci_t *dci, uint8_t subframe, uint8_t cfi) { + + if (q != NULL && + dci != NULL && + slot_symbols != NULL && + subframe < 10 && + cfi > 0 && + cfi < 4) + { + if (pdcch_extract_llr(q, slot_symbols, ce, q->pdcch_llr, subframe, cfi)) { + return LIBLTE_ERROR; + } - if (pdcch_extract_llr(q, slot_symbols, ce, q->pdcch_llr, nsubframe)) { - return -1; - } + if (q->current_search_mode != SEARCH_NONE) { + return pdcch_decode_current_mode(q, q->pdcch_llr, dci, subframe); + } - if (q->current_search_mode != SEARCH_NONE) { - return pdcch_decode_current_mode(q, q->pdcch_llr, dci, nsubframe); + return LIBLTE_SUCCESS; + } else { + return LIBLTE_ERROR_INVALID_INPUTS; } - - return 0; } -void crc_set_mask_rnti(char *crc, unsigned short rnti) { +void crc_set_mask_rnti(char *crc, uint16_t rnti) { int i; char mask[16]; char *r = mask; @@ -522,96 +564,110 @@ 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) { +int dci_encode(pdcch_t *q, char *data, char *e, uint16_t nof_bits, uint16_t E, + uint16_t rnti) { convcoder_t encoder; char tmp[3 * (DCI_MAX_BITS + 16)]; + + if (q != NULL && + data != NULL && + e != NULL && + nof_bits < DCI_MAX_BITS && + E < q->max_bits) + { + + int poly[3] = { 0x6D, 0x4F, 0x57 }; + encoder.K = 7; + encoder.R = 3; + encoder.tail_biting = true; + memcpy(encoder.poly, poly, 3 * sizeof(int)); + + crc_attach(&q->crc, data, nof_bits); + crc_set_mask_rnti(&data[nof_bits], rnti); + + convcoder_encode(&encoder, data, tmp, nof_bits + 16); + + DEBUG("CConv output: ", 0); + if (VERBOSE_ISDEBUG()) { + vec_fprint_b(stdout, tmp, 3 * (nof_bits + 16)); + } - assert(nof_bits < DCI_MAX_BITS); - - int poly[3] = { 0x6D, 0x4F, 0x57 }; - encoder.K = 7; - encoder.R = 3; - encoder.tail_biting = true; - memcpy(encoder.poly, poly, 3 * sizeof(int)); - - crc_attach(&q->crc, data, nof_bits); - crc_set_mask_rnti(&data[nof_bits], rnti); - - convcoder_encode(&encoder, data, tmp, nof_bits + 16); - - DEBUG("CConv output: ", 0); - if (VERBOSE_ISDEBUG()) { - vec_fprint_b(stdout, tmp, 3 * (nof_bits + 16)); + rm_conv_tx(tmp, 3 * (nof_bits + 16), e, E); + + return LIBLTE_SUCCESS; + } else { + return LIBLTE_ERROR_INVALID_INPUTS; } - - rm_conv_tx(tmp, 3 * (nof_bits + 16), e, E); } /** 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 *slot_symbols[MAX_PORTS], - int nsubframe) { + uint8_t nsubframe, uint8_t cfi) { int i; /* Set pointers for layermapping & precoding */ cf_t *x[MAX_LAYERS]; + + if (q != NULL && + dci != NULL && + slot_symbols != NULL && + nsubframe < 10 && + cfi > 0 && + cfi < 4) + { + set_cfi(q, cfi); + + /* number of layers equals number of ports */ + for (i = 0; i < q->cell.nof_ports; i++) { + x[i] = q->pdcch_x[i]; + } + memset(&x[q->cell.nof_ports], 0, sizeof(cf_t*) * (MAX_LAYERS - q->cell.nof_ports)); + + /* should add elements? Or maybe random bits to facilitate power estimation */ + bzero(q->pdcch_e, q->nof_bits); + + /* Encode DCIs */ + for (i = 0; i < dci->nof_dcis; i++) { + /* do some 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 + || dci->msg[i].location.nof_bits > DCI_MAX_BITS) { + fprintf(stderr, "Illegal DCI message nCCE: %d, L: %d, nof_cce: %d\n", + dci->msg[i].location.ncce, dci->msg[i].location.L, q->nof_cce); + return LIBLTE_ERROR; + } + 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.rnti); + } - if (q->nof_bits == -1 || q->nof_cce == -1 || q->nof_regs == -1) { - fprintf(stderr, "Must call pdcch_set_cfi() first to set the CFI\n"); - return -1; - } - 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->pdcch_x[i]; - } - memset(&x[q->nof_ports], 0, sizeof(cf_t*) * (MAX_LAYERS - q->nof_ports)); - - /* should add elements? Or maybe random bits to facilitate power estimation */ - bzero(q->pdcch_e, q->nof_bits); - - /* 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 - || 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); - - 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.rnti); - } + scrambling_b_offset(&q->seq_pdcch[nsubframe], q->pdcch_e, 0, q->nof_bits); - scrambling_b_offset(&q->seq_pdcch[nsubframe], q->pdcch_e, 0, q->nof_bits); + mod_modulate(&q->mod, q->pdcch_e, q->pdcch_d, q->nof_bits); - mod_modulate(&q->mod, q->pdcch_e, q->pdcch_d, q->nof_bits); + /* layer mapping & precoding */ + if (q->cell.nof_ports > 1) { + layermap_diversity(q->pdcch_d, x, q->cell.nof_ports, q->nof_symbols); + precoding_diversity(x, q->pdcch_symbols, q->cell.nof_ports, + q->nof_symbols / q->cell.nof_ports); + } else { + memcpy(q->pdcch_symbols[0], q->pdcch_d, q->nof_symbols * sizeof(cf_t)); + } - /* layer mapping & precoding */ - if (q->nof_ports > 1) { - layermap_diversity(q->pdcch_d, x, q->nof_ports, q->nof_symbols); - precoding_diversity(x, q->pdcch_symbols, q->nof_ports, - q->nof_symbols / q->nof_ports); + /* mapping to resource elements */ + for (i = 0; i < q->cell.nof_ports; i++) { + regs_pdcch_put(q->regs, q->pdcch_symbols[i], slot_symbols[i]); + } + return LIBLTE_SUCCESS; } else { - memcpy(q->pdcch_symbols[0], q->pdcch_d, q->nof_symbols * sizeof(cf_t)); - } - - /* mapping to resource elements */ - for (i = 0; i < q->nof_ports; i++) { - regs_pdcch_put(q->regs, q->pdcch_symbols[i], slot_symbols[i]); + return LIBLTE_ERROR_INVALID_INPUTS; } - return 0; } diff --git a/lte/phy/lib/phch/src/pdsch.c b/lte/phy/lib/phch/src/pdsch.c index c3de1494b..a5459a480 100644 --- a/lte/phy/lib/phch/src/pdsch.c +++ b/lte/phy/lib/phch/src/pdsch.c @@ -41,24 +41,35 @@ #include "liblte/phy/utils/debug.h" #include "liblte/phy/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) * 12) + + +const enum modem_std modulations[4] = + { LTE_BPSK, LTE_QPSK, LTE_QAM16, LTE_QAM64 }; + + +struct cb_segm { + int F; + int C; + int K1; + int K2; + int C1; + int C2; +}; + int pdsch_cp(pdsch_t *q, cf_t *input, cf_t *output, ra_prb_t *prb_alloc, - int nsubframe, bool put) { + uint8_t 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) { + if (q->cell.nof_ports == 1) { nof_refs = 2; } else { nof_refs = 4; @@ -66,66 +77,66 @@ int pdsch_cp(pdsch_t *q, cf_t *input, cf_t *output, ra_prb_t *prb_alloc, for (s = 0; s < 2; s++) { - for (l = 0; l < CP_NSYMB(q->cp); l++) { + for (l = 0; l < CP_NSYMB(q->cell.cp); l++) { for (n = 0; n < prb_alloc->slot[s].nof_prb; n++) { if (s == 0) { lstart = prb_alloc->lstart; } else { lstart = 0; } - lend = CP_NSYMB(q->cp); + lend = CP_NSYMB(q->cell.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; + if (prb_alloc->slot[s].prb_idx[n] >= q->cell.nof_prb / 2 - 3 + && prb_alloc->slot[s].prb_idx[n] <= q->cell.nof_prb / 2 + 3) { + lend = CP_NSYMB(q->cell.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) { + if (prb_alloc->slot[s].prb_idx[n] >= q->cell.nof_prb / 2 - 3 + && prb_alloc->slot[s].prb_idx[n] <= q->cell.nof_prb / 2 + 3) { lstart = 4; is_pbch = true; } } - lp = l + s * CP_NSYMB(q->cp); + lp = l + s * CP_NSYMB(q->cell.cp); if (put) { - out_ptr = &output[(lp * q->nof_prb + prb_alloc->slot[s].prb_idx[n]) + out_ptr = &output[(lp * q->cell.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]) + in_ptr = &input[(lp * q->cell.nof_prb + prb_alloc->slot[s].prb_idx[n]) * RE_X_RB]; } if (l >= lstart && l < lend) { - if (SYMBOL_HAS_REF(l, q->cp, q->nof_ports)) { + if (SYMBOL_HAS_REF(l, q->cell.cp, q->cell.nof_ports)) { if (nof_refs == 2 && l != 0) { - offset = q->cell_id % 3 + 3; + offset = q->cell.id % 3 + 3; } else { - offset = q->cell_id % 3; + offset = q->cell.id % 3; } prb_cp_ref(&in_ptr, &out_ptr, offset, nof_refs, nof_refs, put); } else { prb_cp(&in_ptr, &out_ptr, 1); } } - if ((q->nof_prb % 2) && ((is_pbch && l < lstart) || (is_sss && l >= lend))) { - if (prb_alloc->slot[s].prb_idx[n] == q->nof_prb / 2 - 3) { - if (SYMBOL_HAS_REF(l, q->cp, q->nof_ports)) { + if ((q->cell.nof_prb % 2) && ((is_pbch && l < lstart) || (is_sss && l >= lend))) { + if (prb_alloc->slot[s].prb_idx[n] == q->cell.nof_prb / 2 - 3) { + if (SYMBOL_HAS_REF(l, q->cell.cp, q->cell.nof_ports)) { prb_cp_ref(&in_ptr, &out_ptr, offset, nof_refs, nof_refs/2, put); } else { prb_cp_half(&in_ptr, &out_ptr, 1); } - } else if (prb_alloc->slot[s].prb_idx[n] == q->nof_prb / 2 + 3) { + } else if (prb_alloc->slot[s].prb_idx[n] == q->cell.nof_prb / 2 + 3) { if (put) { out_ptr += 6; } else { in_ptr += 6; } - if (SYMBOL_HAS_REF(l, q->cp, q->nof_ports)) { + if (SYMBOL_HAS_REF(l, q->cell.cp, q->cell.nof_ports)) { prb_cp_ref(&in_ptr, &out_ptr, offset, nof_refs, nof_refs/2, put); } else { prb_cp_half(&in_ptr, &out_ptr, 1); @@ -151,8 +162,8 @@ int pdsch_cp(pdsch_t *q, cf_t *input, cf_t *output, ra_prb_t *prb_alloc, * 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); + ra_prb_t *prb_alloc, uint8_t subframe) { + return pdsch_cp(q, pdsch_symbols, sf_symbols, prb_alloc, subframe, true); } /** @@ -163,117 +174,112 @@ int pdsch_put(pdsch_t *q, cf_t *pdsch_symbols, cf_t *sf_symbols, * 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); + ra_prb_t *prb_alloc, uint8_t subframe) { + return pdsch_cp(q, sf_symbols, pdsch_symbols, prb_alloc, subframe, 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 pdsch_init(pdsch_t *q, uint16_t user_rnti, lte_cell_t cell) { + int ret = LIBLTE_ERROR_INVALID_INPUTS; 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; + if (q != NULL && + lte_cell_isvalid(&cell)) + { + + bzero(q, sizeof(pdsch_t)); + ret = LIBLTE_ERROR; + + q->cell = cell; + q->rnti = user_rnti; - q->max_symbols = nof_prb * MAX_PDSCH_RE(cp); + q->max_symbols = q->cell.nof_prb * MAX_PDSCH_RE(q->cell.cp); - INFO("Init PDSCH: %d ports %d PRBs, max_symbols: %d\n", q->nof_ports, - q->nof_prb, q->max_symbols); + INFO("Init PDSCH: %d ports %d PRBs, max_symbols: %d\n", q->cell.nof_ports, + q->cell.nof_prb, q->max_symbols); - for (i = 0; i < 4; i++) { - if (modem_table_std(&q->mod[i], modulations[i], true)) { + 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_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)) { + if (crc_init(&q->crc_cb, LTE_CRC24B, 24)) { 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; - } + demod_soft_init(&q->demod); + demod_soft_alg_set(&q->demod, APPROX); - 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; - } + 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; + } + } - q->pdsch_e_bits = malloc( - sizeof(char) * q->max_symbols * q->mod[3].nbits_x_symbol); - if (!q->pdsch_e_bits) { - 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->pdsch_llr = malloc( - sizeof(float) * q->max_symbols * q->mod[3].nbits_x_symbol); - if (!q->pdsch_llr) { - 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_d = malloc(sizeof(cf_t) * q->max_symbols); - if (!q->pdsch_d) { - goto clean; - } + q->pdsch_rm_f = malloc(sizeof(float) * (3 * MAX_LONG_CB + 12)); + if (!q->pdsch_rm_f) { + goto clean; + } - for (i = 0; i < nof_ports; i++) { - q->ce[i] = malloc(sizeof(cf_t) * q->max_symbols); - if (!q->ce[i]) { + 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_x[i] = malloc(sizeof(cf_t) * q->max_symbols); - if (!q->pdsch_x[i]) { + + q->pdsch_llr = malloc( + sizeof(float) * q->max_symbols * q->mod[3].nbits_x_symbol); + if (!q->pdsch_llr) { goto clean; } - q->pdsch_symbols[i] = malloc(sizeof(cf_t) * q->max_symbols); - if (!q->pdsch_symbols[i]) { + + q->pdsch_d = malloc(sizeof(cf_t) * q->max_symbols); + if (!q->pdsch_d) { goto clean; } - } - ret = 0; - clean: if (ret == -1) { + for (i = 0; i < q->cell.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 = LIBLTE_SUCCESS; + } + clean: + if (ret == LIBLTE_ERROR) { pdsch_free(q); } return ret; @@ -300,7 +306,7 @@ void pdsch_free(pdsch_t *q) { if (q->pdsch_d) { free(q->pdsch_d); } - for (i = 0; i < q->nof_ports; i++) { + for (i = 0; i < q->cell.nof_ports; i++) { if (q->ce[i]) { free(q->ce[i]); } @@ -325,15 +331,6 @@ void pdsch_free(pdsch_t *q) { } -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; @@ -368,175 +365,191 @@ void codeblock_segmentation(struct cb_segm *s, int tbs) { /* 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) { +int pdsch_decode_tb(pdsch_t *q, char *data, uint16_t tbs, uint16_t nb_e, uint8_t rv_idx) { char parity[24]; char *p_parity = parity; - unsigned int par_rx, par_tx; + uint32_t par_rx, par_tx; int i; int cb_len, rp, wp, rlen, F, n_e; struct cb_segm cbs; + + if (q != NULL && + data != NULL && + nb_e < q->max_symbols * q->mod[3].nbits_x_symbol) + { + /* 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; + } - /* 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; + } - 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); - 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); - /* 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); - /* 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 (cbs.C > 1) { - /* Check Codeblock CRC */ - //crc_attach(&q->crc_cb, q->pdsch_b[wp], 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)); + } - /* 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; } - /* Set read/write pointers */ - wp += (rlen - F); - rp += n_e; - } + INFO("END CB#%d: wp: %d, rp: %d\n", i, wp, rp); - 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); - // Compute transport block CRC - par_rx = crc_checksum(&q->crc_tb, data, tbs); + // check parity bits + par_tx = bit_unpack(&p_parity, 24); - // check parity bits - par_tx = bit_unpack(&p_parity, 24); + if (!par_rx) { + printf("\n\tCAUTION!! Received all-zero transport block\n\n"); + } - if (!par_rx) { - printf("\n\tCAUTION!! Received all-zero transport block\n\n"); + if (par_rx == par_tx) { + return LIBLTE_SUCCESS; + } else { + return LIBLTE_ERROR; + } + } else { + return LIBLTE_ERROR_INVALID_INPUTS; } - - 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) { + uint8_t subframe, ra_mcs_t mcs, ra_prb_t *prb_alloc) { /* Set pointers for layermapping & precoding */ int i, n; cf_t *x[MAX_LAYERS]; int nof_symbols, nof_bits, nof_bits_e; + + if (q != NULL && + sf_symbols != NULL && + data != NULL && + subframe < 10 && + prb_alloc != NULL) + { + + nof_bits = mcs.tbs; + nof_symbols = prb_alloc->re_sf[subframe]; + nof_bits_e = nof_symbols * q->mod[mcs.mod - 1].nbits_x_symbol; - 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 (nof_bits > nof_bits_e) { + fprintf(stderr, "Invalid code rate %.2f\n", (float) nof_bits / nof_bits_e); + return LIBLTE_ERROR_INVALID_INPUTS; + } - if (nsubframe < 0 || nsubframe > NSUBFRAMES_X_FRAME) { - fprintf(stderr, "Invalid subframe %d\n", nsubframe); - 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->cell.nof_prb); + return LIBLTE_ERROR_INVALID_INPUTS; + } - /* 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 */ - n = pdsch_get(q, sf_symbols, q->pdsch_symbols[0], prb_alloc, nsubframe); - if (n != nof_symbols) { - fprintf(stderr, "Error expecting %d symbols but got %d\n", nof_symbols, n); - return -1; - } + INFO("Decoding PDSCH SF: %d, Mod %d, NofBits: %d, NofSymbols: %d, NofBitsE: %d\n", + subframe, mcs.mod, nof_bits, nof_symbols, nof_bits_e); - /* extract channel estimates */ - for (i = 0; i < q->nof_ports; i++) { - n = pdsch_get(q, ce[i], q->ce[i], prb_alloc, nsubframe); + /* number of layers equals number of ports */ + for (i = 0; i < q->cell.nof_ports; i++) { + x[i] = q->pdsch_x[i]; + } + memset(&x[q->cell.nof_ports], 0, sizeof(cf_t*) * (MAX_LAYERS - q->cell.nof_ports)); + + /* extract symbols */ + n = pdsch_get(q, sf_symbols, q->pdsch_symbols[0], prb_alloc, subframe); if (n != nof_symbols) { fprintf(stderr, "Error expecting %d symbols but got %d\n", nof_symbols, n); - return -1; + return LIBLTE_ERROR; + } + + /* extract channel estimates */ + for (i = 0; i < q->cell.nof_ports; i++) { + n = pdsch_get(q, ce[i], q->ce[i], prb_alloc, subframe); + if (n != nof_symbols) { + fprintf(stderr, "Error expecting %d symbols but got %d\n", nof_symbols, n); + return LIBLTE_ERROR; + } + } + + /* TODO: only diversity is supported */ + if (q->cell.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->cell.nof_ports, + nof_symbols); + layerdemap_diversity(x, q->pdsch_d, q->cell.nof_ports, + nof_symbols / q->cell.nof_ports); } - } - /* 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); + /* 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); + /* descramble */ + scrambling_f_offset(&q->seq_pdsch[subframe], q->pdsch_llr, 0, nof_bits_e); - return pdsch_decode_tb(q, data, nof_bits, nof_bits_e, 0); + return pdsch_decode_tb(q, data, nof_bits, nof_bits_e, 0); + } else { + return LIBLTE_ERROR_INVALID_INPUTS; + } } /* 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) { +int pdsch_encode_tb(pdsch_t *q, char *data, uint16_t tbs, uint16_t nb_e, uint8_t rv_idx) { char parity[24]; char *p_parity = parity; unsigned int par; @@ -544,152 +557,174 @@ void pdsch_encode_tb(pdsch_t *q, char *data, int tbs, int nb_e, int rv_idx) { int cb_len, rp, wp, rlen, F, n_e; struct cb_segm cbs; - /* Compute CB segmentation */ - codeblock_segmentation(&cbs, tbs); + if (q != NULL && + data != NULL && + nb_e < q->max_symbols * q->mod[3].nbits_x_symbol) + { + + /* Compute CB segmentation */ + codeblock_segmentation(&cbs, tbs); - /* Compute transport block CRC */ - par = crc_checksum(&q->crc_tb, data, 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); + /* 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); - } + 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; - } + /* 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++) { + 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; - } + /* 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; - } + 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); + 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)); + } - /* 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 (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); + } - 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); - /* 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); - /* 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; + } - /* Set read/write pointers */ - rp += (rlen - F); - wp += n_e; + INFO("END CB#%d: wp: %d, rp: %d\n", i, wp, rp); + + return LIBLTE_SUCCESS; + } else { + return LIBLTE_ERROR_INVALID_INPUTS; } - - 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) { + uint8_t subframe, ra_mcs_t mcs, ra_prb_t *prb_alloc) { int i; - int nof_symbols, nof_bits, nof_bits_e; + uint16_t 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; - } + if (q != NULL && + data != NULL && + subframe < 10 && + prb_alloc != NULL) + { - nof_bits = mcs.tbs; - nof_symbols = prb_alloc->re_sf[nsubframe]; - nof_bits_e = nof_symbols * q->mod[mcs.mod - 1].nbits_x_symbol; + for (i=0;icell.nof_ports;i++) { + if (sf_symbols[i] == NULL) { + return LIBLTE_ERROR_INVALID_INPUTS; + } + } + + nof_bits = mcs.tbs; + nof_symbols = prb_alloc->re_sf[subframe]; + 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_bits > nof_bits_e) { + fprintf(stderr, "Invalid code rate %.2f\n", (float) nof_bits / nof_bits_e); + return LIBLTE_ERROR_INVALID_INPUTS; + } - 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; - } + 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->cell.nof_prb); + return LIBLTE_ERROR_INVALID_INPUTS; + } - INFO( - "Encoding PDSCH SF: %d, Mod %d, NofBits: %d, NofSymbols: %d, NofBitsE: %d\n", - nsubframe, mcs.mod, nof_bits, nof_symbols, nof_bits_e); + INFO("Encoding PDSCH SF: %d, Mod %d, NofBits: %d, NofSymbols: %d, NofBitsE: %d\n", + subframe, 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)); + /* number of layers equals number of ports */ + for (i = 0; i < q->cell.nof_ports; i++) { + x[i] = q->pdsch_x[i]; + } + memset(&x[q->cell.nof_ports], 0, sizeof(cf_t*) * (MAX_LAYERS - q->cell.nof_ports)); - pdsch_encode_tb(q, data, nof_bits, nof_bits_e, 0); + if (pdsch_encode_tb(q, data, nof_bits, nof_bits_e, 0)) { + fprintf(stderr, "Error encoding TB\n"); + return LIBLTE_ERROR; + } - scrambling_b_offset(&q->seq_pdsch[nsubframe], q->pdsch_e_bits, 0, nof_bits_e); + scrambling_b_offset(&q->seq_pdsch[subframe], 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); + 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)); - } + /* TODO: only diversity supported */ + if (q->cell.nof_ports > 1) { + layermap_diversity(q->pdsch_d, x, q->cell.nof_ports, nof_symbols); + precoding_diversity(x, q->pdsch_symbols, q->cell.nof_ports, + nof_symbols / q->cell.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); + /* mapping to resource elements */ + for (i = 0; i < q->cell.nof_ports; i++) { + pdsch_put(q, q->pdsch_symbols[i], sf_symbols[i], prb_alloc, subframe); + } + return LIBLTE_SUCCESS; + } else { + return LIBLTE_ERROR_INVALID_INPUTS; } - return 0; } diff --git a/lte/phy/lib/phch/src/phich.c b/lte/phy/lib/phch/src/phich.c index 0165e59eb..a38c97bf7 100644 --- a/lte/phy/lib/phch/src/phich.c +++ b/lte/phy/lib/phch/src/phich.c @@ -49,11 +49,8 @@ const cf_t w_normal[PHICH_NORM_NSEQUENCES][4] = { { 1, 1, 1, 1 }, const cf_t w_ext[PHICH_EXT_NSEQUENCES][2] = { { 1, 1 }, { 1, -1 }, { I, I }, { I, -I } }; -bool phich_exists(int nframe, int nslot) { - return true; -} -int phich_ngroups(phich_t *q) { +uint8_t phich_ngroups(phich_t *q) { return regs_phich_ngroups(q->regs); } @@ -65,30 +62,36 @@ void phich_reset(phich_t *q, cf_t *slot_symbols[MAX_PORTS]) { } /** Initializes the phich channel receiver */ -int phich_init(phich_t *q, regs_t *regs, int cell_id, int nof_prb, - int nof_tx_ports, lte_cp_t cp) { - int ret = -1; - bzero(q, sizeof(phich_t)); - q->cp = cp; - q->regs = regs; - q->nof_prb = nof_prb; - q->nof_tx_ports = nof_tx_ports; - - if (modem_table_std(&q->mod, LTE_BPSK, false)) { - goto clean; - } +int phich_init(phich_t *q, regs_t *regs, lte_cell_t cell) { + int ret = LIBLTE_ERROR_INVALID_INPUTS; + + if (q != NULL && + regs != NULL && + lte_cell_isvalid(&cell)) + { + + bzero(q, sizeof(phich_t)); + ret = LIBLTE_ERROR; + + q->cell = cell; + q->regs = regs; + + if (modem_table_std(&q->mod, LTE_BPSK, false)) { + goto clean; + } - demod_hard_init(&q->demod); - demod_hard_table_set(&q->demod, LTE_BPSK); + demod_hard_init(&q->demod); + demod_hard_table_set(&q->demod, LTE_BPSK); - for (int nsf = 0; nsf < NSUBFRAMES_X_FRAME; nsf++) { - if (sequence_phich(&q->seq_phich[nsf], 2 * nsf, cell_id)) { - goto clean; + for (int nsf = 0; nsf < NSUBFRAMES_X_FRAME; nsf++) { + if (sequence_phich(&q->seq_phich[nsf], 2 * nsf, q->cell.id)) { + goto clean; + } } + ret = LIBLTE_SUCCESS; } - - ret = 0; - clean: if (ret == -1) { + clean: + if (ret == LIBLTE_ERROR) { phich_free(q); } return ret; @@ -104,7 +107,7 @@ void phich_free(phich_t *q) { /* Decodes ACK * */ -char phich_ack_decode(char bits[PHICH_NBITS], int *distance) { +char phich_ack_decode(char bits[PHICH_NBITS], uint8_t *distance) { int i, n; n = 0; @@ -137,36 +140,40 @@ void phich_ack_encode(char ack, char bits[PHICH_NBITS]) { * Returns 1 if successfully decoded the CFI, 0 if not and -1 on error */ int phich_decode(phich_t *q, cf_t *slot_symbols, cf_t *ce[MAX_PORTS], - int ngroup, int nseq, int nsubframe, char *ack, int *distance) { + uint8_t ngroup, uint8_t nseq, uint8_t subframe, char *ack, uint8_t *distance) { /* Set pointers for layermapping & precoding */ int i, j; cf_t *x[MAX_LAYERS]; cf_t *ce_precoding[MAX_PORTS]; + + if (q == NULL || slot_symbols == NULL) { + return LIBLTE_ERROR_INVALID_INPUTS; + } - DEBUG("Decoding PHICH Ngroup: %d, Nseq: %d\n", ngroup, nseq); - - if (nsubframe < 0 || nsubframe > NSUBFRAMES_X_FRAME) { - fprintf(stderr, "Invalid nslot %d\n", nsubframe); - return -1; + if (subframe >= NSUBFRAMES_X_FRAME) { + fprintf(stderr, "Invalid nslot %d\n", subframe); + return LIBLTE_ERROR_INVALID_INPUTS; } - if (CP_ISEXT(q->cp)) { - if (nseq < 0 || nseq > PHICH_EXT_NSEQUENCES) { + if (CP_ISEXT(q->cell.cp)) { + if (nseq >= PHICH_EXT_NSEQUENCES) { fprintf(stderr, "Invalid nseq %d\n", nseq); - return -1; + return LIBLTE_ERROR_INVALID_INPUTS; } } else { - if (nseq < 0 || nseq > PHICH_NORM_NSEQUENCES) { + if (nseq >= PHICH_NORM_NSEQUENCES) { fprintf(stderr, "Invalid nseq %d\n", nseq); - return -1; + return LIBLTE_ERROR_INVALID_INPUTS; } } if (ngroup >= regs_phich_ngroups(q->regs)) { fprintf(stderr, "Invalid ngroup %d\n", ngroup); - return -1; + return LIBLTE_ERROR_INVALID_INPUTS; } + DEBUG("Decoding PHICH Ngroup: %d, Nseq: %d\n", ngroup, nseq); + /* number of layers equals number of ports */ for (i = 0; i < MAX_PORTS; i++) { x[i] = q->phich_x[i]; @@ -179,34 +186,34 @@ int phich_decode(phich_t *q, cf_t *slot_symbols, cf_t *ce[MAX_PORTS], if (PHICH_MAX_NSYMB != 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; + return LIBLTE_ERROR; } /* extract channel estimates */ - for (i = 0; i < q->nof_tx_ports; i++) { + for (i = 0; i < q->cell.nof_ports; i++) { 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; + return LIBLTE_ERROR; } } /* in control channels, only diversity is supported */ - if (q->nof_tx_ports == 1) { + if (q->cell.nof_ports == 1) { /* no need for layer demapping */ predecoding_single_zf(q->phich_symbols[0], q->ce[0], q->phich_d0, PHICH_MAX_NSYMB); } else { 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); + q->cell.nof_ports, PHICH_MAX_NSYMB); + layerdemap_diversity(x, q->phich_d0, q->cell.nof_ports, + PHICH_MAX_NSYMB / q->cell.nof_ports); } 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 (CP_ISEXT(q->cell.cp)) { if (ngroup % 2) { for (i = 0; i < PHICH_EXT_MSYMB / 2; i++) { q->phich_d[2 * i + 0] = q->phich_d0[4 * i + 2]; @@ -226,10 +233,10 @@ int phich_decode(phich_t *q, cf_t *slot_symbols, cf_t *ce[MAX_PORTS], if (VERBOSE_ISDEBUG()) vec_fprint_c(stdout, q->phich_d, PHICH_EXT_MSYMB); - scrambling_c(&q->seq_phich[nsubframe], q->phich_d); + scrambling_c(&q->seq_phich[subframe], q->phich_d); /* De-spreading */ - if (CP_ISEXT(q->cp)) { + if (CP_ISEXT(q->cell.cp)) { for (i = 0; i < PHICH_NBITS; i++) { q->phich_z[i] = 0; for (j = 0; j < PHICH_EXT_NSF; j++) { @@ -257,43 +264,48 @@ int phich_decode(phich_t *q, cf_t *slot_symbols, cf_t *ce[MAX_PORTS], *ack = phich_ack_decode(q->data, distance); } - return 0; + return LIBLTE_SUCCESS; } /** Encodes ACK/NACK bits, modulates and inserts into resource. * The parameter ack is an array of phich_ngroups() pointers to buffers of nof_sequences chars */ -int phich_encode(phich_t *q, char ack, int ngroup, int nseq, int nsubframe, +int phich_encode(phich_t *q, char ack, uint8_t ngroup, uint8_t nseq, uint8_t subframe, cf_t *slot_symbols[MAX_PORTS]) { int i; - if (nsubframe < 0 || nsubframe > NSUBFRAMES_X_FRAME) { - fprintf(stderr, "Invalid nslot %d\n", nsubframe); - return -1; + if (q == NULL || slot_symbols == NULL) { + return LIBLTE_ERROR_INVALID_INPUTS; } - if (CP_ISEXT(q->cp)) { - if (nseq < 0 || nseq > PHICH_EXT_NSEQUENCES) { + if (subframe >= NSUBFRAMES_X_FRAME) { + fprintf(stderr, "Invalid nslot %d\n", subframe); + return LIBLTE_ERROR_INVALID_INPUTS; + } + + if (CP_ISEXT(q->cell.cp)) { + if (nseq >= PHICH_EXT_NSEQUENCES) { fprintf(stderr, "Invalid nseq %d\n", nseq); - return -1; + return LIBLTE_ERROR_INVALID_INPUTS; } } else { - if (nseq < 0 || nseq > PHICH_NORM_NSEQUENCES) { + if (nseq >= PHICH_NORM_NSEQUENCES) { fprintf(stderr, "Invalid nseq %d\n", nseq); - return -1; + return LIBLTE_ERROR_INVALID_INPUTS; } } if (ngroup >= regs_phich_ngroups(q->regs)) { fprintf(stderr, "Invalid ngroup %d\n", ngroup); - return -1; + return LIBLTE_ERROR_INVALID_INPUTS; } + /* Set pointers for layermapping & precoding */ cf_t *x[MAX_LAYERS]; cf_t *symbols_precoding[MAX_PORTS]; /* number of layers equals number of ports */ - for (i = 0; i < q->nof_tx_ports; i++) { + for (i = 0; i < q->cell.nof_ports; i++) { x[i] = q->phich_x[i]; } for (i = 0; i < MAX_PORTS; i++) { @@ -310,7 +322,7 @@ int phich_encode(phich_t *q, char ack, int ngroup, int nseq, int nsubframe, vec_fprint_c(stdout, q->phich_z, PHICH_NBITS); /* Spread with w */ - if (CP_ISEXT(q->cp)) { + if (CP_ISEXT(q->cell.cp)) { for (i = 0; i < PHICH_EXT_MSYMB; i++) { q->phich_d[i] = w_ext[nseq][i % PHICH_EXT_NSF] * q->phich_z[i / PHICH_EXT_NSF]; @@ -326,10 +338,10 @@ int phich_encode(phich_t *q, char ack, int ngroup, int nseq, int nsubframe, if (VERBOSE_ISDEBUG()) vec_fprint_c(stdout, q->phich_d, PHICH_EXT_MSYMB); - scrambling_c(&q->seq_phich[nsubframe], q->phich_d); + scrambling_c(&q->seq_phich[subframe], q->phich_d); /* align to REG */ - if (CP_ISEXT(q->cp)) { + if (CP_ISEXT(q->cell.cp)) { if (ngroup % 2) { for (i = 0; i < PHICH_EXT_MSYMB / 2; i++) { q->phich_d0[4 * i + 0] = 0; @@ -354,24 +366,24 @@ int phich_encode(phich_t *q, char ack, int ngroup, int nseq, int nsubframe, vec_fprint_c(stdout, q->phich_d0, PHICH_MAX_NSYMB); /* layer mapping & precoding */ - if (q->nof_tx_ports > 1) { - layermap_diversity(q->phich_d0, x, q->nof_tx_ports, PHICH_MAX_NSYMB); - precoding_diversity(x, symbols_precoding, q->nof_tx_ports, - PHICH_MAX_NSYMB / q->nof_tx_ports); + if (q->cell.nof_ports > 1) { + layermap_diversity(q->phich_d0, x, q->cell.nof_ports, PHICH_MAX_NSYMB); + precoding_diversity(x, symbols_precoding, q->cell.nof_ports, + PHICH_MAX_NSYMB / q->cell.nof_ports); /**FIXME: According to 6.9.2, Precoding for 4 tx ports is different! */ } else { memcpy(q->phich_symbols[0], q->phich_d0, PHICH_MAX_NSYMB * sizeof(cf_t)); } /* mapping to resource elements */ - for (i = 0; i < q->nof_tx_ports; i++) { + for (i = 0; i < q->cell.nof_ports; i++) { 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; + return LIBLTE_ERROR; } } - return 0; + return LIBLTE_SUCCESS; } diff --git a/lte/phy/lib/phch/src/regs.c b/lte/phy/lib/phch/src/regs.c index ade13eaa5..50fe5e42a 100644 --- a/lte/phy/lib/phch/src/regs.c +++ b/lte/phy/lib/phch/src/regs.c @@ -34,7 +34,23 @@ #include "liblte/phy/phch/regs.h" #include "liblte/phy/utils/debug.h" -regs_reg_t *regs_find_reg(regs_t *h, int k, int l); +regs_reg_t *regs_find_reg(regs_t *h, uint16_t k, uint8_t l); +int regs_put_reg(regs_reg_t *reg, + cf_t *reg_data, + cf_t *slot_symbols, + uint8_t nof_prb); + +int regs_add_reg(regs_reg_t *reg, + cf_t *reg_data, + cf_t *slot_symbols, + uint8_t nof_prb); + +int regs_get_reg(regs_reg_t *reg, + cf_t *slot_symbols, + cf_t *reg_data, + uint8_t nof_prb); + +int regs_reset_reg(regs_reg_t *reg, cf_t *slot_symbols, uint8_t nof_prb); /*************************************************************** @@ -62,14 +78,14 @@ const unsigned char PDCCH_PERM[PDCCH_NCOLS] = */ int regs_pdcch_init(regs_t *h) { int i, m, cfi, nof_ctrl_symbols; - int ret = -1; + int ret = LIBLTE_ERROR; int nrows, ndummy, j, k, kp; regs_reg_t **tmp = NULL; bzero(&h->pdcch, sizeof(regs_ch_t)); for (cfi=0;cfi<3;cfi++) { - if (h->nof_prb < 10) { + if (h->cell.nof_prb < 10) { nof_ctrl_symbols = cfi+2; } else { nof_ctrl_symbols = cfi+1; @@ -110,7 +126,7 @@ int regs_pdcch_init(regs_t *h) { for (i = 0; i < nrows; i++) { if (i*PDCCH_NCOLS + PDCCH_PERM[j] >= ndummy) { m = i*PDCCH_NCOLS + PDCCH_PERM[j]-ndummy; - kp = (k-h->cell_id)%h->pdcch[cfi].nof_regs; + kp = (k-h->cell.id)%h->pdcch[cfi].nof_regs; if (kp < 0) { kp += h->pdcch[cfi].nof_regs; } @@ -124,23 +140,23 @@ int regs_pdcch_init(regs_t *h) { tmp = NULL; } - ret = 0; + ret = LIBLTE_SUCCESS; clean_and_exit: if (tmp) { free(tmp); } - if (ret == -1) { + if (ret == LIBLTE_ERROR) { regs_pdcch_free(h); } return ret; } -int regs_pdcch_nregs(regs_t *h, int cfi) { +int regs_pdcch_nregs(regs_t *h, uint8_t cfi) { if (cfi < 1 || cfi > 3) { fprintf(stderr, "Invalid CFI=%d\n", cfi); - return -1; + return LIBLTE_ERROR; } else { - return h->pdcch[cfi-1].nof_regs; + return (int) h->pdcch[cfi-1].nof_regs; } } @@ -148,25 +164,25 @@ int regs_pdcch_nregs(regs_t *h, int cfi) { * second part of 6.8.5 in 36.211 */ int regs_pdcch_put(regs_t *h, cf_t *pdcch_symbols, cf_t *slot_symbols) { - if (h->cfi == -1) { + if (!h->cfi_initiated) { fprintf(stderr, "Must call regs_set_cfi() first\n"); - return -1; + return LIBLTE_ERROR; } int i; for (i=0;ipdcch[h->cfi].nof_regs;i++) { - regs_put_reg(h->pdcch[h->cfi].regs[i], &pdcch_symbols[i*4], slot_symbols, h->nof_prb); + regs_put_reg(h->pdcch[h->cfi].regs[i], &pdcch_symbols[i*4], slot_symbols, h->cell.nof_prb); } return h->pdcch[h->cfi].nof_regs*4; } int regs_pdcch_get(regs_t *h, cf_t *slot_symbols, cf_t *pdcch_symbols) { - if (h->cfi == -1) { + if (!h->cfi_initiated) { fprintf(stderr, "Must call regs_set_cfi() first\n"); - return -1; + return LIBLTE_ERROR; } int i; for (i=0;ipdcch[h->cfi].nof_regs;i++) { - regs_get_reg(h->pdcch[h->cfi].regs[i], slot_symbols, &pdcch_symbols[i*4], h->nof_prb); + regs_get_reg(h->pdcch[h->cfi].regs[i], slot_symbols, &pdcch_symbols[i*4], h->cell.nof_prb); } return h->pdcch[h->cfi].nof_regs*4; } @@ -187,7 +203,7 @@ int regs_phich_init(regs_t *h) { float ng; int i,ni,li,n[3],nreg,mi; regs_reg_t **regs_phich[3]; - int ret = -1; + int ret = LIBLTE_ERROR; switch(h->phich_res) { case R_1_6: @@ -206,7 +222,7 @@ int regs_phich_init(regs_t *h) { ng = 0; break; } - h->ngroups_phich = (int) ceilf(ng * ((float) h->nof_prb/8)); + h->ngroups_phich = (int) ceilf(ng * ((float) h->cell.nof_prb/8)); h->phich = malloc(sizeof(regs_ch_t) * h->ngroups_phich); if (!h->phich) { perror("malloc"); @@ -255,7 +271,7 @@ int regs_phich_init(regs_t *h) { for (mi=0;mingroups_phich;mi++) { // here ngroups is the number of mapping units for (i=0;i<3;i++) { li=h->phich_len==PHICH_EXT?i:0; // Step 7 - ni=((h->cell_id*n[li]/n[0])+mi+i*n[li]/3) % n[li]; // Step 8 + ni=((h->cell.id*n[li]/n[0])+mi+i*n[li]/3) % n[li]; // Step 8 h->phich[mi].regs[i] = regs_phich[li][ni]; h->phich[mi].regs[i]->assigned = true; INFO("Assigned PHICH REG#%d (%d,%d)\n",nreg,h->phich[mi].regs[i]->k0,li); @@ -265,13 +281,13 @@ int regs_phich_init(regs_t *h) { // now the number of mapping units = number of groups for normal cp. For extended cp // ngroups = 2 * number mapping units - if (CP_ISEXT(h->cp)) { + if (CP_ISEXT(h->cell.cp)) { h->ngroups_phich *= 2; } - ret = 0; + ret = LIBLTE_SUCCESS; clean_and_exit: - if (ret == -1) { + if (ret == LIBLTE_ERROR) { if (h->phich) { for (i=0;ingroups_phich;i++) { if (h->phich[i].regs) { @@ -292,7 +308,7 @@ clean_and_exit: void regs_phich_free(regs_t *h) { int i; if (h->phich) { - if (CP_ISEXT(h->cp)) { + if (CP_ISEXT(h->cell.cp)) { h->ngroups_phich /= 2; } for (i=0;ingroups_phich;i++) { @@ -304,8 +320,9 @@ void regs_phich_free(regs_t *h) { } } -int regs_phich_nregs(regs_t *h) { - int i, n; +u_int16_t regs_phich_nregs(regs_t *h) { + int i; + u_int16_t n; n=0; for (i=0;ingroups_phich;i++) { n += h->phich[i].nof_regs; @@ -314,7 +331,7 @@ int regs_phich_nregs(regs_t *h) { } -int regs_phich_ngroups(regs_t *h) { +u_int8_t regs_phich_ngroups(regs_t *h) { return h->ngroups_phich; } @@ -325,18 +342,18 @@ int regs_phich_ngroups(regs_t *h) { * * Returns the number of written symbols, or -1 on error */ -int regs_phich_add(regs_t *h, cf_t phich_symbols[REGS_PHICH_NSYM], int ngroup, cf_t *slot_symbols) { +int regs_phich_add(regs_t *h, cf_t phich_symbols[REGS_PHICH_NSYM], u_int8_t ngroup, cf_t *slot_symbols) { int i; - if (ngroup < 0 || ngroup > h->ngroups_phich) { + if (ngroup >= h->ngroups_phich) { fprintf(stderr, "Error invalid ngroup %d\n", ngroup); - return -1; + return LIBLTE_ERROR_INVALID_INPUTS; } - if (CP_ISEXT(h->cp)) { + if (CP_ISEXT(h->cell.cp)) { ngroup /= 2; } regs_ch_t *rch = &h->phich[ngroup]; for (i = 0; i < rch->nof_regs && i*REGS_RE_X_REG < REGS_PHICH_NSYM; i++) { - regs_add_reg(rch->regs[i], &phich_symbols[i*REGS_RE_X_REG], slot_symbols, h->nof_prb); + regs_add_reg(rch->regs[i], &phich_symbols[i*REGS_RE_X_REG], slot_symbols, h->cell.nof_prb); } return i*REGS_RE_X_REG; } @@ -348,19 +365,19 @@ int regs_phich_add(regs_t *h, cf_t phich_symbols[REGS_PHICH_NSYM], int ngroup, c */ int regs_phich_reset(regs_t *h, cf_t *slot_symbols) { int i; - int ngroup, ng; - for (ngroup = 0;ngroup < h->ngroups_phich;CP_ISEXT(h->cp)?ngroup+=2:ngroup++) { - if (CP_ISEXT(h->cp)) { + u_int8_t ngroup, ng; + for (ngroup = 0;ngroup < h->ngroups_phich;CP_ISEXT(h->cell.cp)?ngroup+=2:ngroup++) { + if (CP_ISEXT(h->cell.cp)) { ng = ngroup/2; } else { ng = ngroup; } regs_ch_t *rch = &h->phich[ng]; for (i = 0; i < rch->nof_regs && i*REGS_RE_X_REG < REGS_PHICH_NSYM; i++) { - regs_reset_reg(rch->regs[i], slot_symbols, h->nof_prb); + regs_reset_reg(rch->regs[i], slot_symbols, h->cell.nof_prb); } } - return 0; + return LIBLTE_SUCCESS; } /** @@ -368,18 +385,18 @@ int regs_phich_reset(regs_t *h, cf_t *slot_symbols) { * * Returns the number of written symbols, or -1 on error */ -int regs_phich_get(regs_t *h, cf_t *slot_symbols, cf_t phich_symbols[REGS_PHICH_NSYM], int ngroup) { +int regs_phich_get(regs_t *h, cf_t *slot_symbols, cf_t phich_symbols[REGS_PHICH_NSYM], u_int8_t ngroup) { int i; - if (ngroup < 0 || ngroup > h->ngroups_phich) { + if (ngroup >= h->ngroups_phich) { fprintf(stderr, "Error invalid ngroup %d\n", ngroup); - return -1; + return LIBLTE_ERROR_INVALID_INPUTS; } - if (CP_ISEXT(h->cp)) { + if (CP_ISEXT(h->cell.cp)) { ngroup /= 2; } regs_ch_t *rch = &h->phich[ngroup]; for (i = 0; i < rch->nof_regs && i*REGS_RE_X_REG < REGS_PHICH_NSYM; i++) { - regs_get_reg(rch->regs[i], slot_symbols, &phich_symbols[i*REGS_RE_X_REG], h->nof_prb); + regs_get_reg(rch->regs[i], slot_symbols, &phich_symbols[i*REGS_RE_X_REG], h->cell.nof_prb); } return i*REGS_RE_X_REG; } @@ -404,39 +421,40 @@ int regs_phich_get(regs_t *h, cf_t *slot_symbols, cf_t phich_symbols[REGS_PHICH_ * 36.211 10.3 section 6.7.4 */ int regs_pcfich_init(regs_t *h) { - int i, k_hat, k; + int i; + uint16_t k_hat, k; regs_ch_t *ch = &h->pcfich; ch->regs = malloc(sizeof(regs_reg_t*) * REGS_PCFICH_NREGS); if (!ch->regs) { perror("malloc"); - return -1; + return LIBLTE_ERROR; } ch->nof_regs = REGS_PCFICH_NREGS; - INFO("PCFICH allocating %d regs. CellID: %d, PRB: %d\n", ch->nof_regs, h->cell_id, h->nof_prb); + INFO("PCFICH allocating %d regs. CellID: %d, PRB: %d\n", ch->nof_regs, h->cell.id, h->cell.nof_prb); - k_hat = (RE_X_RB / 2) * (h->cell_id % (2 * h->nof_prb)); + k_hat = (RE_X_RB / 2) * (h->cell.id % (2 * h->cell.nof_prb)); for (i = 0; i < REGS_PCFICH_NREGS; i++) { - k = (k_hat + (i * h->nof_prb / 2) * (RE_X_RB / 2)) - % (h->nof_prb * RE_X_RB); + k = (k_hat + (i * h->cell.nof_prb / 2) * (RE_X_RB / 2)) + % (h->cell.nof_prb * RE_X_RB); ch->regs[i] = regs_find_reg(h, k, 0); if (!ch->regs[i]) { fprintf(stderr, "Error allocating PCFICH: REG (%d,0) not found\n", k); - return -1; + return LIBLTE_ERROR; } else if (ch->regs[i]->assigned) { fprintf(stderr, "Error allocating PCFICH: REG (%d,0) already allocated\n", k); - return -1; + return LIBLTE_ERROR; } else { ch->regs[i]->assigned = true; INFO("Assigned PCFICH REG#%d (%d,0)\n", i, k); } } - return 0; + return LIBLTE_SUCCESS; } void regs_pcfich_free(regs_t *h) { @@ -445,7 +463,7 @@ void regs_pcfich_free(regs_t *h) { } } -int regs_pcfich_nregs(regs_t *h) { +uint16_t regs_pcfich_nregs(regs_t *h) { return h->pcfich.nof_regs; } @@ -459,7 +477,7 @@ int regs_pcfich_put(regs_t *h, cf_t pcfich_symbols[REGS_PCFICH_NSYM], cf_t *slot int i; for (i = 0; i < rch->nof_regs && i*REGS_RE_X_REG < REGS_PCFICH_NSYM; i++) { - regs_put_reg(rch->regs[i], &pcfich_symbols[i*REGS_RE_X_REG], slot_symbols, h->nof_prb); + regs_put_reg(rch->regs[i], &pcfich_symbols[i*REGS_RE_X_REG], slot_symbols, h->cell.nof_prb); } return i*REGS_RE_X_REG; } @@ -473,7 +491,7 @@ int regs_pcfich_get(regs_t *h, cf_t *slot_symbols, cf_t ch_data[REGS_PCFICH_NSYM regs_ch_t *rch = &h->pcfich; int i; for (i = 0; i < rch->nof_regs && i*REGS_RE_X_REG < REGS_PCFICH_NSYM; i++) { - regs_get_reg(rch->regs[i], slot_symbols, &ch_data[i*REGS_RE_X_REG], h->nof_prb); + regs_get_reg(rch->regs[i], slot_symbols, &ch_data[i*REGS_RE_X_REG], h->cell.nof_prb); } return i*REGS_RE_X_REG; } @@ -497,7 +515,7 @@ int regs_pcfich_get(regs_t *h, cf_t *slot_symbols, cf_t ch_data[REGS_PCFICH_NSYM * ***************************************************************/ -regs_reg_t *regs_find_reg(regs_t *h, int k, int l) { +regs_reg_t *regs_find_reg(regs_t *h, uint16_t k, uint8_t l) { int i; for (i=0;inof_regs;i++) { if (h->regs[i].l == l && h->regs[i].k0 == k) { @@ -511,7 +529,7 @@ regs_reg_t *regs_find_reg(regs_t *h, int k, int l) { * Returns the number of REGs in a PRB * 36.211 Section 6.2.4 */ -int regs_num_x_symbol(int symbol, int nof_port, lte_cp_t cp) { +int regs_num_x_symbol(uint8_t symbol, uint8_t nof_port, lte_cp_t cp) { switch (symbol) { case 0: @@ -524,7 +542,7 @@ int regs_num_x_symbol(int symbol, int nof_port, lte_cp_t cp) { case 4: return 2; default: - return -1; + return LIBLTE_ERROR; } break; case 2: @@ -536,7 +554,7 @@ int regs_num_x_symbol(int symbol, int nof_port, lte_cp_t cp) { return 2; } default: - return -1; + return LIBLTE_ERROR; } } @@ -544,7 +562,7 @@ int regs_num_x_symbol(int symbol, int nof_port, lte_cp_t cp) { * Initializes the indices of a REG * 36.211 Section 6.2.4 */ -int regs_reg_init(regs_reg_t *reg, int symbol, int nreg, int k0, int maxreg, int vo) { +int regs_reg_init(regs_reg_t *reg, uint8_t symbol, uint16_t nreg, uint16_t k0, uint8_t maxreg, uint8_t vo) { int i, j, z; reg->l = symbol; @@ -570,7 +588,7 @@ int regs_reg_init(regs_reg_t *reg, int symbol, int nreg, int k0, int maxreg, int } if (j != 4) { fprintf(stderr, "Something went wrong: expected 2 references\n"); - return -1; + return LIBLTE_ERROR; } break; @@ -583,9 +601,9 @@ int regs_reg_init(regs_reg_t *reg, int symbol, int nreg, int k0, int maxreg, int break; default: fprintf(stderr, "Invalid number of REGs per PRB: %d\n", maxreg); - return -1; + return LIBLTE_ERROR; } - return 0; + return LIBLTE_SUCCESS; } void regs_free(regs_t *h) { @@ -601,19 +619,20 @@ void regs_free(regs_t *h) { /** Sets the CFI value for this subframe (CFI must be in the range 1..3). */ -int regs_set_cfi(regs_t *h, int cfi) { +int regs_set_cfi(regs_t *h, uint8_t cfi) { if (cfi > 0 && cfi <= 3) { if (h->phich_len == PHICH_EXT && - ((h->nof_prb < 10 && cfi < 2) || (h->nof_prb >= 10 && cfi < 3))) { + ((h->cell.nof_prb < 10 && cfi < 2) || (h->cell.nof_prb >= 10 && cfi < 3))) { fprintf(stderr, "PHICH length is extended. The number of control symbols should be at least 3.\n"); - return -1; + return LIBLTE_ERROR_INVALID_INPUTS; } else { + h->cfi_initiated = true; h->cfi = cfi - 1; - return 0; + return LIBLTE_SUCCESS; } } else { fprintf(stderr, "Invalid CFI %d\n", cfi); - return -1; + return LIBLTE_ERROR_INVALID_INPUTS; } } @@ -622,84 +641,87 @@ int regs_set_cfi(regs_t *h, int cfi) { * Sets all REG indices and initializes PCFICH, PHICH and PDCCH REGs * Returns 0 if OK, -1 on error */ -int regs_init(regs_t *h, int cell_id, int nof_prb, int nof_ports, - phich_resources_t phich_res, phich_length_t phich_len, lte_cp_t cp) { - int ret = -1; - int i, j[4], jmax, n[4], prb, k; - int vo = cell_id % 3; - int max_ctrl_symbols = nof_prb<10?4:3; - - bzero(h, sizeof(regs_t)); - - h->cell_id = cell_id; - h->nof_prb = nof_prb; - h->max_ctrl_symbols = max_ctrl_symbols; - h->cfi = -1; // not yet initialized - h->phich_res = phich_res; - h->phich_len = phich_len; - h->cp = cp; - h->nof_ports = nof_ports; - - h->nof_regs = 0; - for (i = 0; i < max_ctrl_symbols; i++) { - n[i] = regs_num_x_symbol(i, nof_ports, cp); - if (n[i] == -1) { - return -1; - } - h->nof_regs += nof_prb * n[i]; - } - INFO("Indexing %d REGs. CellId: %d, %d PRB, CP: %s\n", h->nof_regs, h->cell_id, h->nof_prb, - CP_ISNORM(cp)?"Normal":"Extended"); - h->regs = malloc(sizeof(regs_reg_t) * h->nof_regs); - if (!h->regs) { - perror("malloc"); - goto clean_and_exit; - } +int regs_init(regs_t *h, phich_resources_t phich_res, phich_length_t phich_len, lte_cell_t cell) { + int ret = LIBLTE_ERROR_INVALID_INPUTS; + int i, k; + uint16_t j[4], jmax, prb; + uint8_t n[4], vo; + int max_ctrl_symbols; + + if (h != NULL && + lte_cell_isvalid(&cell)) + { + bzero(h, sizeof(regs_t)); + ret = LIBLTE_ERROR; + + max_ctrl_symbols = cell.nof_prb<10?4:3; + vo = cell.id % 3; + h->cell = cell; + h->max_ctrl_symbols = max_ctrl_symbols; + h->cfi_initiated = false; + h->phich_res = phich_res; + h->phich_len = phich_len; + + h->nof_regs = 0; + for (i = 0; i < max_ctrl_symbols; i++) { + n[i] = regs_num_x_symbol(i, h->cell.nof_ports, h->cell.cp); + if (n[i] == -1) { + return -1; + } + h->nof_regs += h->cell.nof_prb * n[i]; + } + INFO("Indexing %d REGs. CellId: %d, %d PRB, CP: %s\n", h->nof_regs, h->cell.id, h->cell.nof_prb, + CP_ISNORM(h->cell.cp)?"Normal":"Extended"); + h->regs = malloc(sizeof(regs_reg_t) * h->nof_regs); + if (!h->regs) { + perror("malloc"); + goto clean_and_exit; + } - /* Sort REGs according to PDCCH mapping, beggining from the lowest l index then k */ - bzero(j, sizeof(int) * 4); - k = i = prb = jmax = 0; - while (k < h->nof_regs) { - if (n[i] == 3 || (n[i] == 2 && jmax != 1)) { - if (regs_reg_init(&h->regs[k], i, j[i], prb * RE_X_RB, n[i], vo)) { - fprintf(stderr, "Error initializing REGs\n"); - goto clean_and_exit; + /* Sort REGs according to PDCCH mapping, beggining from the lowest l index then k */ + bzero(j, sizeof(int) * 4); + k = i = prb = jmax = 0; + while (k < h->nof_regs) { + if (n[i] == 3 || (n[i] == 2 && jmax != 1)) { + if (regs_reg_init(&h->regs[k], i, j[i], prb * RE_X_RB, n[i], vo)) { + fprintf(stderr, "Error initializing REGs\n"); + goto clean_and_exit; + } + /*DEBUG("Available REG #%3d: l=%d, prb=%d, nreg=%d (k0=%d)\n", k, i, prb, j[i], + h->regs[k].k0); + */ + j[i]++; + k++; } - /*DEBUG("Available REG #%3d: l=%d, prb=%d, nreg=%d (k0=%d)\n", k, i, prb, j[i], - h->regs[k].k0); - */ - j[i]++; - k++; + i++; + if (i == max_ctrl_symbols) { + i = 0; + jmax++; + } + if (jmax == 3) { + prb++; + bzero(j, sizeof(int) * 4); + jmax = 0; + } + } + if (regs_pcfich_init(h)) { + fprintf(stderr, "Error initializing PCFICH REGs\n"); + goto clean_and_exit; } - i++; - if (i == max_ctrl_symbols) { - i = 0; - jmax++; + + if (regs_phich_init(h)) { + fprintf(stderr, "Error initializing PHICH REGs\n"); + goto clean_and_exit; } - if (jmax == 3) { - prb++; - bzero(j, sizeof(int) * 4); - jmax = 0; + if (regs_pdcch_init(h)) { + fprintf(stderr, "Error initializing PDCCH REGs\n"); + goto clean_and_exit; } - } - if (regs_pcfich_init(h)) { - fprintf(stderr, "Error initializing PCFICH REGs\n"); - goto clean_and_exit; - } - if (regs_phich_init(h)) { - fprintf(stderr, "Error initializing PHICH REGs\n"); - goto clean_and_exit; + ret = LIBLTE_SUCCESS; } - if (regs_pdcch_init(h)) { - fprintf(stderr, "Error initializing PDCCH REGs\n"); - goto clean_and_exit; - } - - ret = 0; - clean_and_exit: - if (ret == -1) { + if (ret == LIBLTE_ERROR) { regs_free(h); } return ret; @@ -710,7 +732,7 @@ clean_and_exit: /** * Puts one REG data (4 symbols) in the slot symbols array */ -int regs_put_reg(regs_reg_t *reg, cf_t *reg_data, cf_t *slot_symbols, int nof_prb) { +int regs_put_reg(regs_reg_t *reg, cf_t *reg_data, cf_t *slot_symbols, uint8_t nof_prb) { int i; for (i = 0; i < REGS_RE_X_REG; i++) { slot_symbols[REG_IDX(reg, i, nof_prb)] = reg_data[i]; @@ -722,7 +744,7 @@ int regs_put_reg(regs_reg_t *reg, cf_t *reg_data, cf_t *slot_symbols, int nof_pr * Adds one REG data (4 symbols) in the slot symbols array * Used by PHICH */ -int regs_add_reg(regs_reg_t *reg, cf_t *reg_data, cf_t *slot_symbols, int nof_prb) { +int regs_add_reg(regs_reg_t *reg, cf_t *reg_data, cf_t *slot_symbols, uint8_t nof_prb) { int i; for (i = 0; i < REGS_RE_X_REG; i++) { slot_symbols[REG_IDX(reg, i, nof_prb)] += reg_data[i]; @@ -734,7 +756,7 @@ int regs_add_reg(regs_reg_t *reg, cf_t *reg_data, cf_t *slot_symbols, int nof_pr /** * Reset REG data (4 symbols) in the slot symbols array */ -int regs_reset_reg(regs_reg_t *reg, cf_t *slot_symbols, int nof_prb) { +int regs_reset_reg(regs_reg_t *reg, cf_t *slot_symbols, uint8_t nof_prb) { int i; for (i = 0; i < REGS_RE_X_REG; i++) { slot_symbols[REG_IDX(reg, i, nof_prb)] = 0; @@ -745,7 +767,7 @@ int regs_reset_reg(regs_reg_t *reg, cf_t *slot_symbols, int nof_prb) { /** * Gets one REG data (4 symbols) from the slot symbols array */ -int regs_get_reg(regs_reg_t *reg, cf_t *slot_symbols, cf_t *reg_data, int nof_prb) { +int regs_get_reg(regs_reg_t *reg, cf_t *slot_symbols, cf_t *reg_data, uint8_t nof_prb) { int i; for (i = 0; i < REGS_RE_X_REG; i++) { reg_data[i] = slot_symbols[REG_IDX(reg, i, nof_prb)]; @@ -753,3 +775,4 @@ int regs_get_reg(regs_reg_t *reg, cf_t *slot_symbols, cf_t *reg_data, int nof_pr return REGS_RE_X_REG; } + diff --git a/lte/phy/lib/phch/src/sequences.c b/lte/phy/lib/phch/src/sequences.c index 372179926..6a530dc5a 100644 --- a/lte/phy/lib/phch/src/sequences.c +++ b/lte/phy/lib/phch/src/sequences.c @@ -33,7 +33,7 @@ /** * 36.211 6.6.1 */ -int sequence_pbch(sequence_t *seq, lte_cp_t cp, int cell_id) { +int sequence_pbch(sequence_t *seq, lte_cp_t cp, uint16_t cell_id) { bzero(seq, sizeof(sequence_t)); return sequence_LTEPRS(seq, CP_ISNORM(cp)?1920:1728, cell_id); } @@ -41,7 +41,7 @@ int sequence_pbch(sequence_t *seq, lte_cp_t cp, int cell_id) { /** * 36.211 6.7.1 */ -int sequence_pcfich(sequence_t *seq, int nslot, int cell_id) { +int sequence_pcfich(sequence_t *seq, uint8_t nslot, uint16_t cell_id) { bzero(seq, sizeof(sequence_t)); return sequence_LTEPRS(seq, 32, (nslot/2+1) * (2*cell_id + 1) * 512 + cell_id); } @@ -50,7 +50,7 @@ int sequence_pcfich(sequence_t *seq, int nslot, int cell_id) { /** * 36.211 6.9.1 */ -int sequence_phich(sequence_t *seq, int nslot, int cell_id) { +int sequence_phich(sequence_t *seq, uint8_t nslot, uint16_t cell_id) { bzero(seq, sizeof(sequence_t)); return sequence_LTEPRS(seq, 12, (nslot/2+1) * (2*cell_id + 1) * 512 + cell_id); } @@ -58,7 +58,7 @@ int sequence_phich(sequence_t *seq, int nslot, int cell_id) { /** * 36.211 6.8.2 */ -int sequence_pdcch(sequence_t *seq, int nslot, int cell_id, int len) { +int sequence_pdcch(sequence_t *seq, uint8_t nslot, uint16_t cell_id, uint32_t len) { bzero(seq, sizeof(sequence_t)); return sequence_LTEPRS(seq, len, (nslot/2) * 512 + cell_id); } @@ -66,7 +66,7 @@ int sequence_pdcch(sequence_t *seq, int nslot, int cell_id, int len) { /** * 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); +int sequence_pdsch(sequence_t *seq, unsigned short rnti, int q, uint8_t nslot, uint16_t cell_id, uint32_t len) { + bzero(seq, sizeof(sequence_t)); + return sequence_LTEPRS(seq, len, (rnti<<14) + (q<<13) + ((nslot/2)<<9) + cell_id); } diff --git a/lte/phy/lib/phch/test/pbch_file_test.c b/lte/phy/lib/phch/test/pbch_file_test.c index a3fab332e..908af0ed7 100644 --- a/lte/phy/lib/phch/test/pbch_file_test.c +++ b/lte/phy/lib/phch/test/pbch_file_test.c @@ -35,13 +35,16 @@ char *input_file_name = NULL; char *matlab_file_name = NULL; -int cell_id = 150; -lte_cp_t cp = CPNORM; -int nof_prb = 6; FILE *fmatlab = NULL; -#define NOF_PORTS 2 +lte_cell_t cell = { + 6, // nof_prb + 2, // nof_ports + 150, // cell_id + CPNORM // cyclic prefix +}; + #define FLEN 9600 filesource_t fsrc; @@ -53,20 +56,22 @@ chest_t chest; void usage(char *prog) { printf("Usage: %s [vcoe] -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-c cell_id [Default %d]\n", cell.id); + printf("\t-n nof_prb [Default %d]\n", cell.nof_prb); 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, "iovce")) != -1) { switch(opt) { case 'i': input_file_name = argv[optind]; break; case 'c': - cell_id = atoi(argv[optind]); + cell.id = atoi(argv[optind]); break; case 'o': matlab_file_name = argv[optind]; @@ -75,7 +80,7 @@ void parse_args(int argc, char **argv) { verbose++; break; case 'e': - cp = CPEXT; + cell.cp = CPEXT; break; default: usage(argv[0]); @@ -112,36 +117,36 @@ int base_init() { exit(-1); } - fft_buffer = malloc(CP_NSYMB(cp) * nof_prb * RE_X_RB * sizeof(cf_t)); + fft_buffer = malloc(CP_NSYMB(cell.cp) * cell.nof_prb * RE_X_RB * sizeof(cf_t)); if (!fft_buffer) { perror("malloc"); return -1; } for (i=0;i 0) { slot_symbols[0][j] += slot_symbols[i][j]; @@ -190,7 +194,7 @@ int main(int argc, char **argv) { quit: pdsch_free(&pdsch); - for (i=0;i #include "liblte/phy/resampling/decim.h" +#include "liblte/phy/resampling/resample_arb.h" #include "liblte/phy/utils/debug.h" #include "liblte/phy/sync/sync_frame.h" @@ -59,6 +60,8 @@ int sync_frame_init(sync_frame_t *q, int downsampling) { perror("malloc"); goto clean_exit; } + + resample_arb_init(&q->resample, (float) 1/downsampling); q->downsampling = downsampling; sync_frame_reset(q); @@ -78,6 +81,7 @@ void sync_frame_free(sync_frame_t *q) { if (q->input_downsampled) { free(q->input_downsampled); } + cfo_free(&q->cfocorr); sync_free(&q->s); } @@ -183,6 +187,7 @@ int sync_frame_push(sync_frame_t *q, cf_t *input, cf_t *output) { if (q->downsampling == 1) { input_ds = input; } else { + //resample_arb_compute(&q->resample, input, q->input_downsampled, SYNC_SF_LEN * q->downsampling); decim_c(input, q->input_downsampled, q->downsampling, SYNC_SF_LEN * q->downsampling); input_ds = q->input_downsampled; } From 231c29ef211e134fe50aa44d0e4f3c1d36cc99f4 Mon Sep 17 00:00:00 2001 From: ismagom Date: Mon, 30 Jun 2014 00:44:39 +0200 Subject: [PATCH 03/14] Added lte_cell_t struct to PBCH module. --- lte/phy/examples/pbch_enodeb.c | 88 ++--- lte/phy/examples/pbch_ue.c | 15 +- lte/phy/examples/pdsch_enodeb.c | 71 ++-- lte/phy/examples/pdsch_ue.c | 22 +- lte/phy/examples/scan_mib.c | 4 +- lte/phy/include/liblte/phy/fec/crc.h | 3 +- lte/phy/include/liblte/phy/phch/pbch.h | 30 +- lte/phy/include/liblte/phy/phch/ra.h | 127 ++++--- lte/phy/include/liblte/phy/utils/bit.h | 2 +- lte/phy/lib/common/src/phy_common.c | 10 +- lte/phy/lib/fec/src/crc.c | 2 +- lte/phy/lib/phch/src/dci.c | 141 ++++---- lte/phy/lib/phch/src/pbch.c | 434 +++++++++++++----------- lte/phy/lib/phch/src/pdsch.c | 5 +- lte/phy/lib/phch/src/ra.c | 136 ++++---- lte/phy/lib/phch/test/pbch_file_test.c | 21 +- lte/phy/lib/phch/test/pbch_test.c | 48 +-- lte/phy/lib/phch/test/pdsch_file_test.c | 2 +- lte/phy/lib/phch/test/pdsch_re_test.c | 4 +- lte/phy/lib/phch/test/pdsch_test.c | 2 +- lte/phy/lib/utils/src/bit.c | 2 +- 21 files changed, 619 insertions(+), 550 deletions(-) diff --git a/lte/phy/examples/pbch_enodeb.c b/lte/phy/examples/pbch_enodeb.c index 7be23a2b7..529addfa8 100644 --- a/lte/phy/examples/pbch_enodeb.c +++ b/lte/phy/examples/pbch_enodeb.c @@ -38,10 +38,16 @@ void *uhd; #endif + +lte_cell_t cell = { + 6, // nof_prb + 1, // nof_ports + 1, // cell_id + CPNORM // cyclic prefix +}; + 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; @@ -51,7 +57,7 @@ lte_fft_t ifft; pbch_t pbch; cf_t *sf_buffer = NULL, *output_buffer = NULL; -int slot_n_re, slot_n_samples; +int sf_n_re, sf_n_samples; #define UHD_SAMP_FREQ 1920000 @@ -67,8 +73,8 @@ void usage(char *prog) { #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-c cell id [Default %d]\n", cell.id); + printf("\t-p nof_prb [Default %d]\n", cell.nof_prb); printf("\t-v [set verbose to debug, default none]\n"); } @@ -95,10 +101,10 @@ void parse_args(int argc, char **argv) { nof_frames = atoi(argv[optind]); break; case 'p': - nof_prb = atoi(argv[optind]); + cell.nof_prb = atoi(argv[optind]); break; case 'c': - cell_id = atoi(argv[optind]); + cell.id = atoi(argv[optind]); break; case 'v': verbose++; @@ -118,12 +124,12 @@ void parse_args(int argc, char **argv) { void base_init() { /* init memory */ - sf_buffer = malloc(sizeof(cf_t) * slot_n_re); + sf_buffer = malloc(sizeof(cf_t) * sf_n_re); if (!sf_buffer) { perror("malloc"); exit(-1); } - output_buffer = malloc(sizeof(cf_t) * slot_n_samples); + output_buffer = malloc(sizeof(cf_t) * sf_n_samples); if (!output_buffer) { perror("malloc"); exit(-1); @@ -148,11 +154,11 @@ void base_init() { } /* create ifft object */ - if (lte_ifft_init(&ifft, CPNORM, nof_prb)) { + if (lte_ifft_init(&ifft, CPNORM, cell.nof_prb)) { fprintf(stderr, "Error creating iFFT object\n"); exit(-1); } - if (pbch_init(&pbch, 6, cell_id, CPNORM)) { + if (pbch_init(&pbch, cell)) { fprintf(stderr, "Error creating PBCH object\n"); exit(-1); } @@ -180,14 +186,14 @@ void base_free() { } int main(int argc, char **argv) { - int nf, ns, N_id_2; + int nf, sf_idx, 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]; + int i, n; + cf_t *sf_symbols[MAX_PORTS]; #ifdef DISABLE_UHD @@ -199,20 +205,20 @@ int main(int argc, char **argv) { 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)); + N_id_2 = cell.id%3; + sf_n_re = 2 * CPNORM_NSYMB * cell.nof_prb * RE_X_RB; + sf_n_samples = 2 * SLOT_LEN_CPNORM(lte_symbol_sz(cell.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); + sss_generate(sss_signal0, sss_signal5, cell.id); /* Generate CRS signals */ lte_cell_t cell; - cell.id = cell_id; + cell.id = cell.id; cell.nof_prb = 6; cell.cp = CPNORM; cell.nof_ports = 1; @@ -224,14 +230,14 @@ int main(int argc, char **argv) { } } - mib.nof_ports = 1; - mib.nof_prb = 6; + mib.nof_ports = cell.nof_ports; + mib.nof_prb = cell.nof_prb; mib.phich_length = PHICH_NORM; mib.phich_resources = R_1; mib.sfn = 0; for (i=0;i typedef struct LIBLTE_API { unsigned long table[256]; @@ -45,6 +46,6 @@ typedef struct LIBLTE_API { LIBLTE_API int crc_init(crc_t *h, unsigned int crc_poly, int crc_order); LIBLTE_API int crc_set_init(crc_t *h, unsigned long crc_init_value); LIBLTE_API void crc_attach(crc_t *h, char *data, int len); -LIBLTE_API unsigned int crc_checksum(crc_t *h, char *data, int len); +LIBLTE_API uint32_t crc_checksum(crc_t *h, char *data, int len); #endif diff --git a/lte/phy/include/liblte/phy/phch/pbch.h b/lte/phy/include/liblte/phy/phch/pbch.h index ac96c2174..75ee56a42 100644 --- a/lte/phy/include/liblte/phy/phch/pbch.h +++ b/lte/phy/include/liblte/phy/phch/pbch.h @@ -47,19 +47,18 @@ typedef _Complex float cf_t; typedef struct LIBLTE_API { - int nof_ports; - int nof_prb; - int sfn; + uint8_t nof_ports; + uint8_t nof_prb; + uint32_t sfn; phich_length_t phich_length; phich_resources_t phich_resources; }pbch_mib_t; /* PBCH object */ typedef struct LIBLTE_API { - int cell_id; - lte_cp_t cp; - int nof_prb; - int nof_symbols; + lte_cell_t cell; + + uint8_t nof_symbols; /* buffers */ cf_t *ce[MAX_PORTS]; @@ -73,7 +72,7 @@ typedef struct LIBLTE_API { char *data; char *data_enc; - int frame_idx; + uint8_t frame_idx; /* tx & rx objects */ modem_table_t mod; @@ -83,23 +82,20 @@ typedef struct LIBLTE_API { crc_t crc; convcoder_t encoder; -}pbch_t; +} pbch_t; -LIBLTE_API int pbch_init(pbch_t *q, - int nof_prb, - int cell_id, - lte_cp_t cp); +LIBLTE_API int pbch_init(pbch_t *q, + lte_cell_t cell); LIBLTE_API void pbch_free(pbch_t *q); LIBLTE_API int pbch_decode(pbch_t *q, - cf_t *slot1_symbols, + cf_t *sf_symbols, cf_t *ce[MAX_PORTS], pbch_mib_t *mib); -LIBLTE_API void pbch_encode(pbch_t *q, +LIBLTE_API int pbch_encode(pbch_t *q, pbch_mib_t *mib, - cf_t *slot1_symbols[MAX_PORTS], - int nof_ports); + cf_t *sf_symbols[MAX_PORTS]); LIBLTE_API void pbch_decode_reset(pbch_t *q); diff --git a/lte/phy/include/liblte/phy/phch/ra.h b/lte/phy/include/liblte/phy/phch/ra.h index 4e94f277a..7581c4116 100644 --- a/lte/phy/include/liblte/phy/phch/ra.h +++ b/lte/phy/include/liblte/phy/phch/ra.h @@ -46,7 +46,7 @@ typedef struct LIBLTE_API { // 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 + uint32_t 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; @@ -64,9 +64,9 @@ typedef struct LIBLTE_API { } ra_type1_t; typedef struct LIBLTE_API { - uint32_t riv; // if L_crb==0, DCI message packer will take this value directly - uint16_t L_crb; - uint16_t RB_start; + uint16_t riv; // if L_crb==0, DCI message packer will take this value directly + uint8_t L_crb; + uint8_t RB_start; enum { nprb1a_2 = 0, nprb1a_3 = 1 } n_prb1a; @@ -79,7 +79,7 @@ typedef struct LIBLTE_API { } ra_type2_t; typedef struct LIBLTE_API { - unsigned short rnti; + uint16_t rnti; ra_type_t alloc_type; union { ra_type0_t type0_alloc; @@ -88,7 +88,8 @@ 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 { @@ -107,60 +108,108 @@ typedef struct LIBLTE_API { 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; + bool ndi; + bool cqi_request; } ra_pusch_t; typedef struct LIBLTE_API { - uint8_t prb_idx[110]; - int nof_prb; + uint8_t prb_idx[MAX_PRB]; + uint8_t nof_prb; } ra_prb_slot_t; typedef struct LIBLTE_API { ra_prb_slot_t slot[2]; - int lstart; - int re_sf[NSUBFRAMES_X_FRAME]; + uint8_t lstart; + uint16_t re_sf[NSUBFRAMES_X_FRAME]; } ra_prb_t; -LIBLTE_API void ra_prb_fprint(FILE *f, ra_prb_slot_t *prb); +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_prb_get_dl(ra_prb_t *prb, + ra_pdsch_t *ra, + uint8_t nof_prb); -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 int ra_prb_get_ul(ra_prb_slot_t *prb, + ra_pusch_t *ra, + uint8_t nof_prb); + +LIBLTE_API void ra_prb_get_re_dl(ra_prb_t *prb_dist, + uint8_t nof_prb, + uint8_t nof_ports, + uint8_t nof_ctrl_symbols, + lte_cp_t cp); + +LIBLTE_API uint16_t ra_nprb_dl(ra_pdsch_t *ra, + uint8_t nof_prb); + +LIBLTE_API uint16_t ra_nprb_ul(ra_pusch_t *ra, + uint8_t nof_prb); 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); -LIBLTE_API int ra_mcs_from_idx_ul(uint8_t idx, ra_mcs_t *mcs); + +LIBLTE_API int ra_mcs_from_idx_dl(uint8_t idx, + ra_mcs_t *mcs); + +LIBLTE_API int ra_mcs_from_idx_ul(uint8_t idx, + ra_mcs_t *mcs); + LIBLTE_API int ra_tbs_from_idx_format1c(uint8_t tbs_idx); -LIBLTE_API int ra_tbs_to_table_idx_format1c(int tbs); -LIBLTE_API int ra_tbs_from_idx(uint8_t tbs_idx, int n_prb); -LIBLTE_API int ra_tbs_to_table_idx(int tbs, int n_prb); + +LIBLTE_API int ra_tbs_to_table_idx_format1c(uint32_t tbs); + +LIBLTE_API int ra_tbs_from_idx(uint8_t tbs_idx, + uint8_t n_prb); + +LIBLTE_API int ra_tbs_to_table_idx(uint32_t tbs, + uint8_t n_prb); 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); -LIBLTE_API int ra_mcs_from_idx_ul(uint8_t idx, ra_mcs_t *mcs); + +LIBLTE_API int ra_mcs_from_idx_dl(uint8_t idx, + ra_mcs_t *mcs); + +LIBLTE_API int ra_mcs_from_idx_ul(uint8_t idx, + ra_mcs_t *mcs); LIBLTE_API char *ra_mod_string(ra_mod_t mod); -LIBLTE_API int ra_type0_P(int nof_prb); +LIBLTE_API uint8_t ra_type0_P(uint8_t nof_prb); + +LIBLTE_API uint16_t ra_type2_to_riv(uint8_t L_crb, + uint8_t RB_start, + uint8_t nof_prb); + +LIBLTE_API void ra_type2_from_riv(uint16_t riv, + uint8_t *L_crb, + uint8_t *RB_start, + uint8_t nof_prb, + uint8_t nof_vrb); + +LIBLTE_API uint8_t ra_type2_n_vrb_dl(uint8_t nof_prb, + bool ngap_is_1); + +LIBLTE_API uint8_t ra_type2_n_rb_step(uint8_t nof_prb); + +LIBLTE_API uint8_t ra_type2_ngap(uint8_t nof_prb, + bool ngap_is_1); + +LIBLTE_API uint8_t ra_type1_N_rb(uint8_t nof_prb); + +LIBLTE_API void ra_pdsch_set_mcs_index(ra_pdsch_t *ra, + uint8_t mcs_idx); + +LIBLTE_API void ra_pdsch_set_mcs(ra_pdsch_t *ra, + ra_mod_t mod, + uint8_t tbs_idx); -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 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); -LIBLTE_API int ra_type1_N_rb(int nof_prb); +LIBLTE_API void ra_pdsch_fprint(FILE *f, + ra_pdsch_t *ra, + uint8_t nof_prb); -LIBLTE_API void ra_pdsch_set_mcs_index(ra_pdsch_t *ra, uint8_t mcs_idx); -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); +LIBLTE_API void ra_pusch_fprint(FILE *f, + ra_pusch_t *ra, + uint8_t nof_prb); #endif /* RB_ALLOC_H_ */ diff --git a/lte/phy/include/liblte/phy/utils/bit.h b/lte/phy/include/liblte/phy/utils/bit.h index 7256b6d09..92a20a631 100644 --- a/lte/phy/include/liblte/phy/utils/bit.h +++ b/lte/phy/include/liblte/phy/utils/bit.h @@ -38,7 +38,7 @@ LIBLTE_API uint32_t bit_unpack(char **bits, int nof_bits); LIBLTE_API void bit_pack(uint32_t value, char **bits, int nof_bits); LIBLTE_API void bit_fprint(FILE *stream, char *bits, int nof_bits); LIBLTE_API unsigned int bit_diff(char *x, char *y, int nbits); -LIBLTE_API int bit_count(unsigned int n); +LIBLTE_API uint8_t bit_count(uint32_t n); #endif // BIT_ diff --git a/lte/phy/lib/common/src/phy_common.c b/lte/phy/lib/common/src/phy_common.c index f92306150..5cbdae6da 100644 --- a/lte/phy/lib/common/src/phy_common.c +++ b/lte/phy/lib/common/src/phy_common.c @@ -53,11 +53,11 @@ const int tc_cb_sizes[NOF_TC_CB_SIZES] = { 40, 48, 56, 64, 72, 80, 88, 96, 104, /* Returns true if the structure pointed by cell has valid parameters */ bool lte_cell_isvalid(lte_cell_t *cell) { - if (cell->id < 504 && - cell->nof_ports > 0 && - cell->nof_ports < 5 && - cell->nof_prb > 5 && - cell->nof_prb < 111 + if (cell->id < 504 && + cell->nof_ports > 0 && + cell->nof_ports < MAX_PORTS+1 && + cell->nof_prb > 5 && + cell->nof_prb < MAX_PRB+1 ) { return true; } else { diff --git a/lte/phy/lib/fec/src/crc.c b/lte/phy/lib/fec/src/crc.c index 00f74785c..c286c2f63 100644 --- a/lte/phy/lib/fec/src/crc.c +++ b/lte/phy/lib/fec/src/crc.c @@ -114,7 +114,7 @@ int crc_init(crc_t *h, unsigned int crc_poly, int crc_order) { return 0; } -unsigned int crc_checksum(crc_t *h, char *data, int len) { +uint32_t crc_checksum(crc_t *h, char *data, int len) { int i, k, len8, res8, a = 0; unsigned int crc = 0; char *pter; diff --git a/lte/phy/lib/phch/src/dci.c b/lte/phy/lib/phch/src/dci.c index d98426c64..bc1bcccd5 100644 --- a/lte/phy/lib/phch/src/dci.c +++ b/lte/phy/lib/phch/src/dci.c @@ -83,7 +83,7 @@ uint8_t riv_nbits(uint8_t nof_prb) { return (uint8_t) 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 uint8_t ambiguous_sizes[10] = { 12, 14, 16, 20, 24, 26, 32, 40, 44, 56 }; bool is_ambiguous_size(uint8_t size) { int i; @@ -115,7 +115,7 @@ uint8_t dci_format1A_sizeof(uint8_t nof_prb) { } uint8_t dci_format0_sizeof(uint8_t nof_prb) { - int n = dci_format0_sizeof_(nof_prb); + uint8_t n = dci_format0_sizeof_(nof_prb); while (n < dci_format1A_sizeof(nof_prb)) { n++; } @@ -137,9 +137,9 @@ uint8_t dci_format1_sizeof(uint8_t nof_prb) { } uint8_t dci_format1C_sizeof(uint8_t 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); - uint8_t n = +riv_nbits((uint8_t) n_vrb_dl_gap1 / n_step) + 5; + uint8_t n_vrb_dl_gap1 = ra_type2_n_vrb_dl(nof_prb, true); + uint8_t n_step = ra_type2_n_rb_step(nof_prb); + uint8_t n = riv_nbits((uint8_t) n_vrb_dl_gap1 / n_step) + 5; if (nof_prb >= 50) { n++; } @@ -174,7 +174,7 @@ int dci_format0_pack(ra_pusch_t *data, dci_msg_t *msg, uint8_t nof_prb) { /* pack bits */ char *y = msg->data; - int n_ul_hop; + uint8_t n_ul_hop; *y++ = 0; // format differentiation if (data->freq_hop_fl == hop_disabled) { // frequency hopping @@ -193,17 +193,17 @@ int dci_format0_pack(ra_pusch_t *data, dci_msg_t *msg, uint8_t nof_prb) { } /* pack RIV according to 8.1 of 36.213 */ - uint32_t riv; + uint16_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); } else { riv = data->type2_alloc.riv; } - bit_pack(riv, &y, riv_nbits(nof_prb) - n_ul_hop); + bit_pack((uint32_t) riv, &y, riv_nbits(nof_prb) - n_ul_hop); /* pack MCS according to 8.6.1 of 36.213 */ - uint32_t mcs; + uint8_t mcs; if (data->cqi_request) { mcs = 29; } else { @@ -224,7 +224,7 @@ int dci_format0_pack(ra_pusch_t *data, dci_msg_t *msg, uint8_t nof_prb) { } } - bit_pack(mcs, &y, 5); + bit_pack((uint32_t) mcs, &y, 5); *y++ = data->ndi; @@ -241,7 +241,7 @@ int dci_format0_pack(ra_pusch_t *data, dci_msg_t *msg, uint8_t nof_prb) { *y++ = data->cqi_request; // Padding with zeros - int n = dci_format0_sizeof(nof_prb); + uint8_t n = dci_format0_sizeof(nof_prb); while (y - msg->data < n) { *y++ = 0; } @@ -257,7 +257,7 @@ int dci_format0_unpack(dci_msg_t *msg, ra_pusch_t *data, uint8_t nof_prb) { /* pack bits */ char *y = msg->data; - int n_ul_hop; + uint8_t n_ul_hop; /* Make sure it's a Format0 message */ if (msg->location.nof_bits != dci_format_sizeof(Format0, nof_prb)) { @@ -283,14 +283,14 @@ int dci_format0_unpack(dci_msg_t *msg, ra_pusch_t *data, uint8_t nof_prb) { } } /* unpack RIV according to 8.1 of 36.213 */ - uint32_t riv = bit_unpack(&y, riv_nbits(nof_prb) - n_ul_hop); + uint16_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); - bit_pack(riv, &y, riv_nbits(nof_prb) - n_ul_hop); + bit_pack((uint32_t) 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); + uint8_t mcs = bit_unpack(&y, 5); data->ndi = *y++ ? true : false; @@ -336,16 +336,16 @@ int dci_format1_pack(ra_pdsch_t *data, dci_msg_t *msg, uint8_t nof_prb) { } /* Resource allocation: type0 or type 1 */ - int P = ra_type0_P(nof_prb); - int alloc_size = (int) ceilf((float) nof_prb / P); + uint8_t P = ra_type0_P(nof_prb); + uint8_t alloc_size = (uint8_t) ceilf((float) nof_prb / P); switch (data->alloc_type) { case alloc_type0: - bit_pack(data->type0_alloc.rbg_bitmask, &y, alloc_size); + bit_pack((uint32_t) data->type0_alloc.rbg_bitmask, &y, alloc_size); break; case alloc_type1: - bit_pack(data->type1_alloc.rbg_subset, &y, (int) ceilf(log2f(P))); + bit_pack((uint32_t) 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, + bit_pack((uint32_t) data->type1_alloc.vrb_bitmask, &y, alloc_size - (int) ceilf(log2f(P)) - 1); break; default: @@ -355,7 +355,7 @@ int dci_format1_pack(ra_pdsch_t *data, dci_msg_t *msg, uint8_t nof_prb) { } /* pack MCS according to 7.1.7 of 36.213 */ - uint32_t mcs; + uint8_t mcs; if (data->mcs.mod == MOD_NULL) { mcs = data->mcs.mcs_idx; } else { @@ -366,22 +366,22 @@ int dci_format1_pack(ra_pdsch_t *data, dci_msg_t *msg, uint8_t nof_prb) { mcs = ra_mcs_to_table_idx(&data->mcs); data->mcs.mcs_idx = mcs; } - bit_pack(mcs, &y, 5); + bit_pack((uint32_t) mcs, &y, 5); /* harq process number */ - bit_pack(data->harq_process, &y, 3); + bit_pack((uint32_t) data->harq_process, &y, 3); *y++ = data->ndi; // rv version - bit_pack(data->rv_idx, &y, 2); + bit_pack((uint32_t) data->rv_idx, &y, 2); // TPC not implemented *y++ = 0; *y++ = 0; // Padding with zeros - int n = dci_format1_sizeof(nof_prb); + uint8_t n = dci_format1_sizeof(nof_prb); while (y - msg->data < n) { *y++ = 0; } @@ -409,7 +409,7 @@ int dci_format1_unpack(dci_msg_t *msg, ra_pdsch_t *data, uint8_t nof_prb) { /* Resource allocation: type0 or type 1 */ uint8_t P = ra_type0_P(nof_prb); - int alloc_size = (int) ceilf((float) nof_prb / P); + uint8_t alloc_size = (uint8_t) ceilf((float) nof_prb / P); switch (data->alloc_type) { case alloc_type0: data->type0_alloc.rbg_bitmask = bit_unpack(&y, alloc_size); @@ -421,16 +421,24 @@ int dci_format1_unpack(dci_msg_t *msg, ra_pdsch_t *data, uint8_t nof_prb) { 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 LIBLTE_ERROR; } /* unpack MCS according to 7.1.7 of 36.213 */ - uint32_t mcs = bit_unpack(&y, 5); + uint8_t mcs = bit_unpack(&y, 5); data->mcs.mcs_idx = mcs; - ra_mcs_from_idx_dl(mcs, &data->mcs); - data->mcs.tbs = ra_tbs_from_idx(data->mcs.tbs_idx, ra_nprb_dl(data, nof_prb)); + if (ra_mcs_from_idx_dl(mcs, &data->mcs)) { + fprintf(stderr, "Error getting MCS\n"); + return LIBLTE_ERROR; + } + + int t = ra_tbs_from_idx(data->mcs.tbs_idx, ra_nprb_dl(data, nof_prb)); + if (t < 0) { + fprintf(stderr, "Error getting TBS\n"); + return LIBLTE_ERROR; + } + data->mcs.tbs = (uint32_t) t; /* harq process number */ data->harq_process = bit_unpack(&y, 3); @@ -471,7 +479,7 @@ int dci_format1As_pack(ra_pdsch_t *data, dci_msg_t *msg, uint8_t nof_prb, return LIBLTE_ERROR; } } else { - int n_vrb_dl; + uint8_t n_vrb_dl; if (crc_is_crnti && nof_prb > 50) { n_vrb_dl = 16; } else { @@ -485,28 +493,28 @@ int dci_format1As_pack(ra_pdsch_t *data, dci_msg_t *msg, uint8_t nof_prb, } } /* pack RIV according to 7.1.6.3 of 36.213 */ - uint32_t riv; + uint16_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); } else { riv = data->type2_alloc.riv; } - int nb_gap = 0; + uint8_t nb_gap = 0; if (crc_is_crnti && data->type2_alloc.mode == t2_dist && nof_prb >= 50) { nb_gap = 1; *y++ = data->type2_alloc.n_gap; } - bit_pack(riv, &y, riv_nbits(nof_prb) - nb_gap); + bit_pack((uint32_t) riv, &y, riv_nbits(nof_prb) - nb_gap); // in format1A, MCS = TBS according to 7.1.7.2 of 36.213 - uint32_t mcs; + uint8_t mcs; if (data->mcs.mod == MOD_NULL) { mcs = data->mcs.mcs_idx; } else { if (data->mcs.tbs) { // In format 1A, n_prb_1a is 2 or 3 if crc is not scrambled with C-RNTI - int n_prb; + uint8_t n_prb; if (!crc_is_crnti) { n_prb = ra_nprb_dl(data, nof_prb); } else { @@ -516,9 +524,9 @@ int dci_format1As_pack(ra_pdsch_t *data, dci_msg_t *msg, uint8_t nof_prb, } mcs = data->mcs.tbs_idx; } - bit_pack(mcs, &y, 5); + bit_pack((uint32_t) mcs, &y, 5); - bit_pack(data->harq_process, &y, 3); + bit_pack((uint32_t) data->harq_process, &y, 3); if (!crc_is_crnti && nof_prb >= 50 && data->type2_alloc.mode == t2_dist) { *y++ = data->type2_alloc.n_gap; @@ -527,7 +535,7 @@ int dci_format1As_pack(ra_pdsch_t *data, dci_msg_t *msg, uint8_t nof_prb, } // rv version - bit_pack(data->rv_idx, &y, 2); + bit_pack((uint32_t) data->rv_idx, &y, 2); if (crc_is_crnti) { // TPC not implemented @@ -539,7 +547,7 @@ int dci_format1As_pack(ra_pdsch_t *data, dci_msg_t *msg, uint8_t nof_prb, } // Padding with zeros - int n = dci_format1A_sizeof(nof_prb); + uint8_t n = dci_format1A_sizeof(nof_prb); while (y - msg->data < n) { *y++ = 0; } @@ -564,8 +572,7 @@ int dci_format1As_unpack(dci_msg_t *msg, ra_pdsch_t *data, uint8_t nof_prb, } 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 LIBLTE_ERROR; } @@ -576,18 +583,18 @@ int dci_format1As_unpack(dci_msg_t *msg, ra_pdsch_t *data, uint8_t nof_prb, data->type2_alloc.n_gap = t2_ng1; /* unpack RIV according to 7.1.6.3 of 36.213 */ - int nb_gap = 0; + uint8_t nb_gap = 0; if (crc_is_crnti && data->type2_alloc.mode == t2_dist && nof_prb >= 50) { nb_gap = 1; data->type2_alloc.n_gap = *y++; } - int nof_vrb; + uint8_t nof_vrb; if (data->type2_alloc.mode == t2_loc) { nof_vrb = nof_prb; } else { 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); + uint16_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); data->type2_alloc.riv = riv; @@ -604,7 +611,7 @@ int dci_format1As_unpack(dci_msg_t *msg, ra_pdsch_t *data, uint8_t nof_prb, } // rv version - bit_pack(data->rv_idx, &y, 2); + bit_pack((uint32_t) data->rv_idx, &y, 2); if (crc_is_crnti) { // TPC not implemented @@ -615,7 +622,8 @@ int dci_format1As_unpack(dci_msg_t *msg, ra_pdsch_t *data, uint8_t nof_prb, data->type2_alloc.n_prb1a = *y++; // LSB indicates N_prb_1a for TBS } data->mcs.tbs_idx = data->mcs.mcs_idx; - int n_prb; + + uint8_t n_prb; if (crc_is_crnti) { n_prb = ra_nprb_dl(data, nof_prb); } else { @@ -644,13 +652,12 @@ int dci_format1Cs_pack(ra_pdsch_t *data, dci_msg_t *msg, uint8_t nof_prb) { if (nof_prb >= 50) { *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); + uint8_t n_step = ra_type2_n_rb_step(nof_prb); + uint8_t 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 > ((uint8_t) 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, ((uint8_t) n_vrb_dl / n_step) * n_step); return LIBLTE_ERROR; } if (data->type2_alloc.L_crb % n_step) { @@ -661,20 +668,20 @@ int dci_format1Cs_pack(ra_pdsch_t *data, dci_msg_t *msg, uint8_t nof_prb) { fprintf(stderr, "RB_start must be multiple of n_step\n"); return LIBLTE_ERROR; } - 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; + uint8_t L_p = data->type2_alloc.L_crb / n_step; + uint8_t RB_p = data->type2_alloc.RB_start / n_step; + uint8_t n_vrb_p = (int) n_vrb_dl / n_step; - uint32_t riv; + uint16_t riv; if (data->type2_alloc.L_crb) { riv = ra_type2_to_riv(L_p, RB_p, n_vrb_p); } else { riv = data->type2_alloc.riv; } - bit_pack(riv, &y, riv_nbits((int) n_vrb_dl / n_step)); + bit_pack((uint32_t) 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; + uint8_t mcs; if (data->mcs.mod == MOD_NULL) { mcs = data->mcs.mcs_idx; } else { @@ -683,7 +690,7 @@ int dci_format1Cs_pack(ra_pdsch_t *data, dci_msg_t *msg, uint8_t nof_prb) { } mcs = data->mcs.tbs_idx; } - bit_pack(mcs, &y, 5); + bit_pack((uint32_t) mcs, &y, 5); msg->location.nof_bits = (y - msg->data); @@ -691,7 +698,7 @@ int dci_format1Cs_pack(ra_pdsch_t *data, dci_msg_t *msg, uint8_t nof_prb) { } int dci_format1Cs_unpack(dci_msg_t *msg, ra_pdsch_t *data, uint8_t nof_prb) { - uint16_t L_p, RB_p; + uint8_t L_p, RB_p; /* pack bits */ char *y = msg->data; @@ -705,11 +712,11 @@ int dci_format1Cs_unpack(dci_msg_t *msg, ra_pdsch_t *data, uint8_t nof_prb) { if (nof_prb >= 50) { 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); + uint8_t n_step = ra_type2_n_rb_step(nof_prb); + uint8_t 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)); - int n_vrb_p = (int) n_vrb_dl / n_step; + uint16_t riv = bit_unpack(&y, riv_nbits((int) n_vrb_dl / n_step)); + uint8_t n_vrb_p = (uint8_t) n_vrb_dl / n_step; ra_type2_from_riv(riv, &L_p, &RB_p, n_vrb_p, n_vrb_p); data->type2_alloc.L_crb = L_p * n_step; @@ -800,7 +807,7 @@ void dci_msg_type_fprint(FILE *f, dci_msg_type_t type) { } int dci_msg_get_type(dci_msg_t *msg, dci_msg_type_t *type, uint8_t nof_prb, - unsigned short crnti) { + uint16_t crnti) { if (msg->location.nof_bits == dci_format_sizeof(Format0, nof_prb) && !msg->data[0]) { type->type = PUSCH_SCHED; diff --git a/lte/phy/lib/phch/src/pbch.c b/lte/phy/lib/phch/src/pbch.c index 0b7e384ba..caca9061c 100644 --- a/lte/phy/lib/phch/src/pbch.c +++ b/lte/phy/lib/phch/src/pbch.c @@ -50,47 +50,45 @@ 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, lte_cell_t cell, bool put) { int i; cf_t *ptr; - assert(cell_id >= 0); if (put) { ptr = input; - output += nof_prb * RE_X_RB / 2 - 36; + output += cell.nof_prb * RE_X_RB / 2 - 36; } else { ptr = output; - input += nof_prb * RE_X_RB / 2 - 36; + input += cell.nof_prb * RE_X_RB / 2 - 36; } /* symbol 0 & 1 */ for (i = 0; i < 2; i++) { - prb_cp_ref(&input, &output, cell_id % 3, 4, 4*6, put); + prb_cp_ref(&input, &output, cell.id % 3, 4, 4*6, put); if (put) { - output += nof_prb * RE_X_RB - 2*36; + output += cell.nof_prb * RE_X_RB - 2*36; } else { - input += nof_prb * RE_X_RB - 2*36; + input += cell.nof_prb * RE_X_RB - 2*36; } } /* symbols 2 & 3 */ - if (CP_ISNORM(cp)) { + if (CP_ISNORM(cell.cp)) { for (i = 0; i < 2; i++) { prb_cp(&input, &output, 6); if (put) { - output += nof_prb * RE_X_RB - 2*36; + output += cell.nof_prb * RE_X_RB - 2*36; } else { - input += nof_prb * RE_X_RB - 2*36; + input += cell.nof_prb * RE_X_RB - 2*36; } } } else { prb_cp(&input, &output, 6); if (put) { - output += nof_prb * RE_X_RB - 2*36; + output += cell.nof_prb * RE_X_RB - 2*36; } else { - input += nof_prb * RE_X_RB - 2*36; + input += cell.nof_prb * RE_X_RB - 2*36; } - prb_cp_ref(&input, &output, cell_id % 3, 4, 4*6, put); + prb_cp_ref(&input, &output, cell.id % 3, 4, 4*6, put); } if (put) { return input - ptr; @@ -106,9 +104,8 @@ int pbch_cp(cf_t *input, cf_t *output, int nof_prb, lte_cp_t cp, int cell_id, * * 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) { - return pbch_cp(pbch, slot1_data, nof_prb, cp, cell_id, true); +int pbch_put(cf_t *pbch, cf_t *slot1_data, lte_cell_t cell) { + return pbch_cp(pbch, slot1_data, cell, true); } /** @@ -118,92 +115,96 @@ int pbch_put(cf_t *pbch, cf_t *slot1_data, int nof_prb, lte_cp_t cp, * * 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) { - return pbch_cp(slot1_data, pbch, nof_prb, cp, cell_id, false); +int pbch_get(cf_t *slot1_data, cf_t *pbch, lte_cell_t cell) { + return pbch_cp(slot1_data, pbch, cell, false); } -/** Initializes the PBCH transmitter and receiver */ -int pbch_init(pbch_t *q, int nof_prb, int cell_id, lte_cp_t cp) { - int ret = -1; - if (cell_id < 0) { - return -1; - } - bzero(q, sizeof(pbch_t)); - q->cell_id = cell_id; - q->cp = cp; - q->nof_prb = nof_prb; +/** Initializes the PBCH transmitter and receiver. + * At the receiver, the field nof_ports in the cell structure indicates the + * maximum number of BS transmitter ports to look for. + */ +int pbch_init(pbch_t *q, lte_cell_t cell) { + int ret = LIBLTE_ERROR_INVALID_INPUTS; - if (modem_table_std(&q->mod, LTE_QPSK, true)) { - goto clean; - } - demod_soft_init(&q->demod); - demod_soft_table_set(&q->demod, &q->mod); - demod_soft_alg_set(&q->demod, APPROX); - if (sequence_pbch(&q->seq_pbch, q->cp, q->cell_id)) { - goto clean; - } + if (q != NULL && + lte_cell_isvalid(&cell)) + { + ret = LIBLTE_ERROR; - int poly[3] = { 0x6D, 0x4F, 0x57 }; - if (viterbi_init(&q->decoder, viterbi_37, poly, 40, true)) { - goto clean; - } - if (crc_init(&q->crc, LTE_CRC16, 16)) { - goto clean; - } - q->encoder.K = 7; - q->encoder.R = 3; - q->encoder.tail_biting = true; - memcpy(q->encoder.poly, poly, 3 * sizeof(int)); + bzero(q, sizeof(pbch_t)); + q->cell = cell; - q->nof_symbols = (CP_ISNORM(q->cp)) ? PBCH_RE_CPNORM : PBCH_RE_CPEXT; + if (modem_table_std(&q->mod, LTE_QPSK, true)) { + goto clean; + } + demod_soft_init(&q->demod); + demod_soft_table_set(&q->demod, &q->mod); + demod_soft_alg_set(&q->demod, APPROX); + if (sequence_pbch(&q->seq_pbch, q->cell.cp, q->cell.id)) { + goto clean; + } - q->pbch_d = malloc(sizeof(cf_t) * q->nof_symbols); - if (!q->pbch_d) { - goto clean; - } - int i; - for (i = 0; i < MAX_PORTS; i++) { - q->ce[i] = malloc(sizeof(cf_t) * q->nof_symbols); - if (!q->ce[i]) { + int poly[3] = { 0x6D, 0x4F, 0x57 }; + if (viterbi_init(&q->decoder, viterbi_37, poly, 40, true)) { goto clean; } - q->pbch_x[i] = malloc(sizeof(cf_t) * q->nof_symbols); - if (!q->pbch_x[i]) { + if (crc_init(&q->crc, LTE_CRC16, 16)) { goto clean; } - q->pbch_symbols[i] = malloc(sizeof(cf_t) * q->nof_symbols); - if (!q->pbch_symbols[i]) { + q->encoder.K = 7; + q->encoder.R = 3; + q->encoder.tail_biting = true; + memcpy(q->encoder.poly, poly, 3 * sizeof(int)); + + q->nof_symbols = (CP_ISNORM(q->cell.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; i < q->cell.nof_ports; i++) { + q->ce[i] = malloc(sizeof(cf_t) * q->nof_symbols); + if (!q->ce[i]) { + goto clean; + } + q->pbch_x[i] = malloc(sizeof(cf_t) * q->nof_symbols); + if (!q->pbch_x[i]) { + goto clean; + } + q->pbch_symbols[i] = malloc(sizeof(cf_t) * q->nof_symbols); + if (!q->pbch_symbols[i]) { + goto clean; + } + } + q->pbch_llr = malloc(sizeof(float) * q->nof_symbols * 4 * 2); + if (!q->pbch_llr) { + goto clean; + } + q->temp = malloc(sizeof(float) * q->nof_symbols * 4 * 2); + if (!q->temp) { + goto clean; + } + q->pbch_rm_f = malloc(sizeof(float) * 120); + if (!q->pbch_rm_f) { + goto clean; + } + q->pbch_rm_b = malloc(sizeof(float) * q->nof_symbols * 4 * 2); + if (!q->pbch_rm_b) { + goto clean; + } + q->data = malloc(sizeof(char) * 40); + if (!q->data) { + goto clean; + } + q->data_enc = malloc(sizeof(char) * 120); + if (!q->data_enc) { + goto clean; + } + ret = LIBLTE_SUCCESS; } - q->pbch_llr = malloc(sizeof(float) * q->nof_symbols * 4 * 2); - if (!q->pbch_llr) { - goto clean; - } - q->temp = malloc(sizeof(float) * q->nof_symbols * 4 * 2); - if (!q->temp) { - goto clean; - } - q->pbch_rm_f = malloc(sizeof(float) * 120); - if (!q->pbch_rm_f) { - goto clean; - } - q->pbch_rm_b = malloc(sizeof(float) * q->nof_symbols * 4 * 2); - if (!q->pbch_rm_b) { - goto clean; - } - q->data = malloc(sizeof(char) * 40); - if (!q->data) { - goto clean; - } - q->data_enc = malloc(sizeof(char) * 120); - if (!q->data_enc) { - goto clean; - } - - ret = 0; - clean: if (ret == -1) { +clean: + if (ret == LIBLTE_ERROR) { pbch_free(q); } return ret; @@ -214,7 +215,7 @@ void pbch_free(pbch_t *q) { free(q->pbch_d); } int i; - for (i = 0; i < MAX_PORTS; i++) { + for (i = 0; i < q->cell.nof_ports; i++) { if (q->ce[i]) { free(q->ce[i]); } @@ -371,15 +372,15 @@ void crc_set_mask(char *data, int nof_ports) { * * Returns 0 if the data is correct, -1 otherwise */ -int pbch_crc_check(pbch_t *q, char *bits, int nof_ports) { +uint32_t pbch_crc_check(pbch_t *q, char *bits, uint8_t nof_ports) { char data[40]; memcpy(data, bits, 40 * sizeof(char)); crc_set_mask(data, 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, uint8_t src, uint8_t dst, uint8_t n, + uint16_t nof_bits, uint8_t nof_ports) { int j; memcpy(&q->temp[dst * nof_bits], &q->pbch_llr[src * nof_bits], @@ -433,149 +434,178 @@ int pbch_decode_frame(pbch_t *q, pbch_mib_t *mib, int src, int dst, int n, /* Decodes the PBCH channel * * The PBCH spans in 40 ms. This function is called every 10 ms. It tries to decode the MIB - * given the symbols of the slot #1 of each radio frame. Successive calls will use more frames + * given the symbols of a subframe (1 ms). Successive calls will use more subframes * to help the decoding process. * * 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], pbch_mib_t *mib) { - int src, dst, res, nb; - int nant_[3] = { 1, 2, 4 }; - int na, nant; - - /* Set pointers for layermapping & precoding */ +int pbch_decode(pbch_t *q, cf_t *sf_symbols, cf_t *ce[MAX_PORTS], pbch_mib_t *mib) { + uint8_t src, dst, nb; + uint8_t nant_[3] = { 1, 2, 4 }; + uint8_t na, nant; + cf_t *slot1_symbols; int i; - int nof_bits = 2 * q->nof_symbols; + int nof_bits; cf_t *x[MAX_LAYERS]; + cf_t *ce_slot[MAX_PORTS]; + + int ret = LIBLTE_ERROR_INVALID_INPUTS; + + if (q != NULL && + sf_symbols != NULL && + mib != NULL) + { + for (i=0;icell.nof_ports;i++) { + if (ce[i] == NULL) { + return LIBLTE_ERROR_INVALID_INPUTS; + } else { + ce_slot[i] = &ce[i][q->cell.nof_prb * RE_X_RB * CP_NSYMB(q->cell.cp)]; + } + } + slot1_symbols = &sf_symbols[q->cell.nof_prb * RE_X_RB * CP_NSYMB(q->cell.cp)]; - /* number of layers equals number of ports */ - for (i = 0; i < MAX_PORTS; i++) { - x[i] = q->pbch_x[i]; - } - memset(&x[MAX_PORTS], 0, sizeof(cf_t*) * (MAX_LAYERS - MAX_PORTS)); - - /* extract symbols */ - 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; - } + /* Set pointers for layermapping & precoding */ + nof_bits = 2 * q->nof_symbols; - /* extract channel estimates */ - for (i = 0; i < MAX_PORTS; i++) { - if (q->nof_symbols - != pbch_get(ce[i], q->ce[i], q->nof_prb, q->cp, q->cell_id)) { + /* number of layers equals number of ports */ + for (i = 0; i < MAX_PORTS; i++) { + x[i] = q->pbch_x[i]; + } + memset(&x[MAX_PORTS], 0, sizeof(cf_t*) * (MAX_LAYERS - MAX_PORTS)); + + /* extract symbols */ + if (q->nof_symbols != pbch_get(slot1_symbols, q->pbch_symbols[0], q->cell)) { fprintf(stderr, "There was an error getting the PBCH symbols\n"); - return -1; + return LIBLTE_ERROR; } - } - q->frame_idx++; - res = 0; + /* extract channel estimates */ + for (i = 0; i < q->cell.nof_ports; i++) { + if (q->nof_symbols != pbch_get(ce_slot[i], q->ce[i], q->cell)) { + fprintf(stderr, "There was an error getting the PBCH symbols\n"); + return LIBLTE_ERROR; + } + } - /* Try decoding for 1 to 4 antennas */ - for (na = 0; na < 3 && !res; na++) { - nant = nant_[na]; + q->frame_idx++; + ret = 0; - INFO("Trying %d TX antennas with %d frames\n", nant, q->frame_idx); + /* Try decoding for 1 to cell.nof_ports antennas */ + for (na = 0; na < q->cell.nof_ports && !ret; na++) { + nant = nant_[na]; - /* 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); - } else { - 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); - } + INFO("Trying %d TX antennas with %d frames\n", nant, q->frame_idx); - /* demodulate symbols */ - demod_soft_sigma_set(&q->demod, 1.0); - demod_soft_demodulate(&q->demod, q->pbch_d, - &q->pbch_llr[nof_bits * (q->frame_idx - 1)], q->nof_symbols); - - /* We don't know where the 40 ms begin, so we try all combinations. E.g. if we received - * 4 frames, try 1,2,3,4 individually, 12, 23, 34 in pairs, 123, 234 and finally 1234. - * We know they are ordered. - * - * FIXME: There are unnecessary checks because 2,3,4 have already been processed in the previous - * calls. - */ - 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); + /* 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); + } else { + 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 */ + demod_soft_sigma_set(&q->demod, 1.0); + demod_soft_demodulate(&q->demod, q->pbch_d, + &q->pbch_llr[nof_bits * (q->frame_idx - 1)], q->nof_symbols); + + /* We don't know where the 40 ms begin, so we try all combinations. E.g. if we received + * 4 frames, try 1,2,3,4 individually, 12, 23, 34 in pairs, 123, 234 and finally 1234. + * We know they are ordered. + * + * FIXME: There are unnecessary checks because 2,3,4 have already been processed in the previous + * calls. + */ + for (nb = 0; nb < q->frame_idx && !ret; nb++) { + for (dst = 0; (dst < 4 - nb) && !ret; dst++) { + for (src = 0; src < q->frame_idx - nb && !ret; src++) { + DEBUG("Trying %d blocks at offset %d as subframe mod4 number %d\n", + nb + 1, src, dst); + ret = pbch_decode_frame(q, mib, src, dst, nb + 1, nof_bits, nant); + + } } } } - } - /* If not found, make room for the next packet of radio frame symbols */ - if (q->frame_idx == 4) { - memmove(q->pbch_llr, &q->pbch_llr[nof_bits], nof_bits * 3 * sizeof(float)); - q->frame_idx = 3; + /* If not found, make room for the next packet of radio frame symbols */ + if (q->frame_idx == 4) { + memmove(q->pbch_llr, &q->pbch_llr[nof_bits], nof_bits * 3 * sizeof(float)); + q->frame_idx = 3; + } } - return res; + return ret; } /** 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], int nof_ports) { +int pbch_encode(pbch_t *q, pbch_mib_t *mib, cf_t *sf_symbols[MAX_PORTS]) { int i; - int nof_bits = 2 * q->nof_symbols; - - assert(nof_ports <= MAX_PORTS); - - /* Set pointers for layermapping & precoding */ + int nof_bits; + cf_t *slot1_symbols[MAX_PORTS]; cf_t *x[MAX_LAYERS]; + + if (q != NULL && + mib != NULL) + { + for (i=0;icell.nof_ports;i++) { + if (sf_symbols[i] == NULL) { + return LIBLTE_ERROR_INVALID_INPUTS; + } else { + slot1_symbols[i] = &sf_symbols[i][q->cell.nof_prb * RE_X_RB * CP_NSYMB(q->cell.cp)]; + } + } + /* Set pointers for layermapping & precoding */ + nof_bits = 2 * q->nof_symbols; - /* number of layers equals number of ports */ - for (i = 0; i < nof_ports; i++) { - x[i] = q->pbch_x[i]; - } - memset(&x[nof_ports], 0, sizeof(cf_t*) * (MAX_LAYERS - nof_ports)); + /* number of layers equals number of ports */ + for (i = 0; i < q->cell.nof_ports; i++) { + x[i] = q->pbch_x[i]; + } + memset(&x[q->cell.nof_ports], 0, sizeof(cf_t*) * (MAX_LAYERS - q->cell.nof_ports)); + + if (q->frame_idx == 0) { + /* pack MIB */ + pbch_mib_pack(mib, q->data); - if (q->frame_idx == 0) { - /* pack MIB */ - pbch_mib_pack(mib, q->data); + /* encode & modulate */ + crc_attach(&q->crc, q->data, 24); + crc_set_mask(q->data, q->cell.nof_ports); - /* encode & modulate */ - crc_attach(&q->crc, q->data, 24); - crc_set_mask(q->data, nof_ports); + convcoder_encode(&q->encoder, q->data, q->data_enc, 40); - convcoder_encode(&q->encoder, q->data, q->data_enc, 40); + rm_conv_tx(q->data_enc, 120, q->pbch_rm_b, 4 * nof_bits); - rm_conv_tx(q->data_enc, 120, q->pbch_rm_b, 4 * nof_bits); + } - } + 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); - 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); + /* layer mapping & precoding */ + if (q->cell.nof_ports > 1) { + layermap_diversity(q->pbch_d, x, q->cell.nof_ports, q->nof_symbols); + precoding_diversity(x, q->pbch_symbols, q->cell.nof_ports, + q->nof_symbols / q->cell.nof_ports); + } else { + memcpy(q->pbch_symbols[0], q->pbch_d, q->nof_symbols * sizeof(cf_t)); + } - /* 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); + /* mapping to resource elements */ + for (i = 0; i < q->cell.nof_ports; i++) { + pbch_put(q->pbch_symbols[i], slot1_symbols[i], q->cell); + } + q->frame_idx++; + if (q->frame_idx == 4) { + q->frame_idx = 0; + } + return LIBLTE_SUCCESS; } else { - memcpy(q->pbch_symbols[0], q->pbch_d, q->nof_symbols * sizeof(cf_t)); - } - - /* mapping to resource elements */ - 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) { - q->frame_idx = 0; + return LIBLTE_ERROR_INVALID_INPUTS; } } diff --git a/lte/phy/lib/phch/src/pdsch.c b/lte/phy/lib/phch/src/pdsch.c index a5459a480..cb6283deb 100644 --- a/lte/phy/lib/phch/src/pdsch.c +++ b/lte/phy/lib/phch/src/pdsch.c @@ -61,10 +61,10 @@ struct cb_segm { int pdsch_cp(pdsch_t *q, cf_t *input, cf_t *output, ra_prb_t *prb_alloc, uint8_t nsubframe, bool put) { - int s, n, l, lp, lstart, lend, nof_refs; + uint8_t s, n, l, lp, lstart, lend, nof_refs; bool is_pbch, is_sss; cf_t *in_ptr = input, *out_ptr = output; - int offset; + uint8_t offset; INFO("%s %d RE from %d PRB\n", put ? "Putting" : "Getting", prb_alloc->re_sf[nsubframe], prb_alloc->slot[0].nof_prb); @@ -76,7 +76,6 @@ int pdsch_cp(pdsch_t *q, cf_t *input, cf_t *output, ra_prb_t *prb_alloc, } for (s = 0; s < 2; s++) { - for (l = 0; l < CP_NSYMB(q->cell.cp); l++) { for (n = 0; n < prb_alloc->slot[s].nof_prb; n++) { if (s == 0) { diff --git a/lte/phy/lib/phch/src/ra.c b/lte/phy/lib/phch/src/ra.c index 2e30d1764..3056b6fee 100644 --- a/lte/phy/lib/phch/src/ra.c +++ b/lte/phy/lib/phch/src/ra.c @@ -41,23 +41,23 @@ #define min(a,b) (a= nof_prb / 2 - 3 && prb_idx <= nof_prb / 2 + 3)) { - if (nsubframe == 0) { - if (nslot == 0) { + if (subframe == 0) { + if (slot == 0) { re = (CP_NSYMB(cp) - nof_ctrl_symbols - 2) * RE_X_RB; } else { if (CP_ISEXT(cp)) { @@ -67,16 +67,16 @@ int ra_re_x_prb(int nsubframe, int nslot, int prb_idx, int nof_prb, re = (CP_NSYMB(cp) - 4) * RE_X_RB + 2 * nof_ports; } } - } else if (nsubframe == 5) { - if (nslot == 0) { + } else if (subframe == 5) { + if (slot == 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) { + if (slot == 0) { re += 2 * RE_X_RB / 2; - } else if (nsubframe == 0) { + } else if (subframe == 0) { re += 4 * RE_X_RB / 2 - nof_ports; if (CP_ISEXT(cp)) { re -= nof_ports > 2 ? 2 : nof_ports; @@ -90,10 +90,10 @@ int ra_re_x_prb(int nsubframe, int nslot, int prb_idx, int nof_prb, switch (nof_ports) { case 1: case 2: - re -= 2 * (nslot + 1) * nof_ports; + re -= 2 * (slot + 1) * nof_ports; break; case 4: - if (nslot == 1) { + if (slot == 1) { re -= 12; } else { re -= 4; @@ -109,9 +109,9 @@ int ra_re_x_prb(int nsubframe, int nslot, int prb_idx, int nof_prb, } /* 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; +void ra_prb_get_re_dl(ra_prb_t *prb_dist, uint8_t nof_prb, uint8_t nof_ports, + uint8_t nof_ctrl_symbols, lte_cp_t cp) { + uint8_t i, j, s; /* Set start symbol according to Section 7.1.6.4 in 36.213 */ prb_dist->lstart = nof_ctrl_symbols; @@ -139,25 +139,25 @@ void ra_prb_fprint(FILE *f, ra_prb_slot_t *prb) { } /** Compute PRB allocation for Downlink as defined in 8.1 of 36.213 */ -int ra_prb_get_ul(ra_prb_slot_t *prb, ra_pusch_t *ra, int nof_prb) { +int ra_prb_get_ul(ra_prb_slot_t *prb, ra_pusch_t *ra, uint8_t nof_prb) { int i; if (ra->type2_alloc.mode != t2_loc) { fprintf(stderr, "Uplink only accepts type2 localized scheduling\n"); - return -1; + return LIBLTE_ERROR; } 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; + return LIBLTE_SUCCESS; } /** Compute PRB allocation for Downlink as defined in 7.1.6 of 36.213 */ -int ra_prb_get_dl(ra_prb_t *prb_dist, ra_pdsch_t *ra, int nof_prb) { +int ra_prb_get_dl(ra_prb_t *prb_dist, ra_pdsch_t *ra, uint8_t nof_prb) { int i, j; uint32_t bitmask; - int P = ra_type0_P(nof_prb); - int n_rb_rbg_subset, n_rb_type1; + uint8_t P = ra_type0_P(nof_prb); + uint8_t n_rb_rbg_subset, n_rb_type1; bzero(prb_dist, sizeof(ra_prb_t)); switch (ra->alloc_type) { @@ -260,33 +260,33 @@ int ra_prb_get_dl(ra_prb_t *prb_dist, ra_pdsch_t *ra, int nof_prb) { } break; default: - return -1; + return LIBLTE_ERROR; } - return 0; + return LIBLTE_SUCCESS; } /* Returns the number of allocated PRB for Uplink */ -int ra_nprb_ul(ra_pusch_t *ra, int nof_prb) { +uint16_t ra_nprb_ul(ra_pusch_t *ra, uint8_t nof_prb) { return ra->type2_alloc.L_crb; } /* Returns the number of allocated PRB for Downlink */ -int ra_nprb_dl(ra_pdsch_t *ra, int nof_prb) { - int nprb; - int nof_rbg, P; +uint16_t ra_nprb_dl(ra_pdsch_t *ra, uint8_t nof_prb) { + uint8_t nprb; + uint8_t nof_rbg, P; 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)) { - nof_rbg = (int) ceilf((float) nof_prb / P) - 1; + if (nof_rbg > (uint8_t) ceilf((float) nof_prb / P)) { + nof_rbg = (uint8_t) ceilf((float) nof_prb / P) - 1; } nprb = nof_rbg * P; // last RBG may have smaller size. Add if set - int P_last = (nof_prb % P); + uint8_t P_last = (nof_prb % P); if (!P_last) P_last = P; nprb += P_last * (ra->type0_alloc.rbg_bitmask & 1); @@ -296,20 +296,20 @@ int ra_nprb_dl(ra_pdsch_t *ra, int nof_prb) { if (nprb > ra_type1_N_rb(nof_prb)) { fprintf(stderr, "Number of RB (%d) can not exceed %d\n", nprb, ra_type1_N_rb(nof_prb)); - return -1; + return LIBLTE_ERROR; } break; case alloc_type2: nprb = ra->type2_alloc.L_crb; break; default: - return -1; + return LIBLTE_ERROR; } return nprb; } /* RBG size for type0 scheduling as in table 7.1.6.1-1 of 36.213 */ -int ra_type0_P(int nof_prb) { +uint8_t ra_type0_P(uint8_t nof_prb) { if (nof_prb <= 10) { return 1; } else if (nof_prb <= 26) { @@ -322,15 +322,15 @@ 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; +uint8_t ra_type1_N_rb(uint8_t nof_prb) { + uint8_t P = ra_type0_P(nof_prb); + return (uint8_t) ceilf((float) nof_prb / P) - (uint8_t) 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) { +uint16_t ra_type2_to_riv(uint8_t L_crb, uint8_t RB_start, uint8_t nof_prb) { + uint16_t riv; + if (L_crb <= 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; @@ -339,10 +339,10 @@ uint32_t ra_type2_to_riv(uint16_t L_crb, uint16_t RB_start, int nof_prb) { } /* 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(uint16_t riv, uint8_t *L_crb, uint8_t *RB_start, + uint8_t nof_prb, uint8_t nof_vrb) { + *L_crb = (uint8_t) (riv / nof_prb) + 1; + *RB_start = (uint8_t) (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; @@ -350,7 +350,7 @@ void ra_type2_from_riv(uint32_t riv, uint16_t *L_crb, uint16_t *RB_start, } /* Table 6.2.3.2-1 in 36.211 */ -int ra_type2_ngap(int nof_prb, bool ngap_is_1) { +uint8_t ra_type2_ngap(uint8_t nof_prb, bool ngap_is_1) { if (nof_prb <= 10) { return nof_prb / 2; } else if (nof_prb == 11) { @@ -373,7 +373,7 @@ int ra_type2_ngap(int nof_prb, bool ngap_is_1) { } /* Table 7.1.6.3-1 in 36.213 */ -int ra_type2_n_rb_step(int nof_prb) { +uint8_t ra_type2_n_rb_step(uint8_t nof_prb) { if (nof_prb < 50) { return 2; } else { @@ -382,12 +382,12 @@ 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); +uint8_t ra_type2_n_vrb_dl(uint8_t nof_prb, bool ngap_is_1) { + uint8_t ngap = ra_type2_ngap(nof_prb, ngap_is_1); if (ngap_is_1) { return 2 * (ngap < (nof_prb - ngap) ? ngap : nof_prb - ngap); } else { - return ((int) nof_prb / ngap) * 2 * ngap; + return ((uint8_t) nof_prb / ngap) * 2 * ngap; } } @@ -401,7 +401,7 @@ uint8_t ra_mcs_to_table_idx(ra_mcs_t *mcs) { case QAM64: return mcs->tbs_idx + 2; default: - return 0; + return LIBLTE_SUCCESS; } } @@ -428,9 +428,9 @@ int ra_mcs_from_idx_dl(uint8_t idx, ra_mcs_t *mcs) { } else { mcs->mod = MOD_NULL; mcs->tbs_idx = 0; - return -1; + return LIBLTE_ERROR; } - return 0; + return LIBLTE_SUCCESS; } /* Converts MCS index to ra_mcs_t structure for Uplink as defined in Table 8.6.1-1 on 36.213 */ @@ -447,9 +447,9 @@ int ra_mcs_from_idx_ul(uint8_t idx, ra_mcs_t *mcs) { } else { mcs->mod = MOD_NULL; mcs->tbs_idx = 0; - return -1; + return LIBLTE_ERROR; } - return 0; + return LIBLTE_SUCCESS; } /* Downlink Transport Block size for Format 1C as defined in 7.1.7.2.2-1 on 36.213 */ @@ -457,52 +457,52 @@ int ra_tbs_from_idx_format1c(uint8_t tbs_idx) { if (tbs_idx < 32) { return tbs_format1c_table[tbs_idx]; } else { - return -1; + return LIBLTE_ERROR; } } /* Returns lowest nearest index of TBS value in table 7.1.7.2.2-1 on 36.213 * or -1 if the TBS value is not within the valid TBS values */ -int ra_tbs_to_table_idx_format1c(int tbs) { +int ra_tbs_to_table_idx_format1c(uint32_t tbs) { int idx; if (tbs < tbs_format1c_table[0]) { - return -1; + return LIBLTE_ERROR; } for (idx = 1; idx < 32; idx++) { if (tbs_format1c_table[idx - 1] <= tbs && tbs_format1c_table[idx] >= tbs) { return idx; } } - return -1; + return LIBLTE_ERROR; } /* 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) { - if (tbs_idx < 27 && n_prb > 0 && n_prb <= 110) { +int ra_tbs_from_idx(uint8_t tbs_idx, uint8_t n_prb) { + if (tbs_idx < 27 && n_prb > 0 && n_prb <= MAX_PRB) { return tbs_table[tbs_idx][n_prb - 1]; } else { - return -1; + return LIBLTE_ERROR; } } /* Returns lowest nearest index of TBS value in table 7.1.7.2 on 36.213 * or -1 if the TBS value is not within the valid TBS values */ -int ra_tbs_to_table_idx(int tbs, int n_prb) { +int ra_tbs_to_table_idx(uint32_t tbs, uint8_t n_prb) { int idx; - if (n_prb > 0 && n_prb <= 110) { - return -1; + if (n_prb > 0 && n_prb <= MAX_PRB) { + return LIBLTE_ERROR; } if (tbs < tbs_table[0][n_prb]) { - return -1; + return LIBLTE_ERROR; } for (idx = 1; idx < 28; idx++) { if (tbs_table[idx - 1][n_prb] <= tbs && tbs_table[idx][n_prb] >= tbs) { return idx; } } - return -1; + return LIBLTE_ERROR; } char *ra_mod_string(ra_mod_t mod) { @@ -518,7 +518,7 @@ char *ra_mod_string(ra_mod_t mod) { } } -void ra_pusch_fprint(FILE *f, ra_pusch_t *ra, int nof_prb) { +void ra_pusch_fprint(FILE *f, ra_pusch_t *ra, uint8_t nof_prb) { fprintf(f, "Frequency Hopping:\t"); if (ra->freq_hop_fl == hop_disabled) { fprintf(f, "No"); @@ -551,7 +551,7 @@ void ra_pdsch_set_mcs(ra_pdsch_t *ra, ra_mod_t mod, uint8_t tbs_idx) { ra->mcs.tbs = 0; } -void ra_pdsch_fprint(FILE *f, ra_pdsch_t *ra, int nof_prb) { +void ra_pdsch_fprint(FILE *f, ra_pdsch_t *ra, uint8_t nof_prb) { fprintf(f, " - Resource Allocation Type:\t\t%s\n", ra_type_string(ra->alloc_type)); switch (ra->alloc_type) { diff --git a/lte/phy/lib/phch/test/pbch_file_test.c b/lte/phy/lib/phch/test/pbch_file_test.c index 908af0ed7..09ed88980 100644 --- a/lte/phy/lib/phch/test/pbch_file_test.c +++ b/lte/phy/lib/phch/test/pbch_file_test.c @@ -117,14 +117,14 @@ int base_init() { exit(-1); } - fft_buffer = malloc(CP_NSYMB(cell.cp) * cell.nof_prb * RE_X_RB * sizeof(cf_t)); + fft_buffer = malloc(2 * CP_NSYMB(cell.cp) * cell.nof_prb * RE_X_RB * sizeof(cf_t)); if (!fft_buffer) { perror("malloc"); return -1; } - for (i=0;i Date: Mon, 30 Jun 2014 01:32:42 +0200 Subject: [PATCH 04/14] Removed PBCH eNodeB/UE examples and integrated into PDSCH ones using the program argument -b --- lte/phy/examples/CMakeLists.txt | 14 - lte/phy/examples/pbch_enodeb.c | 293 ------------------- lte/phy/examples/pbch_ue.c | 496 -------------------------------- lte/phy/examples/pdsch_ue.c | 64 +++-- 4 files changed, 48 insertions(+), 819 deletions(-) delete mode 100644 lte/phy/examples/pbch_enodeb.c delete mode 100644 lte/phy/examples/pbch_ue.c diff --git a/lte/phy/examples/CMakeLists.txt b/lte/phy/examples/CMakeLists.txt index 5238328c8..a599920ec 100644 --- a/lte/phy/examples/CMakeLists.txt +++ b/lte/phy/examples/CMakeLists.txt @@ -51,12 +51,6 @@ LIST(FIND OPTIONAL_LIBS graphics GRAPHICS_FIND) # These two can be compiled without UHD or graphics support ################################################################# -add_executable(pbch_ue pbch_ue.c) -target_link_libraries(pbch_ue lte_phy) - -add_executable(pbch_enodeb pbch_enodeb.c) -target_link_libraries(pbch_enodeb lte_phy) - add_executable(pdsch_ue pdsch_ue.c) target_link_libraries(pdsch_ue lte_phy) @@ -64,25 +58,17 @@ add_executable(pdsch_enodeb pdsch_enodeb.c) target_link_libraries(pdsch_enodeb lte_phy) IF(${CUHD_FIND} EQUAL -1) - SET_TARGET_PROPERTIES(pbch_ue PROPERTIES COMPILE_DEFINITIONS "DISABLE_UHD") - SET_TARGET_PROPERTIES(pbch_enodeb PROPERTIES COMPILE_DEFINITIONS "DISABLE_UHD") SET_TARGET_PROPERTIES(pdsch_ue PROPERTIES COMPILE_DEFINITIONS "DISABLE_UHD") SET_TARGET_PROPERTIES(pdsch_enodeb PROPERTIES COMPILE_DEFINITIONS "DISABLE_UHD") ELSE(${CUHD_FIND} EQUAL -1) - target_link_libraries(pbch_ue cuhd) - target_link_libraries(pbch_enodeb cuhd) target_link_libraries(pdsch_ue cuhd) target_link_libraries(pdsch_enodeb cuhd) ENDIF(${CUHD_FIND} EQUAL -1) IF(${GRAPHICS_FIND} EQUAL -1) - SET_TARGET_PROPERTIES(pbch_ue PROPERTIES COMPILE_DEFINITIONS "DISABLE_GRAPHICS") - SET_TARGET_PROPERTIES(pbch_enodeb PROPERTIES COMPILE_DEFINITIONS "DISABLE_GRAPHICS") SET_TARGET_PROPERTIES(pdsch_ue PROPERTIES COMPILE_DEFINITIONS "DISABLE_GRAPHICS") SET_TARGET_PROPERTIES(pdsch_enodeb PROPERTIES COMPILE_DEFINITIONS "DISABLE_GRAPHICS") ELSE(${GRAPHICS_FIND} EQUAL -1) - target_link_libraries(pbch_ue graphics) - target_link_libraries(pbch_enodeb graphics) target_link_libraries(pdsch_ue graphics) target_link_libraries(pdsch_enodeb graphics) ENDIF(${GRAPHICS_FIND} EQUAL -1) diff --git a/lte/phy/examples/pbch_enodeb.c b/lte/phy/examples/pbch_enodeb.c deleted file mode 100644 index 529addfa8..000000000 --- a/lte/phy/examples/pbch_enodeb.c +++ /dev/null @@ -1,293 +0,0 @@ -/** - * - * \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 "liblte/phy/phy.h" - -#ifndef DISABLE_UHD - #include "liblte/cuhd/cuhd.h" - void *uhd; -#endif - - -lte_cell_t cell = { - 6, // nof_prb - 1, // nof_ports - 1, // cell_id - CPNORM // cyclic prefix -}; - -char *output_file_name = NULL; -int nof_frames=-1; -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 *sf_buffer = NULL, *output_buffer = NULL; -int sf_n_re, sf_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", cell.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': - cell.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 */ - sf_buffer = malloc(sizeof(cf_t) * sf_n_re); - if (!sf_buffer) { - perror("malloc"); - exit(-1); - } - output_buffer = malloc(sizeof(cf_t) * sf_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, cell.nof_prb)) { - fprintf(stderr, "Error creating iFFT object\n"); - exit(-1); - } - if (pbch_init(&pbch, cell)) { - fprintf(stderr, "Error creating PBCH object\n"); - exit(-1); - } -} - -void base_free() { - - pbch_free(&pbch); - - lte_ifft_free(&ifft); - - if (sf_buffer) { - free(sf_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, sf_idx, 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, n; - cf_t *sf_symbols[MAX_PORTS]; - - -#ifdef DISABLE_UHD - if (argc < 3) { - usage(argv[0]); - exit(-1); - } -#endif - - parse_args(argc,argv); - - N_id_2 = cell.id%3; - sf_n_re = 2 * CPNORM_NSYMB * cell.nof_prb * RE_X_RB; - sf_n_samples = 2 * SLOT_LEN_CPNORM(lte_symbol_sz(cell.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 */ - lte_cell_t cell; - cell.id = cell.id; - cell.nof_prb = 6; - cell.cp = CPNORM; - cell.nof_ports = 1; - - for (i=0;i -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "liblte/phy/phy.h" - -#ifndef DISABLE_UHD -#include "liblte/cuhd/cuhd.h" -void *uhd; -#endif - -#ifndef DISABLE_GRAPHICS -#include "liblte/graphics/plot.h" -plot_real_t poutfft; -plot_complex_t pce; -plot_scatter_t pscatrecv, pscatequal; -#endif - -#define MHZ 1000000 -#define SAMP_FREQ 1920000 -#define FLEN 9600 -#define FLEN_PERIOD 0.005 - -#define NOF_PORTS 2 - -float find_threshold = 9.0; -int max_track_lost = 20, nof_frames = -1; -int track_len = 300; -char *input_file_name = NULL; -int disable_plots = 0; - -int go_exit = 0; - -float uhd_freq = 2600000000.0, uhd_gain = 20.0; -char *uhd_args = ""; - -filesource_t fsrc; -cf_t *input_buffer, *fft_buffer, *ce[MAX_PORTS]; -pbch_t pbch; -lte_fft_t fft; -chest_t chest; -sync_t ssync; -cfo_t cfocorr; - -enum sync_state { - FIND, TRACK -}; - -void usage(char *prog) { - printf("Usage: %s [iagfndvt]\n", prog); - printf("\t-i input_file [Default use USRP]\n"); -#ifndef DISABLE_UHD - printf("\t-a UHD args [Default %s]\n", uhd_args); - printf("\t-g UHD RX gain [Default %.2f dB]\n", uhd_gain); - printf("\t-f UHD RX frequency [Default %.1f MHz]\n", uhd_freq / 1000000); -#else - printf("\t UHD is disabled. CUHD library not available\n"); -#endif - - printf("\t-n nof_frames [Default %d]\n", nof_frames); - printf("\t-t PSS threshold [Default %f]\n", find_threshold); -#ifndef DISABLE_GRAPHICS - printf("\t-d disable plots [Default enabled]\n"); -#else - printf("\t plots are disabled. Graphics library not available\n"); -#endif - printf("\t-v [set verbose to debug, default none]\n"); -} - -void parse_args(int argc, char **argv) { - int opt; - while ((opt = getopt(argc, argv, "iagfndvt")) != -1) { - switch (opt) { - case 'i': - input_file_name = argv[optind]; - break; - case 'a': - uhd_args = argv[optind]; - break; - case 'g': - uhd_gain = atof(argv[optind]); - break; - case 'f': - uhd_freq = atof(argv[optind]); - break; - case 't': - find_threshold = atof(argv[optind]); - break; - case 'n': - nof_frames = atoi(argv[optind]); - break; - case 'd': - disable_plots = 1; - break; - case 'v': - verbose++; - break; - default: - usage(argv[0]); - exit(-1); - } - } -} - -#ifndef DISABLE_GRAPHICS - -void init_plots() { - plot_init(); - plot_real_init(&poutfft); - plot_real_setTitle(&poutfft, "Output FFT - Magnitude"); - plot_real_setLabels(&poutfft, "Index", "dB"); - plot_real_setYAxisScale(&poutfft, -60, 0); - plot_real_setXAxisScale(&poutfft, 1, 504); - - plot_complex_init(&pce); - plot_complex_setTitle(&pce, "Channel Estimates"); - plot_complex_setYAxisScale(&pce, Ip, -0.01, 0.01); - plot_complex_setYAxisScale(&pce, Q, -0.01, 0.01); - plot_complex_setYAxisScale(&pce, Magnitude, 0, 0.01); - plot_complex_setYAxisScale(&pce, Phase, -M_PI, M_PI); - - plot_scatter_init(&pscatrecv); - plot_scatter_setTitle(&pscatrecv, "Received Symbols"); - plot_scatter_setXAxisScale(&pscatrecv, -0.01, 0.01); - plot_scatter_setYAxisScale(&pscatrecv, -0.01, 0.01); - - plot_scatter_init(&pscatequal); - plot_scatter_setTitle(&pscatequal, "Equalized Symbols"); - plot_scatter_setXAxisScale(&pscatequal, -1, 1); - plot_scatter_setYAxisScale(&pscatequal, -1, 1); -} - -#endif - -int base_init(int frame_length) { - int i; - -#ifndef DISABLE_GRAPHICS - if (!disable_plots) { - init_plots(); - } -#else - printf("-- PLOTS are disabled. Graphics library not available --\n\n"); -#endif - - if (input_file_name) { - if (filesource_init(&fsrc, input_file_name, COMPLEX_FLOAT_BIN)) { - return -1; - } - } else { - /* open UHD device */ -#ifndef DISABLE_UHD - printf("Opening UHD device...\n"); - if (cuhd_open(uhd_args, &uhd)) { - fprintf(stderr, "Error opening uhd\n"); - return -1; - } -#else - printf("Error UHD not available. Select an input file\n"); - return -1; -#endif - } - - input_buffer = (cf_t*) malloc(frame_length * sizeof(cf_t)); - if (!input_buffer) { - perror("malloc"); - return -1; - } - - fft_buffer = (cf_t*) malloc(CPNORM_NSYMB * 72 * sizeof(cf_t)); - if (!fft_buffer) { - perror("malloc"); - return -1; - } - for (i = 0; i < MAX_PORTS; i++) { - ce[i] = (cf_t*) malloc(CPNORM_NSYMB * 72 * sizeof(cf_t)); - if (!ce[i]) { - perror("malloc"); - return -1; - } - } - if (sync_init(&ssync, FLEN)) { - fprintf(stderr, "Error initiating PSS/SSS\n"); - return -1; - } - if (chest_init(&chest, LINEAR, CPNORM, 6, NOF_PORTS)) { - fprintf(stderr, "Error initializing equalizer\n"); - return -1; - } - - if (cfo_init(&cfocorr, FLEN)) { - fprintf(stderr, "Error initiating CFO\n"); - return -1; - } - if (lte_fft_init(&fft, CPNORM, 6)) { - fprintf(stderr, "Error initializing FFT\n"); - return -1; - } - - return 0; -} - -void base_free() { - int i; - - if (input_file_name) { - filesource_free(&fsrc); - } else { -#ifndef DISABLE_UHD - cuhd_close(uhd); -#endif - } - -#ifndef DISABLE_GRAPHICS - plot_exit(); -#endif - - sync_free(&ssync); - lte_fft_free(&fft); - chest_free(&chest); - cfo_free(&cfocorr); - - free(input_buffer); - free(fft_buffer); - for (i = 0; i < MAX_PORTS; i++) { - free(ce[i]); - } -} - -int mib_decoder_init(int cell_id) { - - lte_cell_t cell; - - cell.id = cell_id; - cell.nof_ports = MAX_PORTS; - cell.nof_prb = 6; - cell.cp = CPNORM; - - if (chest_ref_LTEDL(&chest, cell)) { - fprintf(stderr, "Error initializing reference signal\n"); - return -1; - } - - if (pbch_init(&pbch, cell)) { - fprintf(stderr, "Error initiating PBCH\n"); - return -1; - } - DEBUG("PBCH initiated cell_id=%d\n", cell.id); - return 0; -} - -int mib_decoder_run(cf_t *input, pbch_mib_t *mib) { - int i, n; - lte_fft_run_slot(&fft, input, fft_buffer); - - /* Get channel estimates for each port */ - for (i = 0; i < NOF_PORTS; i++) { - chest_ce_slot_port(&chest, fft_buffer, ce[i], 1, i); - } - - DEBUG("Decoding PBCH\n", 0); - n = pbch_decode(&pbch, fft_buffer, ce, mib); - -#ifndef DISABLE_GRAPHICS - float tmp[72 * 7]; - if (!disable_plots) { - for (i = 0; i < 72 * 7; i++) { - tmp[i] = 10 * log10f(cabsf(fft_buffer[i])); - if (isinf(tmp[i])) { - tmp[i] = -80; - } - } - - plot_real_setNewData(&poutfft, tmp, 72 * 7); - plot_complex_setNewData(&pce, ce[0], 72 * 7); - plot_scatter_setNewData(&pscatrecv, pbch.pbch_symbols[0], pbch.nof_symbols); - if (n) { - plot_scatter_setNewData(&pscatequal, pbch.pbch_d, pbch.nof_symbols); - } - } -#endif - - return n; -} - -void sigintHandler(int sig_num) { - go_exit = 1; -} - -int main(int argc, char **argv) { - int frame_cnt; - int cell_id; - int find_idx, track_idx, last_found; - enum sync_state state; - int nslot; - pbch_mib_t mib; - float cfo; - int n; - int nof_found_mib = 0; - float timeoffset = 0; - -#ifdef DISABLE_UHD - if (argc < 3) { - usage(argv[0]); - exit(-1); - } -#endif - - parse_args(argc, argv); - - if (base_init(FLEN)) { - fprintf(stderr, "Error initializing memory\n"); - exit(-1); - } - - sync_pss_det_peak_to_avg(&ssync); - - if (!input_file_name) { -#ifndef DISABLE_UHD - INFO("Setting sampling frequency %.2f MHz\n", (float) SAMP_FREQ/MHZ); - cuhd_set_rx_srate(uhd, SAMP_FREQ); - cuhd_set_rx_gain(uhd, uhd_gain); - /* set uhd_freq */ - cuhd_set_rx_freq(uhd, (double) uhd_freq); - cuhd_rx_wait_lo_locked(uhd); - DEBUG("Set uhd_freq to %.3f MHz\n", (double ) uhd_freq); - - DEBUG("Starting receiver...\n", 0); - cuhd_start_rx_stream(uhd); -#endif - } - - printf("\n --- Press Ctrl+C to exit --- \n"); - signal(SIGINT, sigintHandler); - - state = FIND; - nslot = 0; - find_idx = 0; - cfo = 0; - mib.sfn = -1; - frame_cnt = 0; - last_found = 0; - sync_set_threshold(&ssync, find_threshold); - - while (!go_exit && (frame_cnt < nof_frames || nof_frames == -1)) { - INFO(" ----- RECEIVING %d SAMPLES ---- \n", FLEN); - if (input_file_name) { - n = filesource_read(&fsrc, input_buffer, FLEN); - if (n == -1) { - fprintf(stderr, "Error reading file\n"); - exit(-1); - } else if (n < FLEN) { - filesource_seek(&fsrc, 0); - filesource_read(&fsrc, input_buffer, FLEN); - } - } else { -#ifndef DISABLE_UHD - cuhd_recv(uhd, input_buffer, FLEN, 1); -#endif - } - - switch (state) { - case FIND: - /* find peak in all frame */ - find_idx = sync_find(&ssync, input_buffer); - INFO("FIND %3d:\tPAR=%.2f\n", frame_cnt, sync_get_peak_to_avg(&ssync)); - if (find_idx != -1) { - /* if found peak, go to track and set track threshold */ - cell_id = sync_get_cell_id(&ssync); - if (cell_id != -1) { - frame_cnt = -1; - last_found = 0; - mib_decoder_init(cell_id); - nof_found_mib = 0; - nslot = sync_get_slot_id(&ssync); - nslot = (nslot + 10) % 20; - cfo = 0; - timeoffset = 0; - printf("\n"); - state = TRACK; - } else { - printf("cellid=-1\n"); - } - } - if (verbose == VERBOSE_NONE) { - printf("Finding PSS... PAR=%.2f\r", sync_get_peak_to_avg(&ssync)); - } - break; - case TRACK: - /* Find peak around known position find_idx */ - INFO("TRACK %3d: PSS find_idx %d offset %d\n", frame_cnt, find_idx, - find_idx - track_len); - track_idx = sync_track(&ssync, &input_buffer[find_idx - track_len]); - - if (track_idx != -1) { - /* compute cumulative moving average CFO */ - cfo = (sync_get_cfo(&ssync) + frame_cnt * cfo) / (frame_cnt + 1); - /* compute cumulative moving average time offset */ - timeoffset = (float) (track_idx - track_len + timeoffset * frame_cnt) - / (frame_cnt + 1); - last_found = frame_cnt; - find_idx = (find_idx + track_idx - track_len) % FLEN; - } else { - /* if sync not found, adjust time offset with the averaged value */ - find_idx = (find_idx + (int) timeoffset) % FLEN; - } - - /* if we missed too many PSS go back to FIND */ - if (frame_cnt - last_found > max_track_lost) { - INFO("%d frames lost. Going back to FIND", frame_cnt - last_found); - printf("\r\n"); - fflush(stdout); - printf("\r\n"); - state = FIND; - } - - // Correct CFO - INFO("Correcting CFO=%.4f\n", cfo); - - cfo_correct(&cfocorr, input_buffer, -cfo / 128); - - if (nslot == 0 && find_idx + 960 < FLEN) { - INFO("Finding MIB at idx %d\n", find_idx); - if (mib_decoder_run(&input_buffer[find_idx], &mib)) { - INFO("MIB detected attempt=%d\n", frame_cnt); - if (verbose == VERBOSE_NONE) { - if (!nof_found_mib) { - printf("\r\n"); - fflush(stdout); - printf("\r\n"); - printf(" - Phy. CellId:\t%d\n", cell_id); - pbch_mib_fprint(stdout, &mib); - } - } - nof_found_mib++; - } else { - INFO("MIB not found attempt %d\n", frame_cnt); - } - if (frame_cnt) { - printf( - "SFN: %4d, CFO: %+.4f KHz, SFO: %+.4f Khz, TimeOffset: %4d, Errors: %4d/%4d, ErrorRate: %.1e\r", - mib.sfn, cfo * 15, timeoffset / 5, find_idx, - frame_cnt - 2 * (nof_found_mib - 1), frame_cnt, - (float) (frame_cnt - 2 * (nof_found_mib - 1)) / frame_cnt); - fflush(stdout); - } - } - if (input_file_name) { - usleep(5000); - } - nslot = (nslot + 10) % 20; - break; - } - frame_cnt++; - } - - base_free(); - - printf("\nBye\n"); - exit(0); -} - diff --git a/lte/phy/examples/pdsch_ue.c b/lte/phy/examples/pdsch_ue.c index ff6995e0e..89600c686 100644 --- a/lte/phy/examples/pdsch_ue.c +++ b/lte/phy/examples/pdsch_ue.c @@ -57,7 +57,7 @@ plot_scatter_t pscatrecv, pscatequal; float find_threshold = 9.0; int nof_frames = -1; -int pdsch_errors = 0, pdsch_total = 0; +int pkt_errors = 0, pkts_total = 0; int frame_cnt; char *input_file_name = NULL; int disable_plots = 0; @@ -71,7 +71,9 @@ int sf_n_samples; lte_cell_t cell; int cell_id_initated = 0, mib_initiated = 0; -int subframe_number; +int frame_number; + +bool pbch_only = false; int go_exit = 0; @@ -96,7 +98,7 @@ sync_frame_t sframe; #define DOWNSAMPLE_FACTOR(x, y) lte_symbol_sz(x) / lte_symbol_sz(y) void usage(char *prog) { - printf("Usage: %s [iagfndvtp]\n", prog); + printf("Usage: %s [iagfndvtpb]\n", prog); printf("\t-i input_file [Default use USRP]\n"); #ifndef DISABLE_UHD printf("\t-a UHD args [Default %s]\n", uhd_args); @@ -105,6 +107,7 @@ void usage(char *prog) { #else printf("\t UHD is disabled. CUHD library not available\n"); #endif + printf("\t-b Decode PBCH only [Default All]\n"); printf("\t-p sampling_nof_prb [Default %d]\n", sampling_nof_prb); printf("\t-n nof_frames [Default %d]\n", nof_frames); printf("\t-t PSS threshold [Default %f]\n", find_threshold); @@ -118,7 +121,7 @@ void usage(char *prog) { void parse_args(int argc, char **argv) { int opt; - while ((opt = getopt(argc, argv, "iagfndvtp")) != -1) { + while ((opt = getopt(argc, argv, "iagfndvtpb")) != -1) { switch (opt) { case 'i': input_file_name = argv[optind]; @@ -132,6 +135,9 @@ void parse_args(int argc, char **argv) { case 'f': uhd_freq = atof(argv[optind]); break; + case 'b': + pbch_only = true; + break; case 't': find_threshold = atof(argv[optind]); break; @@ -230,13 +236,13 @@ int base_init(int nof_prb) { perror("malloc"); return -1; } + input_decim_buffer = (cf_t*) malloc(sf_n_samples * sizeof(cf_t)); if (!input_decim_buffer) { perror("malloc"); return -1; } - /* This buffer is the aligned version of input_buffer */ sf_buffer = (cf_t*) malloc(sf_n_samples * sizeof(cf_t)); if (!sf_buffer) { @@ -438,7 +444,7 @@ int rx_run(cf_t *input, int sf_idx) { fprintf(stderr, "Can't unpack PDSCH message\n"); break; } - if (VERBOSE_ISINFO() || !pdsch_total) { + if (VERBOSE_ISINFO() || !pkts_total) { printf("\n"); ra_pdsch_fprint(stdout, &ra_dl, cell.nof_prb); printf("\n"); @@ -451,9 +457,9 @@ int rx_run(cf_t *input, int sf_idx) { cell.nof_prb<10?(cfi+1):cfi, CPNORM); if (pdsch_decode(&pdsch, fft_buffer, ce, data, sf_idx, ra_dl.mcs, &prb_alloc)) { - pdsch_errors++; + pkt_errors++; } - pdsch_total++; + pkts_total++; break; default: fprintf(stderr, "Unsupported message type\n"); @@ -497,7 +503,7 @@ int run_receiver(cf_t *input, int cell_id, int sf_idx) { if (!cell_id_initated) { cell_id_init(sampling_nof_prb, cell_id); } - if (!cell.nof_prb) { + if (!cell.nof_prb || pbch_only) { if (!sf_idx) { if (mib_decoder_run(input, &mib)) { @@ -506,7 +512,7 @@ int run_receiver(cf_t *input, int cell_id, int sf_idx) { cell.cp = CPNORM; cell.nof_ports = mib.nof_ports; cell.nof_prb = mib.nof_prb; - subframe_number = mib.sfn; + frame_number = mib.sfn; if (!mib_initiated) { if (mib_init(mib.phich_resources, mib.phich_length)) { @@ -518,10 +524,31 @@ int run_receiver(cf_t *input, int cell_id, int sf_idx) { printf(" - Phy. CellId:\t %d\n", cell_id); pbch_mib_fprint(stdout, &mib); } + } else if (pbch_only) { + pkt_errors++; + } + if (pbch_only) { + #ifndef DISABLE_GRAPHICS + if (!disable_plots) { + int i; + int n_re = 2 * RE_X_RB * CPNORM_NSYMB * sampling_nof_prb; + for (i = 0; i < n_re; i++) { + tmp_plot[i] = 10 * log10f(cabsf(fft_buffer[i])); + if (isinf(tmp_plot[i])) { + tmp_plot[i] = -80; + } + } + plot_real_setNewData(&poutfft, tmp_plot, n_re); + plot_complex_setNewData(&pce, ce[0], n_re); + plot_scatter_setNewData(&pscatrecv, pbch.pbch_symbols[0], pbch.nof_symbols); + plot_scatter_setNewData(&pscatequal, pbch.pbch_d, pbch.nof_symbols); + } + #endif + pkts_total++; } } } - if (cell.nof_prb) { + if (cell.nof_prb && !pbch_only) { if (rx_run(input, sf_idx)) { return -1; } @@ -597,11 +624,12 @@ int main(int argc, char **argv) { } printf("\n --- Press Ctrl+C to exit --- \n"); + signal(SIGINT, sigintHandler); /* Initialize variables */ frame_cnt = 0; - subframe_number = -1; + frame_number = -1; /* The number of samples read from the USRP or file corresponds to 1 ms (subframe) */ sf_n_samples = 1920 * lte_symbol_sz(sampling_nof_prb)/128; @@ -617,19 +645,23 @@ int main(int argc, char **argv) { /* not yet synched */ break; case 1: + /* sf_buffer is aligned to the subframe */ + if (!(frame_cnt%10)) { - subframe_number++; + frame_number++; } + /* synch'd and tracking */ if (run_receiver(sf_buffer, sync_frame_cell_id(&sframe), sync_frame_sfidx(&sframe))) { exit(-1); } + if (!(frame_cnt % 10)) { printf( "SFN: %4d, CFO: %+.4f KHz, SFO: %+.4f Khz, TimeOffset: %4d, Errors: %4d/%4d, BLER: %.1e\r", - subframe_number, sframe.cur_cfo * 15, sframe.timeoffset / 5, sframe.peak_idx, - pdsch_errors, pdsch_total, - (float) pdsch_errors / pdsch_total); + frame_number, sframe.cur_cfo * 15, sframe.timeoffset / 5, sframe.peak_idx, + pkt_errors, pkts_total, + (float) pkt_errors / pkts_total); fflush(stdout); } From 5181b771fd599e75a9741cda2fe5e650753182a3 Mon Sep 17 00:00:00 2001 From: ismagom Date: Tue, 1 Jul 2014 10:48:51 +0200 Subject: [PATCH 05/14] Converted all unsigned data types to uint32_t --- lte/phy/examples/pdsch_enodeb.c | 2 +- lte/phy/examples/pdsch_ue.c | 41 ++++-- .../include/liblte/phy/ch_estimation/chest.h | 60 ++++---- .../liblte/phy/ch_estimation/refsignal.h | 18 +-- .../include/liblte/phy/common/phy_common.h | 6 +- lte/phy/include/liblte/phy/common/sequence.h | 18 +-- lte/phy/include/liblte/phy/phch/dci.h | 30 ++-- lte/phy/include/liblte/phy/phch/pbch.h | 8 +- lte/phy/include/liblte/phy/phch/pcfich.h | 10 +- lte/phy/include/liblte/phy/phch/pdcch.h | 32 ++-- lte/phy/include/liblte/phy/phch/pdsch.h | 8 +- lte/phy/include/liblte/phy/phch/phich.h | 16 +- lte/phy/include/liblte/phy/phch/ra.h | 98 ++++++------- lte/phy/include/liblte/phy/phch/regs.h | 30 ++-- lte/phy/include/liblte/phy/sync/sync_frame.h | 30 ++-- lte/phy/include/liblte/phy/utils/bit.h | 2 +- lte/phy/lib/ch_estimation/src/chest.c | 30 ++-- lte/phy/lib/ch_estimation/src/refsignal.c | 16 +- lte/phy/lib/phch/src/dci.c | 138 +++++++++--------- lte/phy/lib/phch/src/pbch.c | 12 +- lte/phy/lib/phch/src/pcfich.c | 8 +- lte/phy/lib/phch/src/pdcch.c | 32 ++-- lte/phy/lib/phch/src/pdsch.c | 20 +-- lte/phy/lib/phch/src/phich.c | 8 +- lte/phy/lib/phch/src/ra.c | 84 +++++------ lte/phy/lib/phch/src/regs.c | 48 +++--- lte/phy/lib/phch/src/sequences.c | 10 +- lte/phy/lib/phch/test/pcfich_file_test.c | 2 +- lte/phy/lib/phch/test/pcfich_test.c | 2 +- lte/phy/lib/phch/test/pdcch_file_test.c | 2 +- lte/phy/lib/phch/test/pdcch_test.c | 2 +- lte/phy/lib/phch/test/pdsch_file_test.c | 2 +- lte/phy/lib/phch/test/pdsch_re_test.c | 2 +- lte/phy/lib/phch/test/pdsch_test.c | 6 +- lte/phy/lib/phch/test/phich_file_test.c | 4 +- lte/phy/lib/phch/test/phich_test.c | 4 +- lte/phy/lib/sync/src/sync_frame.c | 12 +- lte/phy/lib/utils/src/bit.c | 2 +- 38 files changed, 441 insertions(+), 414 deletions(-) diff --git a/lte/phy/examples/pdsch_enodeb.c b/lte/phy/examples/pdsch_enodeb.c index 024ce2461..10d9c190a 100644 --- a/lte/phy/examples/pdsch_enodeb.c +++ b/lte/phy/examples/pdsch_enodeb.c @@ -47,7 +47,7 @@ lte_cell_t cell = { CPNORM // cyclic prefix }; -uint8_t cfi=1; +uint32_t cfi=1; int nof_frames = -1; char *uhd_args = ""; diff --git a/lte/phy/examples/pdsch_ue.c b/lte/phy/examples/pdsch_ue.c index 89600c686..57963c1a0 100644 --- a/lte/phy/examples/pdsch_ue.c +++ b/lte/phy/examples/pdsch_ue.c @@ -70,6 +70,8 @@ int sf_n_samples; lte_cell_t cell; +uint32_t cell_id_file = 1; + int cell_id_initated = 0, mib_initiated = 0; int frame_number; @@ -98,8 +100,9 @@ sync_frame_t sframe; #define DOWNSAMPLE_FACTOR(x, y) lte_symbol_sz(x) / lte_symbol_sz(y) void usage(char *prog) { - printf("Usage: %s [iagfndvtpb]\n", prog); + printf("Usage: %s [icagfndvtpb]\n", prog); printf("\t-i input_file [Default use USRP]\n"); + printf("\t-c cell_id if reading from file [Default %d]\n", cell_id_file); #ifndef DISABLE_UHD printf("\t-a UHD args [Default %s]\n", uhd_args); printf("\t-g UHD RX gain [Default %.2f dB]\n", uhd_gain); @@ -121,11 +124,14 @@ void usage(char *prog) { void parse_args(int argc, char **argv) { int opt; - while ((opt = getopt(argc, argv, "iagfndvtpb")) != -1) { + while ((opt = getopt(argc, argv, "icagfndvtpb")) != -1) { switch (opt) { case 'i': input_file_name = argv[optind]; break; + case 'c': + cell_id_file = atoi(argv[optind]); + break; case 'a': uhd_args = argv[optind]; break; @@ -367,7 +373,7 @@ int cell_id_init(int nof_prb, int cell_id) { lte_cell_t cell; cell.id = cell_id; - cell.nof_prb = 6; + cell.nof_prb = nof_prb; cell.nof_ports = 2; cell.cp = CPNORM; @@ -390,7 +396,7 @@ int cell_id_init(int nof_prb, int cell_id) { char data[10000]; int rx_run(cf_t *input, int sf_idx) { - uint8_t cfi, cfi_distance; + uint32_t cfi, cfi_distance; int i, nof_dcis; cf_t *input_decim; ra_pdsch_t ra_dl; @@ -497,7 +503,7 @@ int mib_decoder_run(cf_t *input, pbch_mib_t *mib) { return pbch_decode(&pbch, fft_buffer, ce, mib); } -int run_receiver(cf_t *input, int cell_id, int sf_idx) { +int run_receiver(cf_t *input, uint32_t cell_id, uint32_t sf_idx) { pbch_mib_t mib; if (!cell_id_initated) { @@ -603,6 +609,10 @@ void read_io(cf_t *buffer, int nsamples) { } int main(int argc, char **argv) { + int ret; + uint32_t sf_idx; + uint32_t cell_id; + cf_t *in_ptr; #ifdef DISABLE_UHD if (argc < 3) { @@ -640,7 +650,16 @@ int main(int argc, char **argv) { read_io(input_buffer, sf_n_samples); - switch(sync_frame_push(&sframe, input_buffer, sf_buffer)) { + if (input_file_name) { + ret = 1; + sf_idx = 0; + cell_id = cell_id_file; + in_ptr = input_buffer; + } else { + ret = sync_frame_push(&sframe, input_buffer, sf_buffer); + in_ptr = sf_buffer; + } + switch(ret ) { case 0: /* not yet synched */ break; @@ -651,14 +670,18 @@ int main(int argc, char **argv) { frame_number++; } + if (!input_file_name) { + sf_idx = sync_frame_sfidx(&sframe); + cell_id = sync_frame_cell_id(&sframe); + } + /* synch'd and tracking */ - if (run_receiver(sf_buffer, sync_frame_cell_id(&sframe), sync_frame_sfidx(&sframe))) { + if (run_receiver(in_ptr, cell_id, sf_idx)) { exit(-1); } if (!(frame_cnt % 10)) { - printf( - "SFN: %4d, CFO: %+.4f KHz, SFO: %+.4f Khz, TimeOffset: %4d, Errors: %4d/%4d, BLER: %.1e\r", + printf("SFN: %4d, CFO: %+.4f KHz, SFO: %+.4f Khz, TimeOffset: %4d, Errors: %4d/%4d, BLER: %.1e\r", frame_number, sframe.cur_cfo * 15, sframe.timeoffset / 5, sframe.peak_idx, pkt_errors, pkts_total, (float) pkt_errors / pkts_total); diff --git a/lte/phy/include/liblte/phy/ch_estimation/chest.h b/lte/phy/include/liblte/phy/ch_estimation/chest.h index 2d4707870..8e3f8b94b 100644 --- a/lte/phy/include/liblte/phy/ch_estimation/chest.h +++ b/lte/phy/include/liblte/phy/ch_estimation/chest.h @@ -56,9 +56,9 @@ typedef void (*interpolate_fnc_t) (cf_t *input, /* Low-level API */ typedef struct LIBLTE_API { - uint8_t nof_ports; - uint16_t nof_re; - uint8_t nof_symbols; + uint32_t nof_ports; + uint32_t nof_re; + uint32_t nof_symbols; refsignal_t refsignal[MAX_PORTS][NSLOTS_X_FRAME]; interpolate_fnc_t interp; @@ -66,26 +66,26 @@ typedef struct LIBLTE_API { LIBLTE_API int chest_init(chest_t *q, chest_interp_t interp, - uint16_t nof_re, - uint8_t nof_symbols, - uint8_t nof_ports); + uint32_t nof_re, + uint32_t nof_symbols, + uint32_t nof_ports); LIBLTE_API void chest_free(chest_t *q); LIBLTE_API int chest_set_nof_ports(chest_t *q, - uint8_t nof_ports); + uint32_t nof_ports); LIBLTE_API int chest_init_LTEDL(chest_t *q, chest_interp_t interp, lte_cell_t cell); LIBLTE_API int chest_ref_LTEDL_slot_port(chest_t *q, - uint8_t nslot, - uint8_t port_id, + uint32_t nslot, + uint32_t port_id, lte_cell_t cell); LIBLTE_API int chest_ref_LTEDL_slot(chest_t *q, - uint8_t nslot, + uint32_t nslot, lte_cell_t cell); LIBLTE_API int chest_ref_LTEDL(chest_t *q, @@ -93,56 +93,56 @@ LIBLTE_API int chest_ref_LTEDL(chest_t *q, LIBLTE_API int chest_ce_ref(chest_t *q, cf_t *input, - uint8_t nslot, - uint8_t port_id, - uint16_t nref); + uint32_t nslot, + uint32_t port_id, + uint32_t nref); LIBLTE_API int chest_ce_slot_port(chest_t *q, cf_t *input, cf_t *ce, - uint8_t nslot, - uint8_t port_id); + uint32_t nslot, + uint32_t port_id); LIBLTE_API int chest_ce_sf_port(chest_t *q, cf_t *input, cf_t *ce, - uint8_t sf_idx, - uint8_t port_id); + uint32_t sf_idx, + uint32_t port_id); LIBLTE_API int chest_ce_slot(chest_t *q, cf_t *input, cf_t *ce[MAX_PORTS], - uint8_t nslot); + uint32_t nslot); LIBLTE_API int chest_ce_sf(chest_t *q, cf_t *input, cf_t *ce[MAX_PORTS], - uint8_t sf_idx); + uint32_t sf_idx); LIBLTE_API void chest_fprint(chest_t *q, FILE *stream, - uint8_t nslot, - uint8_t port_id); + uint32_t nslot, + uint32_t port_id); LIBLTE_API void chest_ref_fprint(chest_t *q, FILE *stream, - uint8_t nslot, - uint8_t port_id); + uint32_t nslot, + uint32_t port_id); LIBLTE_API void chest_recvsig_fprint(chest_t *q, FILE *stream, - uint8_t nslot, - uint8_t port_id); + uint32_t nslot, + uint32_t port_id); LIBLTE_API void chest_ce_fprint(chest_t *q, FILE *stream, - uint8_t nslot, - uint8_t port_id); + uint32_t nslot, + uint32_t port_id); LIBLTE_API int chest_ref_symbols(chest_t *q, - uint8_t port_id, - uint8_t nslot, - uint8_t l[2]); + uint32_t port_id, + uint32_t nslot, + uint32_t l[2]); /* High-level API */ diff --git a/lte/phy/include/liblte/phy/ch_estimation/refsignal.h b/lte/phy/include/liblte/phy/ch_estimation/refsignal.h index c6ef8d859..51ad505ff 100644 --- a/lte/phy/include/liblte/phy/ch_estimation/refsignal.h +++ b/lte/phy/include/liblte/phy/ch_estimation/refsignal.h @@ -43,25 +43,25 @@ typedef _Complex float cf_t; typedef struct LIBLTE_API{ - uint8_t time_idx; - uint16_t freq_idx; + uint32_t time_idx; + uint32_t freq_idx; cf_t simbol; cf_t recv_simbol; }ref_t; typedef struct LIBLTE_API{ - uint16_t nof_refs; // number of reference signals - uint8_t *symbols_ref; // symbols with at least one reference - uint8_t nsymbols; // number of symbols with at least one reference - uint8_t voffset; // offset of the first reference in the freq domain - uint16_t nof_prb; + uint32_t nof_refs; // number of reference signals + uint32_t *symbols_ref; // symbols with at least one reference + uint32_t nsymbols; // number of symbols with at least one reference + uint32_t voffset; // offset of the first reference in the freq domain + uint32_t nof_prb; ref_t *refs; cf_t *ch_est; } refsignal_t; LIBLTE_API int refsignal_init_LTEDL(refsignal_t *q, - uint8_t port_id, - uint8_t nslot, + uint32_t port_id, + uint32_t nslot, lte_cell_t cell); LIBLTE_API void refsignal_free(refsignal_t *q); diff --git a/lte/phy/include/liblte/phy/common/phy_common.h b/lte/phy/include/liblte/phy/common/phy_common.h index 5fcdbb176..900941a07 100644 --- a/lte/phy/include/liblte/phy/common/phy_common.h +++ b/lte/phy/include/liblte/phy/common/phy_common.h @@ -107,9 +107,9 @@ typedef enum {CPNORM, CPEXT} lte_cp_t; #define NOF_TC_CB_SIZES 188 typedef struct LIBLTE_API { - uint8_t nof_prb; - uint8_t nof_ports; - uint16_t id; + uint32_t nof_prb; + uint32_t nof_ports; + uint32_t id; lte_cp_t cp; }lte_cell_t; diff --git a/lte/phy/include/liblte/phy/common/sequence.h b/lte/phy/include/liblte/phy/common/sequence.h index f237ac20c..972a31ebf 100644 --- a/lte/phy/include/liblte/phy/common/sequence.h +++ b/lte/phy/include/liblte/phy/common/sequence.h @@ -46,26 +46,26 @@ LIBLTE_API int sequence_LTEPRS(sequence_t *q, LIBLTE_API int sequence_pbch(sequence_t *seq, lte_cp_t cp, - uint16_t cell_id); + uint32_t cell_id); LIBLTE_API int sequence_pcfich(sequence_t *seq, - uint8_t nslot, - uint16_t cell_id); + uint32_t nslot, + uint32_t cell_id); LIBLTE_API int sequence_phich(sequence_t *seq, - uint8_t nslot, - uint16_t cell_id); + uint32_t nslot, + uint32_t cell_id); LIBLTE_API int sequence_pdcch(sequence_t *seq, - uint8_t nslot, - uint16_t cell_id, + uint32_t nslot, + uint32_t cell_id, uint32_t len); LIBLTE_API int sequence_pdsch(sequence_t *seq, unsigned short rnti, int q, - uint8_t nslot, - uint16_t cell_id, + uint32_t nslot, + uint32_t cell_id, uint32_t len); #endif diff --git a/lte/phy/include/liblte/phy/phch/dci.h b/lte/phy/include/liblte/phy/phch/dci.h index 23137e214..278a8dd99 100644 --- a/lte/phy/include/liblte/phy/phch/dci.h +++ b/lte/phy/include/liblte/phy/phch/dci.h @@ -62,9 +62,9 @@ typedef enum { } dci_spec_t; typedef struct LIBLTE_API { - uint8_t nof_bits; - uint8_t L; // Aggregation level - uint8_t ncce; // Position of first CCE of the dci + uint32_t nof_bits; + uint32_t L; // Aggregation level + uint32_t ncce; // Position of first CCE of the dci uint16_t rnti; } dci_candidate_t; @@ -75,20 +75,20 @@ typedef struct LIBLTE_API { typedef struct LIBLTE_API { dci_msg_t *msg; - uint8_t nof_dcis; - uint8_t max_dcis; + uint32_t nof_dcis; + uint32_t max_dcis; } dci_t; LIBLTE_API int dci_init(dci_t *q, - uint8_t max_dci); + uint32_t max_dci); LIBLTE_API void dci_free(dci_t *q); LIBLTE_API char* dci_format_string(dci_format_t format); LIBLTE_API int dci_msg_candidate_set(dci_msg_t *msg, - uint8_t L, - uint8_t nCCE, + uint32_t L, + uint32_t nCCE, uint16_t rnti); LIBLTE_API void dci_candidate_fprint(FILE *f, @@ -96,7 +96,7 @@ LIBLTE_API void dci_candidate_fprint(FILE *f, LIBLTE_API int dci_msg_get_type(dci_msg_t *msg, dci_msg_type_t *type, - uint8_t nof_prb, + uint32_t nof_prb, uint16_t crnti); LIBLTE_API void dci_msg_type_fprint(FILE *f, @@ -105,25 +105,25 @@ LIBLTE_API void dci_msg_type_fprint(FILE *f, // For dci_msg_type_t = PUSCH_SCHED LIBLTE_API int dci_msg_pack_pusch(ra_pusch_t *data, dci_msg_t *msg, - uint8_t nof_prb); + uint32_t nof_prb); LIBLTE_API int dci_msg_unpack_pusch(dci_msg_t *msg, ra_pusch_t *data, - uint8_t nof_prb); + uint32_t nof_prb); // For dci_msg_type_t = PDSCH_SCHED LIBLTE_API int dci_msg_pack_pdsch(ra_pdsch_t *data, dci_msg_t *msg, dci_format_t format, - uint8_t nof_prb, + uint32_t nof_prb, bool crc_is_crnti); LIBLTE_API int dci_msg_unpack_pdsch(dci_msg_t *msg, ra_pdsch_t *data, - uint8_t nof_prb, + uint32_t nof_prb, bool crc_is_crnti); -LIBLTE_API uint8_t dci_format_sizeof(dci_format_t format, - uint8_t nof_prb); +LIBLTE_API uint32_t dci_format_sizeof(dci_format_t format, + uint32_t nof_prb); #endif // DCI_ diff --git a/lte/phy/include/liblte/phy/phch/pbch.h b/lte/phy/include/liblte/phy/phch/pbch.h index 75ee56a42..080702807 100644 --- a/lte/phy/include/liblte/phy/phch/pbch.h +++ b/lte/phy/include/liblte/phy/phch/pbch.h @@ -47,8 +47,8 @@ typedef _Complex float cf_t; typedef struct LIBLTE_API { - uint8_t nof_ports; - uint8_t nof_prb; + uint32_t nof_ports; + uint32_t nof_prb; uint32_t sfn; phich_length_t phich_length; phich_resources_t phich_resources; @@ -58,7 +58,7 @@ typedef struct LIBLTE_API { typedef struct LIBLTE_API { lte_cell_t cell; - uint8_t nof_symbols; + uint32_t nof_symbols; /* buffers */ cf_t *ce[MAX_PORTS]; @@ -72,7 +72,7 @@ typedef struct LIBLTE_API { char *data; char *data_enc; - uint8_t frame_idx; + uint32_t frame_idx; /* tx & rx objects */ modem_table_t mod; diff --git a/lte/phy/include/liblte/phy/phch/pcfich.h b/lte/phy/include/liblte/phy/phch/pcfich.h index 7e04267a0..80ad465f9 100644 --- a/lte/phy/include/liblte/phy/phch/pcfich.h +++ b/lte/phy/include/liblte/phy/phch/pcfich.h @@ -76,13 +76,13 @@ LIBLTE_API void pcfich_free(pcfich_t *q); LIBLTE_API int pcfich_decode(pcfich_t *q, cf_t *sf_symbols, cf_t *ce[MAX_PORTS], - uint8_t subframe, - uint8_t *cfi, - uint8_t *distance); + uint32_t subframe, + uint32_t *cfi, + uint32_t *distance); LIBLTE_API int pcfich_encode(pcfich_t *q, - uint8_t cfi, + uint32_t cfi, cf_t *sf_symbols[MAX_PORTS], - uint8_t subframe); + uint32_t subframe); #endif diff --git a/lte/phy/include/liblte/phy/phch/pdcch.h b/lte/phy/include/liblte/phy/phch/pdcch.h index cbcf7824c..4f6d5acad 100644 --- a/lte/phy/include/liblte/phy/phch/pdcch.h +++ b/lte/phy/include/liblte/phy/phch/pdcch.h @@ -56,18 +56,18 @@ typedef enum LIBLTE_API { * DCI messages as defined in Section 7.1 of 36.213 */ typedef struct LIBLTE_API { - uint8_t nof_candidates; + uint32_t nof_candidates; dci_candidate_t candidates[NSUBFRAMES_X_FRAME][MAX_CANDIDATES]; } pdcch_search_t; /* PDCCH object */ typedef struct LIBLTE_API { lte_cell_t cell; - uint16_t nof_bits; - uint16_t nof_symbols; - uint16_t nof_regs; - uint16_t nof_cce; - uint16_t max_bits; + uint32_t nof_bits; + uint32_t nof_symbols; + uint32_t nof_regs; + uint32_t nof_cce; + uint32_t max_bits; pdcch_search_t search_mode[PDCCH_NOF_SEARCH_MODES]; pdcch_search_mode_t current_search_mode; @@ -101,8 +101,8 @@ LIBLTE_API void pdcch_free(pdcch_t *q); LIBLTE_API int pdcch_encode(pdcch_t *q, dci_t *dci, cf_t *slot_symbols[MAX_PORTS], - uint8_t nsubframe, - uint8_t cfi); + uint32_t nsubframe, + uint32_t cfi); /* Decoding functions */ @@ -115,18 +115,18 @@ LIBLTE_API int pdcch_decode(pdcch_t *q, cf_t *slot_symbols, cf_t *ce[MAX_PORTS], dci_t *dci, - uint8_t nsubframe, - uint8_t cfi); + uint32_t nsubframe, + uint32_t cfi); LIBLTE_API int pdcch_extract_llr(pdcch_t *q, cf_t *slot_symbols, cf_t *ce[MAX_PORTS], float *llr, - uint8_t nsubframe, - uint8_t cfi); + uint32_t nsubframe, + uint32_t cfi); LIBLTE_API int pdcch_init_search_si(pdcch_t *q, - uint8_t cfi); + uint32_t cfi); LIBLTE_API void pdcch_set_search_si(pdcch_t *q); @@ -136,18 +136,18 @@ LIBLTE_API int pdcch_decode_si(pdcch_t *q, LIBLTE_API int pdcch_init_search_ue(pdcch_t *q, uint16_t c_rnti, - uint8_t cfi); + uint32_t cfi); LIBLTE_API void pdcch_set_search_ue(pdcch_t *q); LIBLTE_API int pdcch_decode_ue(pdcch_t *q, float *llr, dci_t *dci, - uint8_t nsubframe); + uint32_t nsubframe); LIBLTE_API int pdcch_init_search_ra(pdcch_t *q, uint16_t ra_rnti, - uint8_t cfi); + uint32_t cfi); LIBLTE_API void pdcch_set_search_ra(pdcch_t *q); diff --git a/lte/phy/include/liblte/phy/phch/pdsch.h b/lte/phy/include/liblte/phy/phch/pdsch.h index 9f7ac40cc..c48fa1c5c 100644 --- a/lte/phy/include/liblte/phy/phch/pdsch.h +++ b/lte/phy/include/liblte/phy/phch/pdsch.h @@ -51,7 +51,7 @@ typedef _Complex float cf_t; typedef struct LIBLTE_API { lte_cell_t cell; - uint16_t max_symbols; + uint32_t max_symbols; uint16_t rnti; /* buffers */ @@ -85,7 +85,7 @@ LIBLTE_API void pdsch_free(pdsch_t *q); LIBLTE_API int pdsch_encode(pdsch_t *q, char *data, cf_t *sf_symbols[MAX_PORTS], - uint8_t nsubframe, + uint32_t nsubframe, ra_mcs_t mcs, ra_prb_t *prb_alloc); @@ -93,7 +93,7 @@ LIBLTE_API int pdsch_decode(pdsch_t *q, cf_t *sf_symbols, cf_t *ce[MAX_PORTS], char *data, - uint8_t nsubframe, + uint32_t nsubframe, ra_mcs_t mcs, ra_prb_t *prb_alloc); @@ -101,6 +101,6 @@ LIBLTE_API int pdsch_get(pdsch_t *q, cf_t *sf_symbols, cf_t *pdsch_symbols, ra_prb_t *prb_alloc, - uint8_t subframe); + uint32_t subframe); #endif diff --git a/lte/phy/include/liblte/phy/phch/phich.h b/lte/phy/include/liblte/phy/phch/phich.h index fad03467a..dbe68dfea 100644 --- a/lte/phy/include/liblte/phy/phch/phich.h +++ b/lte/phy/include/liblte/phy/phch/phich.h @@ -87,22 +87,22 @@ LIBLTE_API void phich_free(phich_t *q); LIBLTE_API int phich_decode(phich_t *q, cf_t *slot_symbols, cf_t *ce[MAX_PORTS], - uint8_t ngroup, - uint8_t nseq, - uint8_t nsubframe, + uint32_t ngroup, + uint32_t nseq, + uint32_t nsubframe, char *ack, - uint8_t *distance); + uint32_t *distance); LIBLTE_API int phich_encode(phich_t *q, char ack, - uint8_t ngroup, - uint8_t nseq, - uint8_t nsubframe, + uint32_t ngroup, + uint32_t nseq, + uint32_t nsubframe, cf_t *slot_symbols[MAX_PORTS]); LIBLTE_API void phich_reset(phich_t *q, cf_t *slot_symbols[MAX_PORTS]); -LIBLTE_API uint8_t phich_ngroups(phich_t *q); +LIBLTE_API uint32_t phich_ngroups(phich_t *q); #endif // PHICH_ diff --git a/lte/phy/include/liblte/phy/phch/ra.h b/lte/phy/include/liblte/phy/phch/ra.h index 7581c4116..7b9ed8362 100644 --- a/lte/phy/include/liblte/phy/phch/ra.h +++ b/lte/phy/include/liblte/phy/phch/ra.h @@ -44,8 +44,8 @@ typedef enum LIBLTE_API { 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. - uint8_t tbs_idx; - uint8_t mcs_idx; + uint32_t tbs_idx; + uint32_t mcs_idx; uint32_t 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; @@ -60,13 +60,13 @@ typedef struct LIBLTE_API { typedef struct LIBLTE_API { uint32_t vrb_bitmask; - uint8_t rbg_subset;bool shift; + uint32_t rbg_subset;bool shift; } ra_type1_t; typedef struct LIBLTE_API { - uint16_t riv; // if L_crb==0, DCI message packer will take this value directly - uint8_t L_crb; - uint8_t RB_start; + uint32_t riv; // if L_crb==0, DCI message packer will take this value directly + uint32_t L_crb; + uint32_t RB_start; enum { nprb1a_2 = 0, nprb1a_3 = 1 } n_prb1a; @@ -87,8 +87,8 @@ typedef struct LIBLTE_API { ra_type2_t type2_alloc; }; ra_mcs_t mcs; - uint8_t harq_process; - uint8_t rv_idx; + uint32_t harq_process; + uint32_t rv_idx; bool ndi; } ra_pdsch_t; @@ -106,7 +106,7 @@ 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 + uint32_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; @@ -114,14 +114,14 @@ typedef struct LIBLTE_API { } ra_pusch_t; typedef struct LIBLTE_API { - uint8_t prb_idx[MAX_PRB]; - uint8_t nof_prb; + uint32_t prb_idx[MAX_PRB]; + uint32_t nof_prb; } ra_prb_slot_t; typedef struct LIBLTE_API { ra_prb_slot_t slot[2]; - uint8_t lstart; - uint16_t re_sf[NSUBFRAMES_X_FRAME]; + uint32_t lstart; + uint32_t re_sf[NSUBFRAMES_X_FRAME]; } ra_prb_t; LIBLTE_API void ra_prb_fprint(FILE *f, @@ -129,87 +129,87 @@ LIBLTE_API void ra_prb_fprint(FILE *f, LIBLTE_API int ra_prb_get_dl(ra_prb_t *prb, ra_pdsch_t *ra, - uint8_t nof_prb); + uint32_t nof_prb); LIBLTE_API int ra_prb_get_ul(ra_prb_slot_t *prb, ra_pusch_t *ra, - uint8_t nof_prb); + uint32_t nof_prb); LIBLTE_API void ra_prb_get_re_dl(ra_prb_t *prb_dist, - uint8_t nof_prb, - uint8_t nof_ports, - uint8_t nof_ctrl_symbols, + uint32_t nof_prb, + uint32_t nof_ports, + uint32_t nof_ctrl_symbols, lte_cp_t cp); -LIBLTE_API uint16_t ra_nprb_dl(ra_pdsch_t *ra, - uint8_t nof_prb); +LIBLTE_API uint32_t ra_nprb_dl(ra_pdsch_t *ra, + uint32_t nof_prb); -LIBLTE_API uint16_t ra_nprb_ul(ra_pusch_t *ra, - uint8_t nof_prb); +LIBLTE_API uint32_t ra_nprb_ul(ra_pusch_t *ra, + uint32_t nof_prb); -LIBLTE_API uint8_t ra_mcs_to_table_idx(ra_mcs_t *mcs); +LIBLTE_API uint32_t ra_mcs_to_table_idx(ra_mcs_t *mcs); -LIBLTE_API int ra_mcs_from_idx_dl(uint8_t idx, +LIBLTE_API int ra_mcs_from_idx_dl(uint32_t idx, ra_mcs_t *mcs); -LIBLTE_API int ra_mcs_from_idx_ul(uint8_t idx, +LIBLTE_API int ra_mcs_from_idx_ul(uint32_t idx, ra_mcs_t *mcs); -LIBLTE_API int ra_tbs_from_idx_format1c(uint8_t tbs_idx); +LIBLTE_API int ra_tbs_from_idx_format1c(uint32_t tbs_idx); LIBLTE_API int ra_tbs_to_table_idx_format1c(uint32_t tbs); -LIBLTE_API int ra_tbs_from_idx(uint8_t tbs_idx, - uint8_t n_prb); +LIBLTE_API int ra_tbs_from_idx(uint32_t tbs_idx, + uint32_t n_prb); LIBLTE_API int ra_tbs_to_table_idx(uint32_t tbs, - uint8_t n_prb); + uint32_t n_prb); -LIBLTE_API uint8_t ra_mcs_to_table_idx(ra_mcs_t *mcs); +LIBLTE_API uint32_t ra_mcs_to_table_idx(ra_mcs_t *mcs); -LIBLTE_API int ra_mcs_from_idx_dl(uint8_t idx, +LIBLTE_API int ra_mcs_from_idx_dl(uint32_t idx, ra_mcs_t *mcs); -LIBLTE_API int ra_mcs_from_idx_ul(uint8_t idx, +LIBLTE_API int ra_mcs_from_idx_ul(uint32_t idx, ra_mcs_t *mcs); LIBLTE_API char *ra_mod_string(ra_mod_t mod); -LIBLTE_API uint8_t ra_type0_P(uint8_t nof_prb); +LIBLTE_API uint32_t ra_type0_P(uint32_t nof_prb); -LIBLTE_API uint16_t ra_type2_to_riv(uint8_t L_crb, - uint8_t RB_start, - uint8_t nof_prb); +LIBLTE_API uint32_t ra_type2_to_riv(uint32_t L_crb, + uint32_t RB_start, + uint32_t nof_prb); -LIBLTE_API void ra_type2_from_riv(uint16_t riv, - uint8_t *L_crb, - uint8_t *RB_start, - uint8_t nof_prb, - uint8_t nof_vrb); +LIBLTE_API void ra_type2_from_riv(uint32_t riv, + uint32_t *L_crb, + uint32_t *RB_start, + uint32_t nof_prb, + uint32_t nof_vrb); -LIBLTE_API uint8_t ra_type2_n_vrb_dl(uint8_t nof_prb, +LIBLTE_API uint32_t ra_type2_n_vrb_dl(uint32_t nof_prb, bool ngap_is_1); -LIBLTE_API uint8_t ra_type2_n_rb_step(uint8_t nof_prb); +LIBLTE_API uint32_t ra_type2_n_rb_step(uint32_t nof_prb); -LIBLTE_API uint8_t ra_type2_ngap(uint8_t nof_prb, +LIBLTE_API uint32_t ra_type2_ngap(uint32_t nof_prb, bool ngap_is_1); -LIBLTE_API uint8_t ra_type1_N_rb(uint8_t nof_prb); +LIBLTE_API uint32_t ra_type1_N_rb(uint32_t nof_prb); LIBLTE_API void ra_pdsch_set_mcs_index(ra_pdsch_t *ra, - uint8_t mcs_idx); + uint32_t mcs_idx); LIBLTE_API void ra_pdsch_set_mcs(ra_pdsch_t *ra, ra_mod_t mod, - uint8_t tbs_idx); + uint32_t tbs_idx); LIBLTE_API void ra_pdsch_fprint(FILE *f, ra_pdsch_t *ra, - uint8_t nof_prb); + uint32_t nof_prb); LIBLTE_API void ra_pusch_fprint(FILE *f, ra_pusch_t *ra, - uint8_t nof_prb); + uint32_t nof_prb); #endif /* RB_ALLOC_H_ */ diff --git a/lte/phy/include/liblte/phy/phch/regs.h b/lte/phy/include/liblte/phy/phch/regs.h index 61d289513..38f3515a9 100644 --- a/lte/phy/include/liblte/phy/phch/regs.h +++ b/lte/phy/include/liblte/phy/phch/regs.h @@ -45,23 +45,23 @@ typedef _Complex float cf_t; typedef struct LIBLTE_API { - uint16_t k[4]; - uint16_t k0; - uint8_t l; + uint32_t k[4]; + uint32_t k0; + uint32_t l; bool assigned; }regs_reg_t; typedef struct LIBLTE_API { - uint16_t nof_regs; + uint32_t nof_regs; regs_reg_t **regs; }regs_ch_t; typedef struct LIBLTE_API { lte_cell_t cell; - uint8_t max_ctrl_symbols; - uint8_t cfi; + uint32_t max_ctrl_symbols; + uint32_t cfi; bool cfi_initiated; - uint8_t ngroups_phich; + uint32_t ngroups_phich; phich_resources_t phich_res; phich_length_t phich_len; @@ -71,7 +71,7 @@ typedef struct LIBLTE_API { regs_ch_t pdcch[3]; /* PDCCH indexing, permutation and interleaving is computed for the three possible CFI value */ - uint16_t nof_regs; + uint32_t nof_regs; regs_reg_t *regs; }regs_t; @@ -82,10 +82,10 @@ LIBLTE_API int regs_init(regs_t *h, LIBLTE_API void regs_free(regs_t *h); LIBLTE_API int regs_set_cfi(regs_t *h, - uint8_t nof_ctrl_symbols); + uint32_t nof_ctrl_symbols); -LIBLTE_API uint16_t regs_pcfich_nregs(regs_t *h); +LIBLTE_API uint32_t regs_pcfich_nregs(regs_t *h); LIBLTE_API int regs_pcfich_put(regs_t *h, cf_t pcfich_symbols[REGS_PCFICH_NSYM], cf_t *slot_symbols); @@ -94,22 +94,22 @@ LIBLTE_API int regs_pcfich_get(regs_t *h, cf_t *slot_symbols, cf_t pcfich_symbols[REGS_PCFICH_NSYM]); -LIBLTE_API uint16_t regs_phich_nregs(regs_t *h); +LIBLTE_API uint32_t regs_phich_nregs(regs_t *h); LIBLTE_API int regs_phich_add(regs_t *h, cf_t phich_symbols[REGS_PHICH_NSYM], - uint8_t ngroup, + uint32_t ngroup, cf_t *slot_symbols); LIBLTE_API int regs_phich_get(regs_t *h, cf_t *slot_symbols, cf_t phich_symbols[REGS_PHICH_NSYM], - uint8_t ngroup); + uint32_t ngroup); -LIBLTE_API uint8_t regs_phich_ngroups(regs_t *h); +LIBLTE_API uint32_t regs_phich_ngroups(regs_t *h); LIBLTE_API int regs_phich_reset(regs_t *h, cf_t *slot_symbols); -LIBLTE_API int regs_pdcch_nregs(regs_t *h, uint8_t cfi); +LIBLTE_API int regs_pdcch_nregs(regs_t *h, uint32_t cfi); LIBLTE_API int regs_pdcch_put(regs_t *h, cf_t *pdcch_symbols, cf_t *slot_symbols); diff --git a/lte/phy/include/liblte/phy/sync/sync_frame.h b/lte/phy/include/liblte/phy/sync/sync_frame.h index c4758a5db..afe73c375 100644 --- a/lte/phy/include/liblte/phy/sync/sync_frame.h +++ b/lte/phy/include/liblte/phy/sync/sync_frame.h @@ -55,36 +55,38 @@ enum sync_frame_state { SF_FIND, SF_TRACK }; typedef struct LIBLTE_API { sync_t s; enum sync_frame_state state; - int downsampling; + uint32_t downsampling; resample_arb_t resample; unsigned long frame_cnt; bool fb_wp; - int frame_size; + uint32_t frame_size; cf_t *input_buffer; cf_t *input_downsampled; cfo_t cfocorr; float cur_cfo; - int peak_idx; - int cell_id; + uint32_t peak_idx; + uint32_t cell_id; float timeoffset; - int last_found; - int sf_idx; + uint32_t last_found; + uint32_t sf_idx; }sync_frame_t; /* Initializes the automatic tracker, setting the downsampling ratio for the input signal. - * upsampled is the ratio of the provided signal sampling frequency to 1.92 Mhz. E.g. if input is sampled at 3.84 Mhz, - * upsampled should be 2. + * downsampling is the ratio of the provided signal sampling frequency to 1.92 Mhz. E.g. if input is sampled at 3.84 Mhz, + * downsampling should be 2. */ -LIBLTE_API int sync_frame_init(sync_frame_t *q, int upsampled); +LIBLTE_API int sync_frame_init(sync_frame_t *q, + uint32_t downsampling); LIBLTE_API void sync_frame_free(sync_frame_t *q); -LIBLTE_API void sync_frame_set_threshold(sync_frame_t *q, float threshold); +LIBLTE_API void sync_frame_set_threshold(sync_frame_t *q, + float threshold); -LIBLTE_API int sync_frame_cell_id(sync_frame_t *q); +LIBLTE_API uint32_t sync_frame_cell_id(sync_frame_t *q); -LIBLTE_API int sync_frame_sfidx(sync_frame_t *q); +LIBLTE_API uint32_t sync_frame_sfidx(sync_frame_t *q); /* Automatically time/freq synchronizes the input signal. Returns 1 if the signal is synched and locked, * and fills the output buffer with the time and frequency aligned version of the signal. @@ -95,7 +97,9 @@ LIBLTE_API int sync_frame_sfidx(sync_frame_t *q); * * The buffer input must have subframe_size samples (used in sync_init) */ -LIBLTE_API int sync_frame_push(sync_frame_t *q, cf_t *input, cf_t *output); +LIBLTE_API int sync_frame_push(sync_frame_t *q, + cf_t *input, + cf_t *output); /* Resets the automatic tracker */ LIBLTE_API void sync_frame_reset(sync_frame_t *q); diff --git a/lte/phy/include/liblte/phy/utils/bit.h b/lte/phy/include/liblte/phy/utils/bit.h index 92a20a631..acfdbce3c 100644 --- a/lte/phy/include/liblte/phy/utils/bit.h +++ b/lte/phy/include/liblte/phy/utils/bit.h @@ -38,7 +38,7 @@ LIBLTE_API uint32_t bit_unpack(char **bits, int nof_bits); LIBLTE_API void bit_pack(uint32_t value, char **bits, int nof_bits); LIBLTE_API void bit_fprint(FILE *stream, char *bits, int nof_bits); LIBLTE_API unsigned int bit_diff(char *x, char *y, int nbits); -LIBLTE_API uint8_t bit_count(uint32_t n); +LIBLTE_API uint32_t bit_count(uint32_t n); #endif // BIT_ diff --git a/lte/phy/lib/ch_estimation/src/chest.c b/lte/phy/lib/ch_estimation/src/chest.c index 73d72906b..b8b40b05d 100644 --- a/lte/phy/lib/ch_estimation/src/chest.c +++ b/lte/phy/lib/ch_estimation/src/chest.c @@ -39,7 +39,7 @@ #define SLOT_SZ(q) (q->nof_symbols * q->symbol_sz) #define SF_SZ(q) (2 * SLOT_SZ(q)) -void chest_fprint(chest_t *q, FILE *stream, uint8_t nslot, uint8_t port_id) { +void chest_fprint(chest_t *q, FILE *stream, uint32_t nslot, uint32_t port_id) { chest_ref_fprint(q, stream, nslot, port_id); chest_recvsig_fprint(q, stream, nslot, port_id); chest_ce_fprint(q, stream, nslot, port_id); @@ -48,7 +48,7 @@ void chest_fprint(chest_t *q, FILE *stream, uint8_t nslot, uint8_t port_id) { /* Sets the number of ports to estimate. nof_ports must be smaler than nof_ports * used during the call to chest_init(). */ -int chest_set_nof_ports(chest_t *q, uint8_t nof_ports) { +int chest_set_nof_ports(chest_t *q, uint32_t nof_ports) { if (nof_ports < q->nof_ports) { q->nof_ports = nof_ports; return LIBLTE_SUCCESS; @@ -57,7 +57,7 @@ int chest_set_nof_ports(chest_t *q, uint8_t nof_ports) { } } -void chest_ref_fprint(chest_t *q, FILE *stream, uint8_t nslot, uint8_t port_id) { +void chest_ref_fprint(chest_t *q, FILE *stream, uint32_t nslot, uint32_t port_id) { int i; fprintf(stream, "refs%d=[",port_id); for (i=0;irefsignal[port_id][nslot].nof_refs;i++) { @@ -67,7 +67,7 @@ void chest_ref_fprint(chest_t *q, FILE *stream, uint8_t nslot, uint8_t port_id) fprintf(stream, "];\n"); } -void chest_recvsig_fprint(chest_t *q, FILE *stream, uint8_t nslot, uint8_t port_id) { +void chest_recvsig_fprint(chest_t *q, FILE *stream, uint32_t nslot, uint32_t port_id) { int i; fprintf(stream, "recvsig%d=[",port_id); for (i=0;irefsignal[port_id][nslot].nof_refs;i++) { @@ -77,7 +77,7 @@ void chest_recvsig_fprint(chest_t *q, FILE *stream, uint8_t nslot, uint8_t port_ fprintf(stream, "];\n"); } -void chest_ce_fprint(chest_t *q, FILE *stream, uint8_t nslot, uint8_t port_id) { +void chest_ce_fprint(chest_t *q, FILE *stream, uint32_t nslot, uint32_t port_id) { int i; fprintf(stream, "mag%d=[",port_id); for (i=0;irefsignal[port_id][nslot].nof_refs;i++) { @@ -91,7 +91,7 @@ void chest_ce_fprint(chest_t *q, FILE *stream, uint8_t nslot, uint8_t port_id) { fprintf(stream, "];\n"); } -int chest_ce_ref(chest_t *q, cf_t *input, uint8_t nslot, uint8_t port_id, uint16_t nref) { +int chest_ce_ref(chest_t *q, cf_t *input, uint32_t nslot, uint32_t port_id, uint32_t nref) { int fidx, tidx; cf_t known_ref, channel_ref; int ret = LIBLTE_ERROR_INVALID_INPUTS; @@ -128,7 +128,7 @@ int chest_ce_ref(chest_t *q, cf_t *input, uint8_t nslot, uint8_t port_id, uint16 /* Computes channel estimates for each reference in a slot and port. * Saves the nof_prb * 12 * nof_symbols channel estimates in the array ce */ -int chest_ce_slot_port(chest_t *q, cf_t *input, cf_t *ce, uint8_t nslot, uint8_t port_id) { +int chest_ce_slot_port(chest_t *q, cf_t *input, cf_t *ce, uint32_t nslot, uint32_t port_id) { int i, j; cf_t x[2], y[MAX_NSYMB]; @@ -183,7 +183,7 @@ int chest_ce_slot_port(chest_t *q, cf_t *input, cf_t *ce, uint8_t nslot, uint8_t /* Computes channel estimates for each reference in a subframe and port id. */ -int chest_ce_sf_port(chest_t *q, cf_t *input, cf_t *ce, uint8_t sf_idx, uint8_t port_id) { +int chest_ce_sf_port(chest_t *q, cf_t *input, cf_t *ce, uint32_t sf_idx, uint32_t port_id) { int n, slotsz, ret; slotsz = q->nof_symbols*q->nof_re; for (n=0;n<2;n++) { @@ -197,7 +197,7 @@ int chest_ce_sf_port(chest_t *q, cf_t *input, cf_t *ce, uint8_t sf_idx, uint8_t /* Computes channel estimates for each reference in a slot for all ports. */ -int chest_ce_slot(chest_t *q, cf_t *input, cf_t **ce, uint8_t nslot) { +int chest_ce_slot(chest_t *q, cf_t *input, cf_t **ce, uint32_t nslot) { int p, ret; for (p=0;pnof_ports;p++) { ret = chest_ce_slot_port(q, input, ce[p], nslot, p); @@ -210,7 +210,7 @@ int chest_ce_slot(chest_t *q, cf_t *input, cf_t **ce, uint8_t nslot) { /* Computes channel estimates for each reference in a subframe for all ports. */ -int chest_ce_sf(chest_t *q, cf_t *input, cf_t *ce[MAX_PORTS], uint8_t sf_idx) { +int chest_ce_sf(chest_t *q, cf_t *input, cf_t *ce[MAX_PORTS], uint32_t sf_idx) { int p, n, slotsz, ret; slotsz = q->nof_symbols*q->nof_re; for (p=0;pnof_ports;p++) { @@ -224,7 +224,7 @@ int chest_ce_sf(chest_t *q, cf_t *input, cf_t *ce[MAX_PORTS], uint8_t sf_idx) { return LIBLTE_SUCCESS; } -int chest_init(chest_t *q, chest_interp_t interp, uint16_t nof_re, uint8_t nof_symbols, uint8_t nof_ports) { +int chest_init(chest_t *q, chest_interp_t interp, uint32_t nof_re, uint32_t nof_symbols, uint32_t nof_ports) { int ret = LIBLTE_ERROR_INVALID_INPUTS; if (q != NULL && @@ -259,7 +259,7 @@ int chest_init_LTEDL(chest_t *q, chest_interp_t interp, lte_cell_t cell) { } } -int chest_ref_LTEDL_slot_port(chest_t *q, uint8_t nslot, uint8_t port_id, lte_cell_t cell) { +int chest_ref_LTEDL_slot_port(chest_t *q, uint32_t nslot, uint32_t port_id, lte_cell_t cell) { int ret = LIBLTE_ERROR_INVALID_INPUTS; if (q != NULL && @@ -271,7 +271,7 @@ int chest_ref_LTEDL_slot_port(chest_t *q, uint8_t nslot, uint8_t port_id, lte_ce return ret; } -int chest_ref_LTEDL_slot(chest_t *q, uint8_t nslot, lte_cell_t cell) { +int chest_ref_LTEDL_slot(chest_t *q, uint32_t nslot, lte_cell_t cell) { int p, ret; for (p=0;pnof_ports;p++) { ret = chest_ref_LTEDL_slot_port(q, nslot, p, cell); @@ -306,13 +306,13 @@ void chest_free(chest_t *q) { /* Fills l[2] with the symbols in the slot nslot that contain references. * returns the number of symbols with references (in the slot) */ -int chest_ref_symbols(chest_t *q, uint8_t port_id, uint8_t nslot, uint8_t l[2]) { +int chest_ref_symbols(chest_t *q, uint32_t port_id, uint32_t nslot, uint32_t l[2]) { if (q != NULL && port_id < MAX_PORTS && nslot < NSLOTS_X_FRAME) { - memcpy(l, q->refsignal[port_id][nslot].symbols_ref, sizeof(uint8_t) * q->refsignal[port_id][nslot].nsymbols); + memcpy(l, q->refsignal[port_id][nslot].symbols_ref, sizeof(uint32_t) * q->refsignal[port_id][nslot].nsymbols); return q->refsignal[port_id][nslot].nsymbols; } else { return LIBLTE_ERROR_INVALID_INPUTS; diff --git a/lte/phy/lib/ch_estimation/src/refsignal.c b/lte/phy/lib/ch_estimation/src/refsignal.c index f4eb0dfd8..eb476f0ca 100644 --- a/lte/phy/lib/ch_estimation/src/refsignal.c +++ b/lte/phy/lib/ch_estimation/src/refsignal.c @@ -40,7 +40,7 @@ #define idx(x, y) (l*nof_refs_x_symbol+i) -int refsignal_v(uint8_t port_id, uint8_t ns, uint8_t symbol_id) { +int refsignal_v(uint32_t port_id, uint32_t ns, uint32_t symbol_id) { int v=-1; switch(port_id) { case 0: @@ -67,13 +67,13 @@ int refsignal_v(uint8_t port_id, uint8_t ns, uint8_t symbol_id) { return v; } -int refsignal_k(int m, int v, uint16_t cell_id) { +int refsignal_k(int m, int v, uint32_t cell_id) { return 6*m+((v+(cell_id%6))%6); } int refsignal_put(refsignal_t *q, cf_t *slot_symbols) { int i; - uint16_t fidx, tidx; + uint32_t fidx, tidx; if (q != NULL && slot_symbols != NULL) { @@ -91,18 +91,18 @@ int refsignal_put(refsignal_t *q, cf_t *slot_symbols) { /** Initializes refsignal_t object according to 3GPP 36.211 6.10.1 * */ -int refsignal_init_LTEDL(refsignal_t *q, uint8_t port_id, uint8_t nslot, +int refsignal_init_LTEDL(refsignal_t *q, uint32_t port_id, uint32_t nslot, lte_cell_t cell) { uint32_t c_init; - uint8_t ns, l, lp[2]; + uint32_t ns, l, lp[2]; int N_cp; int i; int ret = LIBLTE_ERROR_INVALID_INPUTS; sequence_t seq; int v; int mp; - uint8_t nof_refs_x_symbol, nof_ref_symbols; + uint32_t nof_refs_x_symbol, nof_ref_symbols; if (q != NULL && port_id < MAX_PORTS && @@ -134,13 +134,13 @@ int refsignal_init_LTEDL(refsignal_t *q, uint8_t port_id, uint8_t nslot, q->voffset = cell.id%6; q->nof_prb = cell.nof_prb; - q->symbols_ref = malloc(sizeof(uint8_t) * nof_ref_symbols); + q->symbols_ref = malloc(sizeof(uint32_t) * nof_ref_symbols); if (!q->symbols_ref) { perror("malloc"); goto free_and_exit; } - memcpy(q->symbols_ref, lp, sizeof(uint8_t) * nof_ref_symbols); + memcpy(q->symbols_ref, lp, sizeof(uint32_t) * nof_ref_symbols); q->refs = vec_malloc(q->nof_refs * sizeof(ref_t)); if (!q->refs) { diff --git a/lte/phy/lib/phch/src/dci.c b/lte/phy/lib/phch/src/dci.c index bc1bcccd5..0e38b0ffd 100644 --- a/lte/phy/lib/phch/src/dci.c +++ b/lte/phy/lib/phch/src/dci.c @@ -40,7 +40,7 @@ #include "liblte/phy/utils/vector.h" #include "liblte/phy/utils/debug.h" -int dci_init(dci_t *q, uint8_t max_dcis) { +int dci_init(dci_t *q, uint32_t max_dcis) { q->msg = calloc(sizeof(dci_msg_t), max_dcis); if (!q->msg) { perror("malloc"); @@ -62,7 +62,7 @@ void dci_candidate_fprint(FILE *f, dci_candidate_t *q) { q->nof_bits); } -int dci_msg_candidate_set(dci_msg_t *msg, uint8_t L, uint8_t nCCE, uint16_t rnti) { +int dci_msg_candidate_set(dci_msg_t *msg, uint32_t L, uint32_t nCCE, uint16_t rnti) { if (L >= 0 && L <= 3) { msg->location.L = L; } else { @@ -79,13 +79,13 @@ int dci_msg_candidate_set(dci_msg_t *msg, uint8_t L, uint8_t nCCE, uint16_t rnti return LIBLTE_SUCCESS; } -uint8_t riv_nbits(uint8_t nof_prb) { - return (uint8_t) ceilf(log2f((float) nof_prb * ((float) nof_prb + 1) / 2)); +uint32_t riv_nbits(uint32_t nof_prb) { + return (uint32_t) ceilf(log2f((float) nof_prb * ((float) nof_prb + 1) / 2)); } -const uint8_t ambiguous_sizes[10] = { 12, 14, 16, 20, 24, 26, 32, 40, 44, 56 }; +const uint32_t ambiguous_sizes[10] = { 12, 14, 16, 20, 24, 26, 32, 40, 44, 56 }; -bool is_ambiguous_size(uint8_t size) { +bool is_ambiguous_size(uint32_t size) { int i; for (i = 0; i < 10; i++) { if (size == ambiguous_sizes[i]) { @@ -98,12 +98,12 @@ bool is_ambiguous_size(uint8_t size) { /********************************** * PAYLOAD sizeof functions * ********************************/ -uint8_t dci_format0_sizeof_(uint8_t nof_prb) { +uint32_t dci_format0_sizeof_(uint32_t nof_prb) { return 1 + 1 + riv_nbits(nof_prb) + 5 + 1 + 2 + 3 + 1; } -uint8_t dci_format1A_sizeof(uint8_t nof_prb) { - uint8_t n; +uint32_t dci_format1A_sizeof(uint32_t nof_prb) { + uint32_t n; n = 1 + 1 + riv_nbits(nof_prb) + 5 + 3 + 1 + 2 + 2; while (n < dci_format0_sizeof_(nof_prb)) { n++; @@ -114,17 +114,17 @@ uint8_t dci_format1A_sizeof(uint8_t nof_prb) { return n; } -uint8_t dci_format0_sizeof(uint8_t nof_prb) { - uint8_t n = dci_format0_sizeof_(nof_prb); +uint32_t dci_format0_sizeof(uint32_t nof_prb) { + uint32_t n = dci_format0_sizeof_(nof_prb); while (n < dci_format1A_sizeof(nof_prb)) { n++; } return n; } -uint8_t dci_format1_sizeof(uint8_t nof_prb) { +uint32_t dci_format1_sizeof(uint32_t nof_prb) { - uint8_t n = (uint8_t) ceilf((float) nof_prb / ra_type0_P(nof_prb)) + 5 + 3 + 1 + 2 + uint32_t n = (uint32_t) ceilf((float) nof_prb / ra_type0_P(nof_prb)) + 5 + 3 + 1 + 2 + 2; if (nof_prb > 10) { n++; @@ -136,17 +136,17 @@ uint8_t dci_format1_sizeof(uint8_t nof_prb) { return n; } -uint8_t dci_format1C_sizeof(uint8_t nof_prb) { - uint8_t n_vrb_dl_gap1 = ra_type2_n_vrb_dl(nof_prb, true); - uint8_t n_step = ra_type2_n_rb_step(nof_prb); - uint8_t n = riv_nbits((uint8_t) n_vrb_dl_gap1 / n_step) + 5; +uint32_t dci_format1C_sizeof(uint32_t nof_prb) { + uint32_t n_vrb_dl_gap1 = ra_type2_n_vrb_dl(nof_prb, true); + uint32_t n_step = ra_type2_n_rb_step(nof_prb); + uint32_t n = riv_nbits((uint32_t) n_vrb_dl_gap1 / n_step) + 5; if (nof_prb >= 50) { n++; } return n; } -uint8_t dci_format_sizeof(dci_format_t format, uint8_t nof_prb) { +uint32_t dci_format_sizeof(dci_format_t format, uint32_t nof_prb) { switch (format) { case Format0: return dci_format0_sizeof(nof_prb); @@ -170,11 +170,11 @@ uint8_t dci_format_sizeof(dci_format_t format, uint8_t nof_prb) { * * TODO: TPC and cyclic shift for DM RS not implemented */ -int dci_format0_pack(ra_pusch_t *data, dci_msg_t *msg, uint8_t nof_prb) { +int dci_format0_pack(ra_pusch_t *data, dci_msg_t *msg, uint32_t nof_prb) { /* pack bits */ char *y = msg->data; - uint8_t n_ul_hop; + uint32_t n_ul_hop; *y++ = 0; // format differentiation if (data->freq_hop_fl == hop_disabled) { // frequency hopping @@ -193,7 +193,7 @@ int dci_format0_pack(ra_pusch_t *data, dci_msg_t *msg, uint8_t nof_prb) { } /* pack RIV according to 8.1 of 36.213 */ - uint16_t riv; + 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); @@ -203,7 +203,7 @@ int dci_format0_pack(ra_pusch_t *data, dci_msg_t *msg, uint8_t nof_prb) { bit_pack((uint32_t) riv, &y, riv_nbits(nof_prb) - n_ul_hop); /* pack MCS according to 8.6.1 of 36.213 */ - uint8_t mcs; + uint32_t mcs; if (data->cqi_request) { mcs = 29; } else { @@ -241,7 +241,7 @@ int dci_format0_pack(ra_pusch_t *data, dci_msg_t *msg, uint8_t nof_prb) { *y++ = data->cqi_request; // Padding with zeros - uint8_t n = dci_format0_sizeof(nof_prb); + uint32_t n = dci_format0_sizeof(nof_prb); while (y - msg->data < n) { *y++ = 0; } @@ -253,11 +253,11 @@ int dci_format0_pack(ra_pusch_t *data, dci_msg_t *msg, uint8_t nof_prb) { * * TODO: TPC and cyclic shift for DM RS not implemented */ -int dci_format0_unpack(dci_msg_t *msg, ra_pusch_t *data, uint8_t nof_prb) { +int dci_format0_unpack(dci_msg_t *msg, ra_pusch_t *data, uint32_t nof_prb) { /* pack bits */ char *y = msg->data; - uint8_t n_ul_hop; + uint32_t n_ul_hop; /* Make sure it's a Format0 message */ if (msg->location.nof_bits != dci_format_sizeof(Format0, nof_prb)) { @@ -283,14 +283,14 @@ int dci_format0_unpack(dci_msg_t *msg, ra_pusch_t *data, uint8_t nof_prb) { } } /* unpack RIV according to 8.1 of 36.213 */ - uint16_t riv = bit_unpack(&y, riv_nbits(nof_prb) - n_ul_hop); + 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); bit_pack((uint32_t) riv, &y, riv_nbits(nof_prb) - n_ul_hop); data->type2_alloc.riv = riv; /* unpack MCS according to 8.6 of 36.213 */ - uint8_t mcs = bit_unpack(&y, 5); + uint32_t mcs = bit_unpack(&y, 5); data->ndi = *y++ ? true : false; @@ -326,7 +326,7 @@ int dci_format0_unpack(dci_msg_t *msg, ra_pusch_t *data, uint8_t nof_prb) { * TODO: TPC commands */ -int dci_format1_pack(ra_pdsch_t *data, dci_msg_t *msg, uint8_t nof_prb) { +int dci_format1_pack(ra_pdsch_t *data, dci_msg_t *msg, uint32_t nof_prb) { /* pack bits */ char *y = msg->data; @@ -336,8 +336,8 @@ int dci_format1_pack(ra_pdsch_t *data, dci_msg_t *msg, uint8_t nof_prb) { } /* Resource allocation: type0 or type 1 */ - uint8_t P = ra_type0_P(nof_prb); - uint8_t alloc_size = (uint8_t) ceilf((float) nof_prb / P); + uint32_t P = ra_type0_P(nof_prb); + uint32_t alloc_size = (uint32_t) ceilf((float) nof_prb / P); switch (data->alloc_type) { case alloc_type0: bit_pack((uint32_t) data->type0_alloc.rbg_bitmask, &y, alloc_size); @@ -355,7 +355,7 @@ int dci_format1_pack(ra_pdsch_t *data, dci_msg_t *msg, uint8_t nof_prb) { } /* pack MCS according to 7.1.7 of 36.213 */ - uint8_t mcs; + uint32_t mcs; if (data->mcs.mod == MOD_NULL) { mcs = data->mcs.mcs_idx; } else { @@ -381,7 +381,7 @@ int dci_format1_pack(ra_pdsch_t *data, dci_msg_t *msg, uint8_t nof_prb) { *y++ = 0; // Padding with zeros - uint8_t n = dci_format1_sizeof(nof_prb); + uint32_t n = dci_format1_sizeof(nof_prb); while (y - msg->data < n) { *y++ = 0; } @@ -390,7 +390,7 @@ int dci_format1_pack(ra_pdsch_t *data, dci_msg_t *msg, uint8_t nof_prb) { return LIBLTE_SUCCESS; } -int dci_format1_unpack(dci_msg_t *msg, ra_pdsch_t *data, uint8_t nof_prb) { +int dci_format1_unpack(dci_msg_t *msg, ra_pdsch_t *data, uint32_t nof_prb) { /* pack bits */ char *y = msg->data; @@ -408,8 +408,8 @@ int dci_format1_unpack(dci_msg_t *msg, ra_pdsch_t *data, uint8_t nof_prb) { } /* Resource allocation: type0 or type 1 */ - uint8_t P = ra_type0_P(nof_prb); - uint8_t alloc_size = (uint8_t) ceilf((float) nof_prb / P); + uint32_t P = ra_type0_P(nof_prb); + uint32_t alloc_size = (uint32_t) ceilf((float) nof_prb / P); switch (data->alloc_type) { case alloc_type0: data->type0_alloc.rbg_bitmask = bit_unpack(&y, alloc_size); @@ -426,7 +426,7 @@ int dci_format1_unpack(dci_msg_t *msg, ra_pdsch_t *data, uint8_t nof_prb) { } /* unpack MCS according to 7.1.7 of 36.213 */ - uint8_t mcs = bit_unpack(&y, 5); + uint32_t mcs = bit_unpack(&y, 5); data->mcs.mcs_idx = mcs; if (ra_mcs_from_idx_dl(mcs, &data->mcs)) { fprintf(stderr, "Error getting MCS\n"); @@ -457,7 +457,7 @@ int dci_format1_unpack(dci_msg_t *msg, ra_pdsch_t *data, uint8_t nof_prb) { * * TODO: RA procedure initiated by PDCCH, TPC commands */ -int dci_format1As_pack(ra_pdsch_t *data, dci_msg_t *msg, uint8_t nof_prb, +int dci_format1As_pack(ra_pdsch_t *data, dci_msg_t *msg, uint32_t nof_prb, bool crc_is_crnti) { /* pack bits */ @@ -479,7 +479,7 @@ int dci_format1As_pack(ra_pdsch_t *data, dci_msg_t *msg, uint8_t nof_prb, return LIBLTE_ERROR; } } else { - uint8_t n_vrb_dl; + uint32_t n_vrb_dl; if (crc_is_crnti && nof_prb > 50) { n_vrb_dl = 16; } else { @@ -493,14 +493,14 @@ int dci_format1As_pack(ra_pdsch_t *data, dci_msg_t *msg, uint8_t nof_prb, } } /* pack RIV according to 7.1.6.3 of 36.213 */ - uint16_t riv; + 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); } else { riv = data->type2_alloc.riv; } - uint8_t nb_gap = 0; + uint32_t nb_gap = 0; if (crc_is_crnti && data->type2_alloc.mode == t2_dist && nof_prb >= 50) { nb_gap = 1; *y++ = data->type2_alloc.n_gap; @@ -508,13 +508,13 @@ int dci_format1As_pack(ra_pdsch_t *data, dci_msg_t *msg, uint8_t nof_prb, bit_pack((uint32_t) riv, &y, riv_nbits(nof_prb) - nb_gap); // in format1A, MCS = TBS according to 7.1.7.2 of 36.213 - uint8_t mcs; + uint32_t mcs; if (data->mcs.mod == MOD_NULL) { mcs = data->mcs.mcs_idx; } else { if (data->mcs.tbs) { // In format 1A, n_prb_1a is 2 or 3 if crc is not scrambled with C-RNTI - uint8_t n_prb; + uint32_t n_prb; if (!crc_is_crnti) { n_prb = ra_nprb_dl(data, nof_prb); } else { @@ -547,7 +547,7 @@ int dci_format1As_pack(ra_pdsch_t *data, dci_msg_t *msg, uint8_t nof_prb, } // Padding with zeros - uint8_t n = dci_format1A_sizeof(nof_prb); + uint32_t n = dci_format1A_sizeof(nof_prb); while (y - msg->data < n) { *y++ = 0; } @@ -559,7 +559,7 @@ int dci_format1As_pack(ra_pdsch_t *data, dci_msg_t *msg, uint8_t nof_prb, /* 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, uint8_t nof_prb, +int dci_format1As_unpack(dci_msg_t *msg, ra_pdsch_t *data, uint32_t nof_prb, bool crc_is_crnti) { /* pack bits */ @@ -583,18 +583,18 @@ int dci_format1As_unpack(dci_msg_t *msg, ra_pdsch_t *data, uint8_t nof_prb, data->type2_alloc.n_gap = t2_ng1; /* unpack RIV according to 7.1.6.3 of 36.213 */ - uint8_t nb_gap = 0; + uint32_t nb_gap = 0; if (crc_is_crnti && data->type2_alloc.mode == t2_dist && nof_prb >= 50) { nb_gap = 1; data->type2_alloc.n_gap = *y++; } - uint8_t nof_vrb; + uint32_t nof_vrb; if (data->type2_alloc.mode == t2_loc) { nof_vrb = nof_prb; } else { nof_vrb = ra_type2_n_vrb_dl(nof_prb, data->type2_alloc.n_gap == t2_ng1); } - uint16_t riv = bit_unpack(&y, riv_nbits(nof_prb) - nb_gap); + 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); data->type2_alloc.riv = riv; @@ -623,7 +623,7 @@ int dci_format1As_unpack(dci_msg_t *msg, ra_pdsch_t *data, uint8_t nof_prb, } data->mcs.tbs_idx = data->mcs.mcs_idx; - uint8_t n_prb; + uint32_t n_prb; if (crc_is_crnti) { n_prb = ra_nprb_dl(data, nof_prb); } else { @@ -638,7 +638,7 @@ int dci_format1As_unpack(dci_msg_t *msg, ra_pdsch_t *data, uint8_t nof_prb, /* Format 1C for compact scheduling of PDSCH words * */ -int dci_format1Cs_pack(ra_pdsch_t *data, dci_msg_t *msg, uint8_t nof_prb) { +int dci_format1Cs_pack(ra_pdsch_t *data, dci_msg_t *msg, uint32_t nof_prb) { /* pack bits */ char *y = msg->data; @@ -652,12 +652,12 @@ int dci_format1Cs_pack(ra_pdsch_t *data, dci_msg_t *msg, uint8_t nof_prb) { if (nof_prb >= 50) { *y++ = data->type2_alloc.n_gap; } - uint8_t n_step = ra_type2_n_rb_step(nof_prb); - uint8_t n_vrb_dl = ra_type2_n_vrb_dl(nof_prb, data->type2_alloc.n_gap == t2_ng1); + uint32_t n_step = ra_type2_n_rb_step(nof_prb); + uint32_t n_vrb_dl = ra_type2_n_vrb_dl(nof_prb, data->type2_alloc.n_gap == t2_ng1); - if (data->type2_alloc.L_crb > ((uint8_t) n_vrb_dl / n_step) * n_step) { + if (data->type2_alloc.L_crb > ((uint32_t) 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, ((uint8_t) n_vrb_dl / n_step) * n_step); + data->type2_alloc.L_crb, ((uint32_t) n_vrb_dl / n_step) * n_step); return LIBLTE_ERROR; } if (data->type2_alloc.L_crb % n_step) { @@ -668,11 +668,11 @@ int dci_format1Cs_pack(ra_pdsch_t *data, dci_msg_t *msg, uint8_t nof_prb) { fprintf(stderr, "RB_start must be multiple of n_step\n"); return LIBLTE_ERROR; } - uint8_t L_p = data->type2_alloc.L_crb / n_step; - uint8_t RB_p = data->type2_alloc.RB_start / n_step; - uint8_t n_vrb_p = (int) n_vrb_dl / n_step; + uint32_t L_p = data->type2_alloc.L_crb / n_step; + uint32_t RB_p = data->type2_alloc.RB_start / n_step; + uint32_t n_vrb_p = (int) n_vrb_dl / n_step; - uint16_t riv; + uint32_t riv; if (data->type2_alloc.L_crb) { riv = ra_type2_to_riv(L_p, RB_p, n_vrb_p); } else { @@ -681,7 +681,7 @@ int dci_format1Cs_pack(ra_pdsch_t *data, dci_msg_t *msg, uint8_t nof_prb) { bit_pack((uint32_t) riv, &y, riv_nbits((int) n_vrb_dl / n_step)); // in format1C, MCS = TBS according to 7.1.7.2 of 36.213 - uint8_t mcs; + uint32_t mcs; if (data->mcs.mod == MOD_NULL) { mcs = data->mcs.mcs_idx; } else { @@ -697,8 +697,8 @@ int dci_format1Cs_pack(ra_pdsch_t *data, dci_msg_t *msg, uint8_t nof_prb) { return LIBLTE_SUCCESS; } -int dci_format1Cs_unpack(dci_msg_t *msg, ra_pdsch_t *data, uint8_t nof_prb) { - uint8_t L_p, RB_p; +int dci_format1Cs_unpack(dci_msg_t *msg, ra_pdsch_t *data, uint32_t nof_prb) { + uint32_t L_p, RB_p; /* pack bits */ char *y = msg->data; @@ -712,11 +712,11 @@ int dci_format1Cs_unpack(dci_msg_t *msg, ra_pdsch_t *data, uint8_t nof_prb) { if (nof_prb >= 50) { data->type2_alloc.n_gap = *y++; } - uint8_t n_step = ra_type2_n_rb_step(nof_prb); - uint8_t n_vrb_dl = ra_type2_n_vrb_dl(nof_prb, data->type2_alloc.n_gap == t2_ng1); + uint32_t n_step = ra_type2_n_rb_step(nof_prb); + uint32_t n_vrb_dl = ra_type2_n_vrb_dl(nof_prb, data->type2_alloc.n_gap == t2_ng1); - uint16_t riv = bit_unpack(&y, riv_nbits((int) n_vrb_dl / n_step)); - uint8_t n_vrb_p = (uint8_t) n_vrb_dl / n_step; + uint32_t riv = bit_unpack(&y, riv_nbits((int) n_vrb_dl / n_step)); + uint32_t n_vrb_p = (uint32_t) n_vrb_dl / n_step; ra_type2_from_riv(riv, &L_p, &RB_p, n_vrb_p, n_vrb_p); data->type2_alloc.L_crb = L_p * n_step; @@ -734,7 +734,7 @@ int dci_format1Cs_unpack(dci_msg_t *msg, ra_pdsch_t *data, uint8_t nof_prb) { } int dci_msg_pack_pdsch(ra_pdsch_t *data, dci_msg_t *msg, dci_format_t format, - uint8_t nof_prb, bool crc_is_crnti) { + uint32_t nof_prb, bool crc_is_crnti) { switch (format) { case Format1: return dci_format1_pack(data, msg, nof_prb); @@ -749,7 +749,7 @@ int dci_msg_pack_pdsch(ra_pdsch_t *data, dci_msg_t *msg, dci_format_t format, } } -int dci_msg_unpack_pdsch(dci_msg_t *msg, ra_pdsch_t *data, uint8_t nof_prb, +int dci_msg_unpack_pdsch(dci_msg_t *msg, ra_pdsch_t *data, uint32_t 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); @@ -762,11 +762,11 @@ int dci_msg_unpack_pdsch(dci_msg_t *msg, ra_pdsch_t *data, uint8_t nof_prb, } } -int dci_msg_pack_pusch(ra_pusch_t *data, dci_msg_t *msg, uint8_t nof_prb) { +int dci_msg_pack_pusch(ra_pusch_t *data, dci_msg_t *msg, uint32_t nof_prb) { return dci_format0_pack(data, msg, nof_prb); } -int dci_msg_unpack_pusch(dci_msg_t *msg, ra_pusch_t *data, uint8_t nof_prb) { +int dci_msg_unpack_pusch(dci_msg_t *msg, ra_pusch_t *data, uint32_t nof_prb) { return dci_format0_unpack(msg, data, nof_prb); } @@ -806,7 +806,7 @@ void dci_msg_type_fprint(FILE *f, dci_msg_type_t type) { } } -int dci_msg_get_type(dci_msg_t *msg, dci_msg_type_t *type, uint8_t nof_prb, +int dci_msg_get_type(dci_msg_t *msg, dci_msg_type_t *type, uint32_t nof_prb, uint16_t crnti) { if (msg->location.nof_bits == dci_format_sizeof(Format0, nof_prb) && !msg->data[0]) { diff --git a/lte/phy/lib/phch/src/pbch.c b/lte/phy/lib/phch/src/pbch.c index caca9061c..dce32ad12 100644 --- a/lte/phy/lib/phch/src/pbch.c +++ b/lte/phy/lib/phch/src/pbch.c @@ -372,15 +372,15 @@ void crc_set_mask(char *data, int nof_ports) { * * Returns 0 if the data is correct, -1 otherwise */ -uint32_t pbch_crc_check(pbch_t *q, char *bits, uint8_t nof_ports) { +uint32_t pbch_crc_check(pbch_t *q, char *bits, uint32_t nof_ports) { char data[40]; memcpy(data, bits, 40 * sizeof(char)); crc_set_mask(data, nof_ports); return crc_checksum(&q->crc, data, 40); } -int pbch_decode_frame(pbch_t *q, pbch_mib_t *mib, uint8_t src, uint8_t dst, uint8_t n, - uint16_t nof_bits, uint8_t nof_ports) { +int pbch_decode_frame(pbch_t *q, pbch_mib_t *mib, uint32_t src, uint32_t dst, uint32_t n, + uint32_t nof_bits, uint32_t nof_ports) { int j; memcpy(&q->temp[dst * nof_bits], &q->pbch_llr[src * nof_bits], @@ -440,9 +440,9 @@ int pbch_decode_frame(pbch_t *q, pbch_mib_t *mib, uint8_t src, uint8_t dst, uint * Returns 1 if successfully decoded MIB, 0 if not and -1 on error */ int pbch_decode(pbch_t *q, cf_t *sf_symbols, cf_t *ce[MAX_PORTS], pbch_mib_t *mib) { - uint8_t src, dst, nb; - uint8_t nant_[3] = { 1, 2, 4 }; - uint8_t na, nant; + uint32_t src, dst, nb; + uint32_t nant_[3] = { 1, 2, 4 }; + uint32_t na, nant; cf_t *slot1_symbols; int i; int nof_bits; diff --git a/lte/phy/lib/phch/src/pcfich.c b/lte/phy/lib/phch/src/pcfich.c index f342d6406..8e8b4b3b9 100644 --- a/lte/phy/lib/phch/src/pcfich.c +++ b/lte/phy/lib/phch/src/pcfich.c @@ -105,7 +105,7 @@ void pcfich_free(pcfich_t *q) { /** Finds the CFI with minimum distance with the vector of received 32 bits. * Saves the CFI value in the cfi pointer and returns the distance. */ -int pcfich_cfi_decode(char bits[PCFICH_CFI_LEN], uint8_t *cfi) { +int pcfich_cfi_decode(char bits[PCFICH_CFI_LEN], uint32_t *cfi) { int i, j; int distance, index = -1; int min = 32; @@ -144,7 +144,7 @@ int pcfich_cfi_encode(int cfi, char bits[PCFICH_CFI_LEN]) { * Returns 1 if successfully decoded the CFI, 0 if not and -1 on error */ int pcfich_decode(pcfich_t *q, cf_t *slot_symbols, cf_t *ce[MAX_PORTS], - uint8_t nsubframe, uint8_t *cfi, uint8_t *distance) { + uint32_t nsubframe, uint32_t *cfi, uint32_t *distance) { int dist; /* Set pointers for layermapping & precoding */ @@ -216,8 +216,8 @@ int pcfich_decode(pcfich_t *q, cf_t *slot_symbols, cf_t *ce[MAX_PORTS], /** Encodes CFI and maps symbols to the slot */ -int pcfich_encode(pcfich_t *q, uint8_t cfi, cf_t *slot_symbols[MAX_PORTS], - uint8_t subframe) { +int pcfich_encode(pcfich_t *q, uint32_t cfi, cf_t *slot_symbols[MAX_PORTS], + uint32_t subframe) { int i; if (q != NULL && diff --git a/lte/phy/lib/phch/src/pdcch.c b/lte/phy/lib/phch/src/pdcch.c index a239d9507..95f9ad6df 100644 --- a/lte/phy/lib/phch/src/pdcch.c +++ b/lte/phy/lib/phch/src/pdcch.c @@ -54,12 +54,12 @@ const dci_format_t ue_formats[NOF_UE_FORMATS] = { Format0, Format1 }; // 1A has #define MIN(a,b) ((a>b)?b:a) -void set_cfi(pdcch_t *q, uint8_t cfi); +void set_cfi(pdcch_t *q, uint32_t cfi); /** * 36.213 9.1 */ -int gen_common_search(dci_candidate_t *c, uint16_t nof_cce, uint16_t nof_bits, +int gen_common_search(dci_candidate_t *c, uint32_t nof_cce, uint32_t nof_bits, uint16_t rnti) { int i, l, L, k; k = 0; @@ -81,8 +81,8 @@ int gen_common_search(dci_candidate_t *c, uint16_t nof_cce, uint16_t nof_bits, /** * 36.213 9.1 */ -int gen_ue_search(dci_candidate_t *c, uint16_t nof_cce, uint8_t nof_bits, - uint16_t rnti, uint8_t subframe) { +int gen_ue_search(dci_candidate_t *c, uint32_t nof_cce, uint32_t nof_bits, + uint16_t rnti, uint32_t subframe) { int i, l, L, k, m; unsigned int Yk; const int S[4] = { 6, 12, 8, 16 }; @@ -124,9 +124,9 @@ int gen_ue_search(dci_candidate_t *c, uint16_t nof_cce, uint8_t nof_bits, * user-specific search space. Currently supported transmission Mode 1: * DCI Format 1A and 1 + PUSCH scheduling format 0 */ -int pdcch_init_search_ue(pdcch_t *q, uint16_t c_rnti, uint8_t cfi) { +int pdcch_init_search_ue(pdcch_t *q, uint16_t c_rnti, uint32_t cfi) { int k, i, r; - uint8_t n; + uint32_t n; set_cfi(q, cfi); @@ -181,7 +181,7 @@ int pdcch_init_common(pdcch_t *q, pdcch_search_t *s, uint16_t rnti) { /** 36.213 v9.3 Table 7.1-1: System Information DCI messages * Expect DCI formats 1C and 1A in the common search space */ -int pdcch_init_search_si(pdcch_t *q, uint8_t cfi) { +int pdcch_init_search_si(pdcch_t *q, uint32_t cfi) { set_cfi(q, cfi); int r = pdcch_init_common(q, &q->search_mode[SEARCH_SI], SIRNTI); if (r >= 0) { @@ -193,7 +193,7 @@ int pdcch_init_search_si(pdcch_t *q, uint8_t cfi) { /** 36.213 v9.3 Table 7.1-3 * Expect DCI formats 1C and 1A in the common search space */ -int pdcch_init_search_ra(pdcch_t *q, uint16_t ra_rnti, uint8_t cfi) { +int pdcch_init_search_ra(pdcch_t *q, uint16_t ra_rnti, uint32_t cfi) { set_cfi(q, cfi); int r = pdcch_init_common(q, &q->search_mode[SEARCH_RA], ra_rnti); if (r >= 0) { @@ -212,7 +212,7 @@ void pdcch_set_search_ra(pdcch_t *q) { q->current_search_mode = SEARCH_RA; } -void set_cfi(pdcch_t *q, uint8_t cfi) { +void set_cfi(pdcch_t *q, uint32_t cfi) { if (cfi > 0 && cfi < 4) { q->nof_regs = (regs_pdcch_nregs(q->regs, cfi) / 9) * 9; q->nof_cce = q->nof_regs / 9; @@ -343,7 +343,7 @@ void pdcch_free(pdcch_t *q) { * * TODO: UE transmit antenna selection CRC mask */ -int dci_decode(pdcch_t *q, float *e, char *data, uint16_t E, uint16_t nof_bits, uint16_t *crc) { +int dci_decode(pdcch_t *q, float *e, char *data, uint32_t E, uint32_t nof_bits, uint16_t *crc) { float tmp[3 * (DCI_MAX_BITS + 16)]; uint16_t p_bits, crc_res; @@ -406,7 +406,7 @@ int pdcch_decode_candidate(pdcch_t *q, float *llr, dci_candidate_t *c, } int pdcch_extract_llr(pdcch_t *q, cf_t *slot_symbols, cf_t *ce[MAX_PORTS], - float *llr, uint8_t nsubframe, uint8_t cfi) { + float *llr, uint32_t nsubframe, uint32_t cfi) { /* Set pointers for layermapping & precoding */ int i; @@ -480,7 +480,7 @@ int pdcch_extract_llr(pdcch_t *q, cf_t *slot_symbols, cf_t *ce[MAX_PORTS], } } -int pdcch_decode_current_mode(pdcch_t *q, float *llr, dci_t *dci, uint8_t subframe) { +int pdcch_decode_current_mode(pdcch_t *q, float *llr, dci_t *dci, uint32_t subframe) { int k, i; int ret; @@ -513,7 +513,7 @@ int pdcch_decode_ra(pdcch_t *q, float *llr, dci_t *dci) { pdcch_set_search_ra(q); return pdcch_decode_current_mode(q, llr, dci, 0); } -int pdcch_decode_ue(pdcch_t *q, float *llr, dci_t *dci, uint8_t nsubframe) { +int pdcch_decode_ue(pdcch_t *q, float *llr, dci_t *dci, uint32_t nsubframe) { pdcch_set_search_ue(q); return pdcch_decode_current_mode(q, llr, dci, nsubframe); } @@ -525,7 +525,7 @@ int pdcch_decode_ue(pdcch_t *q, float *llr, dci_t *dci, uint8_t nsubframe) { * Returns number of messages stored in dci */ int pdcch_decode(pdcch_t *q, cf_t *slot_symbols, cf_t *ce[MAX_PORTS], - dci_t *dci, uint8_t subframe, uint8_t cfi) { + dci_t *dci, uint32_t subframe, uint32_t cfi) { if (q != NULL && dci != NULL && @@ -564,7 +564,7 @@ void crc_set_mask_rnti(char *crc, uint16_t rnti) { /** 36.212 5.3.3.2 to 5.3.3.4 * TODO: UE transmit antenna selection CRC mask */ -int dci_encode(pdcch_t *q, char *data, char *e, uint16_t nof_bits, uint16_t E, +int dci_encode(pdcch_t *q, char *data, char *e, uint32_t nof_bits, uint32_t E, uint16_t rnti) { convcoder_t encoder; char tmp[3 * (DCI_MAX_BITS + 16)]; @@ -603,7 +603,7 @@ int dci_encode(pdcch_t *q, char *data, char *e, uint16_t nof_bits, uint16_t E, /** 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 *slot_symbols[MAX_PORTS], - uint8_t nsubframe, uint8_t cfi) { + uint32_t nsubframe, uint32_t cfi) { int i; /* Set pointers for layermapping & precoding */ cf_t *x[MAX_LAYERS]; diff --git a/lte/phy/lib/phch/src/pdsch.c b/lte/phy/lib/phch/src/pdsch.c index cb6283deb..483f93589 100644 --- a/lte/phy/lib/phch/src/pdsch.c +++ b/lte/phy/lib/phch/src/pdsch.c @@ -60,11 +60,11 @@ struct cb_segm { }; int pdsch_cp(pdsch_t *q, cf_t *input, cf_t *output, ra_prb_t *prb_alloc, - uint8_t nsubframe, bool put) { - uint8_t s, n, l, lp, lstart, lend, nof_refs; + uint32_t nsubframe, bool put) { + uint32_t s, n, l, lp, lstart, lend, nof_refs; bool is_pbch, is_sss; cf_t *in_ptr = input, *out_ptr = output; - uint8_t offset; + uint32_t offset; INFO("%s %d RE from %d PRB\n", put ? "Putting" : "Getting", prb_alloc->re_sf[nsubframe], prb_alloc->slot[0].nof_prb); @@ -161,7 +161,7 @@ int pdsch_cp(pdsch_t *q, cf_t *input, cf_t *output, ra_prb_t *prb_alloc, * 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, uint8_t subframe) { + ra_prb_t *prb_alloc, uint32_t subframe) { return pdsch_cp(q, pdsch_symbols, sf_symbols, prb_alloc, subframe, true); } @@ -173,7 +173,7 @@ int pdsch_put(pdsch_t *q, cf_t *pdsch_symbols, cf_t *sf_symbols, * 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, uint8_t subframe) { + ra_prb_t *prb_alloc, uint32_t subframe) { return pdsch_cp(q, sf_symbols, pdsch_symbols, prb_alloc, subframe, false); } @@ -364,7 +364,7 @@ void codeblock_segmentation(struct cb_segm *s, int tbs) { /* Decode a transport block according to 36.212 5.3.2 * */ -int pdsch_decode_tb(pdsch_t *q, char *data, uint16_t tbs, uint16_t nb_e, uint8_t rv_idx) { +int pdsch_decode_tb(pdsch_t *q, char *data, uint32_t tbs, uint32_t nb_e, uint32_t rv_idx) { char parity[24]; char *p_parity = parity; uint32_t par_rx, par_tx; @@ -464,7 +464,7 @@ int pdsch_decode_tb(pdsch_t *q, char *data, uint16_t tbs, uint16_t nb_e, uint8_t /** Decodes the PDSCH from the received symbols */ int pdsch_decode(pdsch_t *q, cf_t *sf_symbols, cf_t *ce[MAX_PORTS], char *data, - uint8_t subframe, ra_mcs_t mcs, ra_prb_t *prb_alloc) { + uint32_t subframe, ra_mcs_t mcs, ra_prb_t *prb_alloc) { /* Set pointers for layermapping & precoding */ int i, n; @@ -548,7 +548,7 @@ int pdsch_decode(pdsch_t *q, cf_t *sf_symbols, cf_t *ce[MAX_PORTS], char *data, /* Encode a transport block according to 36.212 5.3.2 * */ -int pdsch_encode_tb(pdsch_t *q, char *data, uint16_t tbs, uint16_t nb_e, uint8_t rv_idx) { +int pdsch_encode_tb(pdsch_t *q, char *data, uint32_t tbs, uint32_t nb_e, uint32_t rv_idx) { char parity[24]; char *p_parity = parity; unsigned int par; @@ -656,9 +656,9 @@ int pdsch_encode_tb(pdsch_t *q, char *data, uint16_t tbs, uint16_t nb_e, uint8_t /** 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], - uint8_t subframe, ra_mcs_t mcs, ra_prb_t *prb_alloc) { + uint32_t subframe, ra_mcs_t mcs, ra_prb_t *prb_alloc) { int i; - uint16_t nof_symbols, nof_bits, nof_bits_e; + uint32_t nof_symbols, nof_bits, nof_bits_e; /* Set pointers for layermapping & precoding */ cf_t *x[MAX_LAYERS]; diff --git a/lte/phy/lib/phch/src/phich.c b/lte/phy/lib/phch/src/phich.c index a38c97bf7..f9802dfe3 100644 --- a/lte/phy/lib/phch/src/phich.c +++ b/lte/phy/lib/phch/src/phich.c @@ -50,7 +50,7 @@ const cf_t w_ext[PHICH_EXT_NSEQUENCES][2] = { { 1, 1 }, { 1, -1 }, { I, I }, { I, -I } }; -uint8_t phich_ngroups(phich_t *q) { +uint32_t phich_ngroups(phich_t *q) { return regs_phich_ngroups(q->regs); } @@ -107,7 +107,7 @@ void phich_free(phich_t *q) { /* Decodes ACK * */ -char phich_ack_decode(char bits[PHICH_NBITS], uint8_t *distance) { +char phich_ack_decode(char bits[PHICH_NBITS], uint32_t *distance) { int i, n; n = 0; @@ -140,7 +140,7 @@ void phich_ack_encode(char ack, char bits[PHICH_NBITS]) { * Returns 1 if successfully decoded the CFI, 0 if not and -1 on error */ int phich_decode(phich_t *q, cf_t *slot_symbols, cf_t *ce[MAX_PORTS], - uint8_t ngroup, uint8_t nseq, uint8_t subframe, char *ack, uint8_t *distance) { + uint32_t ngroup, uint32_t nseq, uint32_t subframe, char *ack, uint32_t *distance) { /* Set pointers for layermapping & precoding */ int i, j; @@ -270,7 +270,7 @@ int phich_decode(phich_t *q, cf_t *slot_symbols, cf_t *ce[MAX_PORTS], /** Encodes ACK/NACK bits, modulates and inserts into resource. * The parameter ack is an array of phich_ngroups() pointers to buffers of nof_sequences chars */ -int phich_encode(phich_t *q, char ack, uint8_t ngroup, uint8_t nseq, uint8_t subframe, +int phich_encode(phich_t *q, char ack, uint32_t ngroup, uint32_t nseq, uint32_t subframe, cf_t *slot_symbols[MAX_PORTS]) { int i; diff --git a/lte/phy/lib/phch/src/ra.c b/lte/phy/lib/phch/src/ra.c index 3056b6fee..f53ffafdd 100644 --- a/lte/phy/lib/phch/src/ra.c +++ b/lte/phy/lib/phch/src/ra.c @@ -41,10 +41,10 @@ #define min(a,b) (alstart = nof_ctrl_symbols; @@ -139,7 +139,7 @@ void ra_prb_fprint(FILE *f, ra_prb_slot_t *prb) { } /** Compute PRB allocation for Downlink as defined in 8.1 of 36.213 */ -int ra_prb_get_ul(ra_prb_slot_t *prb, ra_pusch_t *ra, uint8_t nof_prb) { +int ra_prb_get_ul(ra_prb_slot_t *prb, ra_pusch_t *ra, uint32_t nof_prb) { int i; if (ra->type2_alloc.mode != t2_loc) { fprintf(stderr, "Uplink only accepts type2 localized scheduling\n"); @@ -153,11 +153,11 @@ int ra_prb_get_ul(ra_prb_slot_t *prb, ra_pusch_t *ra, uint8_t nof_prb) { } /** Compute PRB allocation for Downlink as defined in 7.1.6 of 36.213 */ -int ra_prb_get_dl(ra_prb_t *prb_dist, ra_pdsch_t *ra, uint8_t nof_prb) { +int ra_prb_get_dl(ra_prb_t *prb_dist, ra_pdsch_t *ra, uint32_t nof_prb) { int i, j; uint32_t bitmask; - uint8_t P = ra_type0_P(nof_prb); - uint8_t n_rb_rbg_subset, n_rb_type1; + uint32_t P = ra_type0_P(nof_prb); + uint32_t n_rb_rbg_subset, n_rb_type1; bzero(prb_dist, sizeof(ra_prb_t)); switch (ra->alloc_type) { @@ -267,26 +267,26 @@ int ra_prb_get_dl(ra_prb_t *prb_dist, ra_pdsch_t *ra, uint8_t nof_prb) { } /* Returns the number of allocated PRB for Uplink */ -uint16_t ra_nprb_ul(ra_pusch_t *ra, uint8_t nof_prb) { +uint32_t ra_nprb_ul(ra_pusch_t *ra, uint32_t nof_prb) { return ra->type2_alloc.L_crb; } /* Returns the number of allocated PRB for Downlink */ -uint16_t ra_nprb_dl(ra_pdsch_t *ra, uint8_t nof_prb) { - uint8_t nprb; - uint8_t nof_rbg, P; +uint32_t ra_nprb_dl(ra_pdsch_t *ra, uint32_t nof_prb) { + uint32_t nprb; + uint32_t nof_rbg, P; 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 > (uint8_t) ceilf((float) nof_prb / P)) { - nof_rbg = (uint8_t) ceilf((float) nof_prb / P) - 1; + if (nof_rbg > (uint32_t) ceilf((float) nof_prb / P)) { + nof_rbg = (uint32_t) ceilf((float) nof_prb / P) - 1; } nprb = nof_rbg * P; // last RBG may have smaller size. Add if set - uint8_t P_last = (nof_prb % P); + uint32_t P_last = (nof_prb % P); if (!P_last) P_last = P; nprb += P_last * (ra->type0_alloc.rbg_bitmask & 1); @@ -309,7 +309,7 @@ uint16_t ra_nprb_dl(ra_pdsch_t *ra, uint8_t nof_prb) { } /* RBG size for type0 scheduling as in table 7.1.6.1-1 of 36.213 */ -uint8_t ra_type0_P(uint8_t nof_prb) { +uint32_t ra_type0_P(uint32_t nof_prb) { if (nof_prb <= 10) { return 1; } else if (nof_prb <= 26) { @@ -322,14 +322,14 @@ uint8_t ra_type0_P(uint8_t nof_prb) { } /* Returns N_rb_type1 according to section 7.1.6.2 */ -uint8_t ra_type1_N_rb(uint8_t nof_prb) { - uint8_t P = ra_type0_P(nof_prb); - return (uint8_t) ceilf((float) nof_prb / P) - (uint8_t) ceilf(log2f((float) P)) - 1; +uint32_t ra_type1_N_rb(uint32_t nof_prb) { + uint32_t P = ra_type0_P(nof_prb); + return (uint32_t) ceilf((float) nof_prb / P) - (uint32_t) ceilf(log2f((float) P)) - 1; } /* Convert Type2 scheduling L_crb and RB_start to RIV value */ -uint16_t ra_type2_to_riv(uint8_t L_crb, uint8_t RB_start, uint8_t nof_prb) { - uint16_t riv; +uint32_t ra_type2_to_riv(uint32_t L_crb, uint32_t RB_start, uint32_t nof_prb) { + uint32_t riv; if (L_crb <= nof_prb / 2) { riv = nof_prb * (L_crb - 1) + RB_start; } else { @@ -339,10 +339,10 @@ uint16_t ra_type2_to_riv(uint8_t L_crb, uint8_t RB_start, uint8_t nof_prb) { } /* Convert Type2 scheduling RIV value to L_crb and RB_start values */ -void ra_type2_from_riv(uint16_t riv, uint8_t *L_crb, uint8_t *RB_start, - uint8_t nof_prb, uint8_t nof_vrb) { - *L_crb = (uint8_t) (riv / nof_prb) + 1; - *RB_start = (uint8_t) (riv % nof_prb); +void ra_type2_from_riv(uint32_t riv, uint32_t *L_crb, uint32_t *RB_start, + uint32_t nof_prb, uint32_t nof_vrb) { + *L_crb = (uint32_t) (riv / nof_prb) + 1; + *RB_start = (uint32_t) (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; @@ -350,7 +350,7 @@ void ra_type2_from_riv(uint16_t riv, uint8_t *L_crb, uint8_t *RB_start, } /* Table 6.2.3.2-1 in 36.211 */ -uint8_t ra_type2_ngap(uint8_t nof_prb, bool ngap_is_1) { +uint32_t ra_type2_ngap(uint32_t nof_prb, bool ngap_is_1) { if (nof_prb <= 10) { return nof_prb / 2; } else if (nof_prb == 11) { @@ -373,7 +373,7 @@ uint8_t ra_type2_ngap(uint8_t nof_prb, bool ngap_is_1) { } /* Table 7.1.6.3-1 in 36.213 */ -uint8_t ra_type2_n_rb_step(uint8_t nof_prb) { +uint32_t ra_type2_n_rb_step(uint32_t nof_prb) { if (nof_prb < 50) { return 2; } else { @@ -382,17 +382,17 @@ uint8_t ra_type2_n_rb_step(uint8_t nof_prb) { } /* as defined in 6.2.3.2 of 36.211 */ -uint8_t ra_type2_n_vrb_dl(uint8_t nof_prb, bool ngap_is_1) { - uint8_t ngap = ra_type2_ngap(nof_prb, ngap_is_1); +uint32_t ra_type2_n_vrb_dl(uint32_t nof_prb, bool ngap_is_1) { + uint32_t ngap = ra_type2_ngap(nof_prb, ngap_is_1); if (ngap_is_1) { return 2 * (ngap < (nof_prb - ngap) ? ngap : nof_prb - ngap); } else { - return ((uint8_t) nof_prb / ngap) * 2 * ngap; + return ((uint32_t) nof_prb / ngap) * 2 * ngap; } } /* Converts ra_mcs_t structure to MCS index for both Uplink and Downlink */ -uint8_t ra_mcs_to_table_idx(ra_mcs_t *mcs) { +uint32_t ra_mcs_to_table_idx(ra_mcs_t *mcs) { switch (mcs->mod) { case QPSK: return mcs->tbs_idx; @@ -406,7 +406,7 @@ uint8_t ra_mcs_to_table_idx(ra_mcs_t *mcs) { } /* Converts MCS index to ra_mcs_t structure for Downlink as defined inTable 7.1.7.1-1 on 36.213 */ -int ra_mcs_from_idx_dl(uint8_t idx, ra_mcs_t *mcs) { +int ra_mcs_from_idx_dl(uint32_t idx, ra_mcs_t *mcs) { if (idx < 10) { mcs->mod = QPSK; mcs->tbs_idx = idx; @@ -434,7 +434,7 @@ int ra_mcs_from_idx_dl(uint8_t idx, ra_mcs_t *mcs) { } /* 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) { +int ra_mcs_from_idx_ul(uint32_t idx, ra_mcs_t *mcs) { if (idx < 11) { mcs->mod = QPSK; mcs->tbs_idx = idx; @@ -453,7 +453,7 @@ int ra_mcs_from_idx_ul(uint8_t idx, ra_mcs_t *mcs) { } /* Downlink Transport Block size for Format 1C as defined in 7.1.7.2.2-1 on 36.213 */ -int ra_tbs_from_idx_format1c(uint8_t tbs_idx) { +int ra_tbs_from_idx_format1c(uint32_t tbs_idx) { if (tbs_idx < 32) { return tbs_format1c_table[tbs_idx]; } else { @@ -478,7 +478,7 @@ int ra_tbs_to_table_idx_format1c(uint32_t 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, uint8_t n_prb) { +int ra_tbs_from_idx(uint32_t tbs_idx, uint32_t n_prb) { if (tbs_idx < 27 && n_prb > 0 && n_prb <= MAX_PRB) { return tbs_table[tbs_idx][n_prb - 1]; } else { @@ -489,7 +489,7 @@ int ra_tbs_from_idx(uint8_t tbs_idx, uint8_t n_prb) { /* Returns lowest nearest index of TBS value in table 7.1.7.2 on 36.213 * or -1 if the TBS value is not within the valid TBS values */ -int ra_tbs_to_table_idx(uint32_t tbs, uint8_t n_prb) { +int ra_tbs_to_table_idx(uint32_t tbs, uint32_t n_prb) { int idx; if (n_prb > 0 && n_prb <= MAX_PRB) { return LIBLTE_ERROR; @@ -518,7 +518,7 @@ char *ra_mod_string(ra_mod_t mod) { } } -void ra_pusch_fprint(FILE *f, ra_pusch_t *ra, uint8_t nof_prb) { +void ra_pusch_fprint(FILE *f, ra_pusch_t *ra, uint32_t nof_prb) { fprintf(f, "Frequency Hopping:\t"); if (ra->freq_hop_fl == hop_disabled) { fprintf(f, "No"); @@ -541,17 +541,17 @@ char *ra_type_string(ra_type_t alloc_type) { } } -void ra_pdsch_set_mcs_index(ra_pdsch_t *ra, uint8_t mcs_idx) { +void ra_pdsch_set_mcs_index(ra_pdsch_t *ra, uint32_t mcs_idx) { ra->mcs.mod = MOD_NULL; ra->mcs.mcs_idx = mcs_idx; } -void ra_pdsch_set_mcs(ra_pdsch_t *ra, ra_mod_t mod, uint8_t tbs_idx) { +void ra_pdsch_set_mcs(ra_pdsch_t *ra, ra_mod_t mod, uint32_t tbs_idx) { ra->mcs.mod = mod; ra->mcs.tbs_idx = tbs_idx; ra->mcs.tbs = 0; } -void ra_pdsch_fprint(FILE *f, ra_pdsch_t *ra, uint8_t nof_prb) { +void ra_pdsch_fprint(FILE *f, ra_pdsch_t *ra, uint32_t nof_prb) { fprintf(f, " - Resource Allocation Type:\t\t%s\n", ra_type_string(ra->alloc_type)); switch (ra->alloc_type) { diff --git a/lte/phy/lib/phch/src/regs.c b/lte/phy/lib/phch/src/regs.c index 50fe5e42a..12f512e7a 100644 --- a/lte/phy/lib/phch/src/regs.c +++ b/lte/phy/lib/phch/src/regs.c @@ -34,23 +34,23 @@ #include "liblte/phy/phch/regs.h" #include "liblte/phy/utils/debug.h" -regs_reg_t *regs_find_reg(regs_t *h, uint16_t k, uint8_t l); +regs_reg_t *regs_find_reg(regs_t *h, uint32_t k, uint32_t l); int regs_put_reg(regs_reg_t *reg, cf_t *reg_data, cf_t *slot_symbols, - uint8_t nof_prb); + uint32_t nof_prb); int regs_add_reg(regs_reg_t *reg, cf_t *reg_data, cf_t *slot_symbols, - uint8_t nof_prb); + uint32_t nof_prb); int regs_get_reg(regs_reg_t *reg, cf_t *slot_symbols, cf_t *reg_data, - uint8_t nof_prb); + uint32_t nof_prb); -int regs_reset_reg(regs_reg_t *reg, cf_t *slot_symbols, uint8_t nof_prb); +int regs_reset_reg(regs_reg_t *reg, cf_t *slot_symbols, uint32_t nof_prb); /*************************************************************** @@ -151,7 +151,7 @@ clean_and_exit: return ret; } -int regs_pdcch_nregs(regs_t *h, uint8_t cfi) { +int regs_pdcch_nregs(regs_t *h, uint32_t cfi) { if (cfi < 1 || cfi > 3) { fprintf(stderr, "Invalid CFI=%d\n", cfi); return LIBLTE_ERROR; @@ -320,9 +320,9 @@ void regs_phich_free(regs_t *h) { } } -u_int16_t regs_phich_nregs(regs_t *h) { +uint32_t regs_phich_nregs(regs_t *h) { int i; - u_int16_t n; + uint32_t n; n=0; for (i=0;ingroups_phich;i++) { n += h->phich[i].nof_regs; @@ -331,7 +331,7 @@ u_int16_t regs_phich_nregs(regs_t *h) { } -u_int8_t regs_phich_ngroups(regs_t *h) { +uint32_t regs_phich_ngroups(regs_t *h) { return h->ngroups_phich; } @@ -342,7 +342,7 @@ u_int8_t regs_phich_ngroups(regs_t *h) { * * Returns the number of written symbols, or -1 on error */ -int regs_phich_add(regs_t *h, cf_t phich_symbols[REGS_PHICH_NSYM], u_int8_t ngroup, cf_t *slot_symbols) { +int regs_phich_add(regs_t *h, cf_t phich_symbols[REGS_PHICH_NSYM], uint32_t ngroup, cf_t *slot_symbols) { int i; if (ngroup >= h->ngroups_phich) { fprintf(stderr, "Error invalid ngroup %d\n", ngroup); @@ -365,7 +365,7 @@ int regs_phich_add(regs_t *h, cf_t phich_symbols[REGS_PHICH_NSYM], u_int8_t ngro */ int regs_phich_reset(regs_t *h, cf_t *slot_symbols) { int i; - u_int8_t ngroup, ng; + uint32_t ngroup, ng; for (ngroup = 0;ngroup < h->ngroups_phich;CP_ISEXT(h->cell.cp)?ngroup+=2:ngroup++) { if (CP_ISEXT(h->cell.cp)) { ng = ngroup/2; @@ -385,7 +385,7 @@ int regs_phich_reset(regs_t *h, cf_t *slot_symbols) { * * Returns the number of written symbols, or -1 on error */ -int regs_phich_get(regs_t *h, cf_t *slot_symbols, cf_t phich_symbols[REGS_PHICH_NSYM], u_int8_t ngroup) { +int regs_phich_get(regs_t *h, cf_t *slot_symbols, cf_t phich_symbols[REGS_PHICH_NSYM], uint32_t ngroup) { int i; if (ngroup >= h->ngroups_phich) { fprintf(stderr, "Error invalid ngroup %d\n", ngroup); @@ -422,7 +422,7 @@ int regs_phich_get(regs_t *h, cf_t *slot_symbols, cf_t phich_symbols[REGS_PHICH_ */ int regs_pcfich_init(regs_t *h) { int i; - uint16_t k_hat, k; + uint32_t k_hat, k; regs_ch_t *ch = &h->pcfich; ch->regs = malloc(sizeof(regs_reg_t*) * REGS_PCFICH_NREGS); @@ -463,7 +463,7 @@ void regs_pcfich_free(regs_t *h) { } } -uint16_t regs_pcfich_nregs(regs_t *h) { +uint32_t regs_pcfich_nregs(regs_t *h) { return h->pcfich.nof_regs; } @@ -515,7 +515,7 @@ int regs_pcfich_get(regs_t *h, cf_t *slot_symbols, cf_t ch_data[REGS_PCFICH_NSYM * ***************************************************************/ -regs_reg_t *regs_find_reg(regs_t *h, uint16_t k, uint8_t l) { +regs_reg_t *regs_find_reg(regs_t *h, uint32_t k, uint32_t l) { int i; for (i=0;inof_regs;i++) { if (h->regs[i].l == l && h->regs[i].k0 == k) { @@ -529,7 +529,7 @@ regs_reg_t *regs_find_reg(regs_t *h, uint16_t k, uint8_t l) { * Returns the number of REGs in a PRB * 36.211 Section 6.2.4 */ -int regs_num_x_symbol(uint8_t symbol, uint8_t nof_port, lte_cp_t cp) { +int regs_num_x_symbol(uint32_t symbol, uint32_t nof_port, lte_cp_t cp) { switch (symbol) { case 0: @@ -562,7 +562,7 @@ int regs_num_x_symbol(uint8_t symbol, uint8_t nof_port, lte_cp_t cp) { * Initializes the indices of a REG * 36.211 Section 6.2.4 */ -int regs_reg_init(regs_reg_t *reg, uint8_t symbol, uint16_t nreg, uint16_t k0, uint8_t maxreg, uint8_t vo) { +int regs_reg_init(regs_reg_t *reg, uint32_t symbol, uint32_t nreg, uint32_t k0, uint32_t maxreg, uint32_t vo) { int i, j, z; reg->l = symbol; @@ -619,7 +619,7 @@ void regs_free(regs_t *h) { /** Sets the CFI value for this subframe (CFI must be in the range 1..3). */ -int regs_set_cfi(regs_t *h, uint8_t cfi) { +int regs_set_cfi(regs_t *h, uint32_t cfi) { if (cfi > 0 && cfi <= 3) { if (h->phich_len == PHICH_EXT && ((h->cell.nof_prb < 10 && cfi < 2) || (h->cell.nof_prb >= 10 && cfi < 3))) { @@ -644,8 +644,8 @@ int regs_set_cfi(regs_t *h, uint8_t cfi) { int regs_init(regs_t *h, phich_resources_t phich_res, phich_length_t phich_len, lte_cell_t cell) { int ret = LIBLTE_ERROR_INVALID_INPUTS; int i, k; - uint16_t j[4], jmax, prb; - uint8_t n[4], vo; + uint32_t j[4], jmax, prb; + uint32_t n[4], vo; int max_ctrl_symbols; if (h != NULL && @@ -732,7 +732,7 @@ clean_and_exit: /** * Puts one REG data (4 symbols) in the slot symbols array */ -int regs_put_reg(regs_reg_t *reg, cf_t *reg_data, cf_t *slot_symbols, uint8_t nof_prb) { +int regs_put_reg(regs_reg_t *reg, cf_t *reg_data, cf_t *slot_symbols, uint32_t nof_prb) { int i; for (i = 0; i < REGS_RE_X_REG; i++) { slot_symbols[REG_IDX(reg, i, nof_prb)] = reg_data[i]; @@ -744,7 +744,7 @@ int regs_put_reg(regs_reg_t *reg, cf_t *reg_data, cf_t *slot_symbols, uint8_t no * Adds one REG data (4 symbols) in the slot symbols array * Used by PHICH */ -int regs_add_reg(regs_reg_t *reg, cf_t *reg_data, cf_t *slot_symbols, uint8_t nof_prb) { +int regs_add_reg(regs_reg_t *reg, cf_t *reg_data, cf_t *slot_symbols, uint32_t nof_prb) { int i; for (i = 0; i < REGS_RE_X_REG; i++) { slot_symbols[REG_IDX(reg, i, nof_prb)] += reg_data[i]; @@ -756,7 +756,7 @@ int regs_add_reg(regs_reg_t *reg, cf_t *reg_data, cf_t *slot_symbols, uint8_t no /** * Reset REG data (4 symbols) in the slot symbols array */ -int regs_reset_reg(regs_reg_t *reg, cf_t *slot_symbols, uint8_t nof_prb) { +int regs_reset_reg(regs_reg_t *reg, cf_t *slot_symbols, uint32_t nof_prb) { int i; for (i = 0; i < REGS_RE_X_REG; i++) { slot_symbols[REG_IDX(reg, i, nof_prb)] = 0; @@ -767,7 +767,7 @@ int regs_reset_reg(regs_reg_t *reg, cf_t *slot_symbols, uint8_t nof_prb) { /** * Gets one REG data (4 symbols) from the slot symbols array */ -int regs_get_reg(regs_reg_t *reg, cf_t *slot_symbols, cf_t *reg_data, uint8_t nof_prb) { +int regs_get_reg(regs_reg_t *reg, cf_t *slot_symbols, cf_t *reg_data, uint32_t nof_prb) { int i; for (i = 0; i < REGS_RE_X_REG; i++) { reg_data[i] = slot_symbols[REG_IDX(reg, i, nof_prb)]; diff --git a/lte/phy/lib/phch/src/sequences.c b/lte/phy/lib/phch/src/sequences.c index 6a530dc5a..499eb1cd0 100644 --- a/lte/phy/lib/phch/src/sequences.c +++ b/lte/phy/lib/phch/src/sequences.c @@ -33,7 +33,7 @@ /** * 36.211 6.6.1 */ -int sequence_pbch(sequence_t *seq, lte_cp_t cp, uint16_t cell_id) { +int sequence_pbch(sequence_t *seq, lte_cp_t cp, uint32_t cell_id) { bzero(seq, sizeof(sequence_t)); return sequence_LTEPRS(seq, CP_ISNORM(cp)?1920:1728, cell_id); } @@ -41,7 +41,7 @@ int sequence_pbch(sequence_t *seq, lte_cp_t cp, uint16_t cell_id) { /** * 36.211 6.7.1 */ -int sequence_pcfich(sequence_t *seq, uint8_t nslot, uint16_t cell_id) { +int sequence_pcfich(sequence_t *seq, uint32_t nslot, uint32_t cell_id) { bzero(seq, sizeof(sequence_t)); return sequence_LTEPRS(seq, 32, (nslot/2+1) * (2*cell_id + 1) * 512 + cell_id); } @@ -50,7 +50,7 @@ int sequence_pcfich(sequence_t *seq, uint8_t nslot, uint16_t cell_id) { /** * 36.211 6.9.1 */ -int sequence_phich(sequence_t *seq, uint8_t nslot, uint16_t cell_id) { +int sequence_phich(sequence_t *seq, uint32_t nslot, uint32_t cell_id) { bzero(seq, sizeof(sequence_t)); return sequence_LTEPRS(seq, 12, (nslot/2+1) * (2*cell_id + 1) * 512 + cell_id); } @@ -58,7 +58,7 @@ int sequence_phich(sequence_t *seq, uint8_t nslot, uint16_t cell_id) { /** * 36.211 6.8.2 */ -int sequence_pdcch(sequence_t *seq, uint8_t nslot, uint16_t cell_id, uint32_t len) { +int sequence_pdcch(sequence_t *seq, uint32_t nslot, uint32_t cell_id, uint32_t len) { bzero(seq, sizeof(sequence_t)); return sequence_LTEPRS(seq, len, (nslot/2) * 512 + cell_id); } @@ -66,7 +66,7 @@ int sequence_pdcch(sequence_t *seq, uint8_t nslot, uint16_t cell_id, uint32_t le /** * 36.211 6.3.1 */ -int sequence_pdsch(sequence_t *seq, unsigned short rnti, int q, uint8_t nslot, uint16_t cell_id, uint32_t len) { +int sequence_pdsch(sequence_t *seq, unsigned short rnti, int q, uint32_t nslot, uint32_t cell_id, uint32_t len) { bzero(seq, sizeof(sequence_t)); return sequence_LTEPRS(seq, len, (rnti<<14) + (q<<13) + ((nslot/2)<<9) + cell_id); } diff --git a/lte/phy/lib/phch/test/pcfich_file_test.c b/lte/phy/lib/phch/test/pcfich_file_test.c index 82fb4922b..f6b5770d1 100644 --- a/lte/phy/lib/phch/test/pcfich_file_test.c +++ b/lte/phy/lib/phch/test/pcfich_file_test.c @@ -188,7 +188,7 @@ void base_free() { } int main(int argc, char **argv) { - uint8_t cfi, distance; + uint32_t cfi, distance; int i, n; if (argc < 3) { diff --git a/lte/phy/lib/phch/test/pcfich_test.c b/lte/phy/lib/phch/test/pcfich_test.c index 829ad8308..5a968165f 100644 --- a/lte/phy/lib/phch/test/pcfich_test.c +++ b/lte/phy/lib/phch/test/pcfich_test.c @@ -80,7 +80,7 @@ int main(int argc, char **argv) { cf_t *ce[MAX_PORTS]; int nof_re; cf_t *slot_symbols[MAX_PORTS]; - uint8_t cfi, cfi_rx, nsf, distance; + uint32_t cfi, cfi_rx, nsf, distance; int cid, max_cid; parse_args(argc,argv); diff --git a/lte/phy/lib/phch/test/pdcch_file_test.c b/lte/phy/lib/phch/test/pdcch_file_test.c index 57a3406f8..874853f48 100644 --- a/lte/phy/lib/phch/test/pdcch_file_test.c +++ b/lte/phy/lib/phch/test/pdcch_file_test.c @@ -44,7 +44,7 @@ lte_cell_t cell = { CPNORM // cyclic prefix }; -uint8_t cfi = 2; +uint32_t cfi = 2; int flen; uint16_t rnti = SIRNTI; int max_frames = 10; diff --git a/lte/phy/lib/phch/test/pdcch_test.c b/lte/phy/lib/phch/test/pdcch_test.c index 37746fc76..16c2eecbb 100644 --- a/lte/phy/lib/phch/test/pdcch_test.c +++ b/lte/phy/lib/phch/test/pdcch_test.c @@ -40,7 +40,7 @@ lte_cell_t cell = { CPNORM // cyclic prefix }; -uint8_t cfi = 1; +uint32_t cfi = 1; void usage(char *prog) { printf("Usage: %s [cell.cpv]\n", prog); diff --git a/lte/phy/lib/phch/test/pdsch_file_test.c b/lte/phy/lib/phch/test/pdsch_file_test.c index f65a85307..7887cfb4f 100644 --- a/lte/phy/lib/phch/test/pdsch_file_test.c +++ b/lte/phy/lib/phch/test/pdsch_file_test.c @@ -45,7 +45,7 @@ lte_cell_t cell = { int flen; -uint8_t cfi = 2; +uint32_t cfi = 2; uint16_t rnti = SIRNTI; int max_frames = 10; diff --git a/lte/phy/lib/phch/test/pdsch_re_test.c b/lte/phy/lib/phch/test/pdsch_re_test.c index 38a3d8dbb..0f772a264 100644 --- a/lte/phy/lib/phch/test/pdsch_re_test.c +++ b/lte/phy/lib/phch/test/pdsch_re_test.c @@ -80,7 +80,7 @@ int main(int argc, char **argv) { pdsch_init(&pdsch, 0, cell); - memset(prb_alloc.re_sf, 0, sizeof(uint16_t) * 10); + memset(prb_alloc.re_sf, 0, sizeof(uint32_t) * 10); prb_alloc.slot[0].nof_prb = test_re_prb[i]; prb_alloc.slot[1].nof_prb = test_re_prb[i]; ra_prb_get_re_dl(&prb_alloc, test_re_prb[i], test_re_ports[i], test_re_csymb[i], test_re_cp[i]); diff --git a/lte/phy/lib/phch/test/pdsch_test.c b/lte/phy/lib/phch/test/pdsch_test.c index e9bd11f88..de6b9f5ce 100644 --- a/lte/phy/lib/phch/test/pdsch_test.c +++ b/lte/phy/lib/phch/test/pdsch_test.c @@ -41,9 +41,9 @@ lte_cell_t cell = { CPNORM // cyclic prefix }; -uint8_t cfi = 1; -uint16_t tbs = -1; -uint8_t subframe = 1; +uint32_t cfi = 1; +uint32_t tbs = -1; +uint32_t subframe = 1; ra_mod_t modulation = BPSK; void usage(char *prog) { diff --git a/lte/phy/lib/phch/test/phich_file_test.c b/lte/phy/lib/phch/test/phich_file_test.c index 5d8f8205b..897d4172a 100644 --- a/lte/phy/lib/phch/test/phich_file_test.c +++ b/lte/phy/lib/phch/test/phich_file_test.c @@ -213,9 +213,9 @@ void base_free() { } int main(int argc, char **argv) { - uint8_t distance; + uint32_t distance; int i, n; - uint8_t ngroup, nseq, max_nseq; + uint32_t ngroup, nseq, max_nseq; char ack_rx; if (argc < 3) { diff --git a/lte/phy/lib/phch/test/phich_test.c b/lte/phy/lib/phch/test/phich_test.c index 265947628..52ef05d74 100644 --- a/lte/phy/lib/phch/test/phich_test.c +++ b/lte/phy/lib/phch/test/phich_test.c @@ -106,9 +106,9 @@ int main(int argc, char **argv) { int nof_re; cf_t *slot_symbols[MAX_PORTS]; char ack[50][PHICH_NORM_NSEQUENCES], ack_rx; - uint8_t nsf, distance; + uint32_t nsf, distance; int cid, max_cid; - uint8_t ngroup, nseq, max_nseq; + uint32_t ngroup, nseq, max_nseq; parse_args(argc,argv); diff --git a/lte/phy/lib/sync/src/sync_frame.c b/lte/phy/lib/sync/src/sync_frame.c index fad21846a..de0254ab5 100644 --- a/lte/phy/lib/sync/src/sync_frame.c +++ b/lte/phy/lib/sync/src/sync_frame.c @@ -35,7 +35,7 @@ #include "liblte/phy/sync/sync_frame.h" -int sync_frame_init(sync_frame_t *q, int downsampling) { +int sync_frame_init(sync_frame_t *q, uint32_t downsampling) { int ret = -1; bzero(q, sizeof(sync_frame_t)); @@ -87,7 +87,7 @@ void sync_frame_free(sync_frame_t *q) { } void sync_frame_run(sync_frame_t *q, cf_t *input) { - int track_idx; + uint32_t track_idx; switch (q->state) { @@ -152,7 +152,7 @@ void sync_frame_run(sync_frame_t *q, cf_t *input) { } } else { /* if sync not found, adjust time offset with the averaged value */ - q->peak_idx = (q->peak_idx + (int) q->timeoffset) % SYNC_SF_LEN; + q->peak_idx = (q->peak_idx + (uint32_t) q->timeoffset) % SYNC_SF_LEN; /* if we missed too many PSS go back to FIND */ if (q->frame_cnt - q->last_found > TRACK_MAX_LOST) { @@ -169,11 +169,11 @@ void sync_frame_set_threshold(sync_frame_t *q, float threshold) { sync_set_threshold(&q->s, threshold); } -int sync_frame_cell_id(sync_frame_t *q) { +uint32_t sync_frame_cell_id(sync_frame_t *q) { return q->cell_id; } -int sync_frame_sfidx(sync_frame_t *q) { +uint32_t sync_frame_sfidx(sync_frame_t *q) { return q->sf_idx; } @@ -182,7 +182,7 @@ int sync_frame_push(sync_frame_t *q, cf_t *input, cf_t *output) { int retval = 0; int frame_start; cf_t *input_ds; - int sf_len; + uint32_t sf_len; if (q->downsampling == 1) { input_ds = input; diff --git a/lte/phy/lib/utils/src/bit.c b/lte/phy/lib/utils/src/bit.c index d002b2503..46b27a426 100644 --- a/lte/phy/lib/utils/src/bit.c +++ b/lte/phy/lib/utils/src/bit.c @@ -75,7 +75,7 @@ unsigned int bit_diff(char *x, char *y, int nbits) { } // Counts the number of ones in a word. K&R book exercise 2.9 -uint8_t bit_count(uint32_t n) { +uint32_t bit_count(uint32_t n) { int c; for (c = 0; n; c++) n &= n - 1; From e84f800e26cdace8b89e09d89c9d42b3ddab92d7 Mon Sep 17 00:00:00 2001 From: ismagom Date: Sat, 5 Jul 2014 20:26:09 +0200 Subject: [PATCH 06/14] Fixed unitialized variable compilation error --- lte/phy/examples/pdsch_ue.c | 4 +++- lte/phy/lib/ch_estimation/test/chest_test.c | 1 + lte/phy/lib/phch/src/pdsch.c | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/lte/phy/examples/pdsch_ue.c b/lte/phy/examples/pdsch_ue.c index 57963c1a0..bbaa8eb94 100644 --- a/lte/phy/examples/pdsch_ue.c +++ b/lte/phy/examples/pdsch_ue.c @@ -640,7 +640,7 @@ int main(int argc, char **argv) { /* Initialize variables */ frame_cnt = 0; frame_number = -1; - + /* The number of samples read from the USRP or file corresponds to 1 ms (subframe) */ sf_n_samples = 1920 * lte_symbol_sz(sampling_nof_prb)/128; @@ -658,6 +658,8 @@ int main(int argc, char **argv) { } else { ret = sync_frame_push(&sframe, input_buffer, sf_buffer); in_ptr = sf_buffer; + cell_id = 0; + sf_idx = 0; } switch(ret ) { case 0: diff --git a/lte/phy/lib/ch_estimation/test/chest_test.c b/lte/phy/lib/ch_estimation/test/chest_test.c index 3408ce553..4fda0a1a9 100644 --- a/lte/phy/lib/ch_estimation/test/chest_test.c +++ b/lte/phy/lib/ch_estimation/test/chest_test.c @@ -125,6 +125,7 @@ int main(int argc, char **argv) { float mse_mag, mse_phase; lte_cell_t cell; + cell.nof_ports = 1; parse_args(argc,argv); if (output_matlab) { diff --git a/lte/phy/lib/phch/src/pdsch.c b/lte/phy/lib/phch/src/pdsch.c index 483f93589..524477730 100644 --- a/lte/phy/lib/phch/src/pdsch.c +++ b/lte/phy/lib/phch/src/pdsch.c @@ -64,7 +64,7 @@ int pdsch_cp(pdsch_t *q, cf_t *input, cf_t *output, ra_prb_t *prb_alloc, uint32_t s, n, l, lp, lstart, lend, nof_refs; bool is_pbch, is_sss; cf_t *in_ptr = input, *out_ptr = output; - uint32_t offset; + uint32_t offset = 0; INFO("%s %d RE from %d PRB\n", put ? "Putting" : "Getting", prb_alloc->re_sf[nsubframe], prb_alloc->slot[0].nof_prb); From 0ebb0e7d007309156a35582a3fe9f06483f83bb2 Mon Sep 17 00:00:00 2001 From: ismagom Date: Sat, 5 Jul 2014 21:00:32 +0200 Subject: [PATCH 07/14] Improved PDCCH candidate search interface. Switched FEC modules to uint32_t --- lte/phy/examples/pdsch_enodeb.c | 27 +- lte/phy/examples/pdsch_ue.c | 31 +- lte/phy/include/liblte/phy/fec/convcoder.h | 8 +- lte/phy/include/liblte/phy/fec/rm_conv.h | 11 +- lte/phy/include/liblte/phy/fec/rm_turbo.h | 22 +- lte/phy/include/liblte/phy/fec/tc_interl.h | 12 +- lte/phy/include/liblte/phy/fec/turbocoder.h | 6 +- lte/phy/include/liblte/phy/fec/turbodecoder.h | 28 +- lte/phy/include/liblte/phy/fec/viterbi.h | 27 +- lte/phy/include/liblte/phy/phch/dci.h | 29 +- lte/phy/include/liblte/phy/phch/pdcch.h | 104 ++-- lte/phy/lib/fec/src/convcoder.c | 9 +- lte/phy/lib/fec/src/parity.c | 31 +- lte/phy/lib/fec/src/parity.h | 10 +- lte/phy/lib/fec/src/rm_conv.c | 14 +- lte/phy/lib/fec/src/rm_turbo.c | 30 +- lte/phy/lib/fec/src/tc_interl_lte.c | 15 +- lte/phy/lib/fec/src/tc_interl_umts.c | 33 +- lte/phy/lib/fec/src/turbocoder.c | 12 +- lte/phy/lib/fec/src/turbodecoder.c | 39 +- lte/phy/lib/fec/src/viterbi.c | 30 +- lte/phy/lib/fec/src/viterbi37.h | 20 +- lte/phy/lib/fec/src/viterbi37_port.c | 28 +- lte/phy/lib/fec/src/viterbi39.h | 21 +- lte/phy/lib/fec/src/viterbi39_port.c | 21 +- lte/phy/lib/fec/test/turbocoder_test.c | 22 +- lte/phy/lib/phch/src/dci.c | 70 +-- lte/phy/lib/phch/src/pbch.c | 2 +- lte/phy/lib/phch/src/pdcch.c | 484 +++++++----------- lte/phy/lib/phch/test/dci_unpacking.c | 5 +- lte/phy/lib/phch/test/pdcch_file_test.c | 33 +- lte/phy/lib/phch/test/pdcch_test.c | 77 ++- lte/phy/lib/phch/test/pdsch_file_test.c | 29 +- 33 files changed, 644 insertions(+), 696 deletions(-) diff --git a/lte/phy/examples/pdsch_enodeb.c b/lte/phy/examples/pdsch_enodeb.c index 10d9c190a..34947396e 100644 --- a/lte/phy/examples/pdsch_enodeb.c +++ b/lte/phy/examples/pdsch_enodeb.c @@ -229,7 +229,8 @@ int main(int argc, char **argv) { int i, n; char *data; cf_t *sf_symbols[MAX_PORTS]; - dci_t dci_tx; + dci_msg_t dci_msg; + dci_location_t locations[NSUBFRAMES_X_FRAME][10]; #ifdef DISABLE_UHD if (argc < 3) { @@ -279,7 +280,6 @@ int main(int argc, char **argv) { } #endif - dci_init(&dci_tx, 1); bzero(&ra_dl, sizeof(ra_pdsch_t)); ra_dl.harq_process = 0; ra_pdsch_set_mcs(&ra_dl, QPSK, 5); @@ -288,16 +288,18 @@ int main(int argc, char **argv) { ra_dl.alloc_type = alloc_type0; ra_dl.type0_alloc.rbg_bitmask = 0xffffffff; - dci_msg_pack_pdsch(&ra_dl, &dci_tx.msg[0], Format1, cell.nof_prb, false); - dci_tx.nof_dcis++; + dci_msg_pack_pdsch(&ra_dl, &dci_msg, Format1, cell.nof_prb, false); - pdcch_init_search_ue(&pdcch, 1234, cfi); - ra_prb_get_dl(&prb_alloc, &ra_dl, cell.nof_prb); ra_prb_get_re_dl(&prb_alloc, cell.nof_prb, 1, cell.nof_prb<10?(cfi+1):cfi, CPNORM); ra_dl.mcs.tbs = ra_tbs_from_idx(ra_dl.mcs.tbs_idx, cell.nof_prb); ra_pdsch_fprint(stdout, &ra_dl, cell.nof_prb); + + /* Initiate valid DCI locations */ + for (i=0;i cell.nof_prb) { @@ -426,26 +426,33 @@ int rx_run(cf_t *input, int sf_idx) { fprintf(stderr, "Error setting CFI\n"); return -1; } + + /* Search only UE-specific locations */ + nof_locations = pdcch_ue_locations(&pdcch, locations, 10, sf_idx, cfi, 1234); + + pdcch_extract_llr(&pdcch, fft_buffer, ce, nof_frames, cfi); + + + nof_dcis = pdcch_decode_msg(&pdcch, &dci_msg, locations, nof_locations, Format1, 1234); + if (nof_dcis < 0) { + fprintf(stderr, "Error decoding DCI messages\n"); + return -1; + } - pdcch_init_search_ue(&pdcch, 1234, cfi); + INFO("Received %d DCI messages\n", nof_dcis); - dci_set.nof_dcis = 0; - nof_dcis = pdcch_decode(&pdcch, fft_buffer, ce, &dci_set, sf_idx, cfi); - INFO("Received %d DCIs\n", nof_dcis); - for (i=0;i #include +#include #include #include "liblte/phy/fec/convcoder.h" #include "parity.h" -int convcoder_encode(convcoder_t *q, char *input, char *output, int frame_length) { - unsigned int sr; - int i,j; - int len = q->tail_biting ? frame_length : (frame_length + q->K - 1); +int convcoder_encode(convcoder_t *q, char *input, char *output, uint32_t frame_length) { + uint32_t sr; + uint32_t i,j; + uint32_t len = q->tail_biting ? frame_length : (frame_length + q->K - 1); if (q->tail_biting) { sr = 0; diff --git a/lte/phy/lib/fec/src/parity.c b/lte/phy/lib/fec/src/parity.c index 568994888..b12edfaee 100644 --- a/lte/phy/lib/fec/src/parity.c +++ b/lte/phy/lib/fec/src/parity.c @@ -4,26 +4,27 @@ */ #include +#include -unsigned char Partab[256]; -int P_init; +uint8_t Partab[256]; +uint32_t P_init; /* Create 256-entry odd-parity lookup table * Needed only on non-ia32 machines */ void partab_init(void) { - int i, cnt, ti; + uint32_t 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; + /* 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/phy/lib/fec/src/parity.h b/lte/phy/lib/fec/src/parity.h index dfda24f57..5ad4b1b5c 100644 --- a/lte/phy/lib/fec/src/parity.h +++ b/lte/phy/lib/fec/src/parity.h @@ -10,16 +10,16 @@ /* Determine parity of argument: 1 = odd, 0 = even */ #ifdef __i386__ -static inline int parityb(unsigned char x){ +static inline uint32_t parityb(uint8_t x){ __asm__ __volatile__ ("test %1,%1;setpo %0" : "=qhm" (x) : "qh" (x)); return x; } #else void partab_init(); -static inline int parityb(unsigned char x){ - extern unsigned char Partab[256]; - extern int P_init; +static inline uint32_t parityb(uint8_t x){ + extern uint8_t Partab[256]; + extern uint32_t P_init; if(!P_init){ partab_init(); } @@ -28,7 +28,7 @@ static inline int parityb(unsigned char x){ #endif -static inline int parity(int x){ +static inline uint32_t parity(int x){ /* Fold down to one byte */ x ^= (x >> 16); x ^= (x >> 8); diff --git a/lte/phy/lib/fec/src/rm_conv.c b/lte/phy/lib/fec/src/rm_conv.c index 3b4254c5f..0c10c9a0d 100644 --- a/lte/phy/lib/fec/src/rm_conv.c +++ b/lte/phy/lib/fec/src/rm_conv.c @@ -27,25 +27,27 @@ #include #include +#include + #include "liblte/phy/fec/rm_conv.h" #define NCOLS 32 #define NROWS_MAX NCOLS -unsigned char RM_PERM_CC[NCOLS] = { 1, 17, 9, 25, 5, 21, 13, 29, 3, 19, 11, 27, +uint8_t 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] = +uint8_t 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) { +int rm_conv_tx(char *input, uint32_t in_len, char *output, uint32_t out_len) { char tmp[3 * NCOLS * NROWS_MAX]; int nrows, ndummy, K_p; int i, j, k, s; - nrows = (int) (in_len / 3 - 1) / NCOLS + 1; + nrows = (uint32_t) (in_len / 3 - 1) / NCOLS + 1; if (nrows > NROWS_MAX) { fprintf(stderr, "Input too large. Max input length is %d\n", 3 * NCOLS * NROWS_MAX); @@ -89,7 +91,7 @@ int rm_conv_tx(char *input, int in_len, char *output, int out_len) { /* Undoes Convolutional Code Rate Matching. * 3GPP TS 36.212 v10.1.0 section 5.1.4.2 */ -int rm_conv_rx(float *input, int in_len, float *output, int out_len) { +int rm_conv_rx(float *input, uint32_t in_len, float *output, uint32_t out_len) { int nrows, ndummy, K_p; int i, j, k; @@ -97,7 +99,7 @@ int rm_conv_rx(float *input, int in_len, float *output, int out_len) { float tmp[3 * NCOLS * NROWS_MAX]; - nrows = (int) (out_len / 3 - 1) / NCOLS + 1; + nrows = (uint32_t) (out_len / 3 - 1) / NCOLS + 1; if (nrows > NROWS_MAX) { fprintf(stderr, "Output too large. Max output length is %d\n", 3 * NCOLS * NROWS_MAX); diff --git a/lte/phy/lib/fec/src/rm_turbo.c b/lte/phy/lib/fec/src/rm_turbo.c index f678a7685..6e677b0d4 100644 --- a/lte/phy/lib/fec/src/rm_turbo.c +++ b/lte/phy/lib/fec/src/rm_turbo.c @@ -30,16 +30,17 @@ #include #include #include +#include #include "liblte/phy/fec/rm_turbo.h" #define NCOLS 32 #define NROWS_MAX NCOLS -unsigned char RM_PERM_TC[NCOLS] = { 0, 16, 8, 24, 4, 20, 12, 28, 2, 18, 10, 26, +uint8_t 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) { +int rm_turbo_init(rm_turbo_t *q, uint32_t buffer_len) { q->buffer_len = buffer_len; q->buffer = malloc(buffer_len * sizeof(float)); if (!q->buffer) { @@ -60,15 +61,16 @@ 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, uint32_t in_len, char *output, + uint32_t out_len, uint32_t rv_idx) { char *tmp = (char*) q->buffer; - int nrows, ndummy, K_p; + int ndummy, kidx; + int nrows, K_p; - int i, j, k, s, kidx, N_cb, k0; + int i, j, k, s, N_cb, k0; - nrows = (int) (in_len / 3 - 1) / NCOLS + 1; + nrows = (uint32_t) (in_len / 3 - 1) / NCOLS + 1; K_p = nrows * NCOLS; if (3 * K_p > q->buffer_len) { fprintf(stderr, @@ -113,10 +115,10 @@ int rm_turbo_tx(rm_turbo_t *q, char *input, int in_len, char *output, } /* 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); + * (2 * (uint32_t) ceilf((float) N_cb / (float) (8 * nrows)) * rv_idx + 2); k = 0; j = 0; @@ -133,8 +135,8 @@ int rm_turbo_tx(rm_turbo_t *q, char *input, int in_len, char *output, /* 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, uint32_t in_len, float *output, + uint32_t out_len, uint32_t rv_idx) { int nrows, ndummy, K_p, k0, N_cb, jp, kidx; int i, j, k; @@ -143,7 +145,7 @@ int rm_turbo_rx(rm_turbo_t *q, float *input, int in_len, float *output, float *tmp = (float*) q->buffer; - nrows = (int) (out_len / 3 - 1) / NCOLS + 1; + nrows = (uint32_t) (out_len / 3 - 1) / NCOLS + 1; K_p = nrows * NCOLS; if (3 * K_p > q->buffer_len) { fprintf(stderr, @@ -164,7 +166,7 @@ int rm_turbo_rx(rm_turbo_t *q, float *input, int in_len, float *output, /* 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); + * (2 * (uint32_t) ceilf((float) N_cb / (float) (8 * nrows)) * rv_idx + 2); k = 0; j = 0; @@ -185,7 +187,7 @@ int rm_turbo_rx(rm_turbo_t *q, float *input, int in_len, float *output, isdummy = true; } } else { - int jpp = (jp - K_p - 1) / 2; + uint32_t jpp = (jp - K_p - 1) / 2; kidx = (RM_PERM_TC[jpp / nrows] + NCOLS * (jpp % nrows) + 1) % K_p; if ((kidx - ndummy) < 0) { isdummy = true; diff --git a/lte/phy/lib/fec/src/tc_interl_lte.c b/lte/phy/lib/fec/src/tc_interl_lte.c index 227d4d9f9..b77c04779 100644 --- a/lte/phy/lib/fec/src/tc_interl_lte.c +++ b/lte/phy/lib/fec/src/tc_interl_lte.c @@ -27,6 +27,7 @@ #include #include +#include #include "liblte/phy/common/phy_common.h" #include "liblte/phy/fec/tc_interl.h" @@ -39,7 +40,7 @@ * ************************************************/ -const int f1_list[NOF_TC_CB_SIZES] = { 3, 7, 19, 7, 7, 11, 5, 11, 7, 41, 103, +const uint32_t 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, @@ -52,7 +53,7 @@ const int f1_list[NOF_TC_CB_SIZES] = { 3, 7, 19, 7, 7, 11, 5, 11, 7, 41, 103, 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, +const uint32_t 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, @@ -65,9 +66,9 @@ const int f2_list[NOF_TC_CB_SIZES] = { 10, 12, 42, 16, 18, 20, 22, 24, 26, 84, 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_gen(tc_interl_t *h, int long_cb) { - int cb_table_idx, f1, f2; - unsigned long long i, j; +int tc_interl_LTE_gen(tc_interl_t *h, uint32_t long_cb) { + uint32_t cb_table_idx, f1, f2; + uint64_t i, j; if (long_cb > h->max_long_cb) { fprintf(stderr, "Interleaver initiated for max_long_cb=%d\n", @@ -90,8 +91,8 @@ int tc_interl_LTE_gen(tc_interl_t *h, int long_cb) { h->reverse[0] = 0; for (i = 1; i < long_cb; i++) { j = (f1 * i + f2 * i * i) % (long_cb); - h->forward[i] = j; - h->reverse[j] = i; + h->forward[i] = (uint32_t) j; + h->reverse[j] = (uint32_t) i; } return 0; diff --git a/lte/phy/lib/fec/src/tc_interl_umts.c b/lte/phy/lib/fec/src/tc_interl_umts.c index 5c2e3213d..931749347 100644 --- a/lte/phy/lib/fec/src/tc_interl_umts.c +++ b/lte/phy/lib/fec/src/tc_interl_umts.c @@ -28,13 +28,14 @@ #include #include #include +#include #include "liblte/phy/fec/tc_interl.h" #include "liblte/phy/fec/turbocoder.h" #define TURBO_RATE 3 -int mcd(int x, int y); +uint32_t mcd(uint32_t x, uint32_t y); /************************************************ * @@ -53,14 +54,14 @@ const unsigned char table_v[52] = { 3, 2, 2, 3, 2, 5, 2, 3, 2, 6, 3, 5, 2, 2, 2, 2, 7, 5, 3, 2, 3, 5, 2, 5, 2, 6, 3, 3, 2, 3, 2, 2, 6, 5, 2, 5, 2, 2, 2, 19, 5, 2, 3, 2, 3, 2, 6, 3, 7, 7, 6, 3 }; -int tc_interl_init(tc_interl_t *h, int max_long_cb) { +int tc_interl_init(tc_interl_t *h, uint32_t max_long_cb) { int ret = -1; - h->forward = malloc(sizeof(int) * max_long_cb); + h->forward = malloc(sizeof(uint32_t) * max_long_cb); if (!h->forward) { perror("malloc"); goto clean_exit; } - h->reverse = malloc(sizeof(int) * max_long_cb); + h->reverse = malloc(sizeof(uint32_t) * max_long_cb); if (!h->reverse) { perror("malloc"); goto clean_exit; @@ -83,17 +84,17 @@ void tc_interl_free(tc_interl_t *h) { bzero(h, sizeof(tc_interl_t)); } -int tc_interl_UMTS_gen(tc_interl_t *h, int long_cb) { +int tc_interl_UMTS_gen(tc_interl_t *h, uint32_t long_cb) { - int i, j; - int res, prim, aux; - int kp, k; - int *per, *desper; - unsigned char v; - unsigned short p; - unsigned short s[MAX_COLS], q[MAX_ROWS], r[MAX_ROWS], T[MAX_ROWS]; - unsigned short U[MAX_COLS * MAX_ROWS]; - int M_Rows, M_Cols, M_long; + uint32_t i, j; + uint32_t res, prim, aux; + uint32_t kp, k; + uint32_t *per, *desper; + uint8_t v; + uint16_t p; + uint16_t s[MAX_COLS], q[MAX_ROWS], r[MAX_ROWS], T[MAX_ROWS]; + uint16_t U[MAX_COLS * MAX_ROWS]; + uint32_t M_Rows, M_Cols, M_long; M_long = long_cb; @@ -260,8 +261,8 @@ int tc_interl_UMTS_gen(tc_interl_t *h, int long_cb) { } -int mcd(int x, int y) { - int r = 1; +uint32_t mcd(uint32_t x, uint32_t y) { + uint32_t r = 1; while (r) { r = x % y; diff --git a/lte/phy/lib/fec/src/turbocoder.c b/lte/phy/lib/fec/src/turbocoder.c index 75aebb6e9..7483601d9 100644 --- a/lte/phy/lib/fec/src/turbocoder.c +++ b/lte/phy/lib/fec/src/turbocoder.c @@ -26,12 +26,14 @@ */ -#include "liblte/phy/fec/turbocoder.h" #include +#include + +#include "liblte/phy/fec/turbocoder.h" #define NOF_REGS 3 -int tcod_init(tcod_t *h, int max_long_cb) { +int tcod_init(tcod_t *h, uint32_t max_long_cb) { if (tc_interl_init(&h->interl, max_long_cb)) { return -1; @@ -45,13 +47,13 @@ void tcod_free(tcod_t *h) { h->max_long_cb = 0; } -int tcod_encode(tcod_t *h, char *input, char *output, int long_cb) { +int tcod_encode(tcod_t *h, char *input, char *output, uint32_t long_cb) { char reg1_0, reg1_1, reg1_2, reg2_0, reg2_1, reg2_2; - int i, k = 0, j; + uint32_t i, k = 0, j; char bit; char in, out; - int *per; + uint32_t *per; if (long_cb > h->max_long_cb) { fprintf(stderr, "Turbo coder initiated for max_long_cb=%d\n", diff --git a/lte/phy/lib/fec/src/turbodecoder.c b/lte/phy/lib/fec/src/turbodecoder.c index 2fbb61787..250b078fd 100644 --- a/lte/phy/lib/fec/src/turbodecoder.c +++ b/lte/phy/lib/fec/src/turbodecoder.c @@ -27,6 +27,7 @@ #include #include +#include #include #include @@ -38,13 +39,13 @@ * Decoder * ************************************************/ -void map_gen_beta(map_gen_t *s, llr_t *input, llr_t *parity, int long_cb) { +void map_gen_beta(map_gen_t *s, llr_t *input, llr_t *parity, uint32_t long_cb) { llr_t m_b[8], new[8], old[8]; llr_t x, y, xy; int k; - int end = long_cb + RATE; + uint32_t end = long_cb + RATE; llr_t *beta = s->beta; - int i; + uint32_t i; for (i = 0; i < 8; i++) { old[i] = beta[8 * (end) + i]; @@ -84,15 +85,15 @@ void map_gen_beta(map_gen_t *s, llr_t *input, llr_t *parity, int long_cb) { } void map_gen_alpha(map_gen_t *s, llr_t *input, llr_t *parity, llr_t *output, - int long_cb) { + uint32_t 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 = long_cb; + uint32_t k; + uint32_t end = long_cb; llr_t *beta = s->beta; - int i; + uint32_t i; old[0] = 0; for (i = 1; i < 8; i++) { @@ -168,8 +169,8 @@ void map_gen_free(map_gen_t *h) { } void map_gen_dec(map_gen_t *h, llr_t *input, llr_t *parity, llr_t *output, - int long_cb) { - int k; + uint32_t long_cb) { + uint32_t k; h->beta[(long_cb + TAIL) * NUMSTATES] = 0; for (k = 1; k < NUMSTATES; k++) @@ -184,10 +185,10 @@ void map_gen_dec(map_gen_t *h, llr_t *input, llr_t *parity, llr_t *output, * TURBO DECODER INTERFACE * ************************************************/ -int tdec_init(tdec_t *h, int max_long_cb) { +int tdec_init(tdec_t *h, uint32_t max_long_cb) { int ret = -1; bzero(h, sizeof(tdec_t)); - int len = max_long_cb + TOTALTAIL; + uint32_t len = max_long_cb + TOTALTAIL; h->max_long_cb = max_long_cb; @@ -256,8 +257,8 @@ void tdec_free(tdec_t *h) { bzero(h, sizeof(tdec_t)); } -void tdec_iteration(tdec_t *h, llr_t *input, int long_cb) { - int i; +void tdec_iteration(tdec_t *h, llr_t *input, uint32_t long_cb) { + uint32_t i; // Prepare systematic and parity bits for MAP DEC #1 for (i = 0; i < long_cb; i++) { @@ -295,7 +296,7 @@ void tdec_iteration(tdec_t *h, llr_t *input, int long_cb) { } -int tdec_reset(tdec_t *h, int long_cb) { +int tdec_reset(tdec_t *h, uint32_t 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", @@ -305,16 +306,16 @@ int tdec_reset(tdec_t *h, int long_cb) { return tc_interl_LTE_gen(&h->interleaver, long_cb); } -void tdec_decision(tdec_t *h, char *output, int long_cb) { - int i; +void tdec_decision(tdec_t *h, char *output, uint32_t long_cb) { + uint32_t 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, - int long_cb) { - int iter = 0; +void tdec_run_all(tdec_t *h, llr_t *input, char *output, uint32_t nof_iterations, + uint32_t long_cb) { + uint32_t iter = 0; tdec_reset(h, long_cb); diff --git a/lte/phy/lib/fec/src/viterbi.c b/lte/phy/lib/fec/src/viterbi.c index aa17e176a..b9fb2b0ec 100644 --- a/lte/phy/lib/fec/src/viterbi.c +++ b/lte/phy/lib/fec/src/viterbi.c @@ -27,6 +27,8 @@ #include #include +#include + #include #include @@ -38,11 +40,11 @@ #define DEB 0 -int decode37(void *o, unsigned char *symbols, char *data, int frame_length) { +int decode37(void *o, uint8_t *symbols, char *data, uint32_t frame_length) { viterbi_t *q = o; - int i; + uint32_t i; - int best_state; + uint32_t best_state; if (frame_length > q->framebits) { fprintf(stderr, "Initialized decoder for max frame length %d bits\n", @@ -73,7 +75,7 @@ int decode37(void *o, unsigned char *symbols, char *data, int frame_length) { return q->framebits; } -int decode39(void *o, unsigned char *symbols, char *data, int frame_length) { +int decode39(void *o, uint8_t *symbols, char *data, uint32_t frame_length) { viterbi_t *q = o; if (frame_length > q->framebits) { @@ -113,7 +115,7 @@ void free39(void *o) { delete_viterbi39_port(q->ptr); } -int init37(viterbi_t *q, int poly[3], int framebits, bool tail_biting) { +int init37(viterbi_t *q, uint32_t poly[3], uint32_t framebits, bool tail_biting) { q->K = 7; q->R = 3; q->framebits = framebits; @@ -145,7 +147,7 @@ int init37(viterbi_t *q, int poly[3], int framebits, bool tail_biting) { } } -int init39(viterbi_t *q, int poly[3], int framebits, bool tail_biting) { +int init39(viterbi_t *q, uint32_t poly[3], uint32_t framebits, bool tail_biting) { q->K = 9; q->R = 3; q->framebits = framebits; @@ -171,8 +173,8 @@ int init39(viterbi_t *q, int poly[3], int framebits, bool tail_biting) { } } -int viterbi_init(viterbi_t *q, viterbi_type_t type, int poly[3], - int max_frame_length, bool tail_bitting) { +int viterbi_init(viterbi_t *q, viterbi_type_t type, uint32_t poly[3], + uint32_t max_frame_length, bool tail_bitting) { switch (type) { case viterbi_37: return init37(q, poly, max_frame_length, tail_bitting); @@ -191,8 +193,8 @@ void viterbi_free(viterbi_t *q) { } /* symbols are real-valued */ -int viterbi_decode_f(viterbi_t *q, float *symbols, char *data, int frame_length) { - int len; +int viterbi_decode_f(viterbi_t *q, float *symbols, char *data, uint32_t frame_length) { + uint32_t len; if (frame_length > q->framebits) { fprintf(stderr, "Initialized decoder for max frame length %d bits\n", q->framebits); @@ -207,13 +209,13 @@ int viterbi_decode_f(viterbi_t *q, float *symbols, char *data, int frame_length) return q->decode(q, q->symbols_uc, data, frame_length); } -int viterbi_decode_uc(viterbi_t *q, unsigned char *symbols, char *data, - int frame_length) { +int viterbi_decode_uc(viterbi_t *q, uint8_t *symbols, char *data, + uint32_t frame_length) { return q->decode(q, symbols, data, frame_length); } int viterbi_initialize(viterbi_hl* h) { - int poly[3]; + uint32_t poly[3]; viterbi_type_t type; if (h->init.rate == 2) { if (h->init.constraint_length == 7) { @@ -243,7 +245,7 @@ int viterbi_initialize(viterbi_hl* h) { poly[0] = h->init.generator_0; poly[1] = h->init.generator_1; poly[2] = h->init.generator_2; - return viterbi_init(&h->obj, type, poly, h->init.frame_length, + return viterbi_init(&h->obj, type, poly, (uint32_t) h->init.frame_length, h->init.tail_bitting ? true : false); } diff --git a/lte/phy/lib/fec/src/viterbi37.h b/lte/phy/lib/fec/src/viterbi37.h index 6afc563e8..7bacca2c8 100644 --- a/lte/phy/lib/fec/src/viterbi37.h +++ b/lte/phy/lib/fec/src/viterbi37.h @@ -27,8 +27,20 @@ #include -void *create_viterbi37_port(int polys[3], int len); -int init_viterbi37_port(void *p, int starting_state); -int chainback_viterbi37_port(void *p, char *data, unsigned int nbits, unsigned int endstate); +void *create_viterbi37_port(uint32_t polys[3], + uint32_t len); + +int init_viterbi37_port(void *p, + uint32_t starting_state); + +int chainback_viterbi37_port(void *p, + char *data, + uint32_t nbits, + uint32_t endstate); + void delete_viterbi37_port(void *p); -int update_viterbi37_blk_port(void *p, unsigned char *syms, int nbits, int *best_state); + +int update_viterbi37_blk_port(void *p, + unsigned char *syms, + uint32_t nbits, + uint32_t *best_state); diff --git a/lte/phy/lib/fec/src/viterbi37_port.c b/lte/phy/lib/fec/src/viterbi37_port.c index 7eb311324..09dfa4bdc 100644 --- a/lte/phy/lib/fec/src/viterbi37_port.c +++ b/lte/phy/lib/fec/src/viterbi37_port.c @@ -4,6 +4,8 @@ */ #include #include +#include + #include #include "viterbi37.h" #include "parity.h" @@ -30,9 +32,9 @@ struct v37 { }; /* Initialize Viterbi decoder for start of new frame */ -int init_viterbi37_port(void *p, int starting_state) { +int init_viterbi37_port(void *p, uint32_t starting_state) { struct v37 *vp = p; - int i; + uint32_t i; if (p == NULL) return -1; @@ -48,8 +50,8 @@ int init_viterbi37_port(void *p, int starting_state) { return 0; } -void set_viterbi37_polynomial_port(int polys[3]) { - int state; +void set_viterbi37_polynomial_port(uint32_t polys[3]) { + uint32_t state; for (state = 0; state < 32; state++) { Branchtab37[0].c[state] = @@ -62,7 +64,7 @@ void set_viterbi37_polynomial_port(int polys[3]) { } /* Create a new instance of a Viterbi decoder */ -void *create_viterbi37_port(int polys[3], int len) { +void *create_viterbi37_port(uint32_t polys[3], uint32_t len) { struct v37 *vp; set_viterbi37_polynomial_port(polys); @@ -82,8 +84,8 @@ void *create_viterbi37_port(int polys[3], int len) { /* Viterbi chainback */ int chainback_viterbi37_port(void *p, char *data, /* Decoded output data */ - unsigned int nbits, /* Number of data bits */ - unsigned int endstate) { /* Terminal encoder state */ + uint32_t nbits, /* Number of data bits */ + uint32_t endstate) { /* Terminal encoder state */ struct v37 *vp = p; decision_t *d; @@ -145,18 +147,18 @@ unsigned int metric,m0,m1,decision;\ * of symbols! */ -int update_viterbi37_blk_port(void *p, unsigned char *syms, int nbits, int *best_state) { +int update_viterbi37_blk_port(void *p, uint8_t *syms, uint32_t nbits, uint32_t *best_state) { struct v37 *vp = p; decision_t *d; if (p == NULL) return -1; - int k=0; + uint32_t k=0; d = (decision_t *) vp->dp; while (nbits--) { void *tmp; - unsigned char sym0, sym1, sym2; - int i; + uint8_t sym0, sym1, sym2; + uint32_t i; d->w[0] = d->w[1] = 0; @@ -174,8 +176,8 @@ int update_viterbi37_blk_port(void *p, unsigned char *syms, int nbits, int *best vp->new_metrics = tmp; } if (best_state) { - int i, bst=0; - unsigned int minmetric=UINT_MAX; + uint32_t i, bst=0; + uint32_t minmetric=UINT_MAX; for (i=0;i<64;i++) { if (vp->old_metrics->w[i] < minmetric) { bst = i; diff --git a/lte/phy/lib/fec/src/viterbi39.h b/lte/phy/lib/fec/src/viterbi39.h index a5830d145..09a3280cf 100644 --- a/lte/phy/lib/fec/src/viterbi39.h +++ b/lte/phy/lib/fec/src/viterbi39.h @@ -27,10 +27,19 @@ #include -void *create_viterbi39_port(int polys[3], int len); -int init_viterbi39_port(void *p, int starting_state); -int chainback_viterbi39_port(void *p, char *data, /* Decoded output data */ - unsigned int nbits, /* Number of data bits */ - unsigned int endstate); +void *create_viterbi39_port(uint32_t polys[3], + uint32_t len); + +int init_viterbi39_port(void *p, + uint32_t starting_state); + +int chainback_viterbi39_port(void *p, + char *data, /* Decoded output data */ + uint32_t nbits, /* Number of data bits */ + uint32_t endstate); + void delete_viterbi39_port(void *p); -int update_viterbi39_blk_port(void *p, unsigned char *syms, int nbits); + +int update_viterbi39_blk_port(void *p, + uint8_t *syms, + uint32_t nbits); diff --git a/lte/phy/lib/fec/src/viterbi39_port.c b/lte/phy/lib/fec/src/viterbi39_port.c index fe57297c7..1d87b2c4a 100644 --- a/lte/phy/lib/fec/src/viterbi39_port.c +++ b/lte/phy/lib/fec/src/viterbi39_port.c @@ -4,6 +4,7 @@ */ #include #include +#include #include #include "viterbi39.h" #include "parity.h" @@ -29,9 +30,9 @@ struct v39 { }; /* Initialize Viterbi decoder for start of new frame */ -int init_viterbi39_port(void *p, int starting_state) { +int init_viterbi39_port(void *p, uint32_t starting_state) { struct v39 *vp = p; - int i; + uint32_t i; if (p == NULL) return -1; @@ -45,8 +46,8 @@ int init_viterbi39_port(void *p, int starting_state) { return 0; } -void set_viterbi39_polynomial_port(int polys[3]) { - int state; +void set_viterbi39_polynomial_port(uint32_t polys[3]) { + uint32_t state; for (state = 0; state < 128; state++) { Branchtab39[0].c[state] = @@ -59,7 +60,7 @@ void set_viterbi39_polynomial_port(int polys[3]) { } /* Create a new instance of a Viterbi decoder */ -void *create_viterbi39_port(int polys[3], int len) { +void *create_viterbi39_port(uint32_t polys[3], uint32_t len) { struct v39 *vp; set_viterbi39_polynomial_port(polys); @@ -79,8 +80,8 @@ void *create_viterbi39_port(int polys[3], int len) { /* Viterbi chainback */ int chainback_viterbi39_port(void *p, char *data, /* Decoded output data */ - unsigned int nbits, /* Number of data bits */ - unsigned int endstate) { /* Terminal encoder state */ + uint32_t nbits, /* Number of data bits */ + uint32_t endstate) { /* Terminal encoder state */ struct v39 *vp = p; decision_t *d; @@ -140,7 +141,7 @@ unsigned int metric,m0,m1,decision;\ * of symbols! */ -int update_viterbi39_blk_port(void *p, unsigned char *syms, int nbits) { +int update_viterbi39_blk_port(void *p, uint8_t *syms, uint32_t nbits) { struct v39 *vp = p; decision_t *d; @@ -150,8 +151,8 @@ int update_viterbi39_blk_port(void *p, unsigned char *syms, int nbits) { d = (decision_t *) vp->dp; while (nbits--) { void *tmp; - unsigned char sym0, sym1, sym2; - int i; + uint8_t sym0, sym1, sym2; + uint32_t i; for (i = 0; i < 8; i++) d->w[i] = 0; diff --git a/lte/phy/lib/fec/test/turbocoder_test.c b/lte/phy/lib/fec/test/turbocoder_test.c index a222b9750..fb0fabc85 100644 --- a/lte/phy/lib/fec/test/turbocoder_test.c +++ b/lte/phy/lib/fec/test/turbocoder_test.c @@ -41,9 +41,9 @@ typedef _Complex float cf_t; -int frame_length = 1000, nof_frames = 100; +uint32_t frame_length = 1000, nof_frames = 100; float ebno_db = 100.0; -unsigned int seed = 0; +uint32_t seed = 0; int K = -1; #define MAX_ITERATIONS 4 @@ -51,9 +51,9 @@ 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); @@ -127,16 +127,16 @@ void output_matlab(float ber[MAX_ITERATIONS][SNR_POINTS], int snr_points) { } int main(int argc, char **argv) { - int frame_cnt; + uint32_t frame_cnt; float *llr; unsigned char *llr_c; char *data_tx, *data_rx, *symbols; - int i, j; + uint32_t i, j; float var[SNR_POINTS]; - int snr_points; + uint32_t snr_points; float ber[MAX_ITERATIONS][SNR_POINTS]; - unsigned int errors[100]; - int coded_length; + uint32_t errors[100]; + uint32_t coded_length; struct timeval tdata[3]; float mean_usec; tdec_t tdec; @@ -247,7 +247,7 @@ int main(int argc, char **argv) { /* decoder */ tdec_reset(&tdec, frame_length); - int t; + uint32_t t; if (nof_iterations == -1) { t = MAX_ITERATIONS; } else { diff --git a/lte/phy/lib/phch/src/dci.c b/lte/phy/lib/phch/src/dci.c index 0e38b0ffd..05e0fc35b 100644 --- a/lte/phy/lib/phch/src/dci.c +++ b/lte/phy/lib/phch/src/dci.c @@ -40,42 +40,20 @@ #include "liblte/phy/utils/vector.h" #include "liblte/phy/utils/debug.h" -int dci_init(dci_t *q, uint32_t max_dcis) { - q->msg = calloc(sizeof(dci_msg_t), max_dcis); - if (!q->msg) { - perror("malloc"); - return LIBLTE_ERROR; - } - q->nof_dcis = 0; - q->max_dcis = max_dcis; - return LIBLTE_SUCCESS; -} - -void dci_free(dci_t *q) { - if (q->msg) { - free(q->msg); - } -} - -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); -} -int dci_msg_candidate_set(dci_msg_t *msg, uint32_t L, uint32_t nCCE, uint16_t rnti) { - if (L >= 0 && L <= 3) { - msg->location.L = L; +int dci_location_set(dci_location_t *c, uint32_t L, uint32_t nCCE) { + if (L <= 3) { + c->L = L; } else { fprintf(stderr, "Invalid L %d\n", L); return LIBLTE_ERROR; } - if (nCCE >= 0 && nCCE <= 87) { - msg->location.ncce = nCCE; + if (nCCE <= 87) { + c->ncce = nCCE; } else { fprintf(stderr, "Invalid nCCE %d\n", nCCE); return LIBLTE_ERROR; } - msg->location.rnti = rnti; return LIBLTE_SUCCESS; } @@ -245,7 +223,7 @@ int dci_format0_pack(ra_pusch_t *data, dci_msg_t *msg, uint32_t nof_prb) { while (y - msg->data < n) { *y++ = 0; } - msg->location.nof_bits = (y - msg->data); + msg->nof_bits = (y - msg->data); return LIBLTE_SUCCESS; } /* Unpacks DCI format 0 data and store result in msg according @@ -260,7 +238,7 @@ int dci_format0_unpack(dci_msg_t *msg, ra_pusch_t *data, uint32_t nof_prb) { uint32_t n_ul_hop; /* Make sure it's a Format0 message */ - if (msg->location.nof_bits != dci_format_sizeof(Format0, nof_prb)) { + if (msg->nof_bits != dci_format_sizeof(Format0, nof_prb)) { fprintf(stderr, "Invalid message length for format 0\n"); return LIBLTE_ERROR; } @@ -385,7 +363,7 @@ int dci_format1_pack(ra_pdsch_t *data, dci_msg_t *msg, uint32_t nof_prb) { while (y - msg->data < n) { *y++ = 0; } - msg->location.nof_bits = (y - msg->data); + msg->nof_bits = (y - msg->data); return LIBLTE_SUCCESS; } @@ -396,7 +374,7 @@ int dci_format1_unpack(dci_msg_t *msg, ra_pdsch_t *data, uint32_t nof_prb) { char *y = msg->data; /* Make sure it's a Format1 message */ - if (msg->location.nof_bits != dci_format_sizeof(Format1, nof_prb)) { + if (msg->nof_bits != dci_format_sizeof(Format1, nof_prb)) { fprintf(stderr, "Invalid message length for format 1\n"); return LIBLTE_ERROR; } @@ -551,7 +529,7 @@ int dci_format1As_pack(ra_pdsch_t *data, dci_msg_t *msg, uint32_t nof_prb, while (y - msg->data < n) { *y++ = 0; } - msg->location.nof_bits = (y - msg->data); + msg->nof_bits = (y - msg->data); return LIBLTE_SUCCESS; } @@ -566,7 +544,7 @@ int dci_format1As_unpack(dci_msg_t *msg, ra_pdsch_t *data, uint32_t nof_prb, char *y = msg->data; /* Make sure it's a Format0 message */ - if (msg->location.nof_bits != dci_format_sizeof(Format1A, nof_prb)) { + if (msg->nof_bits != dci_format_sizeof(Format1A, nof_prb)) { fprintf(stderr, "Invalid message length for format 1A\n"); return LIBLTE_ERROR; } @@ -692,7 +670,7 @@ int dci_format1Cs_pack(ra_pdsch_t *data, dci_msg_t *msg, uint32_t nof_prb) { } bit_pack((uint32_t) mcs, &y, 5); - msg->location.nof_bits = (y - msg->data); + msg->nof_bits = (y - msg->data); return LIBLTE_SUCCESS; } @@ -703,7 +681,7 @@ int dci_format1Cs_unpack(dci_msg_t *msg, ra_pdsch_t *data, uint32_t nof_prb) { /* pack bits */ char *y = msg->data; - if (msg->location.nof_bits != dci_format_sizeof(Format1C, nof_prb)) { + if (msg->nof_bits != dci_format_sizeof(Format1C, nof_prb)) { fprintf(stderr, "Invalid message length for format 1C\n"); return LIBLTE_ERROR; } @@ -728,7 +706,7 @@ int dci_format1Cs_unpack(dci_msg_t *msg, ra_pdsch_t *data, uint32_t nof_prb) { data->mcs.tbs = ra_tbs_from_idx_format1c(data->mcs.tbs_idx); data->mcs.mod = QPSK; - msg->location.nof_bits = (y - msg->data); + msg->nof_bits = (y - msg->data); return LIBLTE_SUCCESS; } @@ -751,11 +729,11 @@ int dci_msg_pack_pdsch(ra_pdsch_t *data, dci_msg_t *msg, dci_format_t format, int dci_msg_unpack_pdsch(dci_msg_t *msg, ra_pdsch_t *data, uint32_t nof_prb, bool crc_is_crnti) { - if (msg->location.nof_bits == dci_format_sizeof(Format1, nof_prb)) { + if (msg->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)) { + } else if (msg->nof_bits == dci_format_sizeof(Format1A, nof_prb)) { return dci_format1As_unpack(msg, data, nof_prb, crc_is_crnti); - } else if (msg->location.nof_bits == dci_format_sizeof(Format1C, nof_prb)) { + } else if (msg->nof_bits == dci_format_sizeof(Format1C, nof_prb)) { return dci_format1Cs_unpack(msg, data, nof_prb); } else { return LIBLTE_ERROR; @@ -807,18 +785,18 @@ void dci_msg_type_fprint(FILE *f, dci_msg_type_t type) { } int dci_msg_get_type(dci_msg_t *msg, dci_msg_type_t *type, uint32_t nof_prb, - uint16_t crnti) { - if (msg->location.nof_bits == dci_format_sizeof(Format0, nof_prb) + uint16_t msg_rnti, uint16_t crnti) { + if (msg->nof_bits == dci_format_sizeof(Format0, nof_prb) && !msg->data[0]) { type->type = PUSCH_SCHED; type->format = Format0; return LIBLTE_SUCCESS; - } else if (msg->location.nof_bits == dci_format_sizeof(Format1, nof_prb)) { + } else if (msg->nof_bits == dci_format_sizeof(Format1, nof_prb)) { type->type = PDSCH_SCHED; // only these 2 types supported type->format = Format1; return LIBLTE_SUCCESS; - } else if (msg->location.nof_bits == dci_format_sizeof(Format1A, nof_prb)) { - if (msg->location.rnti == crnti) { + } else if (msg->nof_bits == dci_format_sizeof(Format1A, nof_prb)) { + if (msg_rnti == crnti) { type->type = RA_PROC_PDCCH; type->format = Format1A; } else { @@ -826,8 +804,8 @@ int dci_msg_get_type(dci_msg_t *msg, dci_msg_type_t *type, uint32_t nof_prb, type->format = Format1A; } return LIBLTE_SUCCESS; - } else if (msg->location.nof_bits == dci_format_sizeof(Format1C, nof_prb)) { - if (msg->location.rnti == MRNTI) { + } else if (msg->nof_bits == dci_format_sizeof(Format1C, nof_prb)) { + if (msg_rnti == MRNTI) { type->type = MCCH_CHANGE; type->format = Format1C; } else { diff --git a/lte/phy/lib/phch/src/pbch.c b/lte/phy/lib/phch/src/pbch.c index dce32ad12..05d8e8cf5 100644 --- a/lte/phy/lib/phch/src/pbch.c +++ b/lte/phy/lib/phch/src/pbch.c @@ -144,7 +144,7 @@ int pbch_init(pbch_t *q, lte_cell_t cell) { goto clean; } - int poly[3] = { 0x6D, 0x4F, 0x57 }; + uint32_t poly[3] = { 0x6D, 0x4F, 0x57 }; if (viterbi_init(&q->decoder, viterbi_37, poly, 40, true)) { goto clean; } diff --git a/lte/phy/lib/phch/src/pdcch.c b/lte/phy/lib/phch/src/pdcch.c index 95f9ad6df..0c719671b 100644 --- a/lte/phy/lib/phch/src/pdcch.c +++ b/lte/phy/lib/phch/src/pdcch.c @@ -46,173 +46,11 @@ #define PDCCH_FORMAT_NOF_REGS(i) ((1<b)?b:a) -void set_cfi(pdcch_t *q, uint32_t cfi); - -/** - * 36.213 9.1 - */ -int gen_common_search(dci_candidate_t *c, uint32_t nof_cce, uint32_t nof_bits, - uint16_t rnti) { - int i, l, L, k; - k = 0; - for (l = 3; l > 1; l--) { - L = (1 << l); - for (i = 0; i < MIN(nof_cce,16) / (L); i++) { - c[k].L = l; - c[k].nof_bits = nof_bits; - c[k].rnti = rnti; - c[k].ncce = (L) * (i % (nof_cce / (L))); - INFO("Common SS Candidate %d: RNTI: 0x%x, nCCE: %d, Nbits: %d, L: %d\n", - k, c[k].rnti, c[k].ncce, c[k].nof_bits, c[k].L); - k++; - } - } - return k; -} - -/** - * 36.213 9.1 - */ -int gen_ue_search(dci_candidate_t *c, uint32_t nof_cce, uint32_t nof_bits, - uint16_t rnti, uint32_t subframe) { - int i, l, L, k, m; - unsigned int Yk; - const int S[4] = { 6, 12, 8, 16 }; - k = 0; - - if (VERBOSE_ISDEBUG()) { - printf("NofBits=%d, RNTI: 0x%x, SF=%d (n, L): ", nof_bits, rnti, subframe); - } - for (l = 3; l >= 0; l--) { - L = (1 << l); - 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; - Yk = rnti; - for (m = 0; m < subframe; m++) { - Yk = (39827 * Yk) % 65537; - } - c[k].ncce = L * ((Yk + i) % (nof_cce / L)); - if (VERBOSE_ISDEBUG()) { - printf("(%d, %d), ", c[k].ncce, c[k].L); - } - if (c[k].ncce + PDCCH_FORMAT_NOF_CCE(c[k].L) > nof_cce || - nof_bits > DCI_MAX_BITS) { - fprintf(stderr, "Illegal DCI message\n"); - return LIBLTE_ERROR; - } - k++; - } - } - if (VERBOSE_ISDEBUG()) { - printf("\n"); - } - return k; -} - - -/** 36.213 v9.3 Table 7.1-5 - * user-specific search space. Currently supported transmission Mode 1: - * DCI Format 1A and 1 + PUSCH scheduling format 0 - */ -int pdcch_init_search_ue(pdcch_t *q, uint16_t c_rnti, uint32_t cfi) { - int k, i, r; - uint32_t n; - - set_cfi(q, cfi); - - pdcch_search_t *s = &q->search_mode[SEARCH_UE]; - for (n = 0; n < NSUBFRAMES_X_FRAME; n++) { - dci_candidate_t *c = s->candidates[n]; - - if (!n) s->nof_candidates = 0; - - // Expect Formats 1, 1A, 0 - k = 0; - for (i = 0; i < NOF_UE_FORMATS && k < MAX_CANDIDATES; i++) { - r = gen_ue_search(&c[k], q->nof_cce, - dci_format_sizeof(ue_formats[i], q->cell.nof_prb), c_rnti, n); - if (r < 0) { - fprintf(stderr, "Error generating UE-specific search space\n"); - return r; - } - k += r; - } - s->nof_candidates = k; - } - INFO("Initiated %d candidate(s) in the UE-specific search space for C-RNTI: 0x%x\n", - s->nof_candidates, c_rnti); - q->current_search_mode = SEARCH_UE; - - return LIBLTE_SUCCESS; -} - - -int pdcch_init_common(pdcch_t *q, pdcch_search_t *s, uint16_t rnti) { - int k, r, i; - dci_candidate_t *c = s->candidates[0]; - s->nof_candidates = 0; - // Format 1A and 1C L=4 and L=8, 4 and 2 candidates, only if nof_cce > 16 - k = 0; - for (i = 0; i < NOF_COMMON_FORMATS && k < MAX_CANDIDATES; i++) { - r = gen_common_search(&c[k], q->nof_cce, - dci_format_sizeof(common_formats[i], q->cell.nof_prb), SIRNTI); - if (r < 0) { - return r; - } - k += r; - } - s->nof_candidates=k; - INFO("Initiated %d candidate(s) in the Common search space for RNTI: 0x%x\n", - s->nof_candidates, rnti); - - return LIBLTE_SUCCESS; -} - -/** 36.213 v9.3 Table 7.1-1: System Information DCI messages - * Expect DCI formats 1C and 1A in the common search space - */ -int pdcch_init_search_si(pdcch_t *q, uint32_t cfi) { - set_cfi(q, cfi); - int r = pdcch_init_common(q, &q->search_mode[SEARCH_SI], SIRNTI); - if (r >= 0) { - q->current_search_mode = SEARCH_SI; - } - return r; -} -/** 36.213 v9.3 Table 7.1-3 - * Expect DCI formats 1C and 1A in the common search space - */ -int pdcch_init_search_ra(pdcch_t *q, uint16_t ra_rnti, uint32_t cfi) { - set_cfi(q, cfi); - int r = pdcch_init_common(q, &q->search_mode[SEARCH_RA], ra_rnti); - if (r >= 0) { - q->current_search_mode = SEARCH_RA; - } - return r; -} - -void pdcch_set_search_si(pdcch_t *q) { - q->current_search_mode = SEARCH_SI; -} -void pdcch_set_search_ue(pdcch_t *q) { - q->current_search_mode = SEARCH_UE; -} -void pdcch_set_search_ra(pdcch_t *q) { - q->current_search_mode = SEARCH_RA; -} - -void set_cfi(pdcch_t *q, uint32_t cfi) { +static void set_cfi(pdcch_t *q, uint32_t cfi) { if (cfi > 0 && cfi < 4) { q->nof_regs = (regs_pdcch_nregs(q->regs, cfi) / 9) * 9; q->nof_cce = q->nof_regs / 9; @@ -221,6 +59,7 @@ void set_cfi(pdcch_t *q, uint32_t cfi) { } } + /** Initializes the PDCCH transmitter and receiver */ int pdcch_init(pdcch_t *q, regs_t *regs, lte_cell_t cell) { int ret = LIBLTE_ERROR_INVALID_INPUTS; @@ -234,7 +73,6 @@ int pdcch_init(pdcch_t *q, regs_t *regs, lte_cell_t cell) { bzero(q, sizeof(pdcch_t)); q->cell = cell; q->regs = regs; - q->current_search_mode = SEARCH_NONE; /* Now allocate memory for the maximum number of REGs (CFI=3) */ @@ -261,7 +99,7 @@ int pdcch_init(pdcch_t *q, regs_t *regs, lte_cell_t cell) { } } - int poly[3] = { 0x6D, 0x4F, 0x57 }; + uint32_t poly[3] = { 0x6D, 0x4F, 0x57 }; if (viterbi_init(&q->decoder, viterbi_37, poly, DCI_MAX_BITS + 16, true)) { goto clean; } @@ -337,13 +175,97 @@ void pdcch_free(pdcch_t *q) { viterbi_free(&q->decoder); } +/** 36.213 v9.1.1 + * Computes up to max_candidates UE-specific candidates for DCI messages and saves them + * in the structure pointed by c. + * Returns the number of candidates saved in the array c. + */ +uint32_t pdcch_ue_locations(pdcch_t *q, dci_location_t *c, uint32_t max_candidates, + uint32_t nsubframe, uint32_t cfi, uint16_t rnti) { + + uint32_t i, k, l, L, m; + uint32_t Yk, ncce; + const int S[4] = { 6, 12, 8, 16 }; + + set_cfi(q, cfi); + + // Compute Yk for this subframe + Yk = rnti; + for (m = 0; m < nsubframe; m++) { + Yk = (39827 * Yk) % 65537; + } + + k = 0; + // All aggregation levels from 8 to 1 + for (l = 3; l >= 0; l--) { + L = (1 << l); + // For all possible ncce offset + for (i = 0; i < MIN(q->nof_cce / L, 16 / S[l]); i++) { + ncce = L * ((Yk + i) % (q->nof_cce / L)); + if (k < max_candidates && + ncce + PDCCH_FORMAT_NOF_CCE(L) < q->nof_cce) + { + c[k].L = l; + c[k].ncce = ncce; + + DEBUG("UE-specific SS Candidate %d: nCCE: %d, L: %d\n", + k, c[k].ncce, c[k].L); + + k++; + } + } + } + + INFO("Initiated %d candidate(s) in the UE-specific search space for C-RNTI: 0x%x\n", k, rnti); + + return k; +} + + + +/** + * 36.213 9.1.1 + * Computes up to max_candidates candidates in the common search space + * for DCI messages and saves them in the structure pointed by c. + * Returns the number of candidates saved in the array c. + */ +uint32_t pdcch_common_locations(pdcch_t *q, dci_location_t *c, uint32_t max_candidates, + uint32_t cfi) { + uint32_t i, l, L, k; + + set_cfi(q, cfi); + + k = 0; + for (l = 3; l > 1; l--) { + L = (1 << l); + for (i = 0; i < MIN(q->nof_cce, 16) / (L); i++) { + if (k < max_candidates) { + c[k].L = l; + c[k].ncce = (L) * (i % (q->nof_cce / (L))); + DEBUG("Common SS Candidate %d: nCCE: %d, L: %d\n", + k, c[k].ncce, c[k].L); + k++; + } + } + } + + INFO("Initiated %d candidate(s) in the Common search space\n", k); + + return k; +} + + + + + + /** 36.212 5.3.3.2 to 5.3.3.4 * * Returns XOR between parity and remainder bits * * TODO: UE transmit antenna selection CRC mask */ -int dci_decode(pdcch_t *q, float *e, char *data, uint32_t E, uint32_t nof_bits, uint16_t *crc) { +static int dci_decode(pdcch_t *q, float *e, char *data, uint32_t E, uint32_t nof_bits, uint16_t *crc) { float tmp[3 * (DCI_MAX_BITS + 16)]; uint16_t p_bits, crc_res; @@ -355,6 +277,10 @@ int dci_decode(pdcch_t *q, float *e, char *data, uint32_t E, uint32_t nof_bits, nof_bits < DCI_MAX_BITS) { + if (VERBOSE_ISDEBUG()) { + vec_fprint_f(stdout, e, E); + } + /* unrate matching */ rm_conv_rx(e, E, tmp, 3 * (nof_bits + 16)); @@ -385,36 +311,63 @@ int dci_decode(pdcch_t *q, float *e, char *data, uint32_t E, uint32_t nof_bits, } } -int pdcch_decode_candidate(pdcch_t *q, float *llr, dci_candidate_t *c, - dci_msg_t *msg) { - uint16_t crc_res; - INFO("Trying Candidate: Nbits: %d, E: %3d, nCCE: %d, L: %d, RNTI: 0x%x\n", - c->nof_bits, PDCCH_FORMAT_NOF_BITS(c->L), c->ncce, c->L, c->rnti); - - if (dci_decode(q, &llr[72 * c->ncce], msg->data, - PDCCH_FORMAT_NOF_BITS(c->L), c->nof_bits, &crc_res)) { - return LIBLTE_ERROR; - } - - 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); - return 1; +/** Tries to decode a DCI message from the LLRs stored in the pdcch_t structure by the function + * pdcch_extract_llr(). This function can be called multiple times. + * The decoded message is stored in msg. Up to nof_locations are tried from the array of dci_locations_t + * pointed by locations. The CRC is checked agains the RNTI parameter. + * + * Returns 1 if the message is correctly decoded, 0 if not and -1 on error. + */ +int pdcch_decode_msg(pdcch_t *q, dci_msg_t *msg, + dci_location_t *locations, uint32_t nof_locations, + dci_format_t format, uint16_t rnti) +{ + if (q != NULL && + msg != NULL && + locations != NULL && + nof_locations > 0) + { + uint16_t crc_res; + uint32_t nof_bits = dci_format_sizeof(format, q->cell.nof_prb); + uint32_t i; + + i = 0; + do { + INFO("Trying Candidate: Nbits: %d, E: %3d, nCCE: %d, L: %d, RNTI: 0x%x\n", + nof_bits, PDCCH_FORMAT_NOF_BITS(locations[i].L), locations[i].ncce, locations[i].L, rnti); + + if (dci_decode(q, &q->pdcch_llr[72 * locations[i].ncce], msg->data, + PDCCH_FORMAT_NOF_BITS(locations[i].L), nof_bits, &crc_res) != LIBLTE_SUCCESS) { + return LIBLTE_ERROR; + } + if (crc_res != rnti) { + i++; + } + } while(i < nof_locations && crc_res != rnti); + + if (rnti == crc_res) { + msg->nof_bits = nof_bits; + INFO("FOUND Candidate: Nbits: %d, E: %d, nCCE: %d, L: %d, RNTI: 0x%x\n", + nof_bits, PDCCH_FORMAT_NOF_BITS(locations[i].L), locations[i].ncce, locations[i].L, rnti); + return 1; + } else { + return LIBLTE_SUCCESS; + } } - return LIBLTE_SUCCESS; + return LIBLTE_ERROR_INVALID_INPUTS; } -int pdcch_extract_llr(pdcch_t *q, cf_t *slot_symbols, cf_t *ce[MAX_PORTS], - float *llr, uint32_t nsubframe, uint32_t cfi) { +/** Extracts the LLRs from the subframe symbols (demodulation) and stores them in the pdcch_t structure. + * DCI messages can be extracted calling the function pdcch_decode_msg(). + * Every time this function is called, the last demodulated symbols are overwritten. + */ +int pdcch_extract_llr(pdcch_t *q, cf_t *sf_symbols, cf_t *ce[MAX_PORTS], uint32_t nsubframe, uint32_t cfi) { /* Set pointers for layermapping & precoding */ - int i; + uint32_t i; cf_t *x[MAX_LAYERS]; if (q != NULL && - llr != NULL && - slot_symbols != NULL && nsubframe < 10 && cfi > 0 && cfi < 4) @@ -428,7 +381,7 @@ int pdcch_extract_llr(pdcch_t *q, cf_t *slot_symbols, cf_t *ce[MAX_PORTS], memset(&x[q->cell.nof_ports], 0, sizeof(cf_t*) * (MAX_LAYERS - q->cell.nof_ports)); /* extract symbols */ - int n = regs_pdcch_get(q->regs, slot_symbols, q->pdcch_symbols[0]); + int n = regs_pdcch_get(q->regs, sf_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); @@ -472,84 +425,18 @@ int pdcch_extract_llr(pdcch_t *q, cf_t *slot_symbols, cf_t *ce[MAX_PORTS], } /* descramble */ - scrambling_f_offset(&q->seq_pdcch[nsubframe], llr, 0, q->nof_bits); + scrambling_f_offset(&q->seq_pdcch[nsubframe], q->pdcch_llr, 0, q->nof_bits); return LIBLTE_SUCCESS; - } else { - return LIBLTE_ERROR_INVALID_INPUTS; - } -} - -int pdcch_decode_current_mode(pdcch_t *q, float *llr, dci_t *dci, uint32_t subframe) { - int k, i; - int ret; - - if (q->current_search_mode == SEARCH_UE) { - k = subframe; - } else { - k = 0; - } - - for (i = 0; - i < q->search_mode[q->current_search_mode].nof_candidates - && dci->nof_dcis < dci->max_dcis; i++) { - ret = pdcch_decode_candidate(q, q->pdcch_llr, - &q->search_mode[q->current_search_mode].candidates[k][i], - &dci->msg[dci->nof_dcis]); - if (ret == 1) { - dci->nof_dcis++; - } else if (ret == -1) { - return LIBLTE_ERROR; - } - } - return dci->nof_dcis; -} - -int pdcch_decode_si(pdcch_t *q, float *llr, dci_t *dci) { - pdcch_set_search_si(q); - return pdcch_decode_current_mode(q, llr, dci, 0); -} -int pdcch_decode_ra(pdcch_t *q, float *llr, dci_t *dci) { - pdcch_set_search_ra(q); - return pdcch_decode_current_mode(q, llr, dci, 0); -} -int pdcch_decode_ue(pdcch_t *q, float *llr, dci_t *dci, uint32_t nsubframe) { - pdcch_set_search_ue(q); - return pdcch_decode_current_mode(q, llr, dci, nsubframe); + } + return LIBLTE_ERROR_INVALID_INPUTS; } -/* 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 *slot_symbols, cf_t *ce[MAX_PORTS], - dci_t *dci, uint32_t subframe, uint32_t cfi) { - - if (q != NULL && - dci != NULL && - slot_symbols != NULL && - subframe < 10 && - cfi > 0 && - cfi < 4) - { - if (pdcch_extract_llr(q, slot_symbols, ce, q->pdcch_llr, subframe, cfi)) { - return LIBLTE_ERROR; - } - if (q->current_search_mode != SEARCH_NONE) { - return pdcch_decode_current_mode(q, q->pdcch_llr, dci, subframe); - } - return LIBLTE_SUCCESS; - } else { - return LIBLTE_ERROR_INVALID_INPUTS; - } -} -void crc_set_mask_rnti(char *crc, uint16_t rnti) { - int i; +static void crc_set_mask_rnti(char *crc, uint16_t rnti) { + uint32_t i; char mask[16]; char *r = mask; @@ -564,7 +451,7 @@ void crc_set_mask_rnti(char *crc, uint16_t rnti) { /** 36.212 5.3.3.2 to 5.3.3.4 * TODO: UE transmit antenna selection CRC mask */ -int dci_encode(pdcch_t *q, char *data, char *e, uint32_t nof_bits, uint32_t E, +static int dci_encode(pdcch_t *q, char *data, char *e, uint32_t nof_bits, uint32_t E, uint16_t rnti) { convcoder_t encoder; char tmp[3 * (DCI_MAX_BITS + 16)]; @@ -600,16 +487,57 @@ int dci_encode(pdcch_t *q, char *data, char *e, uint32_t nof_bits, uint32_t E, } } -/** Converts the set of DCI messages to symbols mapped to the slot ready for transmission +void pdcch_reset(pdcch_t *q) { + /* should add elements? Or maybe random bits to facilitate power estimation */ + bzero(q->pdcch_e, q->nof_bits); +} + +/** Encodes ONE DCI message and allocates the encoded bits to the dci_location_t indicated by + * the parameter location. The CRC is scrambled with the RNTI parameter. + * This function can be called multiple times and encoded DCI messages will be stored in the + * pdcch_t structure. A final call to the function pdcch_gen_symbols() will generate and map the + * symbols to the subframe for transmission. + * If the same location is provided in multiple messages, the encoded bits will be overwritten. + * + * @TODO: Use a bitmask and CFI to ensure message locations are valid and old messages are not overwritten. */ -int pdcch_encode(pdcch_t *q, dci_t *dci, cf_t *slot_symbols[MAX_PORTS], - uint32_t nsubframe, uint32_t cfi) { +int pdcch_encode_msg(pdcch_t *q, dci_msg_t *msg, dci_location_t location, uint16_t rnti) { + + int ret = LIBLTE_ERROR_INVALID_INPUTS; + + if (q != NULL) { + ret = LIBLTE_ERROR; + + if (location.L < 4 && + msg->nof_bits < DCI_MAX_BITS) + { + INFO("Encoding DCI: Nbits: %d, E: %d, nCCE: %d, L: %d, RNTI: 0x%x\n", + msg->nof_bits, + PDCCH_FORMAT_NOF_BITS(location.L), + location.ncce, location.L, rnti); + + dci_encode(q, msg->data, &q->pdcch_e[72 * location.ncce], msg->nof_bits, + PDCCH_FORMAT_NOF_BITS(location.L), rnti); + + ret = LIBLTE_SUCCESS; + + } else { + fprintf(stderr, "Illegal DCI message nCCE: %d, L: %d, nof_cce: %d\n", + location.ncce, location.L, q->nof_cce); + } + } + return ret; +} + +/** Converts the set of DCI messages encoded using the function pdcch_encode_msg() + * to symbols mapped to the subframe ready for transmission + */ +int pdcch_gen_symbols(pdcch_t *q, cf_t *slot_symbols[MAX_PORTS], uint32_t nsubframe, uint32_t cfi) { int i; /* Set pointers for layermapping & precoding */ cf_t *x[MAX_LAYERS]; if (q != NULL && - dci != NULL && slot_symbols != NULL && nsubframe < 10 && cfi > 0 && @@ -623,31 +551,6 @@ int pdcch_encode(pdcch_t *q, dci_t *dci, cf_t *slot_symbols[MAX_PORTS], } memset(&x[q->cell.nof_ports], 0, sizeof(cf_t*) * (MAX_LAYERS - q->cell.nof_ports)); - /* should add elements? Or maybe random bits to facilitate power estimation */ - bzero(q->pdcch_e, q->nof_bits); - - /* Encode DCIs */ - for (i = 0; i < dci->nof_dcis; i++) { - /* do some 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 - || dci->msg[i].location.nof_bits > DCI_MAX_BITS) { - fprintf(stderr, "Illegal DCI message nCCE: %d, L: %d, nof_cce: %d\n", - dci->msg[i].location.ncce, dci->msg[i].location.L, q->nof_cce); - return LIBLTE_ERROR; - } - 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.rnti); - } - scrambling_b_offset(&q->seq_pdcch[nsubframe], q->pdcch_e, 0, q->nof_bits); mod_modulate(&q->mod, q->pdcch_e, q->pdcch_d, q->nof_bits); @@ -671,3 +574,4 @@ int pdcch_encode(pdcch_t *q, dci_t *dci, cf_t *slot_symbols[MAX_PORTS], } } + diff --git a/lte/phy/lib/phch/test/dci_unpacking.c b/lte/phy/lib/phch/test/dci_unpacking.c index b2e377b2e..6a1087d11 100644 --- a/lte/phy/lib/phch/test/dci_unpacking.c +++ b/lte/phy/lib/phch/test/dci_unpacking.c @@ -81,9 +81,8 @@ int main(int argc, char **argv) { printf("\n"); dci_msg_type_t dci_type; - msg.location.rnti = SIRNTI; - msg.location.nof_bits = len; - if (dci_msg_get_type(&msg, &dci_type, nof_prb, 1234)) { + msg.nof_bits = len; + if (dci_msg_get_type(&msg, &dci_type, nof_prb, SIRNTI, 1234)) { fprintf(stderr, "Can't obtain DCI message type\n"); exit(-1); } diff --git a/lte/phy/lib/phch/test/pdcch_file_test.c b/lte/phy/lib/phch/test/pdcch_file_test.c index 874853f48..f583a26b9 100644 --- a/lte/phy/lib/phch/test/pdcch_file_test.c +++ b/lte/phy/lib/phch/test/pdcch_file_test.c @@ -56,7 +56,6 @@ cf_t *input_buffer, *fft_buffer, *ce[MAX_PORTS]; 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); @@ -179,9 +178,7 @@ int base_init() { fprintf(stderr, "Error creating PDCCH object\n"); exit(-1); } - - dci_init(&dci_rx, 10); - + DEBUG("Memory init OK\n",0); return 0; } @@ -204,7 +201,6 @@ void base_free() { chest_free(&chest); lte_fft_free(&fft); - dci_free(&dci_rx); pdcch_free(&pdcch); regs_free(®s); } @@ -215,6 +211,9 @@ int main(int argc, char **argv) { int nof_dcis; int nof_frames; int ret; + dci_location_t locations[10]; + uint32_t nof_locations; + dci_msg_t dci_msg; if (argc < 3) { usage(argv[0]); @@ -230,10 +229,11 @@ int main(int argc, char **argv) { if (rnti == SIRNTI) { INFO("Initializing common search space for SI-RNTI\n",0); - pdcch_init_search_si(&pdcch, cfi); + nof_locations = pdcch_common_locations(&pdcch, locations, 10, cfi); } else { + // For ue-specific, generate locations for subframe 5 INFO("Initializing user-specific search space for RNTI: 0x%x\n", rnti); - pdcch_init_search_ue(&pdcch, rnti, cfi); + nof_locations = pdcch_ue_locations(&pdcch, locations, 10, 5, cfi, rnti); } ret = -1; nof_frames = 0; @@ -263,14 +263,23 @@ int main(int argc, char **argv) { chest_fprint(&chest, fmatlab, 2*nof_frames, i); } } - - nof_dcis = pdcch_decode(&pdcch, fft_buffer, ce, &dci_rx, nof_frames%10, cfi); + + if (pdcch_extract_llr(&pdcch, fft_buffer, ce, nof_frames, cfi)) { + fprintf(stderr, "Error extracting LLRs\n"); + return -1; + } + + nof_dcis = pdcch_decode_msg(&pdcch, &dci_msg, locations, nof_locations, Format1A, rnti); + if (nof_dcis < 0) { + fprintf(stderr, "Error decoding DCI messages\n"); + return -1; + } INFO("Received %d DCI messages\n", nof_dcis); - for (i=0;i Date: Sun, 6 Jul 2014 21:08:11 +0200 Subject: [PATCH 08/14] Fixed error in PDSCH mapping. Further API simplification --- lte/phy/examples/pdsch_enodeb.c | 4 +- lte/phy/examples/pdsch_ue.c | 28 +- lte/phy/include/liblte/phy/common/fft.h | 14 +- lte/phy/include/liblte/phy/phch/dci.h | 2 + lte/phy/include/liblte/phy/phch/pdcch.h | 23 +- lte/phy/include/liblte/phy/phch/regs.h | 12 + lte/phy/lib/ch_estimation/src/refsignal.c | 12 +- lte/phy/lib/common/src/fft.c | 44 +-- lte/phy/lib/fec/src/convcoder.c | 35 ++- lte/phy/lib/phch/src/dci.c | 12 +- lte/phy/lib/phch/src/pdcch.c | 309 ++++++++++------------ lte/phy/lib/phch/src/regs.c | 103 +++++--- lte/phy/lib/phch/test/pdcch_file_test.c | 24 +- lte/phy/lib/phch/test/pdcch_test.c | 31 ++- lte/phy/lib/phch/test/pdsch_file_test.c | 24 +- lte/phy/lib/sync/src/sync_frame.c | 5 +- 16 files changed, 357 insertions(+), 325 deletions(-) diff --git a/lte/phy/examples/pdsch_enodeb.c b/lte/phy/examples/pdsch_enodeb.c index 34947396e..511a0c3a0 100644 --- a/lte/phy/examples/pdsch_enodeb.c +++ b/lte/phy/examples/pdsch_enodeb.c @@ -334,13 +334,11 @@ int main(int argc, char **argv) { data[i] = rand()%2; } - if (pdcch_encode_msg(&pdcch, &dci_msg, locations[sf_idx][0], 1234)) { + if (pdcch_encode(&pdcch, &dci_msg, locations[sf_idx][0], 1234, sf_symbols, sf_idx, cfi)) { fprintf(stderr, "Error encoding DCI message\n"); exit(-1); } - pdcch_gen_symbols(&pdcch, sf_symbols, sf_idx, cfi); - pdsch_encode(&pdsch, data, sf_symbols, sf_idx, ra_dl.mcs, &prb_alloc); /* Transform to OFDM symbols */ diff --git a/lte/phy/examples/pdsch_ue.c b/lte/phy/examples/pdsch_ue.c index 85aed0250..2d6c0af73 100644 --- a/lte/phy/examples/pdsch_ue.c +++ b/lte/phy/examples/pdsch_ue.c @@ -393,8 +393,7 @@ int cell_id_init(int nof_prb, int cell_id) { char data[10000]; int rx_run(cf_t *input, int sf_idx) { - uint32_t cfi, cfi_distance; - int i, nof_dcis; + uint32_t cfi, cfi_distance, i; cf_t *input_decim; ra_pdsch_t ra_dl; ra_prb_t prb_alloc; @@ -430,18 +429,19 @@ int rx_run(cf_t *input, int sf_idx) { /* Search only UE-specific locations */ nof_locations = pdcch_ue_locations(&pdcch, locations, 10, sf_idx, cfi, 1234); - pdcch_extract_llr(&pdcch, fft_buffer, ce, nof_frames, cfi); - - - nof_dcis = pdcch_decode_msg(&pdcch, &dci_msg, locations, nof_locations, Format1, 1234); - if (nof_dcis < 0) { - fprintf(stderr, "Error decoding DCI messages\n"); - return -1; + uint16_t crc_rem = 0; + for (i=0;i 0) { + if (!disable_plots && crc_rem == 1234) { int n_re = 2 * RE_X_RB * CPNORM_NSYMB * cell.nof_prb; for (i = 0; i < n_re; i++) { tmp_plot[i] = 10 * log10f(cabsf(fft_buffer[i])); diff --git a/lte/phy/include/liblte/phy/common/fft.h b/lte/phy/include/liblte/phy/common/fft.h index 048bd37dc..3e20c475f 100644 --- a/lte/phy/include/liblte/phy/common/fft.h +++ b/lte/phy/include/liblte/phy/common/fft.h @@ -42,18 +42,18 @@ typedef _Complex float cf_t; /* this is only a shortcut */ /* This is common for both directions */ typedef struct LIBLTE_API{ dft_plan_t fft_plan; - int nof_symbols; - int symbol_sz; - int nof_guards; - int nof_re; - int slot_sz; + uint32_t nof_symbols; + uint32_t symbol_sz; + uint32_t nof_guards; + uint32_t nof_re; + uint32_t slot_sz; lte_cp_t cp; cf_t *tmp; // for removing zero padding }lte_fft_t; LIBLTE_API int lte_fft_init(lte_fft_t *q, lte_cp_t cp_type, - int nof_prb); + uint32_t nof_prb); LIBLTE_API void lte_fft_free(lte_fft_t *q); @@ -67,7 +67,7 @@ LIBLTE_API void lte_fft_run_sf(lte_fft_t *q, LIBLTE_API int lte_ifft_init(lte_fft_t *q, lte_cp_t cp_type, - int nof_prb); + uint32_t nof_prb); LIBLTE_API void lte_ifft_free(lte_fft_t *q); diff --git a/lte/phy/include/liblte/phy/phch/dci.h b/lte/phy/include/liblte/phy/phch/dci.h index 79f37e1b5..a5ee5e658 100644 --- a/lte/phy/include/liblte/phy/phch/dci.h +++ b/lte/phy/include/liblte/phy/phch/dci.h @@ -78,6 +78,8 @@ LIBLTE_API int dci_location_set(dci_location_t *c, uint32_t L, uint32_t nCCE); +LIBLTE_API bool dci_location_isvalid(dci_location_t *c); + LIBLTE_API int dci_msg_get_type(dci_msg_t *msg, dci_msg_type_t *type, uint32_t nof_prb, diff --git a/lte/phy/include/liblte/phy/phch/pdcch.h b/lte/phy/include/liblte/phy/phch/pdcch.h index c48e84808..87aa91eb8 100644 --- a/lte/phy/include/liblte/phy/phch/pdcch.h +++ b/lte/phy/include/liblte/phy/phch/pdcch.h @@ -59,8 +59,7 @@ typedef enum LIBLTE_API { /* PDCCH object */ typedef struct LIBLTE_API { lte_cell_t cell; - uint32_t nof_bits; - uint32_t nof_symbols; + uint32_t e_bits; uint32_t nof_regs; uint32_t nof_cce; uint32_t max_bits; @@ -91,33 +90,27 @@ LIBLTE_API void pdcch_free(pdcch_t *q); /* Encoding function */ -LIBLTE_API void pdcch_reset(pdcch_t *q); - -LIBLTE_API int pdcch_encode_msg(pdcch_t *q, +LIBLTE_API int pdcch_encode(pdcch_t *q, dci_msg_t *msg, dci_location_t location, - uint16_t rnti); - -LIBLTE_API int pdcch_gen_symbols(pdcch_t *q, - cf_t *sf_symbols[MAX_PORTS], - uint32_t nsubframe, - uint32_t cfi); - + uint16_t rnti, + cf_t *sf_symbols[MAX_PORTS], + uint32_t nsubframe, + uint32_t cfi); /* Decoding functions: Extract the LLRs and save them in the pdcch_t object */ LIBLTE_API int pdcch_extract_llr(pdcch_t *q, cf_t *sf_symbols, cf_t *ce[MAX_PORTS], + dci_location_t location, uint32_t nsubframe, uint32_t cfi); /* Decoding functions: Try to decode a DCI message after calling pdcch_extract_llr */ LIBLTE_API int pdcch_decode_msg(pdcch_t *q, dci_msg_t *msg, - dci_location_t *locations, - uint32_t nof_locations, dci_format_t format, - uint16_t rnti); + uint16_t *crc_rem); /* Function for generation of UE-specific search space DCI locations */ LIBLTE_API uint32_t pdcch_ue_locations(pdcch_t *q, diff --git a/lte/phy/include/liblte/phy/phch/regs.h b/lte/phy/include/liblte/phy/phch/regs.h index 38f3515a9..1b2f470d6 100644 --- a/lte/phy/include/liblte/phy/phch/regs.h +++ b/lte/phy/include/liblte/phy/phch/regs.h @@ -114,10 +114,22 @@ LIBLTE_API int regs_pdcch_put(regs_t *h, cf_t *pdcch_symbols, cf_t *slot_symbols); +LIBLTE_API int regs_pdcch_put_offset(regs_t *h, + cf_t *pdcch_symbols, + cf_t *slot_symbols, + uint32_t start_reg, + uint32_t nof_regs); + LIBLTE_API int regs_pdcch_get(regs_t *h, cf_t *slot_symbols, cf_t *pdcch_symbols); +LIBLTE_API int regs_pdcch_get_offset(regs_t *h, + cf_t *slot_symbols, + cf_t *pdcch_symbols, + uint32_t start_reg, + uint32_t nof_regs); + #endif // REGS_H_ diff --git a/lte/phy/lib/ch_estimation/src/refsignal.c b/lte/phy/lib/ch_estimation/src/refsignal.c index eb476f0ca..0ecdb59c1 100644 --- a/lte/phy/lib/ch_estimation/src/refsignal.c +++ b/lte/phy/lib/ch_estimation/src/refsignal.c @@ -67,12 +67,12 @@ int refsignal_v(uint32_t port_id, uint32_t ns, uint32_t symbol_id) { return v; } -int refsignal_k(int m, int v, uint32_t cell_id) { +uint32_t refsignal_k(uint32_t m, uint32_t v, uint32_t cell_id) { return 6*m+((v+(cell_id%6))%6); } int refsignal_put(refsignal_t *q, cf_t *slot_symbols) { - int i; + uint32_t i; uint32_t fidx, tidx; if (q != NULL && slot_symbols != NULL) @@ -96,12 +96,12 @@ int refsignal_init_LTEDL(refsignal_t *q, uint32_t port_id, uint32_t nslot, uint32_t c_init; uint32_t ns, l, lp[2]; - int N_cp; - int i; + uint32_t N_cp; + uint32_t i; int ret = LIBLTE_ERROR_INVALID_INPUTS; sequence_t seq; int v; - int mp; + uint32_t mp; uint32_t nof_refs_x_symbol, nof_ref_symbols; if (q != NULL && @@ -171,7 +171,7 @@ int refsignal_init_LTEDL(refsignal_t *q, uint32_t port_id, uint32_t nslot, __imag__ q->refs[idx(l,i)].simbol = (1 - 2 * (float) seq.c[2 * mp + 1]) / sqrt(2); /* mapping to resource elements */ - q->refs[idx(l,i)].freq_idx = refsignal_k(i, v, cell.id); + q->refs[idx(l,i)].freq_idx = refsignal_k(i, (uint32_t) v, cell.id); q->refs[idx(l,i)].time_idx = lp[l]; } } diff --git a/lte/phy/lib/common/src/fft.c b/lte/phy/lib/common/src/fft.c index dfe083b16..a21aa2c15 100644 --- a/lte/phy/lib/common/src/fft.c +++ b/lte/phy/lib/common/src/fft.c @@ -35,10 +35,10 @@ #include "liblte/phy/utils/debug.h" #include "liblte/phy/utils/vector.h" -int lte_fft_init_(lte_fft_t *q, lte_cp_t cp, int nof_prb, dft_dir_t dir) { +int lte_fft_init_(lte_fft_t *q, lte_cp_t cp, uint32_t nof_prb, dft_dir_t dir) { int symbol_sz = lte_symbol_sz(nof_prb); - if (symbol_sz == -1) { + if (symbol_sz < 0) { fprintf(stderr, "Error: Invalid nof_prb=%d\n", nof_prb); return -1; } @@ -46,7 +46,7 @@ int lte_fft_init_(lte_fft_t *q, lte_cp_t cp, int nof_prb, dft_dir_t dir) { fprintf(stderr, "Error: Creating DFT plan\n"); return -1; } - q->tmp = malloc(symbol_sz * sizeof(cf_t)); + q->tmp = malloc((uint32_t) symbol_sz * sizeof(cf_t)); if (!q->tmp) { perror("malloc"); return -1; @@ -56,7 +56,7 @@ int lte_fft_init_(lte_fft_t *q, lte_cp_t cp, int nof_prb, dft_dir_t dir) { dft_plan_set_norm(&q->fft_plan, true); dft_plan_set_dc(&q->fft_plan, true); - q->symbol_sz = symbol_sz; + q->symbol_sz = (uint32_t) symbol_sz; q->nof_symbols = CP_NSYMB(cp); q->cp = cp; q->nof_re = nof_prb * RE_X_RB; @@ -66,7 +66,8 @@ int lte_fft_init_(lte_fft_t *q, lte_cp_t cp, int nof_prb, dft_dir_t dir) { DEBUG("Init %s symbol_sz=%d, nof_symbols=%d, cp=%s, nof_re=%d, nof_guards=%d\n", dir==FORWARD?"FFT":"iFFT", q->symbol_sz, q->nof_symbols, q->cp==CPNORM?"Normal":"Extended", q->nof_re, q->nof_guards); - return 0; + + return LIBLTE_SUCCESS; } void lte_fft_free_(lte_fft_t *q) { @@ -77,7 +78,7 @@ void lte_fft_free_(lte_fft_t *q) { bzero(q, sizeof(lte_fft_t)); } -int lte_fft_init(lte_fft_t *q, lte_cp_t cp, int nof_prb) { +int lte_fft_init(lte_fft_t *q, lte_cp_t cp, uint32_t nof_prb) { return lte_fft_init_(q, cp, nof_prb, FORWARD); } @@ -85,17 +86,20 @@ void lte_fft_free(lte_fft_t *q) { lte_fft_free_(q); } -int lte_ifft_init(lte_fft_t *q, lte_cp_t cp, int nof_prb) { - int i; - if (lte_fft_init_(q, cp, nof_prb, BACKWARD)) { - return -1; - } - /* set now zeros at CP */ - for (i=0;inof_symbols;i++) { - bzero(q->tmp, q->nof_guards * sizeof(cf_t)); - bzero(&q->tmp[q->nof_re + q->nof_guards], q->nof_guards * sizeof(cf_t)); +int lte_ifft_init(lte_fft_t *q, lte_cp_t cp, uint32_t nof_prb) { + uint32_t i; + int ret; + + ret = lte_fft_init_(q, cp, nof_prb, BACKWARD); + + if (ret == LIBLTE_SUCCESS) { + /* set now zeros at CP */ + for (i=0;inof_symbols;i++) { + bzero(q->tmp, q->nof_guards * sizeof(cf_t)); + bzero(&q->tmp[q->nof_re + q->nof_guards], q->nof_guards * sizeof(cf_t)); + } } - return 0; + return ret; } void lte_ifft_free(lte_fft_t *q) { @@ -106,7 +110,7 @@ void lte_ifft_free(lte_fft_t *q) { * Performs FFT on a each symbol and removes CP. */ void lte_fft_run_slot(lte_fft_t *q, cf_t *input, cf_t *output) { - int i; + uint32_t i; for (i=0;inof_symbols;i++) { input += CP_ISNORM(q->cp)?CP_NORM(i, q->symbol_sz):CP_EXT(q->symbol_sz); dft_run_c(&q->fft_plan, input, q->tmp); @@ -117,7 +121,7 @@ void lte_fft_run_slot(lte_fft_t *q, cf_t *input, cf_t *output) { } void lte_fft_run_sf(lte_fft_t *q, cf_t *input, cf_t *output) { - int n; + uint32_t n; for (n=0;n<2;n++) { lte_fft_run_slot(q, &input[n*q->slot_sz], &output[n*q->nof_re*q->nof_symbols]); } @@ -127,7 +131,7 @@ void lte_fft_run_sf(lte_fft_t *q, cf_t *input, cf_t *output) { * Performs FFT on a each symbol and adds CP. */ void lte_ifft_run_slot(lte_fft_t *q, cf_t *input, cf_t *output) { - int i, cp_len; + uint32_t i, cp_len; for (i=0;inof_symbols;i++) { cp_len = CP_ISNORM(q->cp)?CP_NORM(i, q->symbol_sz):CP_EXT(q->symbol_sz); memcpy(&q->tmp[q->nof_guards], input, q->nof_re * sizeof(cf_t)); @@ -140,7 +144,7 @@ void lte_ifft_run_slot(lte_fft_t *q, cf_t *input, cf_t *output) { } void lte_ifft_run_sf(lte_fft_t *q, cf_t *input, cf_t *output) { - int n; + uint32_t n; for (n=0;n<2;n++) { lte_ifft_run_slot(q, &input[n*q->nof_re*q->nof_symbols], &output[n*q->slot_sz]); } diff --git a/lte/phy/lib/fec/src/convcoder.c b/lte/phy/lib/fec/src/convcoder.c index 65b8236be..2153327ac 100644 --- a/lte/phy/lib/fec/src/convcoder.c +++ b/lte/phy/lib/fec/src/convcoder.c @@ -39,23 +39,30 @@ int convcoder_encode(convcoder_t *q, char *input, char *output, uint32_t frame_l uint32_t i,j; uint32_t len = q->tail_biting ? frame_length : (frame_length + q->K - 1); - if (q->tail_biting) { - sr = 0; - for (i=frame_length - q->K + 1; i q->K + 1) + { + if (q->tail_biting) { + sr = 0; + for (i=frame_length - q->K + 1; iR;j++) { - output[q->R * i + j] = parity(sr & q->poly[j]); + for (i = 0; i < len; i++) { + char bit = (i < frame_length) ? (input[i] & 1) : 0; + sr = (sr << 1) | bit; + for (j=0;jR;j++) { + output[q->R * i + j] = parity(sr & q->poly[j]); + } } + return q->R*len; + } else { + return LIBLTE_ERROR_INVALID_INPUTS; } - - return q->R*len; } diff --git a/lte/phy/lib/phch/src/dci.c b/lte/phy/lib/phch/src/dci.c index 05e0fc35b..ed8ff16fc 100644 --- a/lte/phy/lib/phch/src/dci.c +++ b/lte/phy/lib/phch/src/dci.c @@ -57,6 +57,14 @@ int dci_location_set(dci_location_t *c, uint32_t L, uint32_t nCCE) { return LIBLTE_SUCCESS; } +bool dci_location_isvalid(dci_location_t *c) { + if (c->L <= 3 && c->ncce <= 87) { + return true; + } else { + return false; + } +} + uint32_t riv_nbits(uint32_t nof_prb) { return (uint32_t) ceilf(log2f((float) nof_prb * ((float) nof_prb + 1) / 2)); } @@ -785,7 +793,9 @@ void dci_msg_type_fprint(FILE *f, dci_msg_type_t type) { } int dci_msg_get_type(dci_msg_t *msg, dci_msg_type_t *type, uint32_t nof_prb, - uint16_t msg_rnti, uint16_t crnti) { + uint16_t msg_rnti, uint16_t crnti) +{ + DEBUG("Get message type: nof_bits=%d, msg_rnti=0x%x, crnti=0x%x\n", msg->nof_bits, msg_rnti, crnti); if (msg->nof_bits == dci_format_sizeof(Format0, nof_prb) && !msg->data[0]) { type->type = PUSCH_SCHED; diff --git a/lte/phy/lib/phch/src/pdcch.c b/lte/phy/lib/phch/src/pdcch.c index 0c719671b..d46c63d96 100644 --- a/lte/phy/lib/phch/src/pdcch.c +++ b/lte/phy/lib/phch/src/pdcch.c @@ -54,8 +54,6 @@ static void set_cfi(pdcch_t *q, uint32_t cfi) { if (cfi > 0 && cfi < 4) { q->nof_regs = (regs_pdcch_nregs(q->regs, cfi) / 9) * 9; q->nof_cce = q->nof_regs / 9; - q->nof_symbols = 4 * q->nof_regs; - q->nof_bits = 2 * q->nof_symbols; } } @@ -63,7 +61,7 @@ static void set_cfi(pdcch_t *q, uint32_t cfi) { /** Initializes the PDCCH transmitter and receiver */ int pdcch_init(pdcch_t *q, regs_t *regs, lte_cell_t cell) { int ret = LIBLTE_ERROR_INVALID_INPUTS; - int i; + uint32_t i; if (q != NULL && regs != NULL && @@ -74,13 +72,10 @@ int pdcch_init(pdcch_t *q, regs_t *regs, lte_cell_t cell) { q->cell = cell; q->regs = regs; - /* Now allocate memory for the maximum number of REGs (CFI=3) - */ - set_cfi(q, 3); - q->max_bits = q->nof_bits; + /* Allocate memory for the largest aggregation level L=3 */ + q->max_bits = PDCCH_FORMAT_NOF_BITS(3); - 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->cell.nof_ports); + INFO("Init PDCCH: %d bits, %d symbols, %d ports\n", q->max_bits, q->max_bits/2, q->cell.nof_ports); if (modem_table_std(&q->mod, LTE_QPSK, true)) { goto clean; @@ -94,7 +89,7 @@ int pdcch_init(pdcch_t *q, regs_t *regs, lte_cell_t cell) { demod_soft_alg_set(&q->demod, APPROX); for (i = 0; i < NSUBFRAMES_X_FRAME; i++) { - if (sequence_pdcch(&q->seq_pdcch[i], 2 * i, q->cell.id, q->nof_bits)) { + if (sequence_pdcch(&q->seq_pdcch[i], 2 * i, q->cell.id, q->max_bits)) { goto clean; } } @@ -104,31 +99,31 @@ int pdcch_init(pdcch_t *q, regs_t *regs, lte_cell_t cell) { goto clean; } - q->pdcch_e = malloc(sizeof(char) * q->nof_bits); + q->pdcch_e = malloc(sizeof(char) * q->max_bits); if (!q->pdcch_e) { goto clean; } - q->pdcch_llr = malloc(sizeof(float) * q->nof_bits); + q->pdcch_llr = malloc(sizeof(float) * q->max_bits); if (!q->pdcch_llr) { goto clean; } - q->pdcch_d = malloc(sizeof(cf_t) * q->nof_symbols); + q->pdcch_d = malloc(sizeof(cf_t) * q->max_bits / 2); if (!q->pdcch_d) { goto clean; } for (i = 0; i < MAX_PORTS; i++) { - q->ce[i] = malloc(sizeof(cf_t) * q->nof_symbols); + q->ce[i] = malloc(sizeof(cf_t) * q->max_bits / 2); if (!q->ce[i]) { goto clean; } - q->pdcch_x[i] = malloc(sizeof(cf_t) * q->nof_symbols); + q->pdcch_x[i] = malloc(sizeof(cf_t) * q->max_bits / 2); if (!q->pdcch_x[i]) { goto clean; } - q->pdcch_symbols[i] = malloc(sizeof(cf_t) * q->nof_symbols); + q->pdcch_symbols[i] = malloc(sizeof(cf_t) * q->max_bits / 2); if (!q->pdcch_symbols[i]) { goto clean; } @@ -277,10 +272,6 @@ static int dci_decode(pdcch_t *q, float *e, char *data, uint32_t E, uint32_t nof nof_bits < DCI_MAX_BITS) { - if (VERBOSE_ISDEBUG()) { - vec_fprint_f(stdout, e, E); - } - /* unrate matching */ rm_conv_rx(e, E, tmp, 3 * (nof_bits + 16)); @@ -299,7 +290,7 @@ static int dci_decode(pdcch_t *q, float *e, char *data, uint32_t E, uint32_t nof x = &data[nof_bits]; p_bits = (uint16_t) bit_unpack(&x, 16); crc_res = ((uint16_t) 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, + DEBUG("p_bits: 0x%x, crc_checksum: 0x%x, crc_rem: 0x%x\n", p_bits, crc_res, p_bits ^ crc_res); if (crc) { @@ -313,123 +304,113 @@ static int dci_decode(pdcch_t *q, float *e, char *data, uint32_t E, uint32_t nof /** Tries to decode a DCI message from the LLRs stored in the pdcch_t structure by the function * pdcch_extract_llr(). This function can be called multiple times. - * The decoded message is stored in msg. Up to nof_locations are tried from the array of dci_locations_t - * pointed by locations. The CRC is checked agains the RNTI parameter. + * The decoded message is stored in msg and the CRC remainder in crc_rem pointer * - * Returns 1 if the message is correctly decoded, 0 if not and -1 on error. */ -int pdcch_decode_msg(pdcch_t *q, dci_msg_t *msg, - dci_location_t *locations, uint32_t nof_locations, - dci_format_t format, uint16_t rnti) +int pdcch_decode_msg(pdcch_t *q, dci_msg_t *msg, dci_format_t format, uint16_t *crc_rem) { + int ret = LIBLTE_ERROR_INVALID_INPUTS; if (q != NULL && msg != NULL && - locations != NULL && - nof_locations > 0) + crc_rem != NULL) { - uint16_t crc_res; uint32_t nof_bits = dci_format_sizeof(format, q->cell.nof_prb); - uint32_t i; - i = 0; - do { - INFO("Trying Candidate: Nbits: %d, E: %3d, nCCE: %d, L: %d, RNTI: 0x%x\n", - nof_bits, PDCCH_FORMAT_NOF_BITS(locations[i].L), locations[i].ncce, locations[i].L, rnti); - - if (dci_decode(q, &q->pdcch_llr[72 * locations[i].ncce], msg->data, - PDCCH_FORMAT_NOF_BITS(locations[i].L), nof_bits, &crc_res) != LIBLTE_SUCCESS) { - return LIBLTE_ERROR; - } - if (crc_res != rnti) { - i++; - } - } while(i < nof_locations && crc_res != rnti); - - if (rnti == crc_res) { + ret = dci_decode(q, q->pdcch_llr, msg->data, q->e_bits, nof_bits, crc_rem); + if (ret == LIBLTE_SUCCESS) { msg->nof_bits = nof_bits; - INFO("FOUND Candidate: Nbits: %d, E: %d, nCCE: %d, L: %d, RNTI: 0x%x\n", - nof_bits, PDCCH_FORMAT_NOF_BITS(locations[i].L), locations[i].ncce, locations[i].L, rnti); - return 1; - } else { - return LIBLTE_SUCCESS; - } + } } - return LIBLTE_ERROR_INVALID_INPUTS; + return ret; } -/** Extracts the LLRs from the subframe symbols (demodulation) and stores them in the pdcch_t structure. - * DCI messages can be extracted calling the function pdcch_decode_msg(). - * Every time this function is called, the last demodulated symbols are overwritten. +/** Extracts the LLRs from dci_location_t location of the subframe and stores them in the pdcch_t structure. + * DCI messages can be extracted from this location calling the function pdcch_decode_msg(). + * Every time this function is called (with a different location), the last demodulated symbols are overwritten and + * new messages from other locations can be decoded */ -int pdcch_extract_llr(pdcch_t *q, cf_t *sf_symbols, cf_t *ce[MAX_PORTS], uint32_t nsubframe, uint32_t cfi) { +int pdcch_extract_llr(pdcch_t *q, cf_t *sf_symbols, cf_t *ce[MAX_PORTS], + dci_location_t location, uint32_t nsubframe, uint32_t cfi) { + int ret = LIBLTE_ERROR_INVALID_INPUTS; + /* Set pointers for layermapping & precoding */ - uint32_t i; + uint32_t i, nof_symbols; cf_t *x[MAX_LAYERS]; if (q != NULL && nsubframe < 10 && cfi > 0 && - cfi < 4) + cfi < 4 && + dci_location_isvalid(&location)) { set_cfi(q, cfi); - /* number of layers equals number of ports */ - for (i = 0; i < q->cell.nof_ports; i++) { - x[i] = q->pdcch_x[i]; - } - memset(&x[q->cell.nof_ports], 0, sizeof(cf_t*) * (MAX_LAYERS - q->cell.nof_ports)); - - /* extract symbols */ - int n = regs_pdcch_get(q->regs, sf_symbols, q->pdcch_symbols[0]); - if (q->nof_symbols != n) { - fprintf(stderr, "Expected %d PDCCH symbols but got %d symbols\n", - q->nof_symbols, n); - return LIBLTE_ERROR; - } + q->e_bits = PDCCH_FORMAT_NOF_BITS(location.L); + nof_symbols = q->e_bits/2; + ret = LIBLTE_ERROR; + + if (location.ncce + PDCCH_FORMAT_NOF_CCE(location.L) <= q->nof_cce) { + + INFO("Extracting LLRs: E: %d, nCCE: %d, L: %d\n", + q->e_bits, location.ncce, location.L); - /* extract channel estimates */ - for (i = 0; i < q->cell.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); - return LIBLTE_ERROR; + /* number of layers equals number of ports */ + for (i = 0; i < q->cell.nof_ports; i++) { + x[i] = q->pdcch_x[i]; + } + memset(&x[q->cell.nof_ports], 0, sizeof(cf_t*) * (MAX_LAYERS - q->cell.nof_ports)); + + /* extract symbols */ + int n = regs_pdcch_get_offset(q->regs, sf_symbols, q->pdcch_symbols[0], + location.ncce * 9, PDCCH_FORMAT_NOF_REGS(location.L)); + if (nof_symbols != n) { + fprintf(stderr, "Expected %d PDCCH symbols but got %d symbols\n", nof_symbols, n); + return ret; } - } - /* in control channels, only diversity is supported */ - if (q->cell.nof_ports == 1) { - /* no need for layer demapping */ - predecoding_single_zf(q->pdcch_symbols[0], q->ce[0], q->pdcch_d, - q->nof_symbols); - } else { - predecoding_diversity_zf(q->pdcch_symbols[0], q->ce, x, q->cell.nof_ports, - q->nof_symbols); - layerdemap_diversity(x, q->pdcch_d, q->cell.nof_ports, - q->nof_symbols / q->cell.nof_ports); - } + /* extract channel estimates */ + for (i = 0; i < q->cell.nof_ports; i++) { + n = regs_pdcch_get_offset(q->regs, ce[i], q->ce[i], + location.ncce * 9, PDCCH_FORMAT_NOF_REGS(location.L)); + if (nof_symbols != n) { + fprintf(stderr, "Expected %d PDCCH symbols but got %d symbols\n", nof_symbols, n); + return ret; + } + } - DEBUG("pdcch d symbols: ", 0); - if (VERBOSE_ISDEBUG()) { - vec_fprint_c(stdout, q->pdcch_d, q->nof_symbols); - } + /* in control channels, only diversity is supported */ + if (q->cell.nof_ports == 1) { + /* no need for layer demapping */ + predecoding_single_zf(q->pdcch_symbols[0], q->ce[0], q->pdcch_d, nof_symbols); + } else { + predecoding_diversity_zf(q->pdcch_symbols[0], q->ce, x, q->cell.nof_ports, nof_symbols); + layerdemap_diversity(x, q->pdcch_d, q->cell.nof_ports, nof_symbols / q->cell.nof_ports); + } - /* demodulate symbols */ - demod_soft_sigma_set(&q->demod, 1.0); - demod_soft_demodulate(&q->demod, q->pdcch_d, q->pdcch_llr, q->nof_symbols); + DEBUG("pdcch d symbols: ", 0); + if (VERBOSE_ISDEBUG()) { + vec_fprint_c(stdout, q->pdcch_d, nof_symbols); + } - DEBUG("llr: ", 0); - if (VERBOSE_ISDEBUG()) { - vec_fprint_f(stdout, q->pdcch_llr, q->nof_bits); - } + /* demodulate symbols */ + demod_soft_sigma_set(&q->demod, 1.0); + demod_soft_demodulate(&q->demod, q->pdcch_d, q->pdcch_llr, nof_symbols); - /* descramble */ - scrambling_f_offset(&q->seq_pdcch[nsubframe], q->pdcch_llr, 0, q->nof_bits); + DEBUG("llr: ", 0); + if (VERBOSE_ISDEBUG()) { + vec_fprint_f(stdout, q->pdcch_llr, q->e_bits); + } - return LIBLTE_SUCCESS; + /* descramble */ + scrambling_f_offset(&q->seq_pdcch[nsubframe], q->pdcch_llr, 72 * location.ncce, q->e_bits); + + ret = LIBLTE_SUCCESS; + } else { + fprintf(stderr, "Illegal DCI message nCCE: %d, L: %d, nof_cce: %d\n", location.ncce, location.L, q->nof_cce); + } } - return LIBLTE_ERROR_INVALID_INPUTS; + return ret; } @@ -487,91 +468,79 @@ static int dci_encode(pdcch_t *q, char *data, char *e, uint32_t nof_bits, uint32 } } -void pdcch_reset(pdcch_t *q) { - /* should add elements? Or maybe random bits to facilitate power estimation */ - bzero(q->pdcch_e, q->nof_bits); -} - /** Encodes ONE DCI message and allocates the encoded bits to the dci_location_t indicated by * the parameter location. The CRC is scrambled with the RNTI parameter. - * This function can be called multiple times and encoded DCI messages will be stored in the - * pdcch_t structure. A final call to the function pdcch_gen_symbols() will generate and map the - * symbols to the subframe for transmission. + * This function can be called multiple times and encoded DCI messages will be allocated to the + * sf_symbols buffer ready for transmission. * If the same location is provided in multiple messages, the encoded bits will be overwritten. * * @TODO: Use a bitmask and CFI to ensure message locations are valid and old messages are not overwritten. */ -int pdcch_encode_msg(pdcch_t *q, dci_msg_t *msg, dci_location_t location, uint16_t rnti) { +int pdcch_encode(pdcch_t *q, dci_msg_t *msg, dci_location_t location, uint16_t rnti, + cf_t *sf_symbols[MAX_PORTS], uint32_t nsubframe, uint32_t cfi) { int ret = LIBLTE_ERROR_INVALID_INPUTS; + uint32_t i; + cf_t *x[MAX_LAYERS]; + uint32_t nof_symbols; - if (q != NULL) { + if (q != NULL && + sf_symbols != NULL && + nsubframe < 10 && + cfi > 0 && + cfi < 4 && + dci_location_isvalid(&location)) + { + + set_cfi(q, cfi); + + q->e_bits = PDCCH_FORMAT_NOF_BITS(location.L); + nof_symbols = q->e_bits/2; ret = LIBLTE_ERROR; - if (location.L < 4 && + if (location.ncce + PDCCH_FORMAT_NOF_CCE(location.L) <= q->nof_cce && msg->nof_bits < DCI_MAX_BITS) { INFO("Encoding DCI: Nbits: %d, E: %d, nCCE: %d, L: %d, RNTI: 0x%x\n", - msg->nof_bits, - PDCCH_FORMAT_NOF_BITS(location.L), - location.ncce, location.L, rnti); + msg->nof_bits, q->e_bits, location.ncce, location.L, rnti); - dci_encode(q, msg->data, &q->pdcch_e[72 * location.ncce], msg->nof_bits, - PDCCH_FORMAT_NOF_BITS(location.L), rnti); + dci_encode(q, msg->data, q->pdcch_e, msg->nof_bits, q->e_bits, rnti); + /* number of layers equals number of ports */ + for (i = 0; i < q->cell.nof_ports; i++) { + x[i] = q->pdcch_x[i]; + } + memset(&x[q->cell.nof_ports], 0, sizeof(cf_t*) * (MAX_LAYERS - q->cell.nof_ports)); + + scrambling_b_offset(&q->seq_pdcch[nsubframe], q->pdcch_e, 72 * location.ncce, q->e_bits); + + DEBUG("Scrambling output: ", 0); + if (VERBOSE_ISDEBUG()) { + vec_fprint_b(stdout, q->pdcch_e, q->e_bits); + } + + mod_modulate(&q->mod, q->pdcch_e, q->pdcch_d, q->e_bits); + + /* layer mapping & precoding */ + if (q->cell.nof_ports > 1) { + layermap_diversity(q->pdcch_d, x, q->cell.nof_ports, nof_symbols); + precoding_diversity(x, q->pdcch_symbols, q->cell.nof_ports, nof_symbols / q->cell.nof_ports); + } else { + memcpy(q->pdcch_symbols[0], q->pdcch_d, nof_symbols * sizeof(cf_t)); + } + + /* mapping to resource elements */ + for (i = 0; i < q->cell.nof_ports; i++) { + regs_pdcch_put_offset(q->regs, q->pdcch_symbols[i], sf_symbols[i], + location.ncce * 9, PDCCH_FORMAT_NOF_REGS(location.L)); + } + ret = LIBLTE_SUCCESS; } else { - fprintf(stderr, "Illegal DCI message nCCE: %d, L: %d, nof_cce: %d\n", - location.ncce, location.L, q->nof_cce); + fprintf(stderr, "Illegal DCI message nCCE: %d, L: %d, nof_cce: %d\n", location.ncce, location.L, q->nof_cce); } } return ret; } -/** Converts the set of DCI messages encoded using the function pdcch_encode_msg() - * to symbols mapped to the subframe ready for transmission - */ -int pdcch_gen_symbols(pdcch_t *q, cf_t *slot_symbols[MAX_PORTS], uint32_t nsubframe, uint32_t cfi) { - int i; - /* Set pointers for layermapping & precoding */ - cf_t *x[MAX_LAYERS]; - - if (q != NULL && - slot_symbols != NULL && - nsubframe < 10 && - cfi > 0 && - cfi < 4) - { - set_cfi(q, cfi); - - /* number of layers equals number of ports */ - for (i = 0; i < q->cell.nof_ports; i++) { - x[i] = q->pdcch_x[i]; - } - memset(&x[q->cell.nof_ports], 0, sizeof(cf_t*) * (MAX_LAYERS - q->cell.nof_ports)); - - scrambling_b_offset(&q->seq_pdcch[nsubframe], q->pdcch_e, 0, q->nof_bits); - - mod_modulate(&q->mod, q->pdcch_e, q->pdcch_d, q->nof_bits); - - /* layer mapping & precoding */ - if (q->cell.nof_ports > 1) { - layermap_diversity(q->pdcch_d, x, q->cell.nof_ports, q->nof_symbols); - precoding_diversity(x, q->pdcch_symbols, q->cell.nof_ports, - q->nof_symbols / q->cell.nof_ports); - } else { - memcpy(q->pdcch_symbols[0], q->pdcch_d, q->nof_symbols * sizeof(cf_t)); - } - - /* mapping to resource elements */ - for (i = 0; i < q->cell.nof_ports; i++) { - regs_pdcch_put(q->regs, q->pdcch_symbols[i], slot_symbols[i]); - } - return LIBLTE_SUCCESS; - } else { - return LIBLTE_ERROR_INVALID_INPUTS; - } -} - - diff --git a/lte/phy/lib/phch/src/regs.c b/lte/phy/lib/phch/src/regs.c index 12f512e7a..0c0bf5405 100644 --- a/lte/phy/lib/phch/src/regs.c +++ b/lte/phy/lib/phch/src/regs.c @@ -34,6 +34,9 @@ #include "liblte/phy/phch/regs.h" #include "liblte/phy/utils/debug.h" +#define REG_IDX(r, i, n) r->k[i]+r->l*n*RE_X_RB + + regs_reg_t *regs_find_reg(regs_t *h, uint32_t k, uint32_t l); int regs_put_reg(regs_reg_t *reg, cf_t *reg_data, @@ -79,7 +82,8 @@ const unsigned char PDCCH_PERM[PDCCH_NCOLS] = int regs_pdcch_init(regs_t *h) { int i, m, cfi, nof_ctrl_symbols; int ret = LIBLTE_ERROR; - int nrows, ndummy, j, k, kp; + int nrows, ndummy, j; + uint32_t k, kp; regs_reg_t **tmp = NULL; bzero(&h->pdcch, sizeof(regs_ch_t)); @@ -126,9 +130,10 @@ int regs_pdcch_init(regs_t *h) { for (i = 0; i < nrows; i++) { if (i*PDCCH_NCOLS + PDCCH_PERM[j] >= ndummy) { m = i*PDCCH_NCOLS + PDCCH_PERM[j]-ndummy; - kp = (k-h->cell.id)%h->pdcch[cfi].nof_regs; - if (kp < 0) { - kp += h->pdcch[cfi].nof_regs; + if (k < h->cell.id) { + kp = (h->pdcch[cfi].nof_regs + k-h->cell.id)%h->pdcch[cfi].nof_regs; + } else { + kp = (k-h->cell.id)%h->pdcch[cfi].nof_regs; } h->pdcch[cfi].regs[m] = tmp[kp]; k++; @@ -163,28 +168,54 @@ int regs_pdcch_nregs(regs_t *h, uint32_t cfi) { /** Copy quadruplets to REGs and cyclic shift them, according to the * second part of 6.8.5 in 36.211 */ -int regs_pdcch_put(regs_t *h, cf_t *pdcch_symbols, cf_t *slot_symbols) { - if (!h->cfi_initiated) { + +int regs_pdcch_put_offset(regs_t *h, cf_t *pdcch_symbols, cf_t *slot_symbols, uint32_t start_reg, uint32_t nof_regs) { + if (h->cfi_initiated) { + if (start_reg + nof_regs <= h->pdcch[h->cfi].nof_regs) { + uint32_t i, k; + k = 0; + for (i=start_reg;ipdcch[h->cfi].regs[i], &pdcch_symbols[k], slot_symbols, h->cell.nof_prb); + k += 4; + } + return k; + } else { + fprintf(stderr, "Out of range: start_reg + nof_reg must be lower than %d\n", h->pdcch[h->cfi].nof_regs); + return LIBLTE_ERROR; + } + } else { fprintf(stderr, "Must call regs_set_cfi() first\n"); return LIBLTE_ERROR; } - int i; - for (i=0;ipdcch[h->cfi].nof_regs;i++) { - regs_put_reg(h->pdcch[h->cfi].regs[i], &pdcch_symbols[i*4], slot_symbols, h->cell.nof_prb); - } - return h->pdcch[h->cfi].nof_regs*4; } -int regs_pdcch_get(regs_t *h, cf_t *slot_symbols, cf_t *pdcch_symbols) { - if (!h->cfi_initiated) { +int regs_pdcch_put(regs_t *h, cf_t *pdcch_symbols, cf_t *slot_symbols) { + return regs_pdcch_put_offset(h, pdcch_symbols, slot_symbols, 0, h->pdcch[h->cfi].nof_regs); +} + +int regs_pdcch_get_offset(regs_t *h, cf_t *slot_symbols, cf_t *pdcch_symbols, uint32_t start_reg, uint32_t nof_regs) { + if (h->cfi_initiated) { + if (start_reg + nof_regs <= h->pdcch[h->cfi].nof_regs) { + uint32_t i, k; + k = 0; + for (i=start_reg;ipdcch[h->cfi].regs[i], slot_symbols, &pdcch_symbols[k], h->cell.nof_prb); + k += 4; + } + return k; + } else { + fprintf(stderr, "Out of range: start_reg + nof_reg must be lower than %d\n", h->pdcch[h->cfi].nof_regs); + return LIBLTE_ERROR; + } + } else { fprintf(stderr, "Must call regs_set_cfi() first\n"); return LIBLTE_ERROR; } - int i; - for (i=0;ipdcch[h->cfi].nof_regs;i++) { - regs_get_reg(h->pdcch[h->cfi].regs[i], slot_symbols, &pdcch_symbols[i*4], h->cell.nof_prb); - } - return h->pdcch[h->cfi].nof_regs*4; +} + + +int regs_pdcch_get(regs_t *h, cf_t *slot_symbols, cf_t *pdcch_symbols) { + return regs_pdcch_get_offset(h, slot_symbols, pdcch_symbols, 0, h->pdcch[h->cfi].nof_regs); } @@ -201,7 +232,7 @@ int regs_pdcch_get(regs_t *h, cf_t *slot_symbols, cf_t *pdcch_symbols) { */ int regs_phich_init(regs_t *h) { float ng; - int i,ni,li,n[3],nreg,mi; + uint32_t i, ni, li, n[3], nreg, mi; regs_reg_t **regs_phich[3]; int ret = LIBLTE_ERROR; @@ -306,7 +337,7 @@ clean_and_exit: } void regs_phich_free(regs_t *h) { - int i; + uint32_t i; if (h->phich) { if (CP_ISEXT(h->cell.cp)) { h->ngroups_phich /= 2; @@ -321,7 +352,7 @@ void regs_phich_free(regs_t *h) { } uint32_t regs_phich_nregs(regs_t *h) { - int i; + uint32_t i; uint32_t n; n=0; for (i=0;ingroups_phich;i++) { @@ -343,7 +374,7 @@ uint32_t regs_phich_ngroups(regs_t *h) { * Returns the number of written symbols, or -1 on error */ int regs_phich_add(regs_t *h, cf_t phich_symbols[REGS_PHICH_NSYM], uint32_t ngroup, cf_t *slot_symbols) { - int i; + uint32_t i; if (ngroup >= h->ngroups_phich) { fprintf(stderr, "Error invalid ngroup %d\n", ngroup); return LIBLTE_ERROR_INVALID_INPUTS; @@ -364,7 +395,7 @@ int regs_phich_add(regs_t *h, cf_t phich_symbols[REGS_PHICH_NSYM], uint32_t ngro * Returns the number of written symbols, or -1 on error */ int regs_phich_reset(regs_t *h, cf_t *slot_symbols) { - int i; + uint32_t i; uint32_t ngroup, ng; for (ngroup = 0;ngroup < h->ngroups_phich;CP_ISEXT(h->cell.cp)?ngroup+=2:ngroup++) { if (CP_ISEXT(h->cell.cp)) { @@ -386,7 +417,7 @@ int regs_phich_reset(regs_t *h, cf_t *slot_symbols) { * Returns the number of written symbols, or -1 on error */ int regs_phich_get(regs_t *h, cf_t *slot_symbols, cf_t phich_symbols[REGS_PHICH_NSYM], uint32_t ngroup) { - int i; + uint32_t i; if (ngroup >= h->ngroups_phich) { fprintf(stderr, "Error invalid ngroup %d\n", ngroup); return LIBLTE_ERROR_INVALID_INPUTS; @@ -421,7 +452,7 @@ int regs_phich_get(regs_t *h, cf_t *slot_symbols, cf_t phich_symbols[REGS_PHICH_ * 36.211 10.3 section 6.7.4 */ int regs_pcfich_init(regs_t *h) { - int i; + uint32_t i; uint32_t k_hat, k; regs_ch_t *ch = &h->pcfich; @@ -475,7 +506,7 @@ uint32_t regs_pcfich_nregs(regs_t *h) { int regs_pcfich_put(regs_t *h, cf_t pcfich_symbols[REGS_PCFICH_NSYM], cf_t *slot_symbols) { regs_ch_t *rch = &h->pcfich; - int i; + uint32_t i; for (i = 0; i < rch->nof_regs && i*REGS_RE_X_REG < REGS_PCFICH_NSYM; i++) { regs_put_reg(rch->regs[i], &pcfich_symbols[i*REGS_RE_X_REG], slot_symbols, h->cell.nof_prb); } @@ -489,7 +520,7 @@ int regs_pcfich_put(regs_t *h, cf_t pcfich_symbols[REGS_PCFICH_NSYM], cf_t *slot */ int regs_pcfich_get(regs_t *h, cf_t *slot_symbols, cf_t ch_data[REGS_PCFICH_NSYM]) { regs_ch_t *rch = &h->pcfich; - int i; + uint32_t i; for (i = 0; i < rch->nof_regs && i*REGS_RE_X_REG < REGS_PCFICH_NSYM; i++) { regs_get_reg(rch->regs[i], slot_symbols, &ch_data[i*REGS_RE_X_REG], h->cell.nof_prb); } @@ -516,7 +547,7 @@ int regs_pcfich_get(regs_t *h, cf_t *slot_symbols, cf_t ch_data[REGS_PCFICH_NSYM ***************************************************************/ regs_reg_t *regs_find_reg(regs_t *h, uint32_t k, uint32_t l) { - int i; + uint32_t i; for (i=0;inof_regs;i++) { if (h->regs[i].l == l && h->regs[i].k0 == k) { return &h->regs[i]; @@ -563,7 +594,7 @@ int regs_num_x_symbol(uint32_t symbol, uint32_t nof_port, lte_cp_t cp) { * 36.211 Section 6.2.4 */ int regs_reg_init(regs_reg_t *reg, uint32_t symbol, uint32_t nreg, uint32_t k0, uint32_t maxreg, uint32_t vo) { - int i, j, z; + uint32_t i, j, z; reg->l = symbol; reg->assigned = false; @@ -643,10 +674,10 @@ int regs_set_cfi(regs_t *h, uint32_t cfi) { */ int regs_init(regs_t *h, phich_resources_t phich_res, phich_length_t phich_len, lte_cell_t cell) { int ret = LIBLTE_ERROR_INVALID_INPUTS; - int i, k; + uint32_t i, k; uint32_t j[4], jmax, prb; uint32_t n[4], vo; - int max_ctrl_symbols; + uint32_t max_ctrl_symbols; if (h != NULL && lte_cell_isvalid(&cell)) @@ -727,13 +758,11 @@ clean_and_exit: return ret; } -#define REG_IDX(r, i, n) r->k[i]+r->l*n*RE_X_RB - /** * Puts one REG data (4 symbols) in the slot symbols array */ int regs_put_reg(regs_reg_t *reg, cf_t *reg_data, cf_t *slot_symbols, uint32_t nof_prb) { - int i; + uint32_t i; for (i = 0; i < REGS_RE_X_REG; i++) { slot_symbols[REG_IDX(reg, i, nof_prb)] = reg_data[i]; } @@ -745,7 +774,7 @@ int regs_put_reg(regs_reg_t *reg, cf_t *reg_data, cf_t *slot_symbols, uint32_t n * Used by PHICH */ int regs_add_reg(regs_reg_t *reg, cf_t *reg_data, cf_t *slot_symbols, uint32_t nof_prb) { - int i; + uint32_t i; for (i = 0; i < REGS_RE_X_REG; i++) { slot_symbols[REG_IDX(reg, i, nof_prb)] += reg_data[i]; } @@ -757,7 +786,7 @@ int regs_add_reg(regs_reg_t *reg, cf_t *reg_data, cf_t *slot_symbols, uint32_t n * Reset REG data (4 symbols) in the slot symbols array */ int regs_reset_reg(regs_reg_t *reg, cf_t *slot_symbols, uint32_t nof_prb) { - int i; + uint32_t i; for (i = 0; i < REGS_RE_X_REG; i++) { slot_symbols[REG_IDX(reg, i, nof_prb)] = 0; } @@ -768,7 +797,7 @@ int regs_reset_reg(regs_reg_t *reg, cf_t *slot_symbols, uint32_t nof_prb) { * Gets one REG data (4 symbols) from the slot symbols array */ int regs_get_reg(regs_reg_t *reg, cf_t *slot_symbols, cf_t *reg_data, uint32_t nof_prb) { - int i; + uint32_t i; for (i = 0; i < REGS_RE_X_REG; i++) { reg_data[i] = slot_symbols[REG_IDX(reg, i, nof_prb)]; } diff --git a/lte/phy/lib/phch/test/pdcch_file_test.c b/lte/phy/lib/phch/test/pdcch_file_test.c index f583a26b9..98ee55743 100644 --- a/lte/phy/lib/phch/test/pdcch_file_test.c +++ b/lte/phy/lib/phch/test/pdcch_file_test.c @@ -208,7 +208,6 @@ void base_free() { int main(int argc, char **argv) { ra_pdsch_t ra_dl; int i; - int nof_dcis; int nof_frames; int ret; dci_location_t locations[10]; @@ -264,20 +263,19 @@ int main(int argc, char **argv) { } } - if (pdcch_extract_llr(&pdcch, fft_buffer, ce, nof_frames, cfi)) { - fprintf(stderr, "Error extracting LLRs\n"); - return -1; + uint16_t crc_rem = 0; + for (i=0;i= 1234 && crc_rem < 1234 + nof_dcis) { + crc_rem -= 1234; + memcpy(&dci_rx[crc_rem], &dci_tmp, sizeof(dci_msg_t)); + } else { + printf("Received invalid DCI CRC 0x%x\n", crc_rem); goto quit; } } diff --git a/lte/phy/lib/phch/test/pdsch_file_test.c b/lte/phy/lib/phch/test/pdsch_file_test.c index def1c9e43..e436a83a1 100644 --- a/lte/phy/lib/phch/test/pdsch_file_test.c +++ b/lte/phy/lib/phch/test/pdsch_file_test.c @@ -218,7 +218,6 @@ int main(int argc, char **argv) { ra_pdsch_t ra_dl; ra_prb_t prb_alloc; int i; - int nof_dcis; int nof_frames; int ret; char *data; @@ -280,17 +279,20 @@ int main(int argc, char **argv) { } } - pdcch_extract_llr(&pdcch, fft_buffer, ce, nof_frames, cfi); - - nof_dcis = pdcch_decode_msg(&pdcch, &dci_msg, locations, nof_locations, Format1A, rnti); - if (nof_dcis < 0) { - fprintf(stderr, "Error decoding DCI messages\n"); - return -1; + + uint16_t crc_rem = 0; + for (i=0;i #include #include +#include #include "liblte/phy/resampling/decim.h" #include "liblte/phy/resampling/resample_arb.h" @@ -120,6 +121,8 @@ void sync_frame_run(sync_frame_t *q, cf_t *input) { break; } + assert(q->peak_idx < TRACK_LEN); + track_idx = sync_track(&q->s, &input[q->peak_idx - TRACK_LEN]); INFO("TRACK %3d: SF=%d. Previous idx is %d New Offset is %d\n", @@ -140,7 +143,7 @@ void sync_frame_run(sync_frame_t *q, cf_t *input) { q->cur_cfo = (sync_get_cfo(&q->s) + q->frame_cnt * q->cur_cfo) / (q->frame_cnt + 1); /* compute cumulative moving average time offset */ - q->timeoffset = (float) (track_idx - TRACK_LEN + q->timeoffset * q->frame_cnt) + q->timeoffset = (float) ((float) track_idx - TRACK_LEN + q->timeoffset * q->frame_cnt) / (q->frame_cnt + 1); q->last_found = q->frame_cnt; From 561a2abd53e939da4e9b66d2ed58fc7269f53f2c Mon Sep 17 00:00:00 2001 From: ismagom Date: Sun, 6 Jul 2014 21:59:12 +0200 Subject: [PATCH 09/14] Fixed bug in channel estimation test --- lte/phy/lib/ch_estimation/src/chest.c | 7 ++++--- lte/phy/lib/ch_estimation/test/chest_test.c | 9 ++++++--- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/lte/phy/lib/ch_estimation/src/chest.c b/lte/phy/lib/ch_estimation/src/chest.c index b8b40b05d..31332eb8f 100644 --- a/lte/phy/lib/ch_estimation/src/chest.c +++ b/lte/phy/lib/ch_estimation/src/chest.c @@ -104,6 +104,7 @@ int chest_ce_ref(chest_t *q, cf_t *input, uint32_t nslot, uint32_t port_id, uint if (nref < q->refsignal[port_id][nslot].nof_refs) { fidx = q->refsignal[port_id][nslot].refs[nref].freq_idx; // reference frequency index tidx = q->refsignal[port_id][nslot].refs[nref].time_idx; // reference time index + known_ref = q->refsignal[port_id][nslot].refs[nref].simbol; channel_ref = input[tidx * q->nof_re + fidx]; q->refsignal[port_id][nslot].refs[nref].recv_simbol = channel_ref; @@ -129,7 +130,7 @@ int chest_ce_ref(chest_t *q, cf_t *input, uint32_t nslot, uint32_t port_id, uint * Saves the nof_prb * 12 * nof_symbols channel estimates in the array ce */ int chest_ce_slot_port(chest_t *q, cf_t *input, cf_t *ce, uint32_t nslot, uint32_t port_id) { - int i, j; + uint32_t i, j; cf_t x[2], y[MAX_NSYMB]; int ret = LIBLTE_ERROR_INVALID_INPUTS; @@ -228,7 +229,7 @@ int chest_init(chest_t *q, chest_interp_t interp, uint32_t nof_re, uint32_t nof_ int ret = LIBLTE_ERROR_INVALID_INPUTS; if (q != NULL && - nof_ports < MAX_PORTS) + nof_ports <= MAX_PORTS) { bzero(q, sizeof(chest_t)); @@ -263,7 +264,7 @@ int chest_ref_LTEDL_slot_port(chest_t *q, uint32_t nslot, uint32_t port_id, lte_ int ret = LIBLTE_ERROR_INVALID_INPUTS; if (q != NULL && - port_id < MAX_PORTS && + port_id < MAX_PORTS && nslot < NSLOTS_X_FRAME) { ret = refsignal_init_LTEDL(&q->refsignal[port_id][nslot], port_id, nslot, cell); diff --git a/lte/phy/lib/ch_estimation/test/chest_test.c b/lte/phy/lib/ch_estimation/test/chest_test.c index 4fda0a1a9..3f97e149d 100644 --- a/lte/phy/lib/ch_estimation/test/chest_test.c +++ b/lte/phy/lib/ch_estimation/test/chest_test.c @@ -123,9 +123,7 @@ int main(int argc, char **argv) { int max_cid; FILE *fmatlab = NULL; float mse_mag, mse_phase; - lte_cell_t cell; - cell.nof_ports = 1; parse_args(argc,argv); if (output_matlab) { @@ -161,7 +159,7 @@ int main(int argc, char **argv) { cid = cell.id; max_cid = cell.id; } - + while(cid <= max_cid) { cell.id = cid; if (chest_init_LTEDL(&eq, LINEAR, cell)) { @@ -172,6 +170,11 @@ int main(int argc, char **argv) { for (n_slot=0;n_slot Date: Mon, 7 Jul 2014 20:42:10 +0200 Subject: [PATCH 10/14] Added HARQ support on PDSCH. Small changes on API. --- lte/phy/examples/pdsch_enodeb.c | 14 +- lte/phy/examples/pdsch_ue.c | 14 +- .../include/liblte/phy/common/phy_common.h | 34 +- lte/phy/include/liblte/phy/fec/rm_turbo.h | 19 +- lte/phy/include/liblte/phy/phch/pdsch.h | 57 ++- lte/phy/include/liblte/phy/phch/ra.h | 2 + lte/phy/lib/common/src/phy_common.c | 73 +-- lte/phy/lib/fec/src/rm_turbo.c | 123 ++--- lte/phy/lib/fec/test/rm_turbo_test.c | 23 +- lte/phy/lib/phch/src/pdsch.c | 480 +++++++++++------- lte/phy/lib/phch/src/ra.c | 17 + lte/phy/lib/phch/test/CMakeLists.txt | 1 + lte/phy/lib/phch/test/pdsch_file_test.c | 15 +- lte/phy/lib/phch/test/pdsch_test.c | 73 ++- 14 files changed, 575 insertions(+), 370 deletions(-) diff --git a/lte/phy/examples/pdsch_enodeb.c b/lte/phy/examples/pdsch_enodeb.c index 511a0c3a0..d8263e739 100644 --- a/lte/phy/examples/pdsch_enodeb.c +++ b/lte/phy/examples/pdsch_enodeb.c @@ -59,6 +59,7 @@ pbch_t pbch; pcfich_t pcfich; pdcch_t pdcch; pdsch_t pdsch; +pdsch_harq_t harq_process; regs_t regs; cf_t *sf_buffer = NULL, *output_buffer = NULL; @@ -191,10 +192,16 @@ void base_init() { fprintf(stderr, "Error creating PDSCH object\n"); exit(-1); } + + if (pdsch_harq_init(&harq_process, &pdsch)) { + fprintf(stderr, "Error initiating HARQ process\n"); + exit(-1); + } } void base_free() { + pdsch_harq_free(&harq_process); pdsch_free(&pdsch); pdcch_free(&pdcch); regs_free(®s); @@ -308,6 +315,11 @@ int main(int argc, char **argv) { } nf = 0; + + if (pdsch_harq_setup(&harq_process, ra_dl.mcs, &prb_alloc)) { + fprintf(stderr, "Error configuring HARQ process\n"); + exit(-1); + } while (nf < nof_frames || nof_frames == -1) { for (sf_idx = 0; sf_idx < NSUBFRAMES_X_FRAME; sf_idx++) { @@ -339,7 +351,7 @@ int main(int argc, char **argv) { exit(-1); } - pdsch_encode(&pdsch, data, sf_symbols, sf_idx, ra_dl.mcs, &prb_alloc); + pdsch_encode(&pdsch, data, sf_symbols, sf_idx, &harq_process, ra_dl.rv_idx); /* Transform to OFDM symbols */ lte_ifft_run_sf(&ifft, sf_buffer, output_buffer); diff --git a/lte/phy/examples/pdsch_ue.c b/lte/phy/examples/pdsch_ue.c index f56da5ccb..f4628db6c 100644 --- a/lte/phy/examples/pdsch_ue.c +++ b/lte/phy/examples/pdsch_ue.c @@ -89,6 +89,7 @@ pbch_t pbch; pcfich_t pcfich; pdcch_t pdcch; pdsch_t pdsch; +pdsch_harq_t harq_process; regs_t regs; lte_fft_t fft; chest_t chest; @@ -356,6 +357,11 @@ int mib_init(phich_resources_t phich_resources, phich_length_t phich_length) { return -1; } + if (pdsch_harq_init(&harq_process, &pdsch)) { + fprintf(stderr, "Error initiating HARQ process\n"); + return -1; + } + chest_set_nof_ports(&chest, cell.nof_ports); mib_initiated = 1; @@ -469,7 +475,13 @@ int rx_run(cf_t *input, int sf_idx) { ra_prb_get_re_dl(&prb_alloc, cell.nof_prb, cell.nof_ports, cell.nof_prb<10?(cfi+1):cfi, CPNORM); - if (pdsch_decode(&pdsch, fft_buffer, ce, data, sf_idx, ra_dl.mcs, &prb_alloc)) { + + if (pdsch_harq_setup(&harq_process, ra_dl.mcs, &prb_alloc)) { + fprintf(stderr, "Error configuring HARQ process\n"); + break; + } + + if (pdsch_decode(&pdsch, fft_buffer, ce, data, sf_idx, &harq_process, ra_dl.rv_idx)) { pkt_errors++; } pkts_total++; diff --git a/lte/phy/include/liblte/phy/common/phy_common.h b/lte/phy/include/liblte/phy/common/phy_common.h index 900941a07..fdda782d2 100644 --- a/lte/phy/include/liblte/phy/common/phy_common.h +++ b/lte/phy/include/liblte/phy/common/phy_common.h @@ -132,38 +132,38 @@ LIBLTE_API enum band_geographical_area { LIBLTE_API bool lte_cell_isvalid(lte_cell_t *cell); -LIBLTE_API const int lte_symbol_sz(int nof_prb); +LIBLTE_API int lte_symbol_sz(uint32_t nof_prb); -LIBLTE_API const int lte_sampling_freq_hz(int nof_prb); +LIBLTE_API int lte_sampling_freq_hz(uint32_t nof_prb); -LIBLTE_API int lte_re_x_prb(int ns, - int symbol, - int nof_ports, - int nof_symbols); +LIBLTE_API uint32_t lte_re_x_prb(uint32_t ns, + uint32_t symbol, + uint32_t nof_ports, + uint32_t nof_symbols); -LIBLTE_API int lte_voffset(int symbol_id, - int cell_id, - int nof_ports); +LIBLTE_API uint32_t lte_voffset(uint32_t symbol_id, + uint32_t cell_id, + uint32_t nof_ports); -LIBLTE_API int lte_cb_size(int index); +LIBLTE_API int lte_cb_size(uint32_t index); -LIBLTE_API int lte_find_cb_index(int long_cb); +LIBLTE_API int lte_find_cb_index(uint32_t long_cb); -LIBLTE_API float lte_band_fd(int earfcn); +LIBLTE_API float lte_band_fd(uint32_t earfcn); -LIBLTE_API int lte_band_get_fd_band(int band, +LIBLTE_API int lte_band_get_fd_band(uint32_t band, lte_earfcn_t *earfcn, int earfcn_start, int earfcn_end, - int max_elems); + uint32_t max_elems); -LIBLTE_API int lte_band_get_fd_band_all(int band, +LIBLTE_API int lte_band_get_fd_band_all(uint32_t band, lte_earfcn_t *earfcn, - int max_nelems); + uint32_t max_nelems); LIBLTE_API int lte_band_get_fd_region(enum band_geographical_area region, lte_earfcn_t *earfcn, - int max_elems); + uint32_t max_elems); LIBLTE_API int lte_str2mimotype(char *mimo_type_str, lte_mimo_type_t *type); diff --git a/lte/phy/include/liblte/phy/fec/rm_turbo.h b/lte/phy/include/liblte/phy/fec/rm_turbo.h index 97bc8c90d..0b5fad70e 100644 --- a/lte/phy/include/liblte/phy/fec/rm_turbo.h +++ b/lte/phy/include/liblte/phy/fec/rm_turbo.h @@ -40,24 +40,17 @@ #include "liblte/config.h" -typedef struct LIBLTE_API { - int buffer_len; - char *buffer; -} rm_turbo_t; - -LIBLTE_API int rm_turbo_init(rm_turbo_t *q, - uint32_t max_codeblock_len); - -LIBLTE_API void rm_turbo_free(rm_turbo_t *q); -LIBLTE_API int rm_turbo_tx(rm_turbo_t *q, +LIBLTE_API int rm_turbo_tx(char *w_buff, + uint32_t buff_len, char *input, uint32_t in_len, char *output, uint32_t out_len, uint32_t rv_idx); -LIBLTE_API int rm_turbo_rx(rm_turbo_t *q, +LIBLTE_API int rm_turbo_rx(float *w_buff, + uint32_t buff_len, float *input, uint32_t in_len, float *output, @@ -66,11 +59,11 @@ LIBLTE_API int rm_turbo_rx(rm_turbo_t *q, /* High-level API */ typedef struct LIBLTE_API { - rm_turbo_t q; + struct rm_turbo_init { int direction; } init; - void *input; // input type may be char or float depending on hard + void *input; // input type may be char or float depending on hard int in_len; struct rm_turbo_ctrl_in { int E; diff --git a/lte/phy/include/liblte/phy/phch/pdsch.h b/lte/phy/include/liblte/phy/phch/pdsch.h index c48fa1c5c..c25acd191 100644 --- a/lte/phy/include/liblte/phy/phch/pdsch.h +++ b/lte/phy/include/liblte/phy/phch/pdsch.h @@ -43,10 +43,32 @@ #include "liblte/phy/phch/dci.h" #include "liblte/phy/phch/regs.h" -#define TDEC_ITERATIONS 1 +#define TDEC_ITERATIONS 1 typedef _Complex float cf_t; +typedef struct LIBLTE_API { + ra_mcs_t mcs; + ra_prb_t prb_alloc; + lte_cell_t cell; + + uint32_t max_cb; + uint32_t w_buff_size; + float **pdsch_w_buff_f; + char **pdsch_w_buff_c; + + + struct cb_segm { + uint32_t F; + uint32_t C; + uint32_t K1; + uint32_t K2; + uint32_t C1; + uint32_t C2; + } cb_segm; + +} pdsch_harq_t; + /* PDSCH object */ typedef struct LIBLTE_API { lte_cell_t cell; @@ -55,23 +77,21 @@ typedef struct LIBLTE_API { uint16_t rnti; /* buffers */ + // void buffers are shared for tx and rx cf_t *ce[MAX_PORTS]; cf_t *pdsch_symbols[MAX_PORTS]; cf_t *pdsch_x[MAX_PORTS]; cf_t *pdsch_d; - char *pdsch_e_bits; - char *cb_in_b; - char *cb_out_b; - float *pdsch_llr; - float *pdsch_rm_f; + void *cb_in; + char *cb_out; + void *pdsch_e; /* tx & rx objects */ modem_table_t mod[4]; demod_soft_t demod; sequence_t seq_pdsch[NSUBFRAMES_X_FRAME]; tcod_t encoder; - tdec_t decoder; - rm_turbo_t rm_turbo; + tdec_t decoder; crc_t crc_tb; crc_t crc_cb; }pdsch_t; @@ -82,20 +102,29 @@ LIBLTE_API int pdsch_init(pdsch_t *q, LIBLTE_API void pdsch_free(pdsch_t *q); +LIBLTE_API int pdsch_harq_init(pdsch_harq_t *p, + pdsch_t *pdsch); + +LIBLTE_API int pdsch_harq_setup(pdsch_harq_t *p, + ra_mcs_t mcs, + ra_prb_t *prb_alloc); + +LIBLTE_API void pdsch_harq_free(pdsch_harq_t *p); + LIBLTE_API int pdsch_encode(pdsch_t *q, char *data, cf_t *sf_symbols[MAX_PORTS], - uint32_t nsubframe, - ra_mcs_t mcs, - ra_prb_t *prb_alloc); + uint32_t nsubframe, + pdsch_harq_t *harq_process, + uint32_t rv_idx); LIBLTE_API int pdsch_decode(pdsch_t *q, cf_t *sf_symbols, cf_t *ce[MAX_PORTS], char *data, - uint32_t nsubframe, - ra_mcs_t mcs, - ra_prb_t *prb_alloc); + uint32_t nsubframe, + pdsch_harq_t *harq_process, + uint32_t rv_idx); LIBLTE_API int pdsch_get(pdsch_t *q, cf_t *sf_symbols, diff --git a/lte/phy/include/liblte/phy/phch/ra.h b/lte/phy/include/liblte/phy/phch/ra.h index 7b9ed8362..0e578a14d 100644 --- a/lte/phy/include/liblte/phy/phch/ra.h +++ b/lte/phy/include/liblte/phy/phch/ra.h @@ -147,6 +147,8 @@ LIBLTE_API uint32_t ra_nprb_dl(ra_pdsch_t *ra, LIBLTE_API uint32_t ra_nprb_ul(ra_pusch_t *ra, uint32_t nof_prb); +LIBLTE_API uint32_t ra_mod_bits_x_symbol(ra_mod_t mod); + LIBLTE_API uint32_t ra_mcs_to_table_idx(ra_mcs_t *mcs); LIBLTE_API int ra_mcs_from_idx_dl(uint32_t idx, diff --git a/lte/phy/lib/common/src/phy_common.c b/lte/phy/lib/common/src/phy_common.c index 5cbdae6da..7987b9034 100644 --- a/lte/phy/lib/common/src/phy_common.c +++ b/lte/phy/lib/common/src/phy_common.c @@ -68,36 +68,41 @@ bool lte_cell_isvalid(lte_cell_t *cell) { /* * 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) { +int lte_cb_size(uint32_t index) { + if (index < NOF_TC_CB_SIZES) { return tc_cb_sizes[index]; } else { - return -1; + return LIBLTE_ERROR; } } /* * 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 lte_find_cb_index(uint32_t long_cb) { int j = 0; while (j < NOF_TC_CB_SIZES && tc_cb_sizes[j] < long_cb) { j++; } if (j == NOF_TC_CB_SIZES) { - return -1; + return LIBLTE_ERROR; } else { return j; } } -const int lte_sampling_freq_hz(int nof_prb) { - return 15000 * lte_symbol_sz(nof_prb); +int lte_sampling_freq_hz(uint32_t nof_prb) { + int n = lte_symbol_sz(nof_prb); + if (n == -1) { + return LIBLTE_ERROR; + } else { + return 15000 * n; + } } -const int lte_symbol_sz(int nof_prb) { +int lte_symbol_sz(uint32_t nof_prb) { if (nof_prb<=0) { - return -1; + return LIBLTE_ERROR; } if (nof_prb<=6) { return 128; @@ -112,10 +117,10 @@ const int lte_symbol_sz(int nof_prb) { } else if (nof_prb<=100) { return 2048; } - return -1; + return LIBLTE_ERROR; } -int lte_voffset(int symbol_id, int cell_id, int nof_ports) { +uint32_t lte_voffset(uint32_t symbol_id, uint32_t cell_id, uint32_t nof_ports) { if (nof_ports == 1 && symbol_id==0) { return (cell_id+3) % 6; } else { @@ -124,7 +129,7 @@ int lte_voffset(int symbol_id, int cell_id, int nof_ports) { } /* Returns the number of available RE per PRB */ -int lte_re_x_prb(int ns, int symbol, int nof_ports, int nof_symbols) { +uint32_t lte_re_x_prb(uint32_t ns, uint32_t symbol, uint32_t nof_ports, uint32_t nof_symbols) { if (symbol == 0) { if (((ns % 2) == 0) || (ns == 1)) { return RE_X_RB - 4; @@ -156,10 +161,10 @@ int lte_re_x_prb(int ns, int symbol, int nof_ports, int nof_symbols) { struct lte_band { - int band; + uint32_t band; float fd_low_mhz; - int earfcn_offset; - int earfcn_max; + uint32_t earfcn_offset; + uint32_t earfcn_max; enum band_geographical_area area; }; @@ -204,9 +209,9 @@ int lte_str2mimotype(char *mimo_type_str, lte_mimo_type_t *type) { } else if (!strcmp(mimo_type_str, "multiplex")) { *type = SPATIAL_MULTIPLEX; } else { - return -1; + return LIBLTE_ERROR; } - return 0; + return LIBLTE_SUCCESS; } char *lte_mimotype2str(lte_mimo_type_t type) { @@ -221,12 +226,16 @@ char *lte_mimotype2str(lte_mimo_type_t type) { return NULL; } -float get_fd(struct lte_band *band, int earfcn) { - return band->fd_low_mhz + 0.1*(earfcn - band->earfcn_offset); +float get_fd(struct lte_band *band, uint32_t earfcn) { + if (earfcn > band->earfcn_offset) { + return band->fd_low_mhz + 0.1*(earfcn - band->earfcn_offset); + } else { + return 0.0; + } } -float lte_band_fd(int earfcn) { - int i; +float lte_band_fd(uint32_t earfcn) { + uint32_t i; i=0; while(i < NOF_LTE_BANDS && lte_bands[i].earfcn_offset lte_bands[i].earfcn_max) { fprintf(stderr, "Error: Invalid end earfcn %d. Max is %d\n", end_earfcn, lte_bands[i].earfcn_max); - return -1; + return LIBLTE_ERROR; } } if (start_earfcn == -1) { @@ -266,7 +275,7 @@ int lte_band_get_fd_band(int band, lte_earfcn_t *earfcn, int start_earfcn, int e } else { if (start_earfcn < lte_bands[i].earfcn_offset) { fprintf(stderr, "Error: Invalid start earfcn %d. Min is %d\n", start_earfcn, lte_bands[i].earfcn_offset); - return -1; + return LIBLTE_ERROR; } } nof_earfcn = end_earfcn - start_earfcn; @@ -278,11 +287,11 @@ int lte_band_get_fd_band(int band, lte_earfcn_t *earfcn, int start_earfcn, int e earfcn[j].id = j + start_earfcn; earfcn[j].fd = get_fd(<e_bands[i], earfcn[j].id); } - return j; + return (int) j; } -int lte_band_get_fd_region(enum band_geographical_area region, lte_earfcn_t *earfcn, int max_elems) { - int i; +int lte_band_get_fd_region(enum band_geographical_area region, lte_earfcn_t *earfcn, uint32_t max_elems) { + uint32_t i; int n; int nof_fd = 0; for (i=0;i 0;i++) { @@ -292,7 +301,7 @@ int lte_band_get_fd_region(enum band_geographical_area region, lte_earfcn_t *ear nof_fd += n; max_elems -= n; } else { - return -1; + return LIBLTE_ERROR; } } } diff --git a/lte/phy/lib/fec/src/rm_turbo.c b/lte/phy/lib/fec/src/rm_turbo.c index 6e677b0d4..ae52d9593 100644 --- a/lte/phy/lib/fec/src/rm_turbo.c +++ b/lte/phy/lib/fec/src/rm_turbo.c @@ -40,31 +40,22 @@ uint8_t 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, uint32_t buffer_len) { - q->buffer_len = buffer_len; - q->buffer = malloc(buffer_len * sizeof(float)); - if (!q->buffer) { - perror("malloc"); - return -1; - } - return 0; -} - -void rm_turbo_free(rm_turbo_t *q) { - if (q->buffer) { - free(q->buffer); - } -} /* Turbo Code Rate Matching. * 3GPP TS 36.212 v10.1.0 section 5.1.4.1 * + * If rv_idx==0, the circular buffer w_buff is filled with all redundancy versions and + * the corresponding version of length out_len is saved in the output buffer. + * Otherwise, the corresponding version is directly obtained from w_buff and saved into output. + * + * Note that calling this function with rv_idx!=0 without having called it first with rv_idx=0 + * will produce unwanted results. + * * TODO: Soft buffer size limitation according to UE category */ -int rm_turbo_tx(rm_turbo_t *q, char *input, uint32_t in_len, char *output, +int rm_turbo_tx(char *w_buff, uint32_t w_buff_len, char *input, uint32_t in_len, char *output, uint32_t out_len, uint32_t rv_idx) { - char *tmp = (char*) q->buffer; int ndummy, kidx; int nrows, K_p; @@ -72,10 +63,10 @@ int rm_turbo_tx(rm_turbo_t *q, char *input, uint32_t in_len, char *output, nrows = (uint32_t) (in_len / 3 - 1) / NCOLS + 1; K_p = nrows * NCOLS; - if (3 * K_p > q->buffer_len) { + if (3 * K_p > w_buff_len) { fprintf(stderr, "Input too large. Max input length including dummy bits is %d (3x%dx32, in_len %d)\n", - q->buffer_len, nrows, in_len); + w_buff_len, nrows, in_len); return -1; } @@ -84,33 +75,35 @@ int rm_turbo_tx(rm_turbo_t *q, char *input, uint32_t in_len, char *output, ndummy = 0; } - /* Sub-block interleaver (5.1.4.1.1) and bit collection */ - k = 0; - for (s = 0; s < 2; s++) { - for (j = 0; j < NCOLS; j++) { - for (i = 0; i < nrows; i++) { - if (s == 0) { - kidx = k % K_p; - } else { - kidx = K_p + 2 * (k % K_p); + if (rv_idx == 0) { + /* Sub-block interleaver (5.1.4.1.1) and bit collection */ + k = 0; + for (s = 0; s < 2; s++) { + for (j = 0; j < NCOLS; j++) { + for (i = 0; i < nrows; i++) { + if (s == 0) { + kidx = k % K_p; + } else { + kidx = K_p + 2 * (k % K_p); + } + if (i * NCOLS + RM_PERM_TC[j] < ndummy) { + w_buff[kidx] = TX_NULL; + } else { + w_buff[kidx] = input[(i * NCOLS + RM_PERM_TC[j] - ndummy) * 3 + s]; + } + k++; } - if (i * NCOLS + RM_PERM_TC[j] < ndummy) { - tmp[kidx] = TX_NULL; - } else { - tmp[kidx] = input[(i * NCOLS + RM_PERM_TC[j] - ndummy) * 3 + s]; - } - k++; } } - } - // d_k^(2) goes through special permutation - for (k = 0; k < K_p; k++) { - kidx = (RM_PERM_TC[k / nrows] + NCOLS * (k % nrows) + 1) % K_p; - if ((kidx - ndummy) < 0) { - tmp[K_p + 2 * k + 1] = TX_NULL; - } else { - tmp[K_p + 2 * k + 1] = input[3 * (kidx - ndummy) + 2]; + // d_k^(2) goes through special permutation + for (k = 0; k < K_p; k++) { + kidx = (RM_PERM_TC[k / nrows] + NCOLS * (k % nrows) + 1) % K_p; + if ((kidx - ndummy) < 0) { + w_buff[K_p + 2 * k + 1] = TX_NULL; + } else { + w_buff[K_p + 2 * k + 1] = input[3 * (kidx - ndummy) + 2]; + } } } @@ -123,8 +116,8 @@ int rm_turbo_tx(rm_turbo_t *q, char *input, uint32_t in_len, char *output, j = 0; while (k < out_len) { - if (tmp[(k0 + j) % N_cb] != TX_NULL) { - output[k] = tmp[(k0 + j) % N_cb]; + if (w_buff[(k0 + j) % N_cb] != TX_NULL) { + output[k] = w_buff[(k0 + j) % N_cb]; k++; } j++; @@ -134,8 +127,11 @@ int rm_turbo_tx(rm_turbo_t *q, char *input, uint32_t in_len, char *output, /* Undoes Turbo Code Rate Matching. * 3GPP TS 36.212 v10.1.0 section 5.1.4.1 + * + * If rv_idx==0, the w_buff circular buffer is initialized. Every subsequent call + * with rv_idx!=0 will soft-combine the LLRs from input with w_buff */ -int rm_turbo_rx(rm_turbo_t *q, float *input, uint32_t in_len, float *output, +int rm_turbo_rx(float *w_buff, uint32_t w_buff_len, float *input, uint32_t in_len, float *output, uint32_t out_len, uint32_t rv_idx) { int nrows, ndummy, K_p, k0, N_cb, jp, kidx; @@ -143,14 +139,12 @@ int rm_turbo_rx(rm_turbo_t *q, float *input, uint32_t in_len, float *output, int d_i, d_j; bool isdummy; - float *tmp = (float*) q->buffer; - nrows = (uint32_t) (out_len / 3 - 1) / NCOLS + 1; K_p = nrows * NCOLS; - if (3 * K_p > q->buffer_len) { + if (3 * K_p > w_buff_len) { fprintf(stderr, "Input too large. Max output length including dummy bits is %d (3x%dx32, in_len %d)\n", - q->buffer_len, nrows, out_len); + w_buff_len, nrows, out_len); return -1; } @@ -159,12 +153,14 @@ int rm_turbo_rx(rm_turbo_t *q, float *input, uint32_t in_len, float *output, ndummy = 0; } - for (i = 0; i < 3 * K_p; i++) { - tmp[i] = RX_NULL; + if (rv_idx == 0) { + for (i = 0; i < 3 * K_p; i++) { + w_buff[i] = RX_NULL; + } } /* Undo bit collection. Account for dummy bits */ - N_cb = 3 * K_p; // TODO: Soft buffer size limitation + N_cb = 3 * K_p; // TODO: Soft buffer size limitation k0 = nrows * (2 * (uint32_t) ceilf((float) N_cb / (float) (8 * nrows)) * rv_idx + 2); @@ -197,10 +193,10 @@ int rm_turbo_rx(rm_turbo_t *q, float *input, uint32_t in_len, float *output, } if (!isdummy) { - if (tmp[jp] == RX_NULL) { - tmp[jp] = input[k]; + if (w_buff[jp] == RX_NULL) { + w_buff[jp] = input[k]; } else if (input[k] != RX_NULL) { - tmp[jp] += input[k]; /* soft combine LLRs */ + w_buff[jp] += input[k]; /* soft combine LLRs */ } k++; } @@ -215,15 +211,14 @@ int rm_turbo_rx(rm_turbo_t *q, float *input, uint32_t in_len, float *output, if (j != 2) { kidx = K_p * j + (j + 1) * (RM_PERM_TC[d_j] * nrows + d_i); } else { - 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; } - if (tmp[kidx] != RX_NULL) { - output[i * 3 + j] = tmp[kidx]; + if (w_buff[kidx] != RX_NULL) { + output[i * 3 + j] = w_buff[kidx]; } else { output[i * 3 + j] = 0; } @@ -235,25 +230,15 @@ int rm_turbo_rx(rm_turbo_t *q, float *input, uint32_t in_len, float *output, /** High-level API */ int rm_turbo_initialize(rm_turbo_hl* h) { - return rm_turbo_init(&h->q, 7000); + return 0; } /** 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); - 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); - hl->out_len = hl->ctrl_in.S; - } return 0; } int rm_turbo_stop(rm_turbo_hl* hl) { - rm_turbo_free(&hl->q); return 0; } diff --git a/lte/phy/lib/fec/test/rm_turbo_test.c b/lte/phy/lib/fec/test/rm_turbo_test.c index aa42ca832..42db72696 100644 --- a/lte/phy/lib/fec/test/rm_turbo_test.c +++ b/lte/phy/lib/fec/test/rm_turbo_test.c @@ -73,10 +73,9 @@ void parse_args(int argc, char **argv) { int main(int argc, char **argv) { int i; - char *bits, *rm_bits; - float *rm_symbols, *unrm_symbols; + char *bits, *rm_bits, *w_buff_c; + float *rm_symbols, *unrm_symbols, *w_buff_f; int nof_errors; - rm_turbo_t rm_turbo; parse_args(argc, argv); @@ -85,6 +84,11 @@ int main(int argc, char **argv) { perror("malloc"); exit(-1); } + w_buff_c = malloc(sizeof(char) * nof_tx_bits * 10); + if (!w_buff_c) { + perror("malloc"); + exit(-1); + } rm_bits = malloc(sizeof(char) * nof_rx_bits); if (!rm_bits) { perror("malloc"); @@ -95,6 +99,11 @@ int main(int argc, char **argv) { perror("malloc"); exit(-1); } + w_buff_f = malloc(sizeof(float) * nof_rx_bits * 10); + if (!w_buff_c) { + perror("malloc"); + exit(-1); + } unrm_symbols = malloc(sizeof(float) * nof_tx_bits); if (!unrm_symbols) { perror("malloc"); @@ -105,15 +114,13 @@ int main(int argc, char **argv) { bits[i] = rand() % 2; } - rm_turbo_init(&rm_turbo, 2000); - - rm_turbo_tx(&rm_turbo, bits, nof_tx_bits, rm_bits, nof_rx_bits, rv_idx); + rm_turbo_tx(w_buff_c, nof_tx_bits * 10, bits, nof_tx_bits, rm_bits, nof_rx_bits, rv_idx); for (i = 0; i < nof_rx_bits; i++) { rm_symbols[i] = (float) rm_bits[i] ? 1 : -1; } - rm_turbo_rx(&rm_turbo, rm_symbols, nof_rx_bits, unrm_symbols, nof_tx_bits, + rm_turbo_rx(w_buff_f, nof_rx_bits * 10, rm_symbols, nof_rx_bits, unrm_symbols, nof_tx_bits, rv_idx); nof_errors = 0; @@ -123,8 +130,6 @@ int main(int argc, char **argv) { } } - rm_turbo_free(&rm_turbo); - free(bits); free(rm_bits); free(rm_symbols); diff --git a/lte/phy/lib/phch/src/pdsch.c b/lte/phy/lib/phch/src/pdsch.c index 524477730..c43b6c03b 100644 --- a/lte/phy/lib/phch/src/pdsch.c +++ b/lte/phy/lib/phch/src/pdsch.c @@ -50,14 +50,7 @@ const enum modem_std modulations[4] = { LTE_BPSK, LTE_QPSK, LTE_QAM16, LTE_QAM64 }; -struct cb_segm { - int F; - int C; - int K1; - int K2; - int C1; - int C2; -}; + int pdsch_cp(pdsch_t *q, cf_t *input, cf_t *output, ra_prb_t *prb_alloc, uint32_t nsubframe, bool put) { @@ -182,7 +175,7 @@ int pdsch_init(pdsch_t *q, uint16_t user_rnti, lte_cell_t cell) { int ret = LIBLTE_ERROR_INVALID_INPUTS; int i; - if (q != NULL && + if (q != NULL && lte_cell_isvalid(&cell)) { @@ -191,7 +184,7 @@ int pdsch_init(pdsch_t *q, uint16_t user_rnti, lte_cell_t cell) { q->cell = cell; q->rnti = user_rnti; - + q->max_symbols = q->cell.nof_prb * MAX_PDSCH_RE(q->cell.cp); INFO("Init PDSCH: %d ports %d PRBs, max_symbols: %d\n", q->cell.nof_ports, @@ -225,36 +218,24 @@ int pdsch_init(pdsch_t *q, uint16_t user_rnti, lte_cell_t cell) { 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) { + // Allocate floats for reception (LLRs) + q->cb_in = malloc(sizeof(float) * MAX_LONG_CB); + if (!q->cb_in) { 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) { + + q->cb_out = malloc(sizeof(char) * (3 * MAX_LONG_CB + 12)); + if (!q->cb_out) { goto clean; } - q->pdsch_llr = malloc( - sizeof(float) * q->max_symbols * q->mod[3].nbits_x_symbol); - if (!q->pdsch_llr) { + // Allocate floats for reception (LLRs) + q->pdsch_e = malloc(sizeof(float) * q->max_symbols * q->mod[3].nbits_x_symbol); + if (!q->pdsch_e) { goto clean; } - + q->pdsch_d = malloc(sizeof(cf_t) * q->max_symbols); if (!q->pdsch_d) { goto clean; @@ -287,20 +268,14 @@ int pdsch_init(pdsch_t *q, uint16_t user_rnti, lte_cell_t cell) { 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->cb_in) { + free(q->cb_in); } - if (q->pdsch_e_bits) { - free(q->pdsch_e_bits); + if (q->cb_out) { + free(q->cb_out); } - if (q->pdsch_rm_f) { - free(q->pdsch_rm_f); - } - if (q->pdsch_llr) { - free(q->pdsch_llr); + if (q->pdsch_e) { + free(q->pdsch_e); } if (q->pdsch_d) { free(q->pdsch_d); @@ -326,14 +301,14 @@ void pdsch_free(pdsch_t *q) { } tdec_free(&q->decoder); tcod_free(&q->encoder); - rm_turbo_free(&q->rm_turbo); } /* 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; - +int codeblock_segmentation(struct cb_segm *s, uint32_t tbs) { + uint32_t Bp, B, idx1; + int ret; + B = tbs + 24; /* Calculate CB sizes */ @@ -341,68 +316,186 @@ void codeblock_segmentation(struct cb_segm *s, int tbs) { s->C = 1; Bp = B; } else { - s->C = (int) ceilf((float) B / (6114 - 24)); + s->C = (uint32_t) 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; + ret = lte_find_cb_index(Bp / s->C); + if (ret != LIBLTE_ERROR) { + idx1 = (uint32_t) ret; + ret = lte_cb_size(idx1); + if (ret != LIBLTE_ERROR) { + s->K1 = (uint32_t) ret; + ret = lte_cb_size(idx1 - 1); + if (ret != LIBLTE_ERROR) { + if (s->C == 1) { + s->K2 = 0; + s->C2 = 0; + s->C1 = 1; + } else { + s->K2 = (uint32_t) ret; + 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); + } + } + } + return ret; +} + +int pdsch_harq_init(pdsch_harq_t *p, pdsch_t *pdsch) { + int ret = LIBLTE_ERROR_INVALID_INPUTS; + + if (p != NULL) { + uint32_t i; + bzero(p, sizeof(pdsch_harq_t)); + + p->cell = pdsch->cell; + ret = ra_tbs_from_idx(26, p->cell.nof_prb); + if (ret != LIBLTE_ERROR) { + p->max_cb = (uint32_t) ret / (6114 - 24) + 1; + + p->pdsch_w_buff_f = malloc(sizeof(float*) * p->max_cb); + if (!p->pdsch_w_buff_f) { + perror("malloc"); + return LIBLTE_ERROR; + } + + p->pdsch_w_buff_c = malloc(sizeof(char*) * p->max_cb); + if (!p->pdsch_w_buff_c) { + perror("malloc"); + return LIBLTE_ERROR; + } + + // We add 50 % larger buffer to the maximum expected bits per subframe + // FIXME: Use HARQ buffer limitation based on UE category + p->w_buff_size = p->cell.nof_prb * MAX_PDSCH_RE(p->cell.cp) * 6 * 2 / p->max_cb; + for (i=0;imax_cb;i++) { + p->pdsch_w_buff_f[i] = malloc(sizeof(float) * p->w_buff_size); + if (!p->pdsch_w_buff_f[i]) { + perror("malloc"); + return LIBLTE_ERROR; + } + p->pdsch_w_buff_c[i] = malloc(sizeof(char) * p->w_buff_size); + if (!p->pdsch_w_buff_c[i]) { + perror("malloc"); + return LIBLTE_ERROR; + } + } + ret = LIBLTE_SUCCESS; + } + } + return ret; +} + +void pdsch_harq_free(pdsch_harq_t *p) { + if (p) { + uint32_t i; + if (p->pdsch_w_buff_f) { + for (i=0;imax_cb;i++) { + if (p->pdsch_w_buff_f[i]) { + free(p->pdsch_w_buff_f[i]); + } + } + free(p->pdsch_w_buff_f); + } + if (p->pdsch_w_buff_c) { + for (i=0;imax_cb;i++) { + if (p->pdsch_w_buff_c[i]) { + free(p->pdsch_w_buff_c[i]); + } + } + free(p->pdsch_w_buff_c); + } + bzero(p, sizeof(pdsch_harq_t)); + } +} + +int pdsch_harq_setup(pdsch_harq_t *p, ra_mcs_t mcs, ra_prb_t *prb_alloc) { + int ret = LIBLTE_ERROR_INVALID_INPUTS; + + if (p != NULL && + mcs.tbs > 0 && + mcs.mod != MOD_NULL) + { + uint32_t nof_bits, nof_bits_e, nof_symbols; + + p->mcs = mcs; + memcpy(&p->prb_alloc, prb_alloc, sizeof(ra_prb_t)); + + codeblock_segmentation(&p->cb_segm, mcs.tbs); + + nof_bits = mcs.tbs; + nof_symbols = prb_alloc->re_sf[1]; // Any subframe except 0 and 5 has maximum RE + nof_bits_e = nof_symbols * ra_mod_bits_x_symbol(mcs.mod); + + if (nof_bits > nof_bits_e) { + fprintf(stderr, "Invalid code rate %.2f\n", (float) nof_bits / nof_bits_e); + return LIBLTE_ERROR; + } + + if (nof_symbols > p->cell.nof_prb * MAX_PDSCH_RE(p->cell.cp)) { + fprintf(stderr, + "Error too many RE per subframe (%d). PDSCH configured for %d RE (%d PRB)\n", + nof_symbols, p->cell.nof_prb * MAX_PDSCH_RE(p->cell.cp), p->cell.nof_prb); + return LIBLTE_ERROR; + } + + if (p->cb_segm.C > p->max_cb) { + fprintf(stderr, "Codeblock segmentation returned more CBs (%d) than allocated (%d)\n", + p->cb_segm.C, p->max_cb); + return LIBLTE_ERROR; + } + ret = LIBLTE_SUCCESS; } - 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); + return ret; } + /* Decode a transport block according to 36.212 5.3.2 * */ -int pdsch_decode_tb(pdsch_t *q, char *data, uint32_t tbs, uint32_t nb_e, uint32_t rv_idx) { +int pdsch_decode_tb(pdsch_t *q, char *data, uint32_t tbs, uint32_t nb_e, + pdsch_harq_t *harq_process, uint32_t rv_idx) +{ char parity[24]; char *p_parity = parity; uint32_t par_rx, par_tx; - int i; - int cb_len, rp, wp, rlen, F, n_e; - struct cb_segm cbs; + uint32_t i; + uint32_t cb_len, rp, wp, rlen, F, n_e; + float *e_bits = q->pdsch_e; if (q != NULL && data != NULL && nb_e < q->max_symbols * q->mod[3].nbits_x_symbol) { - /* Compute CB segmentation for this TBS */ - codeblock_segmentation(&cbs, tbs); rp = 0; rp = 0; wp = 0; - for (i = 0; i < cbs.C; i++) { + for (i = 0; i < harq_process->cb_segm.C; i++) { /* Get read/write lengths */ - if (i < cbs.C - cbs.C2) { - cb_len = cbs.K1; + if (i < harq_process->cb_segm.C - harq_process->cb_segm.C2) { + cb_len = harq_process->cb_segm.K1; } else { - cb_len = cbs.K2; + cb_len = harq_process->cb_segm.K2; } - if (cbs.C == 1) { + if (harq_process->cb_segm.C == 1) { rlen = cb_len; } else { rlen = cb_len - 24; } if (i == 0) { - F = cbs.F; + F = harq_process->cb_segm.F; } else { F = 0; } - if (i < cbs.C - 1) { - n_e = nb_e / cbs.C; + if (i < harq_process->cb_segm.C - 1) { + n_e = nb_e / harq_process->cb_segm.C; } else { n_e = nb_e - rp; } @@ -411,27 +504,34 @@ int pdsch_decode_tb(pdsch_t *q, char *data, uint32_t tbs, uint32_t nb_e, uint32_ 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); + if (rm_turbo_rx(harq_process->pdsch_w_buff_f[i], harq_process->w_buff_size, + &e_bits[rp], n_e, + (float*) q->cb_in, 3 * cb_len + 12, rv_idx)) { + fprintf(stderr, "Error in rate matching\n"); + return LIBLTE_ERROR; + } /* Turbo Decoding */ - tdec_run_all(&q->decoder, q->pdsch_rm_f, q->cb_in_b, TDEC_ITERATIONS, + tdec_run_all(&q->decoder, (float*) q->cb_in, q->cb_out, TDEC_ITERATIONS, cb_len); - if (cbs.C > 1) { - /* Check Codeblock CRC */ - //crc_attach(&q->crc_cb, q->pdsch_b[wp], cb_len); + if (harq_process->cb_segm.C > 1) { + /* Check Codeblock CRC and stop early if incorrect */ + if (crc_checksum(&q->crc_cb, q->cb_out, cb_len)) { + INFO("Error in CB#%d\n",i); + return LIBLTE_ERROR; + } } /* 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)); + if (i < harq_process->cb_segm.C - 1) { + memcpy(&data[wp], &q->cb_out[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)); + memcpy(&data[wp], &q->cb_out[F], (rlen - F - 24) * sizeof(char)); + memcpy(parity, &q->cb_out[rlen - 24], 24 * sizeof(char)); } /* Set read/write pointers */ @@ -463,39 +563,29 @@ int pdsch_decode_tb(pdsch_t *q, char *data, uint32_t tbs, uint32_t nb_e, uint32_ /** Decodes the PDSCH from the received symbols */ -int pdsch_decode(pdsch_t *q, cf_t *sf_symbols, cf_t *ce[MAX_PORTS], char *data, - uint32_t subframe, ra_mcs_t mcs, ra_prb_t *prb_alloc) { +int pdsch_decode(pdsch_t *q, cf_t *sf_symbols, cf_t *ce[MAX_PORTS], char *data, uint32_t subframe, + pdsch_harq_t *harq_process, uint32_t rv_idx) +{ /* Set pointers for layermapping & precoding */ - int i, n; + uint32_t i, n; cf_t *x[MAX_LAYERS]; - int nof_symbols, nof_bits, nof_bits_e; + uint32_t nof_symbols, nof_bits, nof_bits_e; - if (q != NULL && - sf_symbols != NULL && - data != NULL && - subframe < 10 && - prb_alloc != NULL) + if (q != NULL && + sf_symbols != NULL && + data != NULL && + subframe < 10 && + harq_process != NULL) { - nof_bits = mcs.tbs; - nof_symbols = prb_alloc->re_sf[subframe]; - nof_bits_e = nof_symbols * q->mod[mcs.mod - 1].nbits_x_symbol; + nof_bits = harq_process->mcs.tbs; + nof_symbols = harq_process->prb_alloc.re_sf[subframe]; + nof_bits_e = nof_symbols * q->mod[harq_process->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 LIBLTE_ERROR_INVALID_INPUTS; - } - - 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->cell.nof_prb); - return LIBLTE_ERROR_INVALID_INPUTS; - } INFO("Decoding PDSCH SF: %d, Mod %d, NofBits: %d, NofSymbols: %d, NofBitsE: %d\n", - subframe, mcs.mod, nof_bits, nof_symbols, nof_bits_e); + subframe, harq_process->mcs.mod, nof_bits, nof_symbols, nof_bits_e); /* number of layers equals number of ports */ for (i = 0; i < q->cell.nof_ports; i++) { @@ -504,7 +594,7 @@ int pdsch_decode(pdsch_t *q, cf_t *sf_symbols, cf_t *ce[MAX_PORTS], char *data, memset(&x[q->cell.nof_ports], 0, sizeof(cf_t*) * (MAX_LAYERS - q->cell.nof_ports)); /* extract symbols */ - n = pdsch_get(q, sf_symbols, q->pdsch_symbols[0], prb_alloc, subframe); + n = pdsch_get(q, sf_symbols, q->pdsch_symbols[0], &harq_process->prb_alloc, subframe); if (n != nof_symbols) { fprintf(stderr, "Error expecting %d symbols but got %d\n", nof_symbols, n); return LIBLTE_ERROR; @@ -512,7 +602,7 @@ int pdsch_decode(pdsch_t *q, cf_t *sf_symbols, cf_t *ce[MAX_PORTS], char *data, /* extract channel estimates */ for (i = 0; i < q->cell.nof_ports; i++) { - n = pdsch_get(q, ce[i], q->ce[i], prb_alloc, subframe); + n = pdsch_get(q, ce[i], q->ce[i], &harq_process->prb_alloc, subframe); if (n != nof_symbols) { fprintf(stderr, "Error expecting %d symbols but got %d\n", nof_symbols, n); return LIBLTE_ERROR; @@ -531,15 +621,18 @@ int pdsch_decode(pdsch_t *q, cf_t *sf_symbols, cf_t *ce[MAX_PORTS], char *data, nof_symbols / q->cell.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); + /* demodulate symbols + * The MAX-log-MAP algorithm used in turbo decoding is unsensitive to SNR estimation, + * thus we don't need tot set it in the LLRs normalization + */ + demod_soft_sigma_set(&q->demod, 2.0 / q->mod[harq_process->mcs.mod - 1].nbits_x_symbol); + demod_soft_table_set(&q->demod, &q->mod[harq_process->mcs.mod - 1]); + demod_soft_demodulate(&q->demod, q->pdsch_d, q->pdsch_e, nof_symbols); /* descramble */ - scrambling_f_offset(&q->seq_pdsch[subframe], q->pdsch_llr, 0, nof_bits_e); + scrambling_f_offset(&q->seq_pdsch[subframe], q->pdsch_e, 0, nof_bits_e); - return pdsch_decode_tb(q, data, nof_bits, nof_bits_e, 0); + return pdsch_decode_tb(q, data, nof_bits, nof_bits_e, harq_process, rv_idx); } else { return LIBLTE_ERROR_INVALID_INPUTS; } @@ -548,63 +641,65 @@ int pdsch_decode(pdsch_t *q, cf_t *sf_symbols, cf_t *ce[MAX_PORTS], char *data, /* Encode a transport block according to 36.212 5.3.2 * */ -int pdsch_encode_tb(pdsch_t *q, char *data, uint32_t tbs, uint32_t nb_e, uint32_t rv_idx) { +int pdsch_encode_tb(pdsch_t *q, char *data, uint32_t tbs, uint32_t nb_e, + pdsch_harq_t *harq_process, uint32_t 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; - + uint32_t par; + uint32_t i; + uint32_t cb_len, rp, wp, rlen, F, n_e; + char *cb_in = q->cb_in; + char *e_bits = q->pdsch_e; + if (q != NULL && data != NULL && nb_e < q->max_symbols * q->mod[3].nbits_x_symbol) { - /* Compute CB segmentation */ - codeblock_segmentation(&cbs, tbs); - - /* Compute transport block CRC */ - par = crc_checksum(&q->crc_tb, data, tbs); + if (rv_idx == 0) { + /* Compute transport block CRC */ + par = crc_checksum(&q->crc_tb, data, tbs); - /* parity bits will be appended later */ - bit_pack(par, &p_parity, 24); + /* 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); - } + 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; + /* Add filler bits to the new data buffer */ + for (i = 0; i < harq_process->cb_segm.F; i++) { + cb_in[i] = LTE_NULL_BIT; + } } - + wp = 0; rp = 0; - for (i = 0; i < cbs.C; i++) { + for (i = 0; i < harq_process->cb_segm.C; i++) { /* Get read lengths */ - if (i < cbs.C - cbs.C2) { - cb_len = cbs.K1; + if (i < harq_process->cb_segm.C - harq_process->cb_segm.C2) { + cb_len = harq_process->cb_segm.K1; } else { - cb_len = cbs.K2; + cb_len = harq_process->cb_segm.K2; } - if (cbs.C > 1) { + if (harq_process->cb_segm.C > 1) { rlen = cb_len - 24; } else { rlen = cb_len; } if (i == 0) { - F = cbs.F; + F = harq_process->cb_segm.F; } else { F = 0; } - if (i < cbs.C - 1) { - n_e = nb_e / cbs.C; + if (i < harq_process->cb_segm.C - 1) { + n_e = nb_e / harq_process->cb_segm.C; } else { n_e = nb_e - wp; } @@ -612,33 +707,37 @@ int pdsch_encode_tb(pdsch_t *q, char *data, uint32_t tbs, uint32_t nb_e, uint32_ 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); + if (rv_idx == 0) { + /* Copy data to another buffer, making space for the Codeblock CRC */ + if (i < harq_process->cb_segm.C - 1) { + memcpy(&cb_in[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(&cb_in[F], &data[rp], (rlen - F - 24) * sizeof(char)); + memcpy(&cb_in[rlen - 24], parity, 24 * sizeof(char)); + } + if (harq_process->cb_segm.C > 1) { + /* Attach Codeblock CRC */ + crc_attach(&q->crc_cb, cb_in, rlen); + } + if (VERBOSE_ISDEBUG()) { + DEBUG("CB#%d Len=%d: ", i, cb_len); + vec_fprint_b(stdout, cb_in, cb_len); + } + /* Turbo Encoding */ + tcod_encode(&q->encoder, cb_in, q->cb_out, 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); + if (rm_turbo_tx(harq_process->pdsch_w_buff_c[i], harq_process->w_buff_size, + q->cb_out, 3 * cb_len + 12, + &e_bits[wp], n_e, rv_idx)) + { + fprintf(stderr, "Error in rate matching\n"); + return LIBLTE_ERROR; + } /* Set read/write pointers */ rp += (rlen - F); @@ -655,17 +754,18 @@ int pdsch_encode_tb(pdsch_t *q, char *data, uint32_t tbs, uint32_t nb_e, uint32_ /** 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], - uint32_t subframe, ra_mcs_t mcs, ra_prb_t *prb_alloc) { +int pdsch_encode(pdsch_t *q, char *data, cf_t *sf_symbols[MAX_PORTS], uint32_t subframe, + pdsch_harq_t *harq_process, uint32_t rv_idx) +{ int i; uint32_t nof_symbols, nof_bits, nof_bits_e; /* Set pointers for layermapping & precoding */ cf_t *x[MAX_LAYERS]; - if (q != NULL && + if (q != NULL && data != NULL && subframe < 10 && - prb_alloc != NULL) + harq_process != NULL) { for (i=0;icell.nof_ports;i++) { @@ -674,10 +774,14 @@ int pdsch_encode(pdsch_t *q, char *data, cf_t *sf_symbols[MAX_PORTS], } } - nof_bits = mcs.tbs; - nof_symbols = prb_alloc->re_sf[subframe]; - nof_bits_e = nof_symbols * q->mod[mcs.mod - 1].nbits_x_symbol; + nof_bits = harq_process->mcs.tbs; + nof_symbols = harq_process->prb_alloc.re_sf[subframe]; + nof_bits_e = nof_symbols * q->mod[harq_process->mcs.mod - 1].nbits_x_symbol; + if (harq_process->mcs.mod == MOD_NULL) { + return LIBLTE_ERROR_INVALID_INPUTS; + } + if (nof_bits > nof_bits_e) { fprintf(stderr, "Invalid code rate %.2f\n", (float) nof_bits / nof_bits_e); return LIBLTE_ERROR_INVALID_INPUTS; @@ -690,8 +794,8 @@ int pdsch_encode(pdsch_t *q, char *data, cf_t *sf_symbols[MAX_PORTS], return LIBLTE_ERROR_INVALID_INPUTS; } - INFO("Encoding PDSCH SF: %d, Mod %d, NofBits: %d, NofSymbols: %d, NofBitsE: %d\n", - subframe, mcs.mod, nof_bits, nof_symbols, nof_bits_e); + INFO("Encoding PDSCH SF: %d, Mod %d, NofBits: %d, NofSymbols: %d, NofBitsE: %d, rv_idx: %d\n", + subframe, harq_process->mcs.mod, nof_bits, nof_symbols, nof_bits_e, rv_idx); /* number of layers equals number of ports */ for (i = 0; i < q->cell.nof_ports; i++) { @@ -699,14 +803,14 @@ int pdsch_encode(pdsch_t *q, char *data, cf_t *sf_symbols[MAX_PORTS], } memset(&x[q->cell.nof_ports], 0, sizeof(cf_t*) * (MAX_LAYERS - q->cell.nof_ports)); - if (pdsch_encode_tb(q, data, nof_bits, nof_bits_e, 0)) { + if (pdsch_encode_tb(q, data, nof_bits, nof_bits_e, harq_process, rv_idx)) { fprintf(stderr, "Error encoding TB\n"); return LIBLTE_ERROR; } - scrambling_b_offset(&q->seq_pdsch[subframe], q->pdsch_e_bits, 0, nof_bits_e); + scrambling_b_offset(&q->seq_pdsch[subframe], (char*) q->pdsch_e, 0, nof_bits_e); - mod_modulate(&q->mod[mcs.mod - 1], q->pdsch_e_bits, q->pdsch_d, nof_bits_e); + mod_modulate(&q->mod[harq_process->mcs.mod - 1], (char*) q->pdsch_e, q->pdsch_d, nof_bits_e); /* TODO: only diversity supported */ if (q->cell.nof_ports > 1) { @@ -719,7 +823,7 @@ int pdsch_encode(pdsch_t *q, char *data, cf_t *sf_symbols[MAX_PORTS], /* mapping to resource elements */ for (i = 0; i < q->cell.nof_ports; i++) { - pdsch_put(q, q->pdsch_symbols[i], sf_symbols[i], prb_alloc, subframe); + pdsch_put(q, q->pdsch_symbols[i], sf_symbols[i], &harq_process->prb_alloc, subframe); } return LIBLTE_SUCCESS; } else { diff --git a/lte/phy/lib/phch/src/ra.c b/lte/phy/lib/phch/src/ra.c index f53ffafdd..cf703ef63 100644 --- a/lte/phy/lib/phch/src/ra.c +++ b/lte/phy/lib/phch/src/ra.c @@ -405,6 +405,23 @@ uint32_t ra_mcs_to_table_idx(ra_mcs_t *mcs) { } } +uint32_t ra_mod_bits_x_symbol(ra_mod_t mod) { + switch(mod) { + case BPSK: + return 1; + case QPSK: + return 2; + case QAM16: + return 4; + case QAM64: + return 6; + default: + return 0; + } + return 0; +} + + /* Converts MCS index to ra_mcs_t structure for Downlink as defined inTable 7.1.7.1-1 on 36.213 */ int ra_mcs_from_idx_dl(uint32_t idx, ra_mcs_t *mcs) { if (idx < 10) { diff --git a/lte/phy/lib/phch/test/CMakeLists.txt b/lte/phy/lib/phch/test/CMakeLists.txt index 36ed64f2a..328d8128a 100644 --- a/lte/phy/lib/phch/test/CMakeLists.txt +++ b/lte/phy/lib/phch/test/CMakeLists.txt @@ -92,6 +92,7 @@ TARGET_LINK_LIBRARIES(pdsch_re_test lte_phy) ADD_TEST(pdsch_re_test pdsch_re_test) ADD_TEST(pdsch_test pdsch_test -l 50000 -m 4 -n 110) +ADD_TEST(pdsch_test pdsch_test -l 500 -m 2 -n 50 -r 2) ######################################################################## # FILE TEST diff --git a/lte/phy/lib/phch/test/pdsch_file_test.c b/lte/phy/lib/phch/test/pdsch_file_test.c index e436a83a1..fa5a1a822 100644 --- a/lte/phy/lib/phch/test/pdsch_file_test.c +++ b/lte/phy/lib/phch/test/pdsch_file_test.c @@ -54,6 +54,7 @@ FILE *fmatlab = NULL; filesource_t fsrc; pdcch_t pdcch; pdsch_t pdsch; +pdsch_harq_t harq_process; cf_t *input_buffer, *fft_buffer, *ce[MAX_PORTS]; regs_t regs; lte_fft_t fft; @@ -186,6 +187,11 @@ int base_init() { fprintf(stderr, "Error creating PDSCH object\n"); exit(-1); } + + if (pdsch_harq_init(&harq_process, &pdsch)) { + fprintf(stderr, "Error initiating HARQ process\n"); + exit(-1); + } DEBUG("Memory init OK\n",0); return 0; @@ -211,6 +217,7 @@ void base_free() { pdcch_free(&pdcch); pdsch_free(&pdsch); + pdsch_harq_free(&harq_process); regs_free(®s); } @@ -298,7 +305,7 @@ int main(int argc, char **argv) { fprintf(stderr, "Can't get DCI message type\n"); goto goout; } - printf("MSG %d: ",i); + dci_msg_type_fprint(stdout, type); switch(type.type) { case PDSCH_SCHED: @@ -325,7 +332,11 @@ int main(int argc, char **argv) { } ra_prb_get_re_dl(&prb_alloc, cell.nof_prb, cell.nof_ports, cell.nof_prb<10?(cfi+1):cfi, cell.cp); - if (pdsch_decode(&pdsch, fft_buffer, ce, data, nof_frames%10, ra_dl.mcs, &prb_alloc)) { + if (pdsch_harq_setup(&harq_process, ra_dl.mcs, &prb_alloc)) { + fprintf(stderr, "Error configuring HARQ process\n"); + goto goout; + } + if (pdsch_decode(&pdsch, fft_buffer, ce, data, nof_frames%10, &harq_process, ra_dl.rv_idx)) { fprintf(stderr, "Error decoding PDSCH\n"); goto goout; } else { diff --git a/lte/phy/lib/phch/test/pdsch_test.c b/lte/phy/lib/phch/test/pdsch_test.c index de6b9f5ce..40a5b01dd 100644 --- a/lte/phy/lib/phch/test/pdsch_test.c +++ b/lte/phy/lib/phch/test/pdsch_test.c @@ -42,15 +42,17 @@ lte_cell_t cell = { }; uint32_t cfi = 1; -uint32_t tbs = -1; +uint32_t tbs = 0; uint32_t subframe = 1; ra_mod_t modulation = BPSK; +uint32_t rv_idx = 0; void usage(char *prog) { - printf("Usage: %s [cell.cpnfvmt] -l TBS \n", prog); + printf("Usage: %s [cpsrnfvmt] -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-r rv_idx [Default %d]\n", rv_idx); printf("\t-f cfi [Default %d]\n", cfi); printf("\t-p cell.nof_ports [Default %d]\n", cell.nof_ports); printf("\t-n cell.nof_prb [Default %d]\n", cell.nof_prb); @@ -59,7 +61,7 @@ void usage(char *prog) { void parse_args(int argc, char **argv) { int opt; - while ((opt = getopt(argc, argv, "lcell.cpnfvmts")) != -1) { + while ((opt = getopt(argc, argv, "lcpnfvmtsr")) != -1) { switch(opt) { case 'm': switch(atoi(argv[optind])) { @@ -84,6 +86,9 @@ void parse_args(int argc, char **argv) { case 's': subframe = atoi(argv[optind]); break; + case 'r': + rv_idx = atoi(argv[optind]); + break; case 'l': tbs = atoi(argv[optind]); break; @@ -104,7 +109,7 @@ void parse_args(int argc, char **argv) { exit(-1); } } - if (tbs == -1) { + if (tbs == 0) { usage(argv[0]); exit(-1); } @@ -112,15 +117,17 @@ void parse_args(int argc, char **argv) { int main(int argc, char **argv) { pdsch_t pdsch; - int i, j; + uint32_t i, j; char *data = NULL; cf_t *ce[MAX_PORTS]; - int nof_re; + uint32_t nof_re; cf_t *slot_symbols[MAX_PORTS]; int ret = -1; struct timeval t[3]; ra_mcs_t mcs; ra_prb_t prb_alloc; + pdsch_harq_t harq_process; + uint32_t rv; parse_args(argc,argv); @@ -163,32 +170,50 @@ int main(int argc, char **argv) { fprintf(stderr, "Error creating PDSCH object\n"); goto quit; } + + if (pdsch_harq_init(&harq_process, &pdsch)) { + fprintf(stderr, "Error initiating HARQ process\n"); + goto quit; + } + + if (pdsch_harq_setup(&harq_process, mcs, &prb_alloc)) { + fprintf(stderr, "Error configuring HARQ process\n"); + goto quit; + } for (i=0;i 0) { - slot_symbols[0][j] += slot_symbols[i][j]; + /* combine outputs */ + for (i=0;i 0) { + slot_symbols[0][j] += slot_symbols[i][j]; + } + ce[i][j] = 1; } - 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); + + gettimeofday(&t[1], NULL); + int r = pdsch_decode(&pdsch, slot_symbols[0], ce, data, subframe, &harq_process, rv); + gettimeofday(&t[2], NULL); + get_time_interval(t); + if (r) { + printf("Error decoding\n"); + ret = -1; + goto quit; + } 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: From 09243c7996fb5d10d258a54035860045d426de65 Mon Sep 17 00:00:00 2001 From: ismagom Date: Thu, 10 Jul 2014 14:43:18 +0200 Subject: [PATCH 11/14] Fixed PDSCH bugs. Cleaned MCS interface in RA. Converted MODEM module to stdint --- lte/phy/examples/pdsch_enodeb.c | 18 +- lte/phy/examples/pdsch_ue.c | 95 ++++----- .../include/liblte/phy/common/phy_common.h | 34 ++-- lte/phy/include/liblte/phy/modem/demod_hard.h | 8 +- lte/phy/include/liblte/phy/modem/demod_soft.h | 2 +- lte/phy/include/liblte/phy/modem/mod.h | 4 +- .../include/liblte/phy/modem/modem_table.h | 26 ++- lte/phy/include/liblte/phy/phch/dci.h | 17 ++ lte/phy/include/liblte/phy/phch/pdsch.h | 5 +- lte/phy/include/liblte/phy/phch/ra.h | 73 +++---- lte/phy/lib/common/src/phy_common.c | 30 +++ lte/phy/lib/modem/src/demod_hard.c | 8 +- lte/phy/lib/modem/src/demod_soft.c | 2 +- lte/phy/lib/modem/src/hard_demod_lte.c | 17 +- lte/phy/lib/modem/src/hard_demod_lte.h | 20 +- lte/phy/lib/modem/src/lte_tables.c | 6 +- lte/phy/lib/modem/src/lte_tables.h | 19 +- lte/phy/lib/modem/src/mod.c | 13 +- lte/phy/lib/modem/src/modem_table.c | 23 +-- lte/phy/lib/modem/src/soft_algs.c | 4 +- lte/phy/lib/modem/src/soft_algs.h | 20 +- lte/phy/lib/modem/test/modem_test.c | 4 +- lte/phy/lib/phch/src/dci.c | 183 ++++++++---------- lte/phy/lib/phch/src/pbch.c | 2 +- lte/phy/lib/phch/src/pcfich.c | 2 +- lte/phy/lib/phch/src/pdcch.c | 17 +- lte/phy/lib/phch/src/pdsch.c | 47 ++--- lte/phy/lib/phch/src/phich.c | 2 +- lte/phy/lib/phch/src/ra.c | 137 +++---------- lte/phy/lib/phch/test/pdcch_file_test.c | 2 +- lte/phy/lib/phch/test/pdcch_test.c | 4 +- lte/phy/lib/phch/test/pdsch_file_test.c | 37 +--- lte/phy/lib/phch/test/pdsch_test.c | 10 +- lte/phy/lib/scrambling/src/scrambling.c | 2 +- 34 files changed, 414 insertions(+), 479 deletions(-) diff --git a/lte/phy/examples/pdsch_enodeb.c b/lte/phy/examples/pdsch_enodeb.c index d8263e739..78633c6b4 100644 --- a/lte/phy/examples/pdsch_enodeb.c +++ b/lte/phy/examples/pdsch_enodeb.c @@ -48,6 +48,7 @@ lte_cell_t cell = { }; uint32_t cfi=1; +uint32_t mcs_idx = 12; int nof_frames = -1; char *uhd_args = ""; @@ -70,12 +71,12 @@ void usage(char *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-m MCS index [Default %d]\n", mcs_idx); 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", cell.nof_prb); @@ -92,15 +93,15 @@ void parse_args(int argc, char **argv) { 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 'm': + mcs_idx = atoi(argv[optind]); + break; case 'n': nof_frames = atoi(argv[optind]); break; @@ -289,7 +290,7 @@ int main(int argc, char **argv) { bzero(&ra_dl, sizeof(ra_pdsch_t)); ra_dl.harq_process = 0; - ra_pdsch_set_mcs(&ra_dl, QPSK, 5); + ra_dl.mcs_idx = mcs_idx; ra_dl.ndi = 0; ra_dl.rv_idx = 0; ra_dl.alloc_type = alloc_type0; @@ -299,7 +300,7 @@ int main(int argc, char **argv) { ra_prb_get_dl(&prb_alloc, &ra_dl, cell.nof_prb); ra_prb_get_re_dl(&prb_alloc, cell.nof_prb, 1, cell.nof_prb<10?(cfi+1):cfi, CPNORM); - ra_dl.mcs.tbs = ra_tbs_from_idx(ra_dl.mcs.tbs_idx, cell.nof_prb); + ra_mcs_from_idx_dl(mcs_idx, cell.nof_prb, &ra_dl.mcs); ra_pdsch_fprint(stdout, &ra_dl, cell.nof_prb); @@ -322,7 +323,7 @@ int main(int argc, char **argv) { } while (nf < nof_frames || nof_frames == -1) { - for (sf_idx = 0; sf_idx < NSUBFRAMES_X_FRAME; sf_idx++) { + for (sf_idx = 0; sf_idx < NSUBFRAMES_X_FRAME && (nf < nof_frames || nof_frames == -1); sf_idx++) { bzero(sf_buffer, sizeof(cf_t) * sf_n_re); if (sf_idx == 0 || sf_idx == 5) { @@ -346,6 +347,7 @@ int main(int argc, char **argv) { data[i] = rand()%2; } + INFO("Puttting DCI to location: n=%d, L=%d\n", locations[sf_idx][0].ncce, locations[sf_idx][0].L); if (pdcch_encode(&pdcch, &dci_msg, locations[sf_idx][0], 1234, sf_symbols, sf_idx, cfi)) { fprintf(stderr, "Error encoding DCI message\n"); exit(-1); @@ -366,11 +368,11 @@ int main(int argc, char **argv) { cuhd_send(uhd, output_buffer, sf_n_samples, 1); #endif } + nf++; } mib.sfn = (mib.sfn + 1) % 1024; printf("SFN: %4d\r", mib.sfn); fflush(stdout); - nf++; } base_free(); diff --git a/lte/phy/examples/pdsch_ue.c b/lte/phy/examples/pdsch_ue.c index f4628db6c..9ec8c8885 100644 --- a/lte/phy/examples/pdsch_ue.c +++ b/lte/phy/examples/pdsch_ue.c @@ -398,11 +398,10 @@ int cell_id_init(int nof_prb, int cell_id) { char data[10000]; -int rx_run(cf_t *input, int sf_idx) { +int pdsch_run(cf_t *input, uint32_t sf_idx) { uint32_t cfi, cfi_distance, i; cf_t *input_decim; ra_pdsch_t ra_dl; - ra_prb_t prb_alloc; dci_location_t locations[10]; dci_msg_t dci_msg; uint32_t nof_locations; @@ -422,6 +421,7 @@ int rx_run(cf_t *input, int sf_idx) { /* First decode PCFICH and obtain CFI */ if (pcfich_decode(&pcfich, fft_buffer, ce, sf_idx, &cfi, &cfi_distance)<0) { + fprintf(stderr, "Error decoding PCFICH\n"); return -1; } @@ -441,56 +441,27 @@ int rx_run(cf_t *input, int sf_idx) { fprintf(stderr, "Error extracting LLRs\n"); return -1; } - if (pdcch_decode_msg(&pdcch, &dci_msg, Format1A, &crc_rem)) { + if (pdcch_decode_msg(&pdcch, &dci_msg, Format1, &crc_rem)) { fprintf(stderr, "Error decoding DCI msg\n"); return -1; } } if (crc_rem == 1234) { - dci_msg_type_t type; - if (dci_msg_get_type(&dci_msg, &type, cell.nof_prb, 1234, 1234)) { - fprintf(stderr, "Can't get DCI message type\n"); - } else { - if (VERBOSE_ISINFO()) { - dci_msg_type_fprint(stdout, type); - } - switch(type.type) { - case PDSCH_SCHED: - bzero(&ra_dl, sizeof(ra_pdsch_t)); - if (dci_msg_unpack_pdsch(&dci_msg, &ra_dl, cell.nof_prb, - false)) { - fprintf(stderr, "Can't unpack PDSCH message\n"); - break; - } - if (VERBOSE_ISINFO() || !pkts_total) { - printf("\n"); - ra_pdsch_fprint(stdout, &ra_dl, cell.nof_prb); - printf("\n"); - } - if (ra_prb_get_dl(&prb_alloc, &ra_dl, cell.nof_prb)) { - fprintf(stderr, "Error computing resource allocation\n"); - break; - } - ra_prb_get_re_dl(&prb_alloc, cell.nof_prb, cell.nof_ports, - cell.nof_prb<10?(cfi+1):cfi, CPNORM); - - - if (pdsch_harq_setup(&harq_process, ra_dl.mcs, &prb_alloc)) { - fprintf(stderr, "Error configuring HARQ process\n"); - break; - } - - if (pdsch_decode(&pdsch, fft_buffer, ce, data, sf_idx, &harq_process, ra_dl.rv_idx)) { - pkt_errors++; - } - pkts_total++; - break; - default: - fprintf(stderr, "Unsupported message type\n"); - break; - } + if (dci_msg_to_ra_dl(&dci_msg, 1234, 1234, cell, cfi, &ra_dl)) { + fprintf(stderr, "Error unpacking PDSCH scheduling DCI message\n"); + return -1; } + + if (pdsch_harq_setup(&harq_process, ra_dl.mcs, &ra_dl.prb_alloc)) { + fprintf(stderr, "Error configuring HARQ process\n"); + return -1; + } + + if (pdsch_decode(&pdsch, fft_buffer, ce, data, sf_idx, &harq_process, ra_dl.rv_idx)) { + pkt_errors++; + } + pkts_total++; } #ifndef DISABLE_GRAPHICS @@ -504,8 +475,8 @@ int rx_run(cf_t *input, int sf_idx) { } plot_real_setNewData(&poutfft, tmp_plot, n_re); plot_complex_setNewData(&pce, ce[0], n_re); - plot_scatter_setNewData(&pscatrecv, pdsch.pdsch_symbols[0], prb_alloc.re_sf[sf_idx]); - plot_scatter_setNewData(&pscatequal, pdsch.pdsch_d, prb_alloc.re_sf[sf_idx]); + plot_scatter_setNewData(&pscatrecv, pdsch.pdsch_symbols[0], ra_dl.prb_alloc.re_sf[sf_idx]); + plot_scatter_setNewData(&pscatequal, pdsch.pdsch_d, ra_dl.prb_alloc.re_sf[sf_idx]); } #endif @@ -574,7 +545,8 @@ int run_receiver(cf_t *input, uint32_t cell_id, uint32_t sf_idx) { } } if (cell.nof_prb && !pbch_only) { - if (rx_run(input, sf_idx)) { + if (pdsch_run(input, sf_idx)) { + fprintf(stderr, "\nError running PDSCH decoder\n"); return -1; } } @@ -665,20 +637,22 @@ int main(int argc, char **argv) { sync_frame_set_threshold(&sframe, find_threshold); + sf_idx = 0; + cell_id = cell_id_file; + if (input_file_name) { + in_ptr = input_buffer; + } else { + in_ptr = sf_buffer; + } + while (!go_exit && (frame_cnt < nof_frames || nof_frames == -1)) { read_io(input_buffer, sf_n_samples); - if (input_file_name) { - ret = 1; - sf_idx = 0; - cell_id = cell_id_file; - in_ptr = input_buffer; - } else { + if (!input_file_name) { ret = sync_frame_push(&sframe, input_buffer, sf_buffer); - in_ptr = sf_buffer; - cell_id = 0; - sf_idx = 0; + } else { + ret = 1; } switch(ret ) { case 0: @@ -694,10 +668,11 @@ int main(int argc, char **argv) { if (!input_file_name) { sf_idx = sync_frame_sfidx(&sframe); cell_id = sync_frame_cell_id(&sframe); - } + } /* synch'd and tracking */ if (run_receiver(in_ptr, cell_id, sf_idx)) { + fprintf(stderr, "\nError running receiver\n");fflush(stdout); exit(-1); } @@ -708,7 +683,9 @@ int main(int argc, char **argv) { (float) pkt_errors / pkts_total); fflush(stdout); } - + if (input_file_name) { + sf_idx++; + } break; default: fprintf(stderr, "Error running automatic synchronization\n"); diff --git a/lte/phy/include/liblte/phy/common/phy_common.h b/lte/phy/include/liblte/phy/common/phy_common.h index fdda782d2..422fe8699 100644 --- a/lte/phy/include/liblte/phy/common/phy_common.h +++ b/lte/phy/include/liblte/phy/common/phy_common.h @@ -34,40 +34,40 @@ #include "liblte/config.h" #define NSUBFRAMES_X_FRAME 10 -#define NSLOTS_X_FRAME (2*NSUBFRAMES_X_FRAME) +#define NSLOTS_X_FRAME (2*NSUBFRAMES_X_FRAME) #define LTE_NSOFT_BITS 250368 // Soft buffer size for Category 1 UE -#define LTE_NULL_BIT 0 +#define LTE_NULL_BIT 0 #define LTE_NULL_SYMBOL 2 #define LTE_NIL_SYMBOL 2 -#define MAX_PORTS 4 +#define MAX_PORTS 4 #define MAX_LAYERS 8 #define MAX_CODEWORDS 2 #define LTE_CRC24A 0x1864CFB #define LTE_CRC24B 0X1800063 -#define LTE_CRC16 0x11021 -#define LTE_CRC8 0x19B +#define LTE_CRC16 0x11021 +#define LTE_CRC8 0x19B typedef enum {CPNORM, CPEXT} lte_cp_t; -#define SIRNTI 0xFFFF +#define SIRNTI 0xFFFF #define PRNTI 0xFFFE #define MRNTI 0xFFFD -#define MAX_NSYMB 7 +#define MAX_NSYMB 7 -#define CPNORM_NSYMB 7 +#define CPNORM_NSYMB 7 #define CPNORM_SF_NSYMB 2*CPNORM_NSYMB -#define CPNORM_0_LEN 160 -#define CPNORM_LEN 144 +#define CPNORM_0_LEN 160 +#define CPNORM_LEN 144 -#define CPEXT_NSYMB 6 +#define CPEXT_NSYMB 6 #define CPEXT_SF_NSYMB 2*CPEXT_NSYMB -#define CPEXT_LEN 512 -#define CPEXT_7_5_LEN 1024 +#define CPEXT_LEN 512 +#define CPEXT_7_5_LEN 1024 #define CP_ISNORM(cp) (cp==CPNORM) #define CP_ISEXT(cp) (cp==CPEXT) @@ -120,6 +120,10 @@ typedef enum LIBLTE_API { typedef enum LIBLTE_API { PHICH_NORM, PHICH_EXT} phich_length_t; typedef enum LIBLTE_API { R_1_6, R_1_2, R_1, R_2} phich_resources_t; +typedef enum LIBLTE_API { + LTE_BPSK = 1, LTE_QPSK = 2, LTE_QAM16 = 4, LTE_QAM64 = 6 +} lte_mod_t; + typedef struct LIBLTE_API { int id; @@ -147,6 +151,10 @@ LIBLTE_API uint32_t lte_voffset(uint32_t symbol_id, LIBLTE_API int lte_cb_size(uint32_t index); +LIBLTE_API char *lte_mod_string(lte_mod_t mod); + +LIBLTE_API uint32_t lte_mod_bits_x_symbol(lte_mod_t mod); + LIBLTE_API int lte_find_cb_index(uint32_t long_cb); LIBLTE_API float lte_band_fd(uint32_t earfcn); diff --git a/lte/phy/include/liblte/phy/modem/demod_hard.h b/lte/phy/include/liblte/phy/modem/demod_hard.h index a3b621819..51f5b6c53 100644 --- a/lte/phy/include/liblte/phy/modem/demod_hard.h +++ b/lte/phy/include/liblte/phy/modem/demod_hard.h @@ -38,13 +38,13 @@ typedef _Complex float cf_t; typedef struct LIBLTE_API { - enum modem_std table; /* In this implementation, mapping table is hard-coded */ + lte_mod_t mod; /* In this implementation, mapping table is hard-coded */ }demod_hard_t; LIBLTE_API void demod_hard_init(demod_hard_t* q); -LIBLTE_API void demod_hard_table_set(demod_hard_t* q, enum modem_std table); -LIBLTE_API int demod_hard_demodulate(demod_hard_t* q, cf_t* symbols, char *bits, int nsymbols); +LIBLTE_API void demod_hard_table_set(demod_hard_t* q, lte_mod_t mod); +LIBLTE_API int demod_hard_demodulate(demod_hard_t* q, cf_t* symbols, char *bits, uint32_t nsymbols); @@ -52,7 +52,7 @@ LIBLTE_API int demod_hard_demodulate(demod_hard_t* q, cf_t* symbols, char *bits, typedef struct LIBLTE_API { demod_hard_t obj; struct demod_hard_init { - enum modem_std std; // Symbol mapping standard (see modem_table.h) + lte_mod_t std; // Symbol mapping standard (see modem_table.h) } init; cf_t* input; diff --git a/lte/phy/include/liblte/phy/modem/demod_soft.h b/lte/phy/include/liblte/phy/modem/demod_soft.h index bb2c4368b..2a2e40b55 100644 --- a/lte/phy/include/liblte/phy/modem/demod_soft.h +++ b/lte/phy/include/liblte/phy/modem/demod_soft.h @@ -56,7 +56,7 @@ typedef struct LIBLTE_API { modem_table_t table; struct demod_soft_init{ - enum modem_std std; // symbol mapping standard (see modem_table.h) + lte_mod_t std; // symbol mapping standard (see modem_table.h) } init; const cf_t* input; diff --git a/lte/phy/include/liblte/phy/modem/mod.h b/lte/phy/include/liblte/phy/modem/mod.h index 5467f13d0..8ee5defc8 100644 --- a/lte/phy/include/liblte/phy/modem/mod.h +++ b/lte/phy/include/liblte/phy/modem/mod.h @@ -37,13 +37,13 @@ typedef _Complex float cf_t; -LIBLTE_API int mod_modulate(modem_table_t* table, const char *bits, cf_t* symbols, int nbits); +LIBLTE_API int mod_modulate(modem_table_t* table, const char *bits, cf_t* symbols, uint32_t nbits); /* High-level API */ typedef struct LIBLTE_API { modem_table_t obj; struct mod_init { - enum modem_std std; // symbol mapping standard (see modem_table.h) + lte_mod_t std; // symbol mapping standard (see modem_table.h) } init; const char* input; diff --git a/lte/phy/include/liblte/phy/modem/modem_table.h b/lte/phy/include/liblte/phy/modem/modem_table.h index f94c03f86..cbc4fbee9 100644 --- a/lte/phy/include/liblte/phy/modem/modem_table.h +++ b/lte/phy/include/liblte/phy/modem/modem_table.h @@ -34,30 +34,36 @@ #include #include +#include "liblte/phy/common/phy_common.h" #include "liblte/config.h" typedef _Complex float cf_t; typedef struct LIBLTE_API { - int idx[2][6][32]; + uint32_t idx[2][6][32]; }soft_table_t; typedef struct LIBLTE_API { cf_t* symbol_table; // bit-to-symbol mapping soft_table_t soft_table; // symbol-to-bit mapping (used in soft demodulating) - int nsymbols; // number of modulation symbols - int nbits_x_symbol; // number of bits per symbol + uint32_t nsymbols; // number of modulation symbols + uint32_t nbits_x_symbol; // number of bits per symbol }modem_table_t; -// Modulation standards -enum modem_std { - LTE_BPSK = 1, LTE_QPSK = 2, LTE_QAM16 = 4, LTE_QAM64 = 6 -}; - LIBLTE_API void modem_table_init(modem_table_t* q); + LIBLTE_API void modem_table_free(modem_table_t* q); + LIBLTE_API void modem_table_reset(modem_table_t* q); -LIBLTE_API int modem_table_set(modem_table_t* q, cf_t* table, soft_table_t *soft_table, int nsymbols, int nbits_x_symbol); -LIBLTE_API int modem_table_std(modem_table_t* q, enum modem_std table, bool compute_soft_demod); + +LIBLTE_API int modem_table_set(modem_table_t* q, + cf_t* table, + soft_table_t *soft_table, + uint32_t nsymbols, + uint32_t nbits_x_symbol); + +LIBLTE_API int modem_table_lte(modem_table_t* q, + lte_mod_t modulation, + bool compute_soft_demod); #endif // MODEM_TABLE_ diff --git a/lte/phy/include/liblte/phy/phch/dci.h b/lte/phy/include/liblte/phy/phch/dci.h index a5ee5e658..be57914c0 100644 --- a/lte/phy/include/liblte/phy/phch/dci.h +++ b/lte/phy/include/liblte/phy/phch/dci.h @@ -71,7 +71,24 @@ typedef struct LIBLTE_API { uint32_t nof_bits; } dci_msg_t; +/* Converts a received PDSCH DL scheduling DCI message + * to ra structures ready to be passed to the harq setup function + */ +LIBLTE_API int dci_msg_to_ra_dl(dci_msg_t *msg, + uint16_t msg_rnti, + uint16_t c_rnti, + lte_cell_t cell, + uint32_t cfi, + ra_pdsch_t *ra_dl); +/* TODO +LIBLTE_API int dci_msg_to_ra_ul(dci_msg_t *msg, + uint16_t msg_rnti, + uint16_t c_rnti, + lte_cell_t cell, + uint32_t cfi, + ra_pusch_t *ra_ul); +*/ LIBLTE_API char* dci_format_string(dci_format_t format); LIBLTE_API int dci_location_set(dci_location_t *c, diff --git a/lte/phy/include/liblte/phy/phch/pdsch.h b/lte/phy/include/liblte/phy/phch/pdsch.h index c25acd191..6800e1707 100644 --- a/lte/phy/include/liblte/phy/phch/pdsch.h +++ b/lte/phy/include/liblte/phy/phch/pdsch.h @@ -57,7 +57,6 @@ typedef struct LIBLTE_API { float **pdsch_w_buff_f; char **pdsch_w_buff_c; - struct cb_segm { uint32_t F; uint32_t C; @@ -82,8 +81,8 @@ typedef struct LIBLTE_API { cf_t *pdsch_symbols[MAX_PORTS]; cf_t *pdsch_x[MAX_PORTS]; cf_t *pdsch_d; - void *cb_in; - char *cb_out; + char *cb_in; + void *cb_out; void *pdsch_e; /* tx & rx objects */ diff --git a/lte/phy/include/liblte/phy/phch/ra.h b/lte/phy/include/liblte/phy/phch/ra.h index 0e578a14d..0d519c031 100644 --- a/lte/phy/include/liblte/phy/phch/ra.h +++ b/lte/phy/include/liblte/phy/phch/ra.h @@ -37,17 +37,9 @@ * allocation. */ -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. - uint32_t tbs_idx; - uint32_t mcs_idx; - uint32_t 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. + lte_mod_t mod; + uint32_t tbs; } ra_mcs_t; typedef enum LIBLTE_API { @@ -60,7 +52,8 @@ typedef struct LIBLTE_API { typedef struct LIBLTE_API { uint32_t vrb_bitmask; - uint32_t rbg_subset;bool shift; + uint32_t rbg_subset; + bool shift; } ra_type1_t; typedef struct LIBLTE_API { @@ -78,6 +71,17 @@ typedef struct LIBLTE_API { } mode; } ra_type2_t; +typedef struct LIBLTE_API { + uint32_t prb_idx[MAX_PRB]; + uint32_t nof_prb; +} ra_prb_slot_t; + +typedef struct LIBLTE_API { + ra_prb_slot_t slot[2]; + uint32_t lstart; + uint32_t re_sf[NSUBFRAMES_X_FRAME]; +} ra_prb_t; + typedef struct LIBLTE_API { uint16_t rnti; ra_type_t alloc_type; @@ -86,6 +90,8 @@ typedef struct LIBLTE_API { ra_type1_t type1_alloc; ra_type2_t type2_alloc; }; + ra_prb_t prb_alloc; + uint32_t mcs_idx; ra_mcs_t mcs; uint32_t harq_process; uint32_t rv_idx; @@ -93,7 +99,7 @@ typedef struct LIBLTE_API { } ra_pdsch_t; typedef struct LIBLTE_API { - /* 36.213 Table 8.4-2: hop_half is 0 for < 10 Mhz and 10 for > 10 Mh. + /* 36.213 Table 8.4-2: hop_half is 0 for < 10 Mhz and 10 for > 10 Mhz. * hop_quart is 00 for > 10 Mhz and hop_quart_neg is 01 for > 10 Mhz. */ enum { @@ -104,7 +110,10 @@ typedef struct LIBLTE_API { hop_type_2 = 3 } freq_hop_fl; + ra_prb_t prb_alloc; + ra_type2_t type2_alloc; + uint32_t mcs_idx; ra_mcs_t mcs; uint32_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). @@ -113,17 +122,6 @@ typedef struct LIBLTE_API { } ra_pusch_t; -typedef struct LIBLTE_API { - uint32_t prb_idx[MAX_PRB]; - uint32_t nof_prb; -} ra_prb_slot_t; - -typedef struct LIBLTE_API { - ra_prb_slot_t slot[2]; - uint32_t lstart; - uint32_t re_sf[NSUBFRAMES_X_FRAME]; -} ra_prb_t; - LIBLTE_API void ra_prb_fprint(FILE *f, ra_prb_slot_t *prb); @@ -147,36 +145,22 @@ LIBLTE_API uint32_t ra_nprb_dl(ra_pdsch_t *ra, LIBLTE_API uint32_t ra_nprb_ul(ra_pusch_t *ra, uint32_t nof_prb); -LIBLTE_API uint32_t ra_mod_bits_x_symbol(ra_mod_t mod); - -LIBLTE_API uint32_t ra_mcs_to_table_idx(ra_mcs_t *mcs); - -LIBLTE_API int ra_mcs_from_idx_dl(uint32_t idx, +LIBLTE_API int ra_mcs_from_idx_dl(uint32_t mcs_idx, + uint32_t nof_prb, ra_mcs_t *mcs); -LIBLTE_API int ra_mcs_from_idx_ul(uint32_t idx, +LIBLTE_API int ra_mcs_from_idx_ul(uint32_t mcs_idx, + uint32_t nof_prb, ra_mcs_t *mcs); LIBLTE_API int ra_tbs_from_idx_format1c(uint32_t tbs_idx); -LIBLTE_API int ra_tbs_to_table_idx_format1c(uint32_t tbs); - LIBLTE_API int ra_tbs_from_idx(uint32_t tbs_idx, uint32_t n_prb); LIBLTE_API int ra_tbs_to_table_idx(uint32_t tbs, uint32_t n_prb); -LIBLTE_API uint32_t ra_mcs_to_table_idx(ra_mcs_t *mcs); - -LIBLTE_API int ra_mcs_from_idx_dl(uint32_t idx, - ra_mcs_t *mcs); - -LIBLTE_API int ra_mcs_from_idx_ul(uint32_t idx, - ra_mcs_t *mcs); - -LIBLTE_API char *ra_mod_string(ra_mod_t mod); - LIBLTE_API uint32_t ra_type0_P(uint32_t nof_prb); LIBLTE_API uint32_t ra_type2_to_riv(uint32_t L_crb, @@ -199,13 +183,6 @@ LIBLTE_API uint32_t ra_type2_ngap(uint32_t nof_prb, LIBLTE_API uint32_t ra_type1_N_rb(uint32_t nof_prb); -LIBLTE_API void ra_pdsch_set_mcs_index(ra_pdsch_t *ra, - uint32_t mcs_idx); - -LIBLTE_API void ra_pdsch_set_mcs(ra_pdsch_t *ra, - ra_mod_t mod, - uint32_t tbs_idx); - LIBLTE_API void ra_pdsch_fprint(FILE *f, ra_pdsch_t *ra, uint32_t nof_prb); diff --git a/lte/phy/lib/common/src/phy_common.c b/lte/phy/lib/common/src/phy_common.c index 7987b9034..a4b9a314d 100644 --- a/lte/phy/lib/common/src/phy_common.c +++ b/lte/phy/lib/common/src/phy_common.c @@ -76,6 +76,36 @@ int lte_cb_size(uint32_t index) { } } +char *lte_mod_string(lte_mod_t mod) { + switch (mod) { + case LTE_BPSK: + return "BPSK"; + case LTE_QPSK: + return "QPSK"; + case LTE_QAM16: + return "QAM16"; + case LTE_QAM64: + return "QAM64"; + default: + return "N/A"; + } +} + +uint32_t lte_mod_bits_x_symbol(lte_mod_t mod) { + switch (mod) { + case LTE_BPSK: + return 1; + case LTE_QPSK: + return 2; + case LTE_QAM16: + return 4; + case LTE_QAM64: + return 6; + default: + return 0; + } +} + /* * Finds index of minimum K>=long_cb in Table 5.1.3-3 of 36.212 */ diff --git a/lte/phy/lib/modem/src/demod_hard.c b/lte/phy/lib/modem/src/demod_hard.c index 7664821a8..a3b306e0b 100644 --- a/lte/phy/lib/modem/src/demod_hard.c +++ b/lte/phy/lib/modem/src/demod_hard.c @@ -37,14 +37,14 @@ void demod_hard_init(demod_hard_t* q) { bzero((void*) q, sizeof(demod_hard_t)); } -void demod_hard_table_set(demod_hard_t* q, enum modem_std table) { - q->table = table; +void demod_hard_table_set(demod_hard_t* q, lte_mod_t mod) { + q->mod = mod; } -int demod_hard_demodulate(demod_hard_t* q, cf_t* symbols, char *bits, int nsymbols) { +int demod_hard_demodulate(demod_hard_t* q, cf_t* symbols, char *bits, uint32_t nsymbols) { int nbits=-1; - switch(q->table) { + switch(q->mod) { case LTE_BPSK: hard_bpsk_demod(symbols,bits,nsymbols); nbits=nsymbols; diff --git a/lte/phy/lib/modem/src/demod_soft.c b/lte/phy/lib/modem/src/demod_soft.c index 2c874a1af..f79863199 100644 --- a/lte/phy/lib/modem/src/demod_soft.c +++ b/lte/phy/lib/modem/src/demod_soft.c @@ -69,7 +69,7 @@ int demod_soft_demodulate(demod_soft_t *q, const cf_t* symbols, float* llr, int /* High-Level API */ int demod_soft_initialize(demod_soft_hl* hl) { modem_table_init(&hl->table); - if (modem_table_std(&hl->table,hl->init.std,true)) { + if (modem_table_lte(&hl->table,hl->init.std,true)) { return -1; } demod_soft_init(&hl->obj); diff --git a/lte/phy/lib/modem/src/hard_demod_lte.c b/lte/phy/lib/modem/src/hard_demod_lte.c index 761c72140..f841f3ac7 100644 --- a/lte/phy/lib/modem/src/hard_demod_lte.c +++ b/lte/phy/lib/modem/src/hard_demod_lte.c @@ -33,6 +33,7 @@ #include "liblte/phy/modem/demod_hard.h" #include "hard_demod_lte.h" + /** * @ingroup Hard BPSK demodulator * @@ -46,9 +47,9 @@ * \param N Number of input symbols * \param modulation Modulation type */ -inline void hard_bpsk_demod(const cf_t* in, char* out, int N) +inline void hard_bpsk_demod(const cf_t* in, char* out, uint32_t N) { - int s; + uint32_t s; for (s=0; s 0) { @@ -81,9 +82,9 @@ inline void hard_bpsk_demod(const cf_t* in, char* out, int N) * \param N Number of input symbols * \param modulation Modulation type */ -inline void hard_qpsk_demod(const cf_t* in, char* out, int N) +inline void hard_qpsk_demod(const cf_t* in, char* out, uint32_t N) { - int s; + uint32_t s; for (s=0; s 0) { @@ -115,9 +116,9 @@ inline void hard_qpsk_demod(const cf_t* in, char* out, int N) * \param N Number of input symbols * \param modulation Modulation type */ -inline void hard_qam16_demod(const cf_t* in, char* out, int N) +inline void hard_qam16_demod(const cf_t* in, char* out, uint32_t N) { - int s; + uint32_t s; for (s=0; s 0) { @@ -157,9 +158,9 @@ inline void hard_qam16_demod(const cf_t* in, char* out, int N) * \param N Number of input symbols * \param modulation Modulation type */ -inline void hard_qam64_demod(const cf_t* in, char* out, int N) +inline void hard_qam64_demod(const cf_t* in, char* out, uint32_t N) { - int s; + uint32_t s; for (s=0; snbits_x_symbol) { idx = bit_unpack(&b_ptr,q->nbits_x_symbol); - assert(idx >= 0 && idx < q->nsymbols); - symbols[j] = q->symbol_table[idx]; + if (idx < q->nsymbols) { + symbols[j] = q->symbol_table[idx]; + } else { + return LIBLTE_ERROR; + } j++; } return j; @@ -52,7 +55,7 @@ int mod_modulate(modem_table_t* q, const char *bits, cf_t* symbols, int nbits) { /* High-Level API */ int mod_initialize(mod_hl* hl) { modem_table_init(&hl->obj); - if (modem_table_std(&hl->obj,hl->init.std,false)) { + if (modem_table_lte(&hl->obj,hl->init.std,false)) { return -1; } diff --git a/lte/phy/lib/modem/src/modem_table.c b/lte/phy/lib/modem/src/modem_table.c index 578b6dc98..e62ca981e 100644 --- a/lte/phy/lib/modem/src/modem_table.c +++ b/lte/phy/lib/modem/src/modem_table.c @@ -33,6 +33,7 @@ #include #include +#include "liblte/phy/common/phy_common.h" #include "liblte/phy/modem/modem_table.h" #include "lte_tables.h" @@ -56,27 +57,27 @@ void modem_table_reset(modem_table_t* q) { modem_table_init(q); } -int modem_table_set(modem_table_t* q, cf_t* table, soft_table_t *soft_table, int nsymbols, int nbits_x_symbol) { +int modem_table_set(modem_table_t* q, cf_t* table, soft_table_t *soft_table, uint32_t nsymbols, uint32_t nbits_x_symbol) { if (q->nsymbols) { - return -1; + return LIBLTE_ERROR; } q->nsymbols = nsymbols; if (table_create(q)) { - return -1; + return LIBLTE_ERROR; } memcpy(q->symbol_table,table,q->nsymbols*sizeof(cf_t)); memcpy(&q->soft_table,soft_table,sizeof(soft_table_t)); q->nbits_x_symbol = nbits_x_symbol; - return 0; + return LIBLTE_SUCCESS; } -int modem_table_std(modem_table_t* q, enum modem_std std, bool compute_soft_demod) { - switch(std) { +int modem_table_lte(modem_table_t* q, lte_mod_t modulation, bool compute_soft_demod) { + switch(modulation) { case LTE_BPSK: q->nbits_x_symbol = 1; q->nsymbols = 2; if (table_create(q)) { - return -1; + return LIBLTE_ERROR; } set_BPSKtable(q->symbol_table, &q->soft_table, compute_soft_demod); break; @@ -84,7 +85,7 @@ int modem_table_std(modem_table_t* q, enum modem_std std, bool compute_soft_dem q->nbits_x_symbol = 2; q->nsymbols = 4; if (table_create(q)) { - return -1; + return LIBLTE_ERROR; } set_QPSKtable(q->symbol_table, &q->soft_table, compute_soft_demod); break; @@ -92,7 +93,7 @@ int modem_table_std(modem_table_t* q, enum modem_std std, bool compute_soft_dem q->nbits_x_symbol = 4; q->nsymbols = 16; if (table_create(q)) { - return -1; + return LIBLTE_ERROR; } set_16QAMtable(q->symbol_table, &q->soft_table, compute_soft_demod); break; @@ -100,10 +101,10 @@ int modem_table_std(modem_table_t* q, enum modem_std std, bool compute_soft_dem q->nbits_x_symbol = 6; q->nsymbols = 64; if (table_create(q)) { - return -1; + return LIBLTE_ERROR; } set_64QAMtable(q->symbol_table, &q->soft_table, compute_soft_demod); break; } - return 0; + return LIBLTE_SUCCESS; } diff --git a/lte/phy/lib/modem/src/soft_algs.c b/lte/phy/lib/modem/src/soft_algs.c index 7268d2a31..9ecd2b599 100644 --- a/lte/phy/lib/modem/src/soft_algs.c +++ b/lte/phy/lib/modem/src/soft_algs.c @@ -51,7 +51,7 @@ * \param sigma2 Noise vatiance */ void llr_approx(const _Complex float *in, float *out, int N, int M, int B, - _Complex float *symbols, int (*S)[6][32], float sigma2) { + _Complex float *symbols, uint32_t (*S)[6][32], float sigma2) { int i, s, b; float num, den; float new_num, new_den; @@ -112,7 +112,7 @@ void llr_approx(const _Complex float *in, float *out, int N, int M, int B, * \param sigma2 Noise vatiance */ void llr_exact(const _Complex float *in, float *out, int N, int M, int B, - _Complex float *symbols, int (*S)[6][32], float sigma2) { + _Complex float *symbols, uint32_t (*S)[6][32], float sigma2) { int i, s, b; float num, den; float idiff0, qdiff0, idiff1, qdiff1; diff --git a/lte/phy/lib/modem/src/soft_algs.h b/lte/phy/lib/modem/src/soft_algs.h index b0e065b4d..c683700a6 100644 --- a/lte/phy/lib/modem/src/soft_algs.h +++ b/lte/phy/lib/modem/src/soft_algs.h @@ -26,8 +26,20 @@ */ -void llr_approx(const _Complex float *in, float *out, int N, int M, int B, - _Complex float *symbols, int (*S)[6][32], float sigma2); +void llr_approx(const _Complex float *in, + float *out, + int N, + int M, + int B, + _Complex float *symbols, + uint32_t (*S)[6][32], + float sigma2); -void llr_exact(const _Complex float *in, float *out, int N, int M, int B, - _Complex float *symbols, int (*S)[6][32], float sigma2); +void llr_exact(const _Complex float *in, + float *out, + int N, + int M, + int B, + _Complex float *symbols, + uint32_t (*S)[6][32], + float sigma2); diff --git a/lte/phy/lib/modem/test/modem_test.c b/lte/phy/lib/modem/test/modem_test.c index 6a483c0a6..0fc09a642 100644 --- a/lte/phy/lib/modem/test/modem_test.c +++ b/lte/phy/lib/modem/test/modem_test.c @@ -37,7 +37,7 @@ #include "liblte/phy/phy.h" int num_bits = 1000; -enum modem_std modulation; +lte_mod_t modulation; bool soft_output = false, soft_exact = false; void usage(char *prog) { @@ -101,7 +101,7 @@ int main(int argc, char **argv) { parse_args(argc, argv); /* initialize objects */ - if (modem_table_std(&mod, modulation, soft_output)) { + if (modem_table_lte(&mod, modulation, soft_output)) { fprintf(stderr, "Error initializing modem table\n"); exit(-1); } diff --git a/lte/phy/lib/phch/src/dci.c b/lte/phy/lib/phch/src/dci.c index ed8ff16fc..df278efa3 100644 --- a/lte/phy/lib/phch/src/dci.c +++ b/lte/phy/lib/phch/src/dci.c @@ -41,6 +41,54 @@ #include "liblte/phy/utils/debug.h" +int dci_msg_to_ra_dl(dci_msg_t *msg, uint16_t msg_rnti, uint16_t c_rnti, + lte_cell_t cell, uint32_t cfi, + ra_pdsch_t *ra_dl) +{ + int ret = LIBLTE_ERROR_INVALID_INPUTS; + + if (msg != NULL && + ra_dl != NULL && + lte_cell_isvalid(&cell) && + cfi > 0 && + cfi < 4) + { + ret = LIBLTE_ERROR; + + dci_msg_type_t type; + if (dci_msg_get_type(msg, &type, cell.nof_prb, msg_rnti, c_rnti)) { + fprintf(stderr, "Can't get DCI message type\n"); + return ret; + } + + if (VERBOSE_ISINFO()) { + dci_msg_type_fprint(stdout, type); + } + if (type.type == PDSCH_SCHED) { + bzero(ra_dl, sizeof(ra_pdsch_t)); + + if (dci_msg_unpack_pdsch(msg, ra_dl, cell.nof_prb, msg_rnti != SIRNTI)) { + fprintf(stderr, "Can't unpack PDSCH message\n"); + return ret; + } + + if (VERBOSE_ISINFO()) { + ra_pdsch_fprint(stdout, ra_dl, cell.nof_prb); + } + + if (ra_prb_get_dl(&ra_dl->prb_alloc, ra_dl, cell.nof_prb)) { + fprintf(stderr, "Error computing resource allocation\n"); + return ret; + } + + ra_prb_get_re_dl(&ra_dl->prb_alloc, cell.nof_prb, cell.nof_ports, cell.nof_prb<10?(cfi+1):cfi, cell.cp); + + ret = LIBLTE_SUCCESS; + } + } + return ret; +} + int dci_location_set(dci_location_t *c, uint32_t L, uint32_t nCCE) { if (L <= 3) { c->L = L; @@ -186,31 +234,10 @@ int dci_format0_pack(ra_pusch_t *data, dci_msg_t *msg, uint32_t nof_prb) { } else { riv = data->type2_alloc.riv; } - bit_pack((uint32_t) riv, &y, riv_nbits(nof_prb) - n_ul_hop); + bit_pack(riv, &y, riv_nbits(nof_prb) - n_ul_hop); /* pack MCS according to 8.6.1 of 36.213 */ - uint32_t mcs; - if (data->cqi_request) { - mcs = 29; - } else { - if (data->rv_idx) { - mcs = 28 + data->rv_idx; - } else { - if (data->mcs.mod == MOD_NULL) { - mcs = data->mcs.mcs_idx; - } 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)); - } - } - mcs = ra_mcs_to_table_idx(&data->mcs); - } - } - } - - bit_pack((uint32_t) mcs, &y, 5); + bit_pack(data->mcs_idx, &y, 5); *y++ = data->ndi; @@ -276,7 +303,7 @@ int dci_format0_unpack(dci_msg_t *msg, ra_pusch_t *data, uint32_t nof_prb) { data->type2_alloc.riv = riv; /* unpack MCS according to 8.6 of 36.213 */ - uint32_t mcs = bit_unpack(&y, 5); + data->mcs_idx = bit_unpack(&y, 5); data->ndi = *y++ ? true : false; @@ -287,20 +314,16 @@ int dci_format0_unpack(dci_msg_t *msg, ra_pusch_t *data, uint32_t nof_prb) { 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)); - } - - // 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; - } - if (mcs > 29) { - // Else leave MOD_NULL and use the previously used PUSCH modulation - data->mcs.mod = MOD_NULL; - data->rv_idx = mcs - 28; + if (data->mcs_idx <= 28) { + ra_mcs_from_idx_ul(data->mcs_idx, ra_nprb_ul(data, nof_prb), &data->mcs); + } else if (data->mcs_idx == 29 && data->cqi_request && ra_nprb_ul(data, nof_prb) <= 4) { + // 8.6.1 and 8.6.2 36.213 second paragraph + data->mcs.mod = LTE_QPSK; + data->mcs.tbs = 0; + } else if (data->mcs_idx >= 29) { + // Else leave TBS and use the previously used PUSCH modulation + data->mcs.tbs = 0; + data->rv_idx = data->mcs_idx - 28; } return LIBLTE_SUCCESS; @@ -340,27 +363,16 @@ int dci_format1_pack(ra_pdsch_t *data, dci_msg_t *msg, uint32_t nof_prb) { return LIBLTE_ERROR; } - /* pack MCS according to 7.1.7 of 36.213 */ - uint32_t mcs; - if (data->mcs.mod == MOD_NULL) { - 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)); - } - mcs = ra_mcs_to_table_idx(&data->mcs); - data->mcs.mcs_idx = mcs; - } - bit_pack((uint32_t) mcs, &y, 5); + /* pack MCS */ + bit_pack(data->mcs_idx, &y, 5); /* harq process number */ - bit_pack((uint32_t) data->harq_process, &y, 3); + bit_pack(data->harq_process, &y, 3); *y++ = data->ndi; // rv version - bit_pack((uint32_t) data->rv_idx, &y, 2); + bit_pack(data->rv_idx, &y, 2); // TPC not implemented *y++ = 0; @@ -412,20 +424,12 @@ int dci_format1_unpack(dci_msg_t *msg, ra_pdsch_t *data, uint32_t nof_prb) { } /* unpack MCS according to 7.1.7 of 36.213 */ - uint32_t mcs = bit_unpack(&y, 5); - data->mcs.mcs_idx = mcs; - if (ra_mcs_from_idx_dl(mcs, &data->mcs)) { + data->mcs_idx = bit_unpack(&y, 5); + if (ra_mcs_from_idx_dl(data->mcs_idx, ra_nprb_dl(data, nof_prb), &data->mcs)) { fprintf(stderr, "Error getting MCS\n"); return LIBLTE_ERROR; } - int t = ra_tbs_from_idx(data->mcs.tbs_idx, ra_nprb_dl(data, nof_prb)); - if (t < 0) { - fprintf(stderr, "Error getting TBS\n"); - return LIBLTE_ERROR; - } - data->mcs.tbs = (uint32_t) t; - /* harq process number */ data->harq_process = bit_unpack(&y, 3); @@ -491,28 +495,12 @@ int dci_format1As_pack(ra_pdsch_t *data, dci_msg_t *msg, uint32_t nof_prb, nb_gap = 1; *y++ = data->type2_alloc.n_gap; } - bit_pack((uint32_t) 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; - if (data->mcs.mod == MOD_NULL) { - mcs = data->mcs.mcs_idx; - } else { - if (data->mcs.tbs) { - // In format 1A, n_prb_1a is 2 or 3 if crc is not scrambled with C-RNTI - uint32_t 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; - } - data->mcs.tbs_idx = ra_tbs_to_table_idx(data->mcs.tbs, n_prb); - } - mcs = data->mcs.tbs_idx; - } - bit_pack((uint32_t) mcs, &y, 5); + bit_pack(data->mcs_idx, &y, 5); - bit_pack((uint32_t) data->harq_process, &y, 3); + bit_pack(data->harq_process, &y, 3); if (!crc_is_crnti && nof_prb >= 50 && data->type2_alloc.mode == t2_dist) { *y++ = data->type2_alloc.n_gap; @@ -521,7 +509,7 @@ int dci_format1As_pack(ra_pdsch_t *data, dci_msg_t *msg, uint32_t nof_prb, } // rv version - bit_pack((uint32_t) data->rv_idx, &y, 2); + bit_pack(data->rv_idx, &y, 2); if (crc_is_crnti) { // TPC not implemented @@ -586,7 +574,7 @@ int dci_format1As_unpack(dci_msg_t *msg, ra_pdsch_t *data, uint32_t nof_prb, data->type2_alloc.riv = riv; // unpack MCS - data->mcs.mcs_idx = bit_unpack(&y, 5); + data->mcs_idx = bit_unpack(&y, 5); data->harq_process = bit_unpack(&y, 3); @@ -597,7 +585,7 @@ int dci_format1As_unpack(dci_msg_t *msg, ra_pdsch_t *data, uint32_t nof_prb, } // rv version - bit_pack((uint32_t) data->rv_idx, &y, 2); + bit_pack(data->rv_idx, &y, 2); if (crc_is_crnti) { // TPC not implemented @@ -607,7 +595,6 @@ int dci_format1As_unpack(dci_msg_t *msg, ra_pdsch_t *data, uint32_t nof_prb, y++; // MSB of TPC is reserved data->type2_alloc.n_prb1a = *y++; // LSB indicates N_prb_1a for TBS } - data->mcs.tbs_idx = data->mcs.mcs_idx; uint32_t n_prb; if (crc_is_crnti) { @@ -615,8 +602,8 @@ int dci_format1As_unpack(dci_msg_t *msg, ra_pdsch_t *data, uint32_t nof_prb, } else { 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; + data->mcs.tbs = ra_tbs_from_idx(data->mcs_idx, n_prb); + data->mcs.mod = LTE_QPSK; return LIBLTE_SUCCESS; } @@ -664,19 +651,10 @@ int dci_format1Cs_pack(ra_pdsch_t *data, dci_msg_t *msg, uint32_t nof_prb) { } else { riv = data->type2_alloc.riv; } - bit_pack((uint32_t) 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; - if (data->mcs.mod == MOD_NULL) { - mcs = data->mcs.mcs_idx; - } else { - if (data->mcs.tbs) { - data->mcs.tbs_idx = ra_tbs_to_table_idx_format1c(data->mcs.tbs); - } - mcs = data->mcs.tbs_idx; - } - bit_pack((uint32_t) mcs, &y, 5); + bit_pack(data->mcs_idx, &y, 5); msg->nof_bits = (y - msg->data); @@ -709,10 +687,9 @@ int dci_format1Cs_unpack(dci_msg_t *msg, ra_pdsch_t *data, uint32_t nof_prb) { data->type2_alloc.RB_start = RB_p * n_step; data->type2_alloc.riv = riv; - data->mcs.mcs_idx = bit_unpack(&y, 5); - data->mcs.tbs_idx = data->mcs.mcs_idx; - data->mcs.tbs = ra_tbs_from_idx_format1c(data->mcs.tbs_idx); - data->mcs.mod = QPSK; + data->mcs_idx = bit_unpack(&y, 5); + data->mcs.tbs = ra_tbs_from_idx_format1c(data->mcs_idx); + data->mcs.mod = LTE_QPSK; msg->nof_bits = (y - msg->data); diff --git a/lte/phy/lib/phch/src/pbch.c b/lte/phy/lib/phch/src/pbch.c index 05d8e8cf5..353dc7639 100644 --- a/lte/phy/lib/phch/src/pbch.c +++ b/lte/phy/lib/phch/src/pbch.c @@ -134,7 +134,7 @@ int pbch_init(pbch_t *q, lte_cell_t cell) { bzero(q, sizeof(pbch_t)); q->cell = cell; - if (modem_table_std(&q->mod, LTE_QPSK, true)) { + if (modem_table_lte(&q->mod, LTE_QPSK, true)) { goto clean; } demod_soft_init(&q->demod); diff --git a/lte/phy/lib/phch/src/pcfich.c b/lte/phy/lib/phch/src/pcfich.c index 8e8b4b3b9..f65d3394e 100644 --- a/lte/phy/lib/phch/src/pcfich.c +++ b/lte/phy/lib/phch/src/pcfich.c @@ -70,7 +70,7 @@ int pcfich_init(pcfich_t *q, regs_t *regs, lte_cell_t cell) { q->cell = cell; q->regs = regs; - if (modem_table_std(&q->mod, LTE_QPSK, false)) { + if (modem_table_lte(&q->mod, LTE_QPSK, false)) { goto clean; } diff --git a/lte/phy/lib/phch/src/pdcch.c b/lte/phy/lib/phch/src/pdcch.c index d46c63d96..111420be4 100644 --- a/lte/phy/lib/phch/src/pdcch.c +++ b/lte/phy/lib/phch/src/pdcch.c @@ -77,7 +77,7 @@ int pdcch_init(pdcch_t *q, regs_t *regs, lte_cell_t cell) { INFO("Init PDCCH: %d bits, %d symbols, %d ports\n", q->max_bits, q->max_bits/2, q->cell.nof_ports); - if (modem_table_std(&q->mod, LTE_QPSK, true)) { + if (modem_table_lte(&q->mod, LTE_QPSK, true)) { goto clean; } if (crc_init(&q->crc, LTE_CRC16, 16)) { @@ -89,7 +89,9 @@ int pdcch_init(pdcch_t *q, regs_t *regs, lte_cell_t cell) { demod_soft_alg_set(&q->demod, APPROX); for (i = 0; i < NSUBFRAMES_X_FRAME; i++) { - if (sequence_pdcch(&q->seq_pdcch[i], 2 * i, q->cell.id, q->max_bits)) { + // we need to pregenerate the sequence for the maximum number of bits, which is 8 times + // the maximum number of REGs (for CFI=3) + if (sequence_pdcch(&q->seq_pdcch[i], 2 * i, q->cell.id, 8*regs_pdcch_nregs(q->regs, 3))) { goto clean; } } @@ -178,7 +180,8 @@ void pdcch_free(pdcch_t *q) { uint32_t pdcch_ue_locations(pdcch_t *q, dci_location_t *c, uint32_t max_candidates, uint32_t nsubframe, uint32_t cfi, uint16_t rnti) { - uint32_t i, k, l, L, m; + int l; // this must be int because of the for(;;--) loop + uint32_t i, k, L, m; uint32_t Yk, ncce; const int S[4] = { 6, 12, 8, 16 }; @@ -198,7 +201,7 @@ uint32_t pdcch_ue_locations(pdcch_t *q, dci_location_t *c, uint32_t max_candidat for (i = 0; i < MIN(q->nof_cce / L, 16 / S[l]); i++) { ncce = L * ((Yk + i) % (q->nof_cce / L)); if (k < max_candidates && - ncce + PDCCH_FORMAT_NOF_CCE(L) < q->nof_cce) + ncce + PDCCH_FORMAT_NOF_CCE(l) <= q->nof_cce) { c[k].L = l; c[k].ncce = ncce; @@ -352,8 +355,8 @@ int pdcch_extract_llr(pdcch_t *q, cf_t *sf_symbols, cf_t *ce[MAX_PORTS], if (location.ncce + PDCCH_FORMAT_NOF_CCE(location.L) <= q->nof_cce) { - INFO("Extracting LLRs: E: %d, nCCE: %d, L: %d\n", - q->e_bits, location.ncce, location.L); + INFO("Extracting LLRs: E: %d, nCCE: %d, L: %d, SF: %d, CFI: %d\n", + q->e_bits, location.ncce, location.L, nsubframe, cfi); /* number of layers equals number of ports */ for (i = 0; i < q->cell.nof_ports; i++) { @@ -518,7 +521,7 @@ int pdcch_encode(pdcch_t *q, dci_msg_t *msg, dci_location_t location, uint16_t r if (VERBOSE_ISDEBUG()) { vec_fprint_b(stdout, q->pdcch_e, q->e_bits); } - + mod_modulate(&q->mod, q->pdcch_e, q->pdcch_d, q->e_bits); /* layer mapping & precoding */ diff --git a/lte/phy/lib/phch/src/pdsch.c b/lte/phy/lib/phch/src/pdsch.c index c43b6c03b..6b92c4e0b 100644 --- a/lte/phy/lib/phch/src/pdsch.c +++ b/lte/phy/lib/phch/src/pdsch.c @@ -46,7 +46,7 @@ -const enum modem_std modulations[4] = +const lte_mod_t modulations[4] = { LTE_BPSK, LTE_QPSK, LTE_QAM16, LTE_QAM64 }; @@ -191,7 +191,7 @@ int pdsch_init(pdsch_t *q, uint16_t user_rnti, lte_cell_t cell) { q->cell.nof_prb, q->max_symbols); for (i = 0; i < 4; i++) { - if (modem_table_std(&q->mod[i], modulations[i], true)) { + if (modem_table_lte(&q->mod[i], modulations[i], true)) { goto clean; } } @@ -220,12 +220,12 @@ int pdsch_init(pdsch_t *q, uint16_t user_rnti, lte_cell_t cell) { } // Allocate floats for reception (LLRs) - q->cb_in = malloc(sizeof(float) * MAX_LONG_CB); + q->cb_in = malloc(sizeof(char) * MAX_LONG_CB); if (!q->cb_in) { goto clean; } - q->cb_out = malloc(sizeof(char) * (3 * MAX_LONG_CB + 12)); + q->cb_out = malloc(sizeof(float) * (3 * MAX_LONG_CB + 12)); if (!q->cb_out) { goto clean; } @@ -417,8 +417,7 @@ int pdsch_harq_setup(pdsch_harq_t *p, ra_mcs_t mcs, ra_prb_t *prb_alloc) { int ret = LIBLTE_ERROR_INVALID_INPUTS; if (p != NULL && - mcs.tbs > 0 && - mcs.mod != MOD_NULL) + mcs.tbs > 0) { uint32_t nof_bits, nof_bits_e, nof_symbols; @@ -429,7 +428,7 @@ int pdsch_harq_setup(pdsch_harq_t *p, ra_mcs_t mcs, ra_prb_t *prb_alloc) { nof_bits = mcs.tbs; nof_symbols = prb_alloc->re_sf[1]; // Any subframe except 0 and 5 has maximum RE - nof_bits_e = nof_symbols * ra_mod_bits_x_symbol(mcs.mod); + nof_bits_e = nof_symbols * lte_mod_bits_x_symbol(mcs.mod); if (nof_bits > nof_bits_e) { fprintf(stderr, "Invalid code rate %.2f\n", (float) nof_bits / nof_bits_e); @@ -506,18 +505,18 @@ int pdsch_decode_tb(pdsch_t *q, char *data, uint32_t tbs, uint32_t nb_e, /* Rate Unmatching */ if (rm_turbo_rx(harq_process->pdsch_w_buff_f[i], harq_process->w_buff_size, &e_bits[rp], n_e, - (float*) q->cb_in, 3 * cb_len + 12, rv_idx)) { + (float*) q->cb_out, 3 * cb_len + 12, rv_idx)) { fprintf(stderr, "Error in rate matching\n"); return LIBLTE_ERROR; } /* Turbo Decoding */ - tdec_run_all(&q->decoder, (float*) q->cb_in, q->cb_out, TDEC_ITERATIONS, + tdec_run_all(&q->decoder, (float*) q->cb_out, q->cb_in, TDEC_ITERATIONS, cb_len); if (harq_process->cb_segm.C > 1) { /* Check Codeblock CRC and stop early if incorrect */ - if (crc_checksum(&q->crc_cb, q->cb_out, cb_len)) { + if (crc_checksum(&q->crc_cb, q->cb_in, cb_len)) { INFO("Error in CB#%d\n",i); return LIBLTE_ERROR; } @@ -525,13 +524,13 @@ int pdsch_decode_tb(pdsch_t *q, char *data, uint32_t tbs, uint32_t nb_e, /* Copy data to another buffer, removing the Codeblock CRC */ if (i < harq_process->cb_segm.C - 1) { - memcpy(&data[wp], &q->cb_out[F], (rlen - F) * sizeof(char)); + memcpy(&data[wp], &q->cb_in[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_out[F], (rlen - F - 24) * sizeof(char)); - memcpy(parity, &q->cb_out[rlen - 24], 24 * sizeof(char)); + memcpy(&data[wp], &q->cb_in[F], (rlen - F - 24) * sizeof(char)); + memcpy(parity, &q->cb_in[rlen - 24], 24 * sizeof(char)); } /* Set read/write pointers */ @@ -552,8 +551,10 @@ int pdsch_decode_tb(pdsch_t *q, char *data, uint32_t tbs, uint32_t nb_e, } if (par_rx == par_tx) { + INFO("TB decoded OK\n",i); return LIBLTE_SUCCESS; } else { + INFO("Error in TB parity\n",i); return LIBLTE_ERROR; } } else { @@ -649,7 +650,6 @@ int pdsch_encode_tb(pdsch_t *q, char *data, uint32_t tbs, uint32_t nb_e, uint32_t par; uint32_t i; uint32_t cb_len, rp, wp, rlen, F, n_e; - char *cb_in = q->cb_in; char *e_bits = q->pdsch_e; if (q != NULL && @@ -673,7 +673,7 @@ int pdsch_encode_tb(pdsch_t *q, char *data, uint32_t tbs, uint32_t nb_e, /* Add filler bits to the new data buffer */ for (i = 0; i < harq_process->cb_segm.F; i++) { - cb_in[i] = LTE_NULL_BIT; + q->cb_in[i] = LTE_NULL_BIT; } } @@ -710,29 +710,29 @@ int pdsch_encode_tb(pdsch_t *q, char *data, uint32_t tbs, uint32_t nb_e, if (rv_idx == 0) { /* Copy data to another buffer, making space for the Codeblock CRC */ if (i < harq_process->cb_segm.C - 1) { - memcpy(&cb_in[F], &data[rp], (rlen - F) * sizeof(char)); + memcpy(&q->cb_in[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(&cb_in[F], &data[rp], (rlen - F - 24) * sizeof(char)); - memcpy(&cb_in[rlen - 24], parity, 24 * sizeof(char)); + memcpy(&q->cb_in[F], &data[rp], (rlen - F - 24) * sizeof(char)); + memcpy(&q->cb_in[rlen - 24], parity, 24 * sizeof(char)); } if (harq_process->cb_segm.C > 1) { /* Attach Codeblock CRC */ - crc_attach(&q->crc_cb, cb_in, rlen); + crc_attach(&q->crc_cb, q->cb_in, rlen); } if (VERBOSE_ISDEBUG()) { DEBUG("CB#%d Len=%d: ", i, cb_len); - vec_fprint_b(stdout, cb_in, cb_len); + vec_fprint_b(stdout, q->cb_in, cb_len); } /* Turbo Encoding */ - tcod_encode(&q->encoder, cb_in, q->cb_out, cb_len); + tcod_encode(&q->encoder, q->cb_in, (char*) q->cb_out, cb_len); } /* Rate matching */ if (rm_turbo_tx(harq_process->pdsch_w_buff_c[i], harq_process->w_buff_size, - q->cb_out, 3 * cb_len + 12, + (char*) q->cb_out, 3 * cb_len + 12, &e_bits[wp], n_e, rv_idx)) { fprintf(stderr, "Error in rate matching\n"); @@ -778,7 +778,7 @@ int pdsch_encode(pdsch_t *q, char *data, cf_t *sf_symbols[MAX_PORTS], uint32_t s nof_symbols = harq_process->prb_alloc.re_sf[subframe]; nof_bits_e = nof_symbols * q->mod[harq_process->mcs.mod - 1].nbits_x_symbol; - if (harq_process->mcs.mod == MOD_NULL) { + if (harq_process->mcs.tbs == 0) { return LIBLTE_ERROR_INVALID_INPUTS; } @@ -807,6 +807,7 @@ int pdsch_encode(pdsch_t *q, char *data, cf_t *sf_symbols[MAX_PORTS], uint32_t s fprintf(stderr, "Error encoding TB\n"); return LIBLTE_ERROR; } + scrambling_b_offset(&q->seq_pdsch[subframe], (char*) q->pdsch_e, 0, nof_bits_e); diff --git a/lte/phy/lib/phch/src/phich.c b/lte/phy/lib/phch/src/phich.c index f9802dfe3..d27765269 100644 --- a/lte/phy/lib/phch/src/phich.c +++ b/lte/phy/lib/phch/src/phich.c @@ -76,7 +76,7 @@ int phich_init(phich_t *q, regs_t *regs, lte_cell_t cell) { q->cell = cell; q->regs = regs; - if (modem_table_std(&q->mod, LTE_BPSK, false)) { + if (modem_table_lte(&q->mod, LTE_BPSK, false)) { goto clean; } diff --git a/lte/phy/lib/phch/src/ra.c b/lte/phy/lib/phch/src/ra.c index cf703ef63..f48ff6324 100644 --- a/lte/phy/lib/phch/src/ra.c +++ b/lte/phy/lib/phch/src/ra.c @@ -391,79 +391,44 @@ uint32_t ra_type2_n_vrb_dl(uint32_t nof_prb, bool ngap_is_1) { } } -/* Converts ra_mcs_t structure to MCS index for both Uplink and Downlink */ -uint32_t ra_mcs_to_table_idx(ra_mcs_t *mcs) { - switch (mcs->mod) { - case QPSK: - return mcs->tbs_idx; - case QAM16: - return mcs->tbs_idx + 1; - case QAM64: - return mcs->tbs_idx + 2; - default: - return LIBLTE_SUCCESS; - } -} - -uint32_t ra_mod_bits_x_symbol(ra_mod_t mod) { - switch(mod) { - case BPSK: - return 1; - case QPSK: - return 2; - case QAM16: - return 4; - case QAM64: - return 6; - default: - return 0; - } - return 0; -} - - /* Converts MCS index to ra_mcs_t structure for Downlink as defined inTable 7.1.7.1-1 on 36.213 */ -int ra_mcs_from_idx_dl(uint32_t idx, ra_mcs_t *mcs) { - if (idx < 10) { - mcs->mod = QPSK; - mcs->tbs_idx = idx; - } else if (idx < 17) { - mcs->mod = QAM16; - mcs->tbs_idx = idx - 1; - } else if (idx < 29) { - mcs->mod = QAM64; - mcs->tbs_idx = idx - 2; - } else if (idx == 29) { - mcs->mod = QPSK; - mcs->tbs_idx = 0; - } else if (idx == 30) { - mcs->mod = QAM16; - mcs->tbs_idx = 0; - } else if (idx == 31) { - mcs->mod = QAM64; - mcs->tbs_idx = 0; +int ra_mcs_from_idx_dl(uint32_t mcs_idx, uint32_t nof_prb, ra_mcs_t *mcs) { + if (mcs_idx < 10) { + mcs->mod = LTE_QPSK; + mcs->tbs = ra_tbs_from_idx(mcs_idx, nof_prb); + } else if (mcs_idx < 17) { + mcs->mod = LTE_QAM16; + mcs->tbs = ra_tbs_from_idx(mcs_idx - 1, nof_prb); + } else if (mcs_idx < 29) { + mcs->mod = LTE_QAM64; + mcs->tbs = ra_tbs_from_idx(mcs_idx - 2, nof_prb); + } else if (mcs_idx == 29) { + mcs->mod = LTE_QPSK; + mcs->tbs = 0; + } else if (mcs_idx == 30) { + mcs->mod = LTE_QAM16; + mcs->tbs = 0; + } else if (mcs_idx == 31) { + mcs->mod = LTE_QAM64; + mcs->tbs = 0; } else { - mcs->mod = MOD_NULL; - mcs->tbs_idx = 0; return LIBLTE_ERROR; } return LIBLTE_SUCCESS; } /* 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(uint32_t idx, ra_mcs_t *mcs) { - if (idx < 11) { - mcs->mod = QPSK; - mcs->tbs_idx = idx; - } else if (idx < 21) { - mcs->mod = QAM16; - mcs->tbs_idx = idx - 1; - } else if (idx < 29) { - mcs->mod = QAM64; - mcs->tbs_idx = idx - 2; +int ra_mcs_from_idx_ul(uint32_t mcs_idx, uint32_t nof_prb, ra_mcs_t *mcs) { + if (mcs_idx < 11) { + mcs->mod = LTE_QPSK; + mcs->tbs = ra_tbs_from_idx(mcs_idx, nof_prb); + } else if (mcs_idx < 21) { + mcs->mod = LTE_QAM16; + mcs->tbs = ra_tbs_from_idx(mcs_idx - 1, nof_prb); + } else if (mcs_idx < 29) { + mcs->mod = LTE_QAM64; + mcs->tbs = ra_tbs_from_idx(mcs_idx - 2, nof_prb); } else { - mcs->mod = MOD_NULL; - mcs->tbs_idx = 0; return LIBLTE_ERROR; } return LIBLTE_SUCCESS; @@ -478,22 +443,6 @@ int ra_tbs_from_idx_format1c(uint32_t tbs_idx) { } } -/* Returns lowest nearest index of TBS value in table 7.1.7.2.2-1 on 36.213 - * or -1 if the TBS value is not within the valid TBS values - */ -int ra_tbs_to_table_idx_format1c(uint32_t tbs) { - int idx; - if (tbs < tbs_format1c_table[0]) { - return LIBLTE_ERROR; - } - for (idx = 1; idx < 32; idx++) { - if (tbs_format1c_table[idx - 1] <= tbs && tbs_format1c_table[idx] >= tbs) { - return idx; - } - } - return LIBLTE_ERROR; -} - /* Downlink Transport Block size determination as defined in 7.1.7.2 on 36.213 */ int ra_tbs_from_idx(uint32_t tbs_idx, uint32_t n_prb) { if (tbs_idx < 27 && n_prb > 0 && n_prb <= MAX_PRB) { @@ -507,7 +456,7 @@ int ra_tbs_from_idx(uint32_t tbs_idx, uint32_t n_prb) { * or -1 if the TBS value is not within the valid TBS values */ int ra_tbs_to_table_idx(uint32_t tbs, uint32_t n_prb) { - int idx; + uint32_t idx; if (n_prb > 0 && n_prb <= MAX_PRB) { return LIBLTE_ERROR; } @@ -522,19 +471,6 @@ int ra_tbs_to_table_idx(uint32_t tbs, uint32_t n_prb) { return LIBLTE_ERROR; } -char *ra_mod_string(ra_mod_t mod) { - switch (mod) { - case QPSK: - return "QPSK"; - case QAM16: - return "QAM16"; - case QAM64: - return "QAM64"; - default: - return "N/A"; - } -} - void ra_pusch_fprint(FILE *f, ra_pusch_t *ra, uint32_t nof_prb) { fprintf(f, "Frequency Hopping:\t"); if (ra->freq_hop_fl == hop_disabled) { @@ -558,15 +494,6 @@ char *ra_type_string(ra_type_t alloc_type) { } } -void ra_pdsch_set_mcs_index(ra_pdsch_t *ra, uint32_t mcs_idx) { - ra->mcs.mod = MOD_NULL; - ra->mcs.mcs_idx = mcs_idx; -} -void ra_pdsch_set_mcs(ra_pdsch_t *ra, ra_mod_t mod, uint32_t tbs_idx) { - ra->mcs.mod = mod; - ra->mcs.tbs_idx = tbs_idx; - ra->mcs.tbs = 0; -} void ra_pdsch_fprint(FILE *f, ra_pdsch_t *ra, uint32_t nof_prb) { fprintf(f, " - Resource Allocation Type:\t\t%s\n", @@ -609,8 +536,8 @@ void ra_pdsch_fprint(FILE *f, ra_pdsch_t *ra, uint32_t nof_prb) { } fprintf(f, " - Number of PRBs:\t\t\t%d\n", ra_nprb_dl(ra, nof_prb)); - fprintf(f, " - Modulation and coding scheme index:\t%d\n", ra->mcs.mcs_idx); - fprintf(f, " - Modulation type:\t\t\t%s\n", ra_mod_string(ra->mcs.mod)); + fprintf(f, " - Modulation and coding scheme index:\t%d\n", ra->mcs_idx); + fprintf(f, " - Modulation type:\t\t\t%s\n", lte_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"); diff --git a/lte/phy/lib/phch/test/pdcch_file_test.c b/lte/phy/lib/phch/test/pdcch_file_test.c index 98ee55743..3f400b662 100644 --- a/lte/phy/lib/phch/test/pdcch_file_test.c +++ b/lte/phy/lib/phch/test/pdcch_file_test.c @@ -292,7 +292,7 @@ int main(int argc, char **argv) { ra_pdsch_fprint(stdout, &ra_dl, cell.nof_prb); if (ra_dl.alloc_type == alloc_type2 && ra_dl.type2_alloc.mode == t2_loc && ra_dl.type2_alloc.riv == 11 && ra_dl.rv_idx == 0 - && ra_dl.harq_process == 0 && ra_dl.mcs.mcs_idx == 2) { + && ra_dl.harq_process == 0 && ra_dl.mcs_idx == 2) { printf("This is the file signal.1.92M.amar.dat\n"); ret = 0; } diff --git a/lte/phy/lib/phch/test/pdcch_test.c b/lte/phy/lib/phch/test/pdcch_test.c index 05704f58e..e0b1717a5 100644 --- a/lte/phy/lib/phch/test/pdcch_test.c +++ b/lte/phy/lib/phch/test/pdcch_test.c @@ -160,7 +160,7 @@ int main(int argc, char **argv) { nof_dcis = 2; bzero(&ra_dl, sizeof(ra_pdsch_t)); ra_dl.harq_process = 0; - ra_pdsch_set_mcs(&ra_dl, QAM16, 5); + ra_dl.mcs_idx = 5; ra_dl.ndi = 0; ra_dl.rv_idx = 0; ra_dl.alloc_type = alloc_type0; @@ -169,7 +169,7 @@ int main(int argc, char **argv) { dci_msg_pack_pdsch(&ra_dl, &dci_tx[0], Format1, cell.nof_prb, false); dci_location_set(&dci_locations[0], 0, 0); - ra_pdsch_set_mcs(&ra_dl, QAM16, 15); + ra_dl.mcs_idx = 15; dci_msg_pack_pdsch(&ra_dl, &dci_tx[1], Format1, cell.nof_prb, false); dci_location_set(&dci_locations[1], 0, 1); diff --git a/lte/phy/lib/phch/test/pdsch_file_test.c b/lte/phy/lib/phch/test/pdsch_file_test.c index fa5a1a822..ac2185471 100644 --- a/lte/phy/lib/phch/test/pdsch_file_test.c +++ b/lte/phy/lib/phch/test/pdsch_file_test.c @@ -223,7 +223,6 @@ void base_free() { int main(int argc, char **argv) { ra_pdsch_t ra_dl; - ra_prb_t prb_alloc; int i; int nof_frames; int ret; @@ -300,39 +299,11 @@ int main(int argc, char **argv) { } if (crc_rem == rnti) { - dci_msg_type_t type; - if (dci_msg_get_type(&dci_msg, &type, cell.nof_prb, rnti, 1234)) { - fprintf(stderr, "Can't get DCI message type\n"); + if (dci_msg_to_ra_dl(&dci_msg, rnti, 1234, cell, cfi, &ra_dl)) { + fprintf(stderr, "Error unpacking PDSCH scheduling DCI message\n"); goto goout; } - - dci_msg_type_fprint(stdout, type); - switch(type.type) { - case PDSCH_SCHED: - bzero(&ra_dl, sizeof(ra_pdsch_t)); - if (dci_msg_unpack_pdsch(&dci_msg, &ra_dl, cell.nof_prb, rnti != SIRNTI)) { - fprintf(stderr, "Can't unpack PDSCH message\n"); - } else { - ra_pdsch_fprint(stdout, &ra_dl, cell.nof_prb); - if (ra_dl.alloc_type == alloc_type2 && ra_dl.type2_alloc.mode == t2_loc - && ra_dl.type2_alloc.riv == 11 && ra_dl.rv_idx == 0 - && ra_dl.harq_process == 0 && ra_dl.mcs.mcs_idx == 2) { - printf("This is the file signal.1.92M.amar.dat\n"); - ret = 0; - } - } - break; - default: - fprintf(stderr, "Unsupported message type\n"); - break; - } - if (ra_prb_get_dl(&prb_alloc, &ra_dl, cell.nof_prb)) { - fprintf(stderr, "Error computing resource allocation\n"); - goto goout; - } - ra_prb_get_re_dl(&prb_alloc, cell.nof_prb, cell.nof_ports, cell.nof_prb<10?(cfi+1):cfi, cell.cp); - - if (pdsch_harq_setup(&harq_process, ra_dl.mcs, &prb_alloc)) { + if (pdsch_harq_setup(&harq_process, ra_dl.mcs, &ra_dl.prb_alloc)) { fprintf(stderr, "Error configuring HARQ process\n"); goto goout; } @@ -348,6 +319,8 @@ int main(int argc, char **argv) { nof_frames++; } while (nof_frames <= max_frames); + ret = 0; + goout: base_free(); exit(ret); diff --git a/lte/phy/lib/phch/test/pdsch_test.c b/lte/phy/lib/phch/test/pdsch_test.c index 40a5b01dd..97c54308d 100644 --- a/lte/phy/lib/phch/test/pdsch_test.c +++ b/lte/phy/lib/phch/test/pdsch_test.c @@ -44,7 +44,7 @@ lte_cell_t cell = { uint32_t cfi = 1; uint32_t tbs = 0; uint32_t subframe = 1; -ra_mod_t modulation = BPSK; +lte_mod_t modulation = LTE_BPSK; uint32_t rv_idx = 0; void usage(char *prog) { @@ -66,16 +66,16 @@ void parse_args(int argc, char **argv) { case 'm': switch(atoi(argv[optind])) { case 1: - modulation = BPSK; + modulation = LTE_BPSK; break; case 2: - modulation = QPSK; + modulation = LTE_QPSK; break; case 4: - modulation = QAM16; + modulation = LTE_QAM16; break; case 6: - modulation = QAM64; + modulation = LTE_QAM64; break; default: fprintf(stderr, "Invalid modulation %d. Possible values: " diff --git a/lte/phy/lib/scrambling/src/scrambling.c b/lte/phy/lib/scrambling/src/scrambling.c index 7ddf9c06f..d6ebead94 100644 --- a/lte/phy/lib/scrambling/src/scrambling.c +++ b/lte/phy/lib/scrambling/src/scrambling.c @@ -36,7 +36,7 @@ void scrambling_f(sequence_t *s, float *data) { } void scrambling_f_offset(sequence_t *s, float *data, int offset, int len) { - int i; + int i; assert (len + offset <= s->len); for (i = 0; i < len; i++) { From 7372d3a3864794cd3bb8c14e202eea858e4e82be Mon Sep 17 00:00:00 2001 From: ismagom Date: Mon, 21 Jul 2014 16:19:17 +0200 Subject: [PATCH 12/14] Fixed PDSCH UE example. Added ue_dl and ue_sync modules. Fixed other minor bugs --- CMakeLists.txt | 7 +- cmake/modules/FindVolk.cmake | 60 +- cuhd/include/liblte/cuhd/cuhd.h | 61 +- cuhd/lib/cuhd_handler.hpp | 8 +- cuhd/lib/cuhd_imp.cpp | 348 ++++---- lte/phy/CMakeLists.txt | 8 +- lte/phy/examples/CMakeLists.txt | 2 +- lte/phy/examples/pdsch_enodeb.c | 6 +- lte/phy/examples/pdsch_ue.c | 766 +++++------------- lte/phy/examples/scan_mib.c | 22 +- lte/phy/examples/scan_pss.c | 22 +- lte/phy/examples/synch_file.c | 10 +- .../include/liblte/phy/ch_estimation/chest.h | 18 +- .../include/liblte/phy/common/phy_common.h | 27 +- lte/phy/include/liblte/phy/phch/pdcch.h | 6 - lte/phy/include/liblte/phy/phch/pdsch.h | 11 +- lte/phy/include/liblte/phy/phch/ue_sync.h | 168 ++++ lte/phy/include/liblte/phy/phy.h | 13 +- .../include/liblte/phy/resampling/interp.h | 66 +- lte/phy/include/liblte/phy/sync/cfo.h | 16 +- lte/phy/include/liblte/phy/sync/pss.h | 58 +- lte/phy/include/liblte/phy/sync/sss.h | 94 ++- lte/phy/include/liblte/phy/sync/sync.h | 68 +- lte/phy/include/liblte/phy/sync/sync_frame.h | 111 --- lte/phy/include/liblte/phy/utils/cexptab.h | 17 +- .../include/liblte/phy/utils/convolution.h | 35 +- lte/phy/include/liblte/phy/utils/vector.h | 63 +- lte/phy/lib/CMakeLists.txt | 38 +- lte/phy/lib/ch_estimation/src/chest.c | 41 +- lte/phy/lib/ch_estimation/test/chest_test.c | 2 +- lte/phy/lib/common/src/phy_common.c | 40 +- lte/phy/lib/phch/src/dci.c | 4 +- lte/phy/lib/phch/src/pdcch.c | 15 +- lte/phy/lib/phch/src/pdsch.c | 320 ++++---- lte/phy/lib/phch/src/ue_sync.c | 555 +++++++++++++ lte/phy/lib/phch/test/CMakeLists.txt | 17 + lte/phy/lib/phch/test/pbch_file_test.c | 2 +- lte/phy/lib/phch/test/pcfich_file_test.c | 2 +- lte/phy/lib/phch/test/pdcch_file_test.c | 2 +- lte/phy/lib/phch/test/pdsch_file_test.c | 5 +- lte/phy/lib/phch/test/pdsch_re_test.c | 3 +- lte/phy/lib/phch/test/pdsch_test.c | 4 +- lte/phy/lib/phch/test/phich_file_test.c | 2 +- lte/phy/lib/resampling/src/interp.c | 175 +++- lte/phy/lib/resampling/test/CMakeLists.txt | 2 + lte/phy/lib/sync/src/cfo.c | 28 +- lte/phy/lib/sync/src/find_sss.c | 114 +-- lte/phy/lib/sync/src/gen_sss.c | 50 +- lte/phy/lib/sync/src/pss.c | 440 ++++------ lte/phy/lib/sync/src/sss.c | 163 ++-- lte/phy/lib/sync/src/sync.c | 322 +++++--- lte/phy/lib/sync/src/sync_frame.c | 244 ------ lte/phy/lib/sync/test/CMakeLists.txt | 1 + lte/phy/lib/sync/test/cfo_test.c | 4 +- lte/phy/lib/sync/test/sync_test.c | 9 +- lte/phy/lib/utils/src/cexptab.c | 20 +- lte/phy/lib/utils/src/convolution.c | 72 +- lte/phy/lib/utils/src/vector.c | 222 ++++- matlab/sync/find_pss.m | 12 - matlab/sync/lte_generate_sss.m | 123 --- matlab/sync/test.m | 35 - 61 files changed, 2849 insertions(+), 2330 deletions(-) create mode 100644 lte/phy/include/liblte/phy/phch/ue_sync.h delete mode 100644 lte/phy/include/liblte/phy/sync/sync_frame.h create mode 100644 lte/phy/lib/phch/src/ue_sync.c delete mode 100644 lte/phy/lib/sync/src/sync_frame.c delete mode 100644 matlab/sync/lte_generate_sss.m delete mode 100644 matlab/sync/test.m diff --git a/CMakeLists.txt b/CMakeLists.txt index 73195b1d5..8abc0c063 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -36,7 +36,7 @@ PROJECT (LIBLTE) LIST(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake/modules") -INCLUDE(libLTEPackage) #setup cpack +INCLUDE(libLTEPackage) #setup cpack include(CTest) set( CTEST_MEMORYCHECK_COMMAND valgrind ) @@ -77,7 +77,10 @@ IF(CMAKE_COMPILER_IS_GNUCXX) ENDIF(CMAKE_COMPILER_IS_GNUCXX) IF(CMAKE_COMPILER_IS_GNUCC) - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror -Wall -Wno-format-extra-args -Winline -Wno-unused-result -Wno-format -std=c99 -D_GNU_SOURCE") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wno-format-extra-args -Winline -Wno-unused-result -Wno-format -std=c99 -D_GNU_SOURCE") + # IF(${CMAKE_BUILD_TYPE} STREQUAL "Debug") + # set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror -Wno-error=implicit-function-declaration -Wno-error=unused-but-set-variable") + # ENDIF(${CMAKE_BUILD_TYPE} STREQUAL "Debug") IF(NOT WIN32) ADD_CXX_COMPILER_FLAG_IF_AVAILABLE(-fvisibility=hidden HAVE_VISIBILITY_HIDDEN) ENDIF(NOT WIN32) diff --git a/cmake/modules/FindVolk.cmake b/cmake/modules/FindVolk.cmake index 7a9cb5349..d9e90e9e4 100644 --- a/cmake/modules/FindVolk.cmake +++ b/cmake/modules/FindVolk.cmake @@ -5,7 +5,7 @@ FIND_PATH( VOLK_INCLUDE_DIRS NAMES volk.h HINTS $ENV{VOLK_DIR}/include/volk - ${CMAKE_INSTALL_PREFIX}/include/volk + ${CMAKE_INSTALL_PREFIX}/include/volk ${PC_VOLK_INCLUDE_DIR} PATHS /usr/local/include/volk /usr/include/volk @@ -15,9 +15,9 @@ FIND_LIBRARY( VOLK_LIBRARIES NAMES volk HINTS $ENV{VOLK_DIR}/lib - ${CMAKE_INSTALL_PREFIX}/lib - ${CMAKE_INSTALL_PREFIX}/lib64 - ${PC_VOLK_LIBDIR} + ${CMAKE_INSTALL_PREFIX}/lib + ${CMAKE_INSTALL_PREFIX}/lib64 + ${PC_VOLK_LIBDIR} PATHS /usr/local/lib /usr/local/lib64 /usr/lib @@ -25,35 +25,71 @@ FIND_LIBRARY( ) # Some functions are not defined in old volk versions -SET(CMAKE_REQUIRED_LIBRARIES volk m) +SET(CMAKE_REQUIRED_LIBRARIES ${VOLK_LIBRARIES} m) CHECK_FUNCTION_EXISTS_MATH(volk_32f_index_max_16u HAVE_VOLK_MAX_FUNCTION) CHECK_FUNCTION_EXISTS_MATH(volk_32f_accumulator_s32f HAVE_VOLK_ACC_FUNCTION) CHECK_FUNCTION_EXISTS_MATH(volk_32fc_s32fc_multiply_32fc HAVE_VOLK_MULT_FUNCTION) CHECK_FUNCTION_EXISTS_MATH(volk_32fc_conjugate_32fc HAVE_VOLK_CONJ_FUNCTION) CHECK_FUNCTION_EXISTS_MATH(volk_32fc_x2_multiply_32fc HAVE_VOLK_MULT2_FUNCTION) +CHECK_FUNCTION_EXISTS_MATH(volk_32fc_32f_multiply_32fc HAVE_VOLK_MULT_REAL_FUNCTION) +CHECK_FUNCTION_EXISTS_MATH(volk_32f_s32f_multiply_32f HAVE_VOLK_MULT_FLOAT_FUNCTION) CHECK_FUNCTION_EXISTS_MATH(volk_32fc_magnitude_32f HAVE_VOLK_MAG_FUNCTION) +CHECK_FUNCTION_EXISTS_MATH(volk_32f_x2_divide_32f HAVE_VOLK_DIVIDE_FUNCTION) +CHECK_FUNCTION_EXISTS_MATH(volk_32fc_32f_dot_prod_32fc HAVE_VOLK_DOTPROD_FC_FUNCTION) +CHECK_FUNCTION_EXISTS_MATH(volk_32f_x2_dot_prod_32f HAVE_VOLK_DOTPROD_F_FUNCTION) +CHECK_FUNCTION_EXISTS_MATH(volk_32fc_s32f_atan2_32f HAVE_VOLK_ATAN_FUNCTION) +CHECK_FUNCTION_EXISTS_MATH(volk_32f_s32f_convert_16i HAVE_VOLK_CONVERT_FI_FUNCTION) +CHECK_FUNCTION_EXISTS_MATH(volk_32fc_deinterleave_32f_x2 HAVE_VOLK_DEINTERLEAVE_FUNCTION) + +CHECK_FUNCTION_EXISTS_MATH(volk_32f_x2_subtract_32f HAVE_VOLK_SUB_FLOAT_FUNCTION) SET(VOLK_DEFINITIONS "HAVE_VOLK") +IF(${HAVE_VOLK_SUB_FLOAT_FUNCTION}) + SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_SUB_FLOAT_FUNCTION") +ENDIF() +IF(${HAVE_VOLK_DEINTERLEAVE_FUNCTION}) + SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_DEINTERLEAVE_FUNCTION") +ENDIF() +IF(${HAVE_VOLK_CONVERT_FI_FUNCTION}) + SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_CONVERT_FI_FUNCTION") +ENDIF() IF(${HAVE_VOLK_MAX_FUNCTION}) - SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_MAX_FUNCTION") + SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_MAX_FUNCTION") ENDIF() IF(${HAVE_VOLK_ACC_FUNCTION}) - SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_ACC_FUNCTION") + SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_ACC_FUNCTION") ENDIF() IF(${HAVE_VOLK_MULT_FUNCTION}) - SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_MULT_FUNCTION") + SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_MULT_FUNCTION") ENDIF() IF(${HAVE_VOLK_CONJ_FUNCTION}) - SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_CONJ_FUNCTION") + SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_CONJ_FUNCTION") ENDIF() IF(${HAVE_VOLK_MULT2_FUNCTION}) - SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_MULT2_FUNCTION") + SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_MULT2_FUNCTION") +ENDIF() +IF(${HAVE_VOLK_MULT_FLOAT_FUNCTION}) + SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_MULT_FLOAT_FUNCTION") +ENDIF() +IF(${HAVE_VOLK_MULT_REAL_FUNCTION}) + SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_MULT_REAL_FUNCTION") ENDIF() IF(${HAVE_VOLK_MAG_FUNCTION}) - SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_MAG_FUNCTION") + SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_MAG_FUNCTION") +ENDIF() +IF(${HAVE_VOLK_DIVIDE_FUNCTION}) + SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_DIVIDE_FUNCTION") +ENDIF() +IF(${HAVE_VOLK_DOTPROD_FC_FUNCTION}) + SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_DOTPROD_FC_FUNCTION") +ENDIF() +IF(${HAVE_VOLK_DOTPROD_F_FUNCTION}) + SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_DOTPROD_F_FUNCTION") +ENDIF() +IF(${HAVE_VOLK_ATAN_FUNCTION}) + SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_ATAN_FUNCTION") ENDIF() - INCLUDE(FindPackageHandleStandardArgs) FIND_PACKAGE_HANDLE_STANDARD_ARGS(VOLK DEFAULT_MSG VOLK_LIBRARIES VOLK_INCLUDE_DIRS) MARK_AS_ADVANCED(VOLK_LIBRARIES VOLK_INCLUDE_DIRS VOLK_DEFINITIONS) diff --git a/cuhd/include/liblte/cuhd/cuhd.h b/cuhd/include/liblte/cuhd/cuhd.h index d67c2eba1..48da5883d 100644 --- a/cuhd/include/liblte/cuhd/cuhd.h +++ b/cuhd/include/liblte/cuhd/cuhd.h @@ -31,26 +31,63 @@ extern "C" { #endif #include - +#include + #include "liblte/config.h" #include "liblte/cuhd/cuhd_utils.h" -LIBLTE_API int cuhd_open(char *args, void **handler); +LIBLTE_API int cuhd_open(char *args, + void **handler); + LIBLTE_API int cuhd_close(void *h); LIBLTE_API int cuhd_start_rx_stream(void *h); -LIBLTE_API int cuhd_start_rx_stream_nsamples(void *h, int nsamples); + +LIBLTE_API int cuhd_start_rx_stream_nsamples(void *h, + uint32_t nsamples); + LIBLTE_API int cuhd_stop_rx_stream(void *h); + LIBLTE_API bool cuhd_rx_wait_lo_locked(void *h); -LIBLTE_API double cuhd_set_rx_srate(void *h, double freq); -LIBLTE_API double cuhd_set_rx_gain(void *h, double gain); -LIBLTE_API double cuhd_set_rx_freq(void *h, double freq); -LIBLTE_API int cuhd_recv(void *h, void *data, int nsamples, int blocking); - -LIBLTE_API double cuhd_set_tx_srate(void *h, double freq); -LIBLTE_API double cuhd_set_tx_gain(void *h, double gain); -LIBLTE_API double cuhd_set_tx_freq(void *h, double freq); -LIBLTE_API int cuhd_send(void *h, void *data, int nsamples, int blocking); + +LIBLTE_API double cuhd_set_rx_srate(void *h, + double freq); + +LIBLTE_API double cuhd_set_rx_gain(void *h, + double gain); + +LIBLTE_API double cuhd_set_rx_freq(void *h, + double freq); + +LIBLTE_API double cuhd_set_rx_freq_offset(void *h, + double freq, + double off); + +LIBLTE_API int cuhd_recv(void *h, + void *data, + uint32_t nsamples, + bool blocking); + +LIBLTE_API int cuhd_recv_timed(void *h, + void *data, + uint32_t nsamples, + bool blocking, + time_t *secs, + double *frac_secs); + +LIBLTE_API double cuhd_set_tx_srate(void *h, + double freq); + +LIBLTE_API double cuhd_set_tx_gain(void *h, + double gain); + +LIBLTE_API double cuhd_set_tx_freq(void *h, + double freq); + +LIBLTE_API int cuhd_send(void *h, + void *data, + uint32_t nsamples, + bool blocking); #ifdef __cplusplus diff --git a/cuhd/lib/cuhd_handler.hpp b/cuhd/lib/cuhd_handler.hpp index 349117a88..8e3ecedd6 100644 --- a/cuhd/lib/cuhd_handler.hpp +++ b/cuhd/lib/cuhd_handler.hpp @@ -30,9 +30,9 @@ class cuhd_handler { public: - uhd::usrp::multi_usrp::sptr usrp; - uhd::rx_streamer::sptr rx_stream; - bool rx_stream_enable; - uhd::tx_streamer::sptr tx_stream; + uhd::usrp::multi_usrp::sptr usrp; + uhd::rx_streamer::sptr rx_stream; + bool rx_stream_enable; + uhd::tx_streamer::sptr tx_stream; }; diff --git a/cuhd/lib/cuhd_imp.cpp b/cuhd/lib/cuhd_imp.cpp index 626415f7e..ca98b9e2e 100644 --- a/cuhd/lib/cuhd_imp.cpp +++ b/cuhd/lib/cuhd_imp.cpp @@ -35,8 +35,9 @@ #include "liblte/cuhd/cuhd.h" -void my_handler(uhd::msg::type_t type, const std::string &msg){ - //handle the message... +void my_handler(uhd::msg::type_t type, const std::string & msg) +{ + //handle the message... } typedef _Complex float complex_t; @@ -45,161 +46,216 @@ typedef _Complex float complex_t; bool isLocked(void *h) { - cuhd_handler* handler = static_cast(h); - std::vector mb_sensors = handler->usrp->get_mboard_sensor_names(); - std::vector rx_sensors = handler->usrp->get_rx_sensor_names(0); - if(std::find(rx_sensors.begin(), rx_sensors.end(), "lo_locked") != rx_sensors.end()) { - return handler->usrp->get_rx_sensor("lo_locked", 0).to_bool(); - } - else if(std::find(mb_sensors.begin(), mb_sensors.end(), "ref_locked") != mb_sensors.end()) { - return handler->usrp->get_mboard_sensor("ref_locked", 0).to_bool(); - } - else { - usleep(500); - return true; - } + cuhd_handler *handler = static_cast < cuhd_handler * >(h); + std::vector < std::string > mb_sensors = + handler->usrp->get_mboard_sensor_names(); + std::vector < std::string > rx_sensors = + handler->usrp->get_rx_sensor_names(0); + if (std::find(rx_sensors.begin(), rx_sensors.end(), "lo_locked") != + rx_sensors.end()) { + return handler->usrp->get_rx_sensor("lo_locked", 0).to_bool(); + } else if (std::find(mb_sensors.begin(), mb_sensors.end(), "ref_locked") != + mb_sensors.end()) { + return handler->usrp->get_mboard_sensor("ref_locked", 0).to_bool(); + } else { + usleep(500); + return true; + } } bool cuhd_rx_wait_lo_locked(void *h) { - double report = 0.0; - while(isLocked(h) && report < 3.0) - { - report += 0.1; - usleep(1000); - } - return isLocked(h); + double report = 0.0; + while (isLocked(h) && report < 3.0) { + report += 0.1; + usleep(1000); + } + return isLocked(h); +} + +int cuhd_start_rx_stream(void *h) +{ + cuhd_handler *handler = static_cast < cuhd_handler * >(h); + uhd::stream_cmd_t cmd(uhd::stream_cmd_t::STREAM_MODE_START_CONTINUOUS); + cmd.time_spec = handler->usrp->get_time_now(); + cmd.stream_now = true; + handler->usrp->issue_stream_cmd(cmd); + return 0; +} + +int cuhd_stop_rx_stream(void *h) +{ + cuhd_handler *handler = static_cast < cuhd_handler * >(h); + uhd::stream_cmd_t cmd(uhd::stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS); + cmd.time_spec = handler->usrp->get_time_now(); + cmd.stream_now = true; + handler->usrp->issue_stream_cmd(cmd); + return 0; +} + +int cuhd_start_rx_stream_nsamples(void *h, uint32_t nsamples) +{ + cuhd_handler *handler = static_cast < cuhd_handler * >(h); + uhd::stream_cmd_t cmd(uhd::stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_MORE); + cmd.time_spec = handler->usrp->get_time_now(); + cmd.stream_now = true; + cmd.num_samps = nsamples; + handler->usrp->issue_stream_cmd(cmd); + return 0; +} + +int cuhd_open(char *args, void **h) +{ + cuhd_handler *handler = new cuhd_handler(); + std::string _args = std::string(args); + handler->usrp = uhd::usrp::multi_usrp::make(_args + ", master_clock_rate=30720000"); + + handler->usrp->set_clock_source("internal"); + + std::string otw, cpu; + otw = "sc16"; + cpu = "fc32"; + uhd::stream_args_t stream_args(cpu, otw); + handler->rx_stream = handler->usrp->get_rx_stream(stream_args); + handler->tx_stream = handler->usrp->get_tx_stream(stream_args); + + *h = handler; + + return 0; +} + +int cuhd_close(void *h) +{ + cuhd_stop_rx_stream(h); + /** Something else to close the USRP?? */ + return 0; +} + + +double cuhd_set_rx_srate(void *h, double freq) +{ + cuhd_handler *handler = static_cast < cuhd_handler * >(h); + handler->usrp->set_rx_rate(freq); + double ret = handler->usrp->get_rx_rate(); + return ret; } -int cuhd_start_rx_stream(void *h) { - cuhd_handler* handler = static_cast(h); - uhd::stream_cmd_t cmd(uhd::stream_cmd_t::STREAM_MODE_START_CONTINUOUS); - cmd.time_spec = handler->usrp->get_time_now(); - cmd.stream_now = true; - handler->usrp->issue_stream_cmd(cmd); - return 0; +double cuhd_set_rx_gain(void *h, double gain) +{ + cuhd_handler *handler = static_cast < cuhd_handler * >(h); + handler->usrp->set_rx_gain(gain); + return handler->usrp->get_rx_gain(); } -int cuhd_stop_rx_stream(void *h) { - cuhd_handler* handler = static_cast(h); - uhd::stream_cmd_t cmd(uhd::stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS); - cmd.time_spec = handler->usrp->get_time_now(); - cmd.stream_now = true; - handler->usrp->issue_stream_cmd(cmd); - return 0; +double cuhd_set_rx_freq(void *h, double freq) +{ + cuhd_handler *handler = static_cast < cuhd_handler * >(h); + handler->usrp->set_rx_freq(freq); + return handler->usrp->get_rx_freq(); } -int cuhd_start_rx_stream_nsamples(void *h, int nsamples) { - cuhd_handler* handler = static_cast(h); - uhd::stream_cmd_t cmd(uhd::stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_MORE); - cmd.time_spec = handler->usrp->get_time_now(); - cmd.stream_now = true; - cmd.num_samps = nsamples; - handler->usrp->issue_stream_cmd(cmd); - return 0; +double cuhd_set_rx_freq_offset(void *h, double freq, double off) { + cuhd_handler* handler = static_cast(h); + handler->usrp->set_rx_freq(uhd::tune_request_t(freq,off)); + return handler->usrp->get_rx_freq(); } -int cuhd_open(char *args, void **h) { - cuhd_handler* handler = new cuhd_handler(); - std::string _args=std::string(args); - handler->usrp = uhd::usrp::multi_usrp::make(_args); - - // Try to set LTE clock - handler->usrp->set_master_clock_rate(30720000); - - handler->usrp->set_clock_source("internal"); - - std::string otw, cpu; - otw="sc16"; - cpu="fc32"; - uhd::stream_args_t stream_args(cpu, otw); - handler->rx_stream = handler->usrp->get_rx_stream(stream_args); - handler->tx_stream = handler->usrp->get_tx_stream(stream_args); - - *h = handler; - - return 0; -} - -int cuhd_close(void *h) { - cuhd_stop_rx_stream(h); - /** Something else to close the USRP?? */ - return 0; -} - - -double cuhd_set_rx_srate(void *h, double freq) { - cuhd_handler* handler = static_cast(h); - handler->usrp->set_rx_rate(freq); - double ret = handler->usrp->get_rx_rate(); - return ret; -} - -double cuhd_set_rx_gain(void *h, double gain) { - cuhd_handler* handler = static_cast(h); - handler->usrp->set_rx_gain(gain); - return handler->usrp->get_rx_gain(); -} - -double cuhd_set_rx_freq(void *h, double freq) { - cuhd_handler* handler = static_cast(h); - handler->usrp->set_rx_freq(freq); - return handler->usrp->get_rx_freq(); -} - -int cuhd_recv(void *h, void *data, int nsamples, int blocking) { - cuhd_handler* handler = static_cast(h); - uhd::rx_metadata_t md; - if (blocking) { - int n=0,p; - complex_t *data_c = (complex_t*) data; - do { - p=handler->rx_stream->recv(&data_c[n], nsamples-n, md); - if (p == -1) { - return -1; - } - n+=p; - } while(nrx_stream->recv(data, nsamples, md, 0.0); - } -} - -double cuhd_set_tx_gain(void *h, double gain) { - cuhd_handler* handler = static_cast(h); - handler->usrp->set_tx_gain(gain); - return handler->usrp->get_tx_gain(); -} - -double cuhd_set_tx_srate(void *h, double freq) { - cuhd_handler* handler = static_cast(h); - handler->usrp->set_tx_rate(freq); - return handler->usrp->get_tx_rate(); -} - -double cuhd_set_tx_freq(void *h, double freq) { - cuhd_handler* handler = static_cast(h); - handler->usrp->set_tx_freq(freq); - return handler->usrp->get_tx_freq(); -} - -int cuhd_send(void *h, void *data, int nsamples, int blocking) { - cuhd_handler* handler = static_cast(h); - uhd::tx_metadata_t md; - if (blocking) { - int n=0,p; - complex_t *data_c = (complex_t*) data; - do { - p=handler->tx_stream->send(&data_c[n], nsamples-n, md); - if (p == -1) { - return -1; - } - n+=p; - } while(ntx_stream->send(data, nsamples, md, 0.0); - } +int cuhd_recv(void *h, void *data, uint32_t nsamples, bool blocking) +{ + cuhd_handler *handler = static_cast < cuhd_handler * >(h); + uhd::rx_metadata_t md; + if (blocking) { + int n = 0, p; + complex_t *data_c = (complex_t *) data; + do { + p = handler->rx_stream->recv(&data_c[n], nsamples - n, md); + if (p == -1) { + return -1; + } + n += p; + if (md.error_code != uhd::rx_metadata_t::ERROR_CODE_NONE) { + std::cout << "\nError code: " << md.to_pp_string() << "\n\n"; + } + } while (n < nsamples); + return nsamples; + } else { + return handler->rx_stream->recv(data, nsamples, md, 0.0); + } +} + +int cuhd_recv_timed(void *h, + void *data, + uint32_t nsamples, + int blocking, + time_t *secs, + double *frac_secs) { + cuhd_handler* handler = static_cast(h); + uhd::rx_metadata_t md; + *secs = -1; + *frac_secs = -1; + int p; + if (blocking) { + int n=0; + complex_t *data_c = (complex_t*) data; + do { + p=handler->rx_stream->recv(&data_c[n], nsamples-n, md); + if (p == -1) { + return -1; + } + if(*secs < 0){ + *secs = md.time_spec.get_full_secs(); + *frac_secs = md.time_spec.get_frac_secs(); + } + n+=p; + } while(nrx_stream->recv(data, nsamples, md, 0.0); + *secs = md.time_spec.get_full_secs(); + *frac_secs = md.time_spec.get_frac_secs(); + return p; + } +} + + +double cuhd_set_tx_gain(void *h, double gain) +{ + cuhd_handler *handler = static_cast < cuhd_handler * >(h); + handler->usrp->set_tx_gain(gain); + return handler->usrp->get_tx_gain(); +} + +double cuhd_set_tx_srate(void *h, double freq) +{ + cuhd_handler *handler = static_cast < cuhd_handler * >(h); + handler->usrp->set_tx_rate(freq); + return handler->usrp->get_tx_rate(); +} + +double cuhd_set_tx_freq(void *h, double freq) +{ + cuhd_handler *handler = static_cast < cuhd_handler * >(h); + handler->usrp->set_tx_freq(freq); + return handler->usrp->get_tx_freq(); +} + +int cuhd_send(void *h, void *data, uint32_t nsamples, bool blocking) +{ + cuhd_handler *handler = static_cast < cuhd_handler * >(h); + uhd::tx_metadata_t md; + if (blocking) { + int n = 0, p; + complex_t *data_c = (complex_t *) data; + do { + p = handler->tx_stream->send(&data_c[n], nsamples - n, md); + if (p == -1) { + return -1; + } + n += p; + } while (n < nsamples); + return nsamples; + } else { + return handler->tx_stream->send(data, nsamples, md, 0.0); + } } diff --git a/lte/phy/CMakeLists.txt b/lte/phy/CMakeLists.txt index 77373e308..886b9d311 100644 --- a/lte/phy/CMakeLists.txt +++ b/lte/phy/CMakeLists.txt @@ -34,10 +34,10 @@ INSTALL(DIRECTORY include/ SET(HEADERS_ALL "") FILE(GLOB headers *) FOREACH (_header ${headers}) - IF(IS_DIRECTORY ${_header}) - FILE(GLOB_RECURSE tmp "${_header}/*.h") - LIST(APPEND HEADERS_ALL ${tmp}) - ENDIF(IS_DIRECTORY ${_header}) + IF(IS_DIRECTORY ${_header}) + FILE(GLOB_RECURSE tmp "${_header}/*.h") + LIST(APPEND HEADERS_ALL ${tmp}) + ENDIF(IS_DIRECTORY ${_header}) ENDFOREACH() ADD_CUSTOM_TARGET (add_lte_headers SOURCES ${HEADERS_ALL}) diff --git a/lte/phy/examples/CMakeLists.txt b/lte/phy/examples/CMakeLists.txt index a599920ec..b14924cc7 100644 --- a/lte/phy/examples/CMakeLists.txt +++ b/lte/phy/examples/CMakeLists.txt @@ -51,7 +51,7 @@ LIST(FIND OPTIONAL_LIBS graphics GRAPHICS_FIND) # These two can be compiled without UHD or graphics support ################################################################# -add_executable(pdsch_ue pdsch_ue.c) +add_executable(pdsch_ue pdsch_ue.c iodev.c) target_link_libraries(pdsch_ue lte_phy) add_executable(pdsch_enodeb pdsch_enodeb.c) diff --git a/lte/phy/examples/pdsch_enodeb.c b/lte/phy/examples/pdsch_enodeb.c index 78633c6b4..7aeb435f2 100644 --- a/lte/phy/examples/pdsch_enodeb.c +++ b/lte/phy/examples/pdsch_enodeb.c @@ -189,11 +189,13 @@ void base_init() { exit(-1); } - if (pdsch_init(&pdsch, 1234, cell)) { + if (pdsch_init(&pdsch, cell)) { fprintf(stderr, "Error creating PDSCH object\n"); exit(-1); } + pdsch_set_rnti(&pdsch, 1234); + if (pdsch_harq_init(&harq_process, &pdsch)) { fprintf(stderr, "Error initiating HARQ process\n"); exit(-1); @@ -365,7 +367,7 @@ int main(int argc, char **argv) { } else { #ifndef DISABLE_UHD vec_sc_prod_cfc(output_buffer, uhd_amp, output_buffer, sf_n_samples); - cuhd_send(uhd, output_buffer, sf_n_samples, 1); + cuhd_send(uhd, output_buffer, sf_n_samples, true); #endif } nf++; diff --git a/lte/phy/examples/pdsch_ue.c b/lte/phy/examples/pdsch_ue.c index 9ec8c8885..70b6cb121 100644 --- a/lte/phy/examples/pdsch_ue.c +++ b/lte/phy/examples/pdsch_ue.c @@ -37,83 +37,59 @@ #include #include "liblte/phy/phy.h" - -#ifndef DISABLE_UHD -#include "liblte/cuhd/cuhd.h" -void *uhd; -#endif +#include "iodev.h" #ifndef DISABLE_GRAPHICS -#include "liblte/graphics/plot.h" -plot_real_t poutfft; -plot_complex_t pce; -plot_scatter_t pscatrecv, pscatequal; +void init_plots(); +void do_plots(ue_dl_t *q, uint32_t sf_idx); #endif -#define MHZ 1000000 -#define SAMP_FREQ 1920000 - -#define NOF_PORTS 2 - -float find_threshold = 9.0; -int nof_frames = -1; -int pkt_errors = 0, pkts_total = 0; -int frame_cnt; -char *input_file_name = NULL; -int disable_plots = 0; - -/* These are the number of PRBs used during the SYNC procedure */ -int sampling_nof_prb = 6; - -/* Number of samples in a subframe */ -int sf_n_samples; - -lte_cell_t cell; - -uint32_t cell_id_file = 1; - -int cell_id_initated = 0, mib_initiated = 0; -int frame_number; - -bool pbch_only = false; - int go_exit = 0; -float uhd_freq = 2600000000.0, uhd_gain = 20.0; -char *uhd_args = ""; - -filesource_t fsrc; -cf_t *input_buffer, *sf_buffer, *fft_buffer, *input_decim_buffer, *ce[MAX_PORTS]; -float *tmp_plot; -pbch_t pbch; -pcfich_t pcfich; -pdcch_t pdcch; -pdsch_t pdsch; -pdsch_harq_t harq_process; -regs_t regs; -lte_fft_t fft; -chest_t chest; -sync_frame_t sframe; - -#define CLRSTDOUT printf("\r\n"); fflush(stdout); printf("\r\n") - -#define DOWNSAMPLE_FACTOR(x, y) lte_symbol_sz(x) / lte_symbol_sz(y) +/* Local function definitions */ +void init_plots(); + +/********************************************************************** + * Program arguments processing + ***********************************************************************/ +typedef struct { + uint32_t cell_id_file; + uint32_t nof_prb_file; + uint16_t rnti; + int nof_subframes; + bool disable_plots; + bool pbch_only; + iodev_cfg_t io_config; +}prog_args_t; + +void args_default(prog_args_t *args) { + args->cell_id_file = 1; + args->nof_prb_file = 6; + args->rnti = SIRNTI; + args->nof_subframes = -1; + args->disable_plots = false; + args->pbch_only = false; + args->io_config.find_threshold = -1.0; + args->io_config.input_file_name = NULL; + args->io_config.uhd_args = ""; + args->io_config.uhd_freq = -1.0; + args->io_config.uhd_gain = 20.0; +} -void usage(char *prog) { - printf("Usage: %s [icagfndvtpb]\n", prog); - printf("\t-i input_file [Default use USRP]\n"); - printf("\t-c cell_id if reading from file [Default %d]\n", cell_id_file); +void usage(prog_args_t *args, char *prog) { + printf("Usage: %s [cargfndvtb] [-i input_file | -f rx_frequency (in Hz)]\n", prog); + printf("\t-c cell_id if reading from file [Default %d]\n", args->cell_id_file); + printf("\t-p nof_prb if reading from file [Default %d]\n", args->nof_prb_file); + printf("\t-r RNTI to look for [Default 0x%x]\n", args->rnti); #ifndef DISABLE_UHD - printf("\t-a UHD args [Default %s]\n", uhd_args); - printf("\t-g UHD RX gain [Default %.2f dB]\n", uhd_gain); - printf("\t-f UHD RX frequency [Default %.1f MHz]\n", uhd_freq / 1000000); + printf("\t-a UHD args [Default %s]\n", args->io_config.uhd_args); + printf("\t-g UHD RX gain [Default %.2f dB]\n", args->io_config.uhd_gain); #else printf("\t UHD is disabled. CUHD library not available\n"); #endif - printf("\t-b Decode PBCH only [Default All]\n"); - printf("\t-p sampling_nof_prb [Default %d]\n", sampling_nof_prb); - printf("\t-n nof_frames [Default %d]\n", nof_frames); - printf("\t-t PSS threshold [Default %f]\n", find_threshold); + printf("\t-b Decode PBCH only [Default All channels]\n"); + printf("\t-n nof_subframes [Default %d]\n", args->nof_subframes); + printf("\t-t PSS threshold [Default %f]\n", args->io_config.find_threshold); #ifndef DISABLE_GRAPHICS printf("\t-d disable plots [Default enabled]\n"); #else @@ -122,585 +98,219 @@ void usage(char *prog) { printf("\t-v [set verbose to debug, default none]\n"); } -void parse_args(int argc, char **argv) { +void parse_args(prog_args_t *args, int argc, char **argv) { int opt; - while ((opt = getopt(argc, argv, "icagfndvtpb")) != -1) { + args_default(args); + while ((opt = getopt(argc, argv, "icagfndvtbp")) != -1) { switch (opt) { case 'i': - input_file_name = argv[optind]; + args->io_config.input_file_name = argv[optind]; break; case 'c': - cell_id_file = atoi(argv[optind]); + args->cell_id_file = atoi(argv[optind]); + break; + case 'p': + args->nof_prb_file = atoi(argv[optind]); break; case 'a': - uhd_args = argv[optind]; + args->io_config.uhd_args = argv[optind]; break; case 'g': - uhd_gain = atof(argv[optind]); + args->io_config.uhd_gain = atof(argv[optind]); break; case 'f': - uhd_freq = atof(argv[optind]); + args->io_config.uhd_freq = atof(argv[optind]); break; case 'b': - pbch_only = true; + args->pbch_only = true; break; case 't': - find_threshold = atof(argv[optind]); - break; - case 'p': - sampling_nof_prb = atof(argv[optind]); + args->io_config.find_threshold = atof(argv[optind]); break; case 'n': - nof_frames = atoi(argv[optind]); + args->nof_subframes = atoi(argv[optind]); break; case 'd': - disable_plots = 1; + args->disable_plots = true; break; case 'v': verbose++; break; default: - usage(argv[0]); + usage(args, argv[0]); exit(-1); } } -} - -#ifndef DISABLE_GRAPHICS - -void init_plots() { - plot_init(); - plot_real_init(&poutfft); - plot_real_setTitle(&poutfft, "Output FFT - Magnitude"); - plot_real_setLabels(&poutfft, "Index", "dB"); - plot_real_setYAxisScale(&poutfft, -60, 0); - plot_real_setXAxisScale(&poutfft, 1, 504); - - plot_complex_init(&pce); - plot_complex_setTitle(&pce, "Channel Estimates"); - plot_complex_setYAxisScale(&pce, Ip, -0.01, 0.01); - plot_complex_setYAxisScale(&pce, Q, -0.01, 0.01); - plot_complex_setYAxisScale(&pce, Magnitude, 0, 0.01); - plot_complex_setYAxisScale(&pce, Phase, -M_PI, M_PI); - - plot_scatter_init(&pscatrecv); - plot_scatter_setTitle(&pscatrecv, "Received Symbols"); - plot_scatter_setXAxisScale(&pscatrecv, -0.01, 0.01); - plot_scatter_setYAxisScale(&pscatrecv, -0.01, 0.01); - - plot_scatter_init(&pscatequal); - plot_scatter_setTitle(&pscatequal, "Equalized Symbols"); - plot_scatter_setXAxisScale(&pscatequal, -1, 1); - plot_scatter_setYAxisScale(&pscatequal, -1, 1); -} - -#endif - - -/* This function initializes the objects defined as global variables */ -int base_init(int nof_prb) { - int i; - - int sf_n_re = 2 * CPNORM_NSYMB * nof_prb * RE_X_RB; - int sf_n_samples = 2 * SLOT_LEN_CPNORM(lte_symbol_sz(nof_prb)); - - -#ifndef DISABLE_GRAPHICS - if (!disable_plots) { - tmp_plot = malloc(sizeof(cf_t) * sf_n_re); - if (!tmp_plot) { - perror("malloc"); - return -1; - } - init_plots(); + if (args->io_config.uhd_freq < 0 && args->io_config.input_file_name == NULL) { + usage(args, argv[0]); } -#else - printf("-- PLOTS are disabled. Graphics library not available --\n\n"); -#endif - - if (input_file_name) { - if (filesource_init(&fsrc, input_file_name, COMPLEX_FLOAT_BIN)) { - return -1; - } - } else { - /* open UHD device */ -#ifndef DISABLE_UHD - printf("Opening UHD device...\n"); - if (cuhd_open(uhd_args, &uhd)) { - fprintf(stderr, "Error opening uhd\n"); - return -1; - } -#else - printf("Error UHD not available. Select an input file\n"); - return -1; -#endif - } - - /* For the input buffer, we allocate space for 1 ms of samples */ - input_buffer = (cf_t*) malloc(sf_n_samples * sizeof(cf_t)); - if (!input_buffer) { - perror("malloc"); - return -1; - } - - input_decim_buffer = (cf_t*) malloc(sf_n_samples * sizeof(cf_t)); - if (!input_decim_buffer) { - perror("malloc"); - return -1; - } - - /* This buffer is the aligned version of input_buffer */ - sf_buffer = (cf_t*) malloc(sf_n_samples * sizeof(cf_t)); - if (!sf_buffer) { - perror("malloc"); - return -1; - } - - /* For the rest of the buffers, we allocate for the number of RE in one subframe */ - fft_buffer = (cf_t*) malloc(sf_n_re * sizeof(cf_t)); - if (!fft_buffer) { - perror("malloc"); - return -1; - } - - for (i = 0; i < MAX_PORTS; i++) { - ce[i] = (cf_t*) malloc(sf_n_re * sizeof(cf_t)); - if (!ce[i]) { - perror("malloc"); - return -1; - } - } - - if (sync_frame_init(&sframe, DOWNSAMPLE_FACTOR(nof_prb,6))) { - fprintf(stderr, "Error initiating PSS/SSS\n"); - return -1; - } - - if (chest_init(&chest, LINEAR, nof_prb * RE_X_RB, CPNORM_NSYMB, NOF_PORTS)) { - fprintf(stderr, "Error initializing equalizer\n"); - return -1; - } - - if (lte_fft_init(&fft, CPNORM, nof_prb)) { - fprintf(stderr, "Error initializing FFT\n"); - return -1; - } - - return 0; } +/**********************************************************************/ -void base_free() { - int i; - - if (input_file_name) { - filesource_free(&fsrc); - } else { -#ifndef DISABLE_UHD - cuhd_close(uhd); -#endif - } - -#ifndef DISABLE_GRAPHICS - if (!disable_plots) { - if (tmp_plot) { - free(tmp_plot); - } - plot_exit(); - } -#endif - - pbch_free(&pbch); - pdsch_free(&pdsch); - pdcch_free(&pdcch); - regs_free(®s); - sync_frame_free(&sframe); - lte_fft_free(&fft); - chest_free(&chest); - - free(input_buffer); - free(input_decim_buffer); - free(fft_buffer); - for (i = 0; i < MAX_PORTS; i++) { - free(ce[i]); - } -} - -int mib_init(phich_resources_t phich_resources, phich_length_t phich_length) { - - if (!lte_cell_isvalid(&cell)) { - fprintf(stderr, "Invalid cell properties: Id=%d, Ports=%d, PRBs=%d\n", - cell.id, cell.nof_ports, cell.nof_prb); - return -1; - } - if (cell.nof_prb > sampling_nof_prb) { - fprintf(stderr, "Error sampling frequency is %.2f Mhz but captured signal has %d PRB\n", - (float) lte_sampling_freq_hz(sampling_nof_prb)/MHZ, cell.nof_prb); - return -1; - } - if (regs_init(®s, phich_resources, phich_length, cell)) { - fprintf(stderr, "Error initiating REGs\n"); - return -1; - } - - if (pcfich_init(&pcfich, ®s, cell)) { - fprintf(stderr, "Error creating PCFICH object\n"); - return -1; - } - - if (pdcch_init(&pdcch, ®s, cell)) { - fprintf(stderr, "Error creating PDCCH object\n"); - return -1; - } - - if (pdsch_init(&pdsch, 1234, cell)) { - fprintf(stderr, "Error creating PDSCH object\n"); - return -1; - } - - if (pdsch_harq_init(&harq_process, &pdsch)) { - fprintf(stderr, "Error initiating HARQ process\n"); - return -1; - } - - chest_set_nof_ports(&chest, cell.nof_ports); - - mib_initiated = 1; - - DEBUG("Receiver initiated cell.id=%d nof_prb=%d\n", cell.id, cell.nof_prb); - - return 0; +void sigintHandler(int x) { + go_exit = 1; } -int cell_id_init(int nof_prb, int cell_id) { - - lte_cell_t cell; - - cell.id = cell_id; - cell.nof_prb = nof_prb; - cell.nof_ports = 2; - cell.cp = CPNORM; - - if (chest_ref_LTEDL(&chest, cell)) { - fprintf(stderr, "Error initializing reference signal\n"); - return -1; - } - - if (pbch_init(&pbch, cell)) { - fprintf(stderr, "Error initiating PBCH\n"); - return -1; - } - - cell_id_initated = 1; - DEBUG("PBCH initiated cell_id=%d\n", cell_id); +int main(int argc, char **argv) { + int ret; + cf_t *sf_buffer; + iodev_t iodev; + prog_args_t prog_args; + lte_cell_t cell; + ue_dl_t ue_dl; + bool ue_dl_initiated = false; + int64_t sf_cnt; + uint32_t sf_idx; + pbch_mib_t mib; - return 0; -} - -char data[10000]; - -int pdsch_run(cf_t *input, uint32_t sf_idx) { - uint32_t cfi, cfi_distance, i; - cf_t *input_decim; - ra_pdsch_t ra_dl; - dci_location_t locations[10]; - dci_msg_t dci_msg; - uint32_t nof_locations; + parse_args(&prog_args, argc, argv); - /* Downsample if the signal bandwith is shorter */ - if (sampling_nof_prb > cell.nof_prb) { - decim_c(input, input_decim_buffer, sf_n_samples, DOWNSAMPLE_FACTOR(sampling_nof_prb, cell.nof_prb)); - input_decim = input_decim_buffer; - } else { - input_decim = input; + if (iodev_init(&iodev, &prog_args.io_config)) { + fprintf(stderr, "Error initiating input device\n"); + exit(-1); } - lte_fft_run_sf(&fft, input_decim, fft_buffer); - - /* Get channel estimates for each port */ - chest_ce_sf(&chest, fft_buffer, ce, sf_idx); - - /* First decode PCFICH and obtain CFI */ - if (pcfich_decode(&pcfich, fft_buffer, ce, sf_idx, &cfi, &cfi_distance)<0) { - fprintf(stderr, "Error decoding PCFICH\n"); - return -1; + if (!prog_args.disable_plots) { + init_plots(); } - INFO("Decoded CFI=%d with distance %d\n", cfi, cfi_distance); + /* Setup SIGINT handler */ + printf("\n --- Press Ctrl+C to exit --- \n"); + signal(SIGINT, sigintHandler); - if (regs_set_cfi(®s, cfi)) { - fprintf(stderr, "Error setting CFI\n"); - return -1; - } + /* Initialize frame and subframe counters */ + sf_cnt = 0; + sf_idx = 0; - /* Search only UE-specific locations */ - nof_locations = pdcch_ue_locations(&pdcch, locations, 10, sf_idx, cfi, 1234); + /* Main loop */ + while (!go_exit && (sf_cnt < prog_args.nof_subframes || prog_args.nof_subframes == -1)) { - uint16_t crc_rem = 0; - for (i=0;i 0) { + sf_cnt++; } - } - if (cell.nof_prb && !pbch_only) { - if (pdsch_run(input, sf_idx)) { - fprintf(stderr, "\nError running PDSCH decoder\n"); - return -1; + if (iodev_isfile(&iodev)) { + usleep(5000); } } - return 0; -} - -void sigintHandler(int sig_num) { - go_exit = 1; -} - -void setup_uhd() { - double samp_freq; - -#ifndef DISABLE_UHD - /* Get the sampling rate from the number of PRB */ - samp_freq = lte_sampling_freq_hz(sampling_nof_prb); - INFO("Setting sampling frequency %.2f MHz\n", (float) samp_freq/MHZ); - cuhd_set_rx_srate(uhd, samp_freq); - cuhd_set_rx_gain(uhd, uhd_gain); - - /* set uhd_freq */ - cuhd_set_rx_freq(uhd, (double) uhd_freq); - cuhd_rx_wait_lo_locked(uhd); - DEBUG("Set uhd_freq to %.3f MHz\n", (double ) uhd_freq); + if (ue_dl_initiated) { + ue_dl_free(&ue_dl); + } + iodev_free(&iodev); - DEBUG("Starting receiver...\n", 0); - cuhd_start_rx_stream(uhd); -#endif + printf("\nBye\n"); + exit(0); } -void read_io(cf_t *buffer, int nsamples) { - int n; - DEBUG(" ----- RECEIVING %d SAMPLES ---- \n", nsamples); - if (input_file_name) { - n = filesource_read(&fsrc, buffer, nsamples); - if (n == -1) { - fprintf(stderr, "Error reading file\n"); - exit(-1); - /* wrap file if arrive to end */ - } else if (n < nsamples) { - DEBUG("Read %d from file. Seeking to 0\n",n); - filesource_seek(&fsrc, 0); - filesource_read(&fsrc, buffer, nsamples); - } - } else { -#ifndef DISABLE_UHD - cuhd_recv(uhd, buffer, nsamples, 1); -#endif - } -} -int main(int argc, char **argv) { - int ret; - uint32_t sf_idx; - uint32_t cell_id; - cf_t *in_ptr; - -#ifdef DISABLE_UHD - if (argc < 3) { - usage(argv[0]); - exit(-1); - } -#endif - parse_args(argc, argv); - if (base_init(sampling_nof_prb)) { - fprintf(stderr, "Error initializing memory\n"); - exit(-1); - } +/********************************************************************** + * Plotting Functions + ***********************************************************************/ +#ifndef DISABLE_GRAPHICS - /* If input_file_name is NULL, we read from the USRP */ - if (!input_file_name) { - setup_uhd(); - } - printf("\n --- Press Ctrl+C to exit --- \n"); - - signal(SIGINT, sigintHandler); +#include "liblte/graphics/plot.h" +plot_real_t poutfft; +plot_complex_t pce; +plot_scatter_t pscatrecv, pscatequal; - /* Initialize variables */ - frame_cnt = 0; - frame_number = -1; - - /* The number of samples read from the USRP or file corresponds to 1 ms (subframe) */ - sf_n_samples = 1920 * lte_symbol_sz(sampling_nof_prb)/128; - - sync_frame_set_threshold(&sframe, find_threshold); +float tmp_plot[SLOT_LEN_RE(MAX_PRB, CPNORM)]; - sf_idx = 0; - cell_id = cell_id_file; - if (input_file_name) { - in_ptr = input_buffer; - } else { - in_ptr = sf_buffer; - } +void init_plots() { + plot_init(); + plot_real_init(&poutfft); + plot_real_setTitle(&poutfft, "Output FFT - Magnitude"); + plot_real_setLabels(&poutfft, "Index", "dB"); + plot_real_setYAxisScale(&poutfft, -60, 0); - while (!go_exit && (frame_cnt < nof_frames || nof_frames == -1)) { + plot_complex_init(&pce); + plot_complex_setTitle(&pce, "Channel Estimates"); + plot_complex_setYAxisScale(&pce, Ip, -0.01, 0.01); + plot_complex_setYAxisScale(&pce, Q, -0.01, 0.01); + plot_complex_setYAxisScale(&pce, Magnitude, 0, 0.01); + plot_complex_setYAxisScale(&pce, Phase, -M_PI, M_PI); - read_io(input_buffer, sf_n_samples); + plot_scatter_init(&pscatrecv); + plot_scatter_setTitle(&pscatrecv, "Received Symbols"); + plot_scatter_setXAxisScale(&pscatrecv, -0.01, 0.01); + plot_scatter_setYAxisScale(&pscatrecv, -0.01, 0.01); - if (!input_file_name) { - ret = sync_frame_push(&sframe, input_buffer, sf_buffer); - } else { - ret = 1; - } - switch(ret ) { - case 0: - /* not yet synched */ - break; - case 1: - /* sf_buffer is aligned to the subframe */ - - if (!(frame_cnt%10)) { - frame_number++; - } - - if (!input_file_name) { - sf_idx = sync_frame_sfidx(&sframe); - cell_id = sync_frame_cell_id(&sframe); - } - - /* synch'd and tracking */ - if (run_receiver(in_ptr, cell_id, sf_idx)) { - fprintf(stderr, "\nError running receiver\n");fflush(stdout); - exit(-1); - } - - if (!(frame_cnt % 10)) { - printf("SFN: %4d, CFO: %+.4f KHz, SFO: %+.4f Khz, TimeOffset: %4d, Errors: %4d/%4d, BLER: %.1e\r", - frame_number, sframe.cur_cfo * 15, sframe.timeoffset / 5, sframe.peak_idx, - pkt_errors, pkts_total, - (float) pkt_errors / pkts_total); - fflush(stdout); - } - if (input_file_name) { - sf_idx++; - } - break; - default: - fprintf(stderr, "Error running automatic synchronization\n"); - exit(-1); - } + plot_scatter_init(&pscatequal); + plot_scatter_setTitle(&pscatequal, "Equalized Symbols"); + plot_scatter_setXAxisScale(&pscatequal, -1, 1); + plot_scatter_setYAxisScale(&pscatequal, -1, 1); +} - frame_cnt++; - if (input_file_name) { - usleep(5000); +void do_plots(ue_dl_t *q, uint32_t sf_idx) { + int i; + uint32_t nof_re = SLOT_LEN_RE(q->cell.nof_prb, q->cell.cp); + uint32_t nof_symbols = q->harq_process[0].prb_alloc.re_sf[sf_idx]; + for (i = 0; i < nof_re; i++) { + tmp_plot[i] = 10 * log10f(cabsf(q->sf_symbols[i])); + if (isinf(tmp_plot[i])) { + tmp_plot[i] = -80; } } - - base_free(); - - printf("\nBye\n"); - exit(0); + plot_real_setNewData(&poutfft, tmp_plot, nof_re); + plot_complex_setNewData(&pce, q->ce[0], nof_re); + plot_scatter_setNewData(&pscatrecv, q->pdsch.pdsch_symbols[0], nof_symbols); + plot_scatter_setNewData(&pscatequal, q->pdsch.pdsch_d, nof_symbols); } +#endif diff --git a/lte/phy/examples/scan_mib.c b/lte/phy/examples/scan_mib.c index 33f39f2b5..94782c308 100644 --- a/lte/phy/examples/scan_mib.c +++ b/lte/phy/examples/scan_mib.c @@ -162,11 +162,11 @@ int base_init(int frame_length) { return -1; } } - if (sync_init(&ssync, FLEN)) { + if (sync_init(&ssync, FLEN, 128, 128)) { fprintf(stderr, "Error initiating PSS/SSS\n"); return -1; } - if (chest_init(&chest, LINEAR, CPNORM, 6, MAX_PORTS)) { + if (chest_init(&chest, CPNORM, 6, MAX_PORTS)) { fprintf(stderr, "Error initializing equalizer\n"); return -1; } @@ -349,13 +349,15 @@ int main(int argc, char **argv) { int cell_id; float max_peak_to_avg; float sfo; - int find_idx, track_idx, last_found; + uint32_t track_idx, find_idx; + int last_found; enum sync_state state; int n; int mib_attempts; int nslot; pbch_mib_t mib; - + int ret; + if (argc < 3) { usage(argv[0]); exit(-1); @@ -434,14 +436,14 @@ int main(int argc, char **argv) { cuhd_recv(uhd, input_buffer, FLEN, 1); #endif /* set find_threshold and go to FIND state */ - sync_set_threshold(&ssync, find_threshold); + sync_set_threshold(&ssync, find_threshold, find_threshold/2); state = FIND; break; case FIND: /* find peak in all frame */ - find_idx = sync_find(&ssync, &input_buffer[FLEN]); + ret = sync_find(&ssync, &input_buffer[FLEN], &find_idx); DEBUG("[%3d/%d]: PAR=%.2f\n", freq, nof_bands, sync_get_peak_to_avg(&ssync)); - if (find_idx != -1) { + if (ret == 1) { /* if found peak, go to track and set lower threshold */ frame_cnt = -1; last_found = 0; @@ -462,7 +464,7 @@ int main(int argc, char **argv) { case TRACK: INFO("Tracking PSS find_idx %d offset %d\n", find_idx, find_idx - track_len); - track_idx = sync_track(&ssync, &input_buffer[FLEN + find_idx - track_len]); + ret = sync_track(&ssync, input_buffer, FLEN + find_idx - track_len, &track_idx); p2a_v[frame_cnt] = sync_get_peak_to_avg(&ssync); /* save cell id for the best peak-to-avg */ @@ -470,7 +472,7 @@ int main(int argc, char **argv) { max_peak_to_avg = p2a_v[frame_cnt]; cell_id = sync_get_cell_id(&ssync); } - if (track_idx != -1) { + if (ret == 1) { cfo_v[frame_cnt] = sync_get_cfo(&ssync); last_found = frame_cnt; find_idx += track_idx - track_len; @@ -506,7 +508,7 @@ int main(int argc, char **argv) { // Correct CFO INFO("Correcting CFO=%.4f\n", cfo[freq]); - cfo_correct(&cfocorr, &input_buffer[FLEN], (-cfo[freq])/128); + cfo_correct(&cfocorr, &input_buffer[FLEN], &input_buffer[FLEN], (-cfo[freq])/128); if (nslot == 0) { if (mib_decoder_run(&input_buffer[FLEN+find_idx], &mib)) { diff --git a/lte/phy/examples/scan_pss.c b/lte/phy/examples/scan_pss.c index 7ba271498..e6e052cd6 100644 --- a/lte/phy/examples/scan_pss.c +++ b/lte/phy/examples/scan_pss.c @@ -261,10 +261,12 @@ int main(int argc, char **argv) { sync_t sfind, strack; float max_peak_to_avg; float sfo; - int find_idx, track_idx, last_found; + uint32_t find_idx, track_idx; + int last_found; enum sync_state state; int n; filesink_t fs; + int ret; if (argc < 3) { usage(argv[0]); @@ -278,13 +280,13 @@ int main(int argc, char **argv) { exit(-1); } - if (sync_init(&sfind, FLEN)) { + if (sync_init(&sfind, FLEN, 128, 128)) { fprintf(stderr, "Error initiating PSS/SSS\n"); exit(-1); } sync_pss_det_peak_to_avg(&sfind); - if (sync_init(&strack, track_len)) { + if (sync_init(&strack, track_len, 128, 128)) { fprintf(stderr, "Error initiating PSS/SSS\n"); exit(-1); } @@ -315,6 +317,9 @@ int main(int argc, char **argv) { max_peak_to_avg = 0; last_found = 0; frame_cnt = 0; + + sync_set_threshold(&sfind, find_threshold, track_threshold); + while(freq #include "liblte/config.h" + +#include "liblte/phy/resampling/interp.h" #include "liblte/phy/ch_estimation/refsignal.h" -#include "liblte/phy/filter/filter2d.h" #include "liblte/phy/common/phy_common.h" typedef _Complex float cf_t; /* this is only a shortcut */ -typedef enum {LINEAR} chest_interp_t; typedef void (*interpolate_fnc_t) (cf_t *input, cf_t *output, - int M, - int len, - int off_st, - int off_end); + uint32_t M, + uint32_t len, + uint32_t off_st, + uint32_t off_end); /** This is an OFDM channel estimator. * It works with any reference signal pattern, provided by the object @@ -61,11 +61,12 @@ typedef struct LIBLTE_API { uint32_t nof_symbols; refsignal_t refsignal[MAX_PORTS][NSLOTS_X_FRAME]; - interpolate_fnc_t interp; + interp_t interp_time[MAX_PORTS]; + interp_t interp_freq[MAX_PORTS]; + }chest_t; LIBLTE_API int chest_init(chest_t *q, - chest_interp_t interp, uint32_t nof_re, uint32_t nof_symbols, uint32_t nof_ports); @@ -76,7 +77,6 @@ LIBLTE_API int chest_set_nof_ports(chest_t *q, uint32_t nof_ports); LIBLTE_API int chest_init_LTEDL(chest_t *q, - chest_interp_t interp, lte_cell_t cell); LIBLTE_API int chest_ref_LTEDL_slot_port(chest_t *q, diff --git a/lte/phy/include/liblte/phy/common/phy_common.h b/lte/phy/include/liblte/phy/common/phy_common.h index 422fe8699..29e8c233e 100644 --- a/lte/phy/include/liblte/phy/common/phy_common.h +++ b/lte/phy/include/liblte/phy/common/phy_common.h @@ -59,6 +59,11 @@ typedef enum {CPNORM, CPEXT} lte_cp_t; #define MAX_NSYMB 7 +#define MAX_PRB 110 +#define RE_X_RB 12 + +#define SYMBOL_SZ_MAX 2048 + #define CPNORM_NSYMB 7 #define CPNORM_SF_NSYMB 2*CPNORM_NSYMB #define CPNORM_0_LEN 160 @@ -79,20 +84,21 @@ typedef enum {CPNORM, CPEXT} lte_cp_t; #define SLOT_LEN_CPNORM(symbol_sz) (symbol_sz+CP(symbol_sz,CPNORM_0_LEN)+(CPNORM_NSYMB-1)*(symbol_sz+CP(symbol_sz,CPNORM_LEN))) #define SLOT_LEN_CPEXT(symbol_sz) (CPEXT_NSYMB*(symbol_sz+CP(symbol_sz, CPEXT_LEN))) -#define SLOT_LEN(symbol_sz, cp) CP_ISNORM(cp)?SLOT_LEN_CPNORM(symbol_sz):SLOT_LEN_CPEXT(symbol_sz) +#define SLOT_LEN(symbol_sz, cp) (CP_ISNORM(cp)?SLOT_LEN_CPNORM(symbol_sz):SLOT_LEN_CPEXT(symbol_sz)) -#define SF_LEN_CPNORM(symbol_sz) 2*SLOT_LEN_CPNORM(symbol_sz) -#define SF_LEN_CPEXT(symbol_sz) 2*SLOT_LEN_CPEXT(symbol_sz) +#define SF_LEN_CPNORM(symbol_sz) (2*SLOT_LEN_CPNORM(symbol_sz)) +#define SF_LEN_CPEXT(symbol_sz) (2*SLOT_LEN_CPEXT(symbol_sz)) #define SF_LEN(symbol_sz, cp) (2*SLOT_LEN(symbol_sz, cp)) +#define SF_LEN_MAX SF_LEN(SYMBOL_SZ_MAX, CPNORM) + +#define SLOT_LEN_RE(nof_prb, cp) (nof_prb*RE_X_RB*CP_NSYMB(cp)) +#define SF_LEN_RE(nof_prb, cp) (2*SLOT_LEN_RE(nof_prb, cp)) #define SLOT_IDX_CPNORM(idx, symbol_sz) (idx==0?(CP(symbol_sz, CPNORM_0_LEN)):(CP(symbol_sz, CPNORM_0_LEN)+idx*(symbol_sz+CP(symbol_sz, CPNORM_LEN)))) #define SLOT_IDX_CPEXT(idx, symbol_sz) (idx*(symbol_sz+CP(symbol_sz, CPEXT_LEN))) #define SAMPLE_IDX(nof_prb, symbol_idx, sample_idx) (symbol_idx*nof_prb*RE_X_RB + sample_idx) -#define MAX_PRB 110 -#define RE_X_RB 12 - #define RS_VSHIFT(cell_id) (cell_id%6) #define GUARD_RE(nof_prb) ((lte_symbol_sz(nof_prb)-nof_prb*RE_X_RB)/2) @@ -136,8 +142,15 @@ LIBLTE_API enum band_geographical_area { LIBLTE_API bool lte_cell_isvalid(lte_cell_t *cell); +LIBLTE_API bool lte_N_id_2_isvalid(uint32_t N_id_2); + +LIBLTE_API bool lte_N_id_1_isvalid(uint32_t N_id_1); + +LIBLTE_API bool lte_symbol_sz_isvalid(uint32_t symbol_sz); + LIBLTE_API int lte_symbol_sz(uint32_t nof_prb); + LIBLTE_API int lte_sampling_freq_hz(uint32_t nof_prb); LIBLTE_API uint32_t lte_re_x_prb(uint32_t ns, @@ -151,6 +164,8 @@ LIBLTE_API uint32_t lte_voffset(uint32_t symbol_id, LIBLTE_API int lte_cb_size(uint32_t index); +LIBLTE_API char *lte_cp_string(lte_cp_t cp); + LIBLTE_API char *lte_mod_string(lte_mod_t mod); LIBLTE_API uint32_t lte_mod_bits_x_symbol(lte_mod_t mod); diff --git a/lte/phy/include/liblte/phy/phch/pdcch.h b/lte/phy/include/liblte/phy/phch/pdcch.h index 87aa91eb8..f15dd1519 100644 --- a/lte/phy/include/liblte/phy/phch/pdcch.h +++ b/lte/phy/include/liblte/phy/phch/pdcch.h @@ -44,12 +44,6 @@ typedef _Complex float cf_t; -#define NOF_COMMON_FORMATS 2 -const dci_format_t common_formats[NOF_COMMON_FORMATS] = { Format1A, Format1C }; - -#define NOF_UE_FORMATS 2 -const dci_format_t ue_formats[NOF_UE_FORMATS] = { Format0, Format1 }; // 1A has the same payload as 0 - typedef enum LIBLTE_API { SEARCH_UE, SEARCH_COMMON diff --git a/lte/phy/include/liblte/phy/phch/pdsch.h b/lte/phy/include/liblte/phy/phch/pdsch.h index 6800e1707..44717689b 100644 --- a/lte/phy/include/liblte/phy/phch/pdsch.h +++ b/lte/phy/include/liblte/phy/phch/pdsch.h @@ -43,7 +43,7 @@ #include "liblte/phy/phch/dci.h" #include "liblte/phy/phch/regs.h" -#define TDEC_ITERATIONS 1 +#define TDEC_ITERATIONS 6 typedef _Complex float cf_t; @@ -73,8 +73,9 @@ typedef struct LIBLTE_API { lte_cell_t cell; uint32_t max_symbols; - uint16_t rnti; - + bool rnti_is_set; + uint16_t rnti; + /* buffers */ // void buffers are shared for tx and rx cf_t *ce[MAX_PORTS]; @@ -96,11 +97,13 @@ typedef struct LIBLTE_API { }pdsch_t; LIBLTE_API int pdsch_init(pdsch_t *q, - uint16_t user_rnti, lte_cell_t cell); LIBLTE_API void pdsch_free(pdsch_t *q); +LIBLTE_API int pdsch_set_rnti(pdsch_t *q, + uint16_t rnti); + LIBLTE_API int pdsch_harq_init(pdsch_harq_t *p, pdsch_t *pdsch); diff --git a/lte/phy/include/liblte/phy/phch/ue_sync.h b/lte/phy/include/liblte/phy/phch/ue_sync.h new file mode 100644 index 000000000..cf1e2f7a2 --- /dev/null +++ b/lte/phy/include/liblte/phy/phch/ue_sync.h @@ -0,0 +1,168 @@ +/** + * + * \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/. + * + */ + +#ifndef UE_SYNC_ +#define UE_SYNC_ + +#include + +#include "liblte/config.h" +#include "liblte/phy/sync/sync.h" +#include "liblte/phy/sync/cfo.h" +#include "liblte/phy/ch_estimation/chest.h" +#include "liblte/phy/phch/pbch.h" +#include "liblte/phy/common/fft.h" + +/************************************************************** + * + * This object automatically manages the cell association and + * synchronization procedure. By default, it associates with the + * CELL whose correlation peak to average ratio is the highest. + * + * TODO: Associate with arbitrary CELL ID + * + * The main function is ue_sync_get_buffer(), which returns a pointer + * to the aligned subframe of samples (before FFT). This function + * should be called regularly, returning every 1 ms. It reads from the + * USRP, aligns the samples to the subframe and performs time/freq synch. + * + * The function returns 0 during the cell association procedure, which includes + * PSS/SSS synchronization, MIB decoding from the PBCH and sampling frequency + * adjustment (according to signal bandwidth) and resynchronization. + * + * The function returns 1 when the signal is correctly acquired and the + * returned buffer is aligned with the subframe. + * + * + *************************************************************/ + +typedef enum LIBLTE_API { SF_FIND, SF_TRACK} ue_sync_state_t; + +#define SYNC_PBCH_NOF_PRB 6 +#define SYNC_PBCH_NOF_PORTS 2 + +#define TRACK_MAX_LOST 10 +#define PAR_THRESHOLD_FIND 20 + +#define NOF_MIB_DECODES 10 + +#define MEASURE_EXEC_TIME + +typedef struct LIBLTE_API { + sync_t s; + + void *stream; + double (*set_rate_callback)(void*, double); + int (*recv_callback)(void*, void*, uint32_t); + + ue_sync_state_t state; + + cf_t *input_buffer; + cf_t *sf_symbols; + cf_t *ce[SYNC_PBCH_NOF_PORTS]; + + /* These count half frames (5ms) */ + uint64_t frame_ok_cnt; + uint32_t frame_no_cnt; + uint32_t frame_total_cnt; + + /* this is the system frame number (SFN) */ + uint32_t frame_number; + + lte_cell_t cell; + uint32_t sf_idx; + + cfo_t cfocorr; + float cur_cfo; + + /* Variables for PBCH decoding */ + pbch_mib_t mib; + lte_fft_t fft; + chest_t chest; + pbch_t pbch; + bool pbch_initialized; + uint32_t pbch_decoded; + bool pbch_decode_always; + bool pbch_decoder_enabled; + uint32_t pbch_last_trial; + + bool decode_sss_on_track; + + uint32_t peak_idx; + int time_offset; + float mean_time_offset; + #ifdef MEASURE_EXEC_TIME + float mean_exec_time; + #endif +} ue_sync_t; + + +LIBLTE_API int ue_sync_init(ue_sync_t *q, + double (set_rate_callback)(void*, double), + int (recv_callback)(void*, void*, uint32_t), + void *stream_handler); + +LIBLTE_API void ue_sync_free(ue_sync_t *q); + +LIBLTE_API int ue_sync_get_buffer(ue_sync_t *q, + cf_t **sf_symbols); + + +LIBLTE_API void ue_sync_reset(ue_sync_t *q); + +LIBLTE_API void ue_sync_decode_sss_on_track(ue_sync_t *q, bool enabled); + +LIBLTE_API void ue_sync_pbch_enable(ue_sync_t *q, bool enabled); + +LIBLTE_API void ue_sync_pbch_always(ue_sync_t *q, bool enabled); + +LIBLTE_API void ue_sync_set_threshold(ue_sync_t *q, + float threshold); + +LIBLTE_API ue_sync_state_t ue_sync_get_state(ue_sync_t *q); + +LIBLTE_API uint32_t ue_sync_get_sfidx(ue_sync_t *q); + +LIBLTE_API uint32_t ue_sync_get_peak_idx(ue_sync_t *q); + +LIBLTE_API lte_cell_t ue_sync_get_cell(ue_sync_t *q); + +LIBLTE_API pbch_mib_t ue_sync_get_mib(ue_sync_t *q); + +LIBLTE_API bool ue_sync_is_mib_decoded(ue_sync_t *q); + +LIBLTE_API float ue_sync_get_cfo(ue_sync_t *q); + +LIBLTE_API float ue_sync_get_sfo(ue_sync_t *q); + + + + + + +#endif // SYNC_FRAME_ + diff --git a/lte/phy/include/liblte/phy/phy.h b/lte/phy/include/liblte/phy/phy.h index 0b5ba19d2..3de436895 100644 --- a/lte/phy/include/liblte/phy/phy.h +++ b/lte/phy/include/liblte/phy/phy.h @@ -50,10 +50,14 @@ #include "liblte/phy/common/phy_common.h" #include "liblte/phy/common/fft.h" - + #include "liblte/phy/ch_estimation/chest.h" #include "liblte/phy/ch_estimation/refsignal.h" +#include "liblte/phy/resampling/interp.h" +#include "liblte/phy/resampling/decim.h" +#include "liblte/phy/resampling/resample_arb.h" + #include "liblte/phy/channel/ch_awgn.h" #include "liblte/phy/fec/viterbi.h" @@ -88,18 +92,15 @@ #include "liblte/phy/phch/pbch.h" #include "liblte/phy/phch/pcfich.h" #include "liblte/phy/phch/phich.h" +#include "liblte/phy/phch/ue_sync.h" +#include "liblte/phy/phch/ue_dl.h" #include "liblte/phy/scrambling/scrambling.h" -#include "liblte/phy/resampling/interp.h" -#include "liblte/phy/resampling/decim.h" -#include "liblte/phy/resampling/resample_arb.h" - #include "liblte/phy/sync/pss.h" #include "liblte/phy/sync/sfo.h" #include "liblte/phy/sync/sss.h" #include "liblte/phy/sync/sync.h" -#include "liblte/phy/sync/sync_frame.h" #include "liblte/phy/sync/cfo.h" #ifdef __cplusplus diff --git a/lte/phy/include/liblte/phy/resampling/interp.h b/lte/phy/include/liblte/phy/resampling/interp.h index 3c0a652e7..c39c83602 100644 --- a/lte/phy/include/liblte/phy/resampling/interp.h +++ b/lte/phy/include/liblte/phy/resampling/interp.h @@ -26,15 +26,73 @@ */ #ifndef INTERP_H -#define INTERP_H_ +#define INTERP_H + +#include #include "liblte/config.h" typedef _Complex float cf_t; +typedef enum LIBLTE_API {LINEAR} interp_type_t; + +typedef struct LIBLTE_API { + interp_type_t type; + + float *in_mag; + float *in_arg; + float *in_mag0; + float *in_arg0; + float *in_mag1; + float *in_arg1; + + float *out_mag; + float *out_arg; + float *out_arg2; + int16_t *table_idx; + + cf_t *out_cexp; + cf_t *out_prod; + + cf_t *cexptable; + + uint32_t len; + uint32_t M; + +}interp_t; + +LIBLTE_API int interp_init(interp_t *q, + interp_type_t type, + uint32_t len, + uint32_t M); + +LIBLTE_API void interp_free(interp_t *q); + +LIBLTE_API void interp_run(interp_t *q, + cf_t *input, + cf_t *output); + +LIBLTE_API void interp_run_offset(interp_t *q, + cf_t *input, + cf_t *output, + uint32_t off_st, + uint32_t off_end); + +LIBLTE_API void interp_linear_offset(cf_t *input, + cf_t *output, + uint32_t M, + uint32_t len, + uint32_t off_st, + uint32_t off_end); + +LIBLTE_API void interp_linear_c(cf_t *input, + cf_t *output, + uint32_t M, + uint32_t len); -LIBLTE_API void interp_linear_offset(cf_t *input, cf_t *output, int M, int len, int off_st, int off_end); -LIBLTE_API void interp_linear_c(cf_t *input, cf_t *output, int M, int len); -LIBLTE_API void interp_linear_f(float *input, float *output, int M, int len); +LIBLTE_API void interp_linear_f(float *input, + float *output, + uint32_t M, + uint32_t len); #endif // INTERP_H diff --git a/lte/phy/include/liblte/phy/sync/cfo.h b/lte/phy/include/liblte/phy/sync/cfo.h index b3f282fe0..b88683ad1 100644 --- a/lte/phy/include/liblte/phy/sync/cfo.h +++ b/lte/phy/include/liblte/phy/sync/cfo.h @@ -49,10 +49,20 @@ typedef struct LIBLTE_API { cf_t *cur_cexp; }cfo_t; -LIBLTE_API int cfo_init(cfo_t *h, int nsamples); +LIBLTE_API int cfo_init(cfo_t *h, + uint32_t nsamples); + LIBLTE_API void cfo_free(cfo_t *h); -LIBLTE_API void cfo_set_tol(cfo_t *h, float tol); -LIBLTE_API void cfo_correct(cfo_t *h, cf_t *x, float freq); +LIBLTE_API int cfo_realloc(cfo_t *h, + uint32_t samples); + +LIBLTE_API void cfo_set_tol(cfo_t *h, + float tol); + +LIBLTE_API void cfo_correct(cfo_t *h, + cf_t *input, + cf_t *output, + float freq); #endif // CFO_ diff --git a/lte/phy/include/liblte/phy/sync/pss.h b/lte/phy/include/liblte/phy/sync/pss.h index 9e0e87727..a27f92f6b 100644 --- a/lte/phy/include/liblte/phy/sync/pss.h +++ b/lte/phy/include/liblte/phy/sync/pss.h @@ -42,8 +42,7 @@ typedef _Complex float cf_t; /* this is only a shortcut */ #define DEFAULT_CORRELATION_TH 10000 #define DEFAULT_NOSYNC_TIMEOUT 5 -#define PSS_LEN_FREQ 129 // FFT-based convolution removes 1 leaving it in 128 -#define PSS_LEN 62 +#define PSS_LEN 62 #define PSS_RE 6*12 @@ -67,50 +66,47 @@ typedef struct LIBLTE_API { conv_fft_cc_t conv_fft; #endif - int frame_size; - int N_id_2; + uint32_t frame_size; + uint32_t N_id_2; + uint32_t fft_size; cf_t *pss_signal_freq[3]; // One sequence for each N_id_2 cf_t *tmp_input; float *conv_abs; cf_t *conv_output; - -#ifdef ENABLE_HL - cf_t *frame_buffer; - cf_t *tmp_nco; - float current_cfo; - bool cfo_auto; - int nof_nosync_frames; - int nosync_timeout_frames; - float correlation_threshold; - int frame_start_idx; - int fb_wp; -#endif - - + }pss_synch_t; typedef enum { PSS_TX, PSS_RX } pss_direction_t; /* Basic functionality */ -LIBLTE_API int pss_synch_init(pss_synch_t *q, int frame_size); +LIBLTE_API int pss_synch_init_fft(pss_synch_t *q, + uint32_t frame_size, + uint32_t fft_size); + +LIBLTE_API int pss_synch_init(pss_synch_t *q, + uint32_t frame_size); + LIBLTE_API void pss_synch_free(pss_synch_t *q); -LIBLTE_API int pss_generate(cf_t *signal, int N_id_2); -LIBLTE_API void pss_put_slot(cf_t *pss_signal, cf_t *slot, int nof_prb, lte_cp_t cp); -LIBLTE_API int pss_synch_set_N_id_2(pss_synch_t *q, int N_id_2); -LIBLTE_API int pss_synch_find_pss(pss_synch_t *q, cf_t *input, float *corr_peak_value, float *corr_mean_value); -LIBLTE_API float pss_synch_cfo_compute(pss_synch_t* q, cf_t *pss_recv); +LIBLTE_API int pss_generate(cf_t *signal, + uint32_t N_id_2); + +LIBLTE_API void pss_put_slot(cf_t *pss_signal, + cf_t *slot, + uint32_t nof_prb, + lte_cp_t cp); +LIBLTE_API int pss_synch_set_N_id_2(pss_synch_t *q, + uint32_t N_id_2); -/* Automatic frame management functions (for periodic calling) */ -LIBLTE_API int pss_synch_periodic(pss_synch_t *q, cf_t *input, cf_t *output, int nsamples); -LIBLTE_API void pss_synch_set_timeout(pss_synch_t *q, int nof_frames); -LIBLTE_API void pss_synch_set_threshold(pss_synch_t *q, float threshold); -LIBLTE_API void pss_synch_set_cfo_mode(pss_synch_t *q, bool cfo_auto); -LIBLTE_API float pss_synch_get_cfo(pss_synch_t *q); -LIBLTE_API int pss_synch_get_frame_start_idx(pss_synch_t *q); +LIBLTE_API int pss_synch_find_pss(pss_synch_t *q, + cf_t *input, + float *corr_peak_value, + float *corr_mean_value); +LIBLTE_API float pss_synch_cfo_compute(pss_synch_t* q, + cf_t *pss_recv); /* High-level API */ diff --git a/lte/phy/include/liblte/phy/sync/sss.h b/lte/phy/include/liblte/phy/sync/sss.h index 48c78add4..bdc219542 100644 --- a/lte/phy/include/liblte/phy/sync/sss.h +++ b/lte/phy/include/liblte/phy/sync/sss.h @@ -38,17 +38,12 @@ typedef _Complex float cf_t; /* this is only a shortcut */ -/** gives the beginning of the SSS symbol (to be passed to sss_synch_m0m1). - * subframe_sz is the length of the subframe, e.g. 1920 for the 1.9 MHz - * symbol_sz is the OFDM symbol size (including CP), e.g. 137 for the 1.9 MHz - */ -#define SSS_SYMBOL_ST(subframe_sz, symbol_sz) (subframe_sz/2-2*symbol_sz) -#define SSS_POS_SYMBOL 33 -#define SSS_DFT_LEN 128 -#define N_SSS 31 +#define N_SSS 31 #define SSS_LEN 2*N_SSS +#define SSS_MAX_FFT_LEN 2048 + struct sss_tables{ int z1[N_SSS][N_SSS]; int c[2][N_SSS]; @@ -56,7 +51,7 @@ struct sss_tables{ }; /* Allocate 32 complex to make it multiple of 32-byte AVX instructions alignment requirement. - * Should use vect_malloc() to make it platform agnostic. + * Should use vec_malloc() to make it platform agnostic. */ struct fc_tables{ cf_t z1[N_SSS+1][N_SSS+1]; @@ -69,35 +64,68 @@ struct fc_tables{ typedef struct LIBLTE_API { dft_plan_t dftp_input; + + uint32_t fft_size; float corr_peak_threshold; - int symbol_sz; - int subframe_sz; - int N_id_2; - - int N_id_1_table[30][30]; + uint32_t symbol_sz; + uint32_t subframe_sz; + uint32_t N_id_2; + + uint32_t N_id_1_table[30][30]; struct fc_tables fc_tables[3]; // one for each N_id_2 }sss_synch_t; /* Basic functionality */ -LIBLTE_API int sss_synch_init(sss_synch_t *q); +LIBLTE_API int sss_synch_init(sss_synch_t *q, + uint32_t fft_size); + +LIBLTE_API int sss_synch_realloc(sss_synch_t *q, + uint32_t fft_size); + LIBLTE_API void sss_synch_free(sss_synch_t *q); -LIBLTE_API void sss_generate(float *signal0, float *signal5, int cell_id); -LIBLTE_API void sss_put_slot(float *sss, cf_t *symbol, int nof_prb, lte_cp_t cp); -LIBLTE_API int sss_synch_set_N_id_2(sss_synch_t *q, int N_id_2); +LIBLTE_API void sss_generate(float *signal0, + float *signal5, + uint32_t cell_id); + +LIBLTE_API void sss_put_slot(float *sss, + cf_t *symbol, + uint32_t nof_prb, + lte_cp_t cp); + +LIBLTE_API int sss_synch_set_N_id_2(sss_synch_t *q, + uint32_t N_id_2); + +LIBLTE_API int sss_synch_m0m1(sss_synch_t *q, + cf_t *input, + uint32_t *m0, + float *m0_value, + uint32_t *m1, + float *m1_value); + +LIBLTE_API uint32_t sss_synch_subframe(uint32_t m0, + uint32_t m1); + +LIBLTE_API int sss_synch_N_id_1(sss_synch_t *q, + uint32_t m0, + uint32_t m1); + +LIBLTE_API int sss_synch_frame(sss_synch_t *q, + cf_t *input, + uint32_t *subframe_idx, + uint32_t *N_id_1); + +LIBLTE_API void sss_synch_set_threshold(sss_synch_t *q, + float threshold); -LIBLTE_API void sss_synch_m0m1(sss_synch_t *q, cf_t *input, int *m0, float *m0_value, - int *m1, float *m1_value); -LIBLTE_API int sss_synch_subframe(int m0, int m1); -LIBLTE_API int sss_synch_N_id_1(sss_synch_t *q, int m0, int m1); +LIBLTE_API void sss_synch_set_symbol_sz(sss_synch_t *q, + uint32_t symbol_sz); -LIBLTE_API int sss_synch_frame(sss_synch_t *q, cf_t *input, int *subframe_idx, int *N_id_1); -LIBLTE_API void sss_synch_set_threshold(sss_synch_t *q, float threshold); -LIBLTE_API void sss_synch_set_symbol_sz(sss_synch_t *q, int symbol_sz); -LIBLTE_API void sss_synch_set_subframe_sz(sss_synch_t *q, int subframe_sz); +LIBLTE_API void sss_synch_set_subframe_sz(sss_synch_t *q, + uint32_t subframe_sz); /* High-level API */ @@ -105,18 +133,18 @@ LIBLTE_API void sss_synch_set_subframe_sz(sss_synch_t *q, int subframe_sz); typedef struct LIBLTE_API { sss_synch_t obj; struct sss_synch_init { - int N_id_2; + uint32_t N_id_2; } init; cf_t *input; - int in_len; + uint32_t in_len; struct sss_synch_ctrl_in { - int symbol_sz; - int subframe_sz; - int correlation_threshold; + uint32_t symbol_sz; + uint32_t subframe_sz; + uint32_t correlation_threshold; } ctrl_in; struct sss_synch_ctrl_out { - int subframe_idx; - int N_id_1; + uint32_t subframe_idx; + uint32_t N_id_1; } ctrl_out; }sss_synch_hl; diff --git a/lte/phy/include/liblte/phy/sync/sync.h b/lte/phy/include/liblte/phy/sync/sync.h index 0288b29d6..6f40777dd 100644 --- a/lte/phy/include/liblte/phy/sync/sync.h +++ b/lte/phy/include/liblte/phy/sync/sync.h @@ -30,11 +30,15 @@ #define SYNC_ #include +#include #include "liblte/config.h" #include "liblte/phy/sync/pss.h" #include "liblte/phy/sync/sss.h" +#define FFT_SIZE_MIN 64 +#define FFT_SIZE_MAX 2048 + /** * * This object performs time and frequency synchronization using the PSS and SSS signals. @@ -49,19 +53,19 @@ enum sync_pss_det { ABSOLUTE, PEAK_MEAN}; -#define TRACK_THRESHOLD 10.0 -#define TRACK_LEN 300 - typedef struct LIBLTE_API { - pss_synch_t pss; + pss_synch_t pss_find; pss_synch_t pss_track; sss_synch_t sss; enum sync_pss_det pss_mode; - float threshold; + float find_threshold; + float track_threshold; float peak_to_avg; - int N_id_2; - int N_id_1; - int slot_id; + uint32_t N_id_2; + uint32_t N_id_1; + uint32_t slot_id; + uint32_t fft_size; + uint32_t find_frame_size; float cfo; bool detect_cp; bool sss_en; @@ -69,42 +73,72 @@ typedef struct LIBLTE_API { }sync_t; -LIBLTE_API int sync_init(sync_t *q, int frame_size); +LIBLTE_API int sync_init(sync_t *q, + uint32_t find_frame_size, + uint32_t track_frame_size, + uint32_t fft_size); + LIBLTE_API void sync_free(sync_t *q); +LIBLTE_API int sync_realloc(sync_t *q, + uint32_t find_frame_size, + uint32_t track_frame_size, + uint32_t fft_size); + /* Finds a correlation peak in the input signal. The signal must be sampled at 1.92 MHz and should be subframe_size long at least */ -LIBLTE_API int sync_find(sync_t *q, cf_t *input); +LIBLTE_API int sync_find(sync_t *q, + cf_t *input, + uint32_t *peak_position); /* Tracks the correlation peak in the input signal. The signal must be sampled at 1.92 MHz and should be TRACK_LEN long at least */ -LIBLTE_API int sync_track(sync_t *q, cf_t *input); +LIBLTE_API int sync_track(sync_t *q, + cf_t *input, + uint32_t offset, + uint32_t *peak_position); /* Sets the threshold for peak comparison */ -LIBLTE_API void sync_set_threshold(sync_t *q, float threshold); +LIBLTE_API void sync_set_threshold(sync_t *q, + float find_threshold, + float track_threshold); + /* Set peak comparison to absolute value */ LIBLTE_API void sync_pss_det_absolute(sync_t *q); + /* Set peak comparison to relative to the mean */ LIBLTE_API void sync_pss_det_peak_to_avg(sync_t *q); /* Gets the slot id (0 or 10) */ -LIBLTE_API int sync_get_slot_id(sync_t *q); +LIBLTE_API uint32_t sync_get_slot_id(sync_t *q); + /* Gets the last peak-to-average ratio */ LIBLTE_API float sync_get_peak_to_avg(sync_t *q); + /* Gets the N_id_2 from the last call to synch_run() */ -LIBLTE_API int sync_get_N_id_2(sync_t *q); +LIBLTE_API uint32_t sync_get_N_id_2(sync_t *q); + /* Gets the N_id_1 from the last call to synch_run() */ -LIBLTE_API int sync_get_N_id_1(sync_t *q); +LIBLTE_API uint32_t sync_get_N_id_1(sync_t *q); + /* Gets the Physical CellId from the last call to synch_run() */ LIBLTE_API int sync_get_cell_id(sync_t *q); + /* Gets the CFO estimation from the last call to synch_run() */ LIBLTE_API float sync_get_cfo(sync_t *q); + /* Gets the CP length estimation from the last call to synch_run() */ LIBLTE_API lte_cp_t sync_get_cp(sync_t *q); + /* Enables/Disables SSS detection */ -LIBLTE_API void sync_sss_en(sync_t *q, bool enabled); +LIBLTE_API void sync_sss_en(sync_t *q, + bool enabled); + +LIBLTE_API bool sync_sss_detected(sync_t *q); + /* Enables/Disables CP detection */ -LIBLTE_API void sync_cp_en(sync_t *q, bool enabled); +LIBLTE_API void sync_cp_en(sync_t *q, + bool enabled); #endif // SYNC_ diff --git a/lte/phy/include/liblte/phy/sync/sync_frame.h b/lte/phy/include/liblte/phy/sync/sync_frame.h deleted file mode 100644 index afe73c375..000000000 --- a/lte/phy/include/liblte/phy/sync/sync_frame.h +++ /dev/null @@ -1,111 +0,0 @@ -/** - * - * \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/. - * - */ - -#ifndef SYNC_FRAME_ -#define SYNC_FRAME_ - -#include - -#include "liblte/config.h" -#include "liblte/phy/sync/sync.h" -#include "liblte/phy/sync/cfo.h" - -/** - * - * Uses sync object to automatically manage the FIND and TRACKING states. - * It is suposed to work on a subframe basis. The input signal must be sampled at - * a frequency integer multiple of 1.92 MHz. The signal is internally downsampled - * and fed to the sync object. - * - * This object also deals with frame alignment and CFO correction, returning an - * output signal aligned both in time and frequency. - */ - -enum sync_frame_state { SF_FIND, SF_TRACK }; - -#define SYNC_SF_LEN 1920 // 1ms at 1.92 MHz - -#define TRACK_MAX_LOST 10 - - -typedef struct LIBLTE_API { - sync_t s; - enum sync_frame_state state; - uint32_t downsampling; - resample_arb_t resample; - unsigned long frame_cnt; - bool fb_wp; - uint32_t frame_size; - cf_t *input_buffer; - cf_t *input_downsampled; - cfo_t cfocorr; - float cur_cfo; - uint32_t peak_idx; - uint32_t cell_id; - float timeoffset; - uint32_t last_found; - uint32_t sf_idx; -}sync_frame_t; - - -/* Initializes the automatic tracker, setting the downsampling ratio for the input signal. - * downsampling is the ratio of the provided signal sampling frequency to 1.92 Mhz. E.g. if input is sampled at 3.84 Mhz, - * downsampling should be 2. -*/ -LIBLTE_API int sync_frame_init(sync_frame_t *q, - uint32_t downsampling); - -LIBLTE_API void sync_frame_free(sync_frame_t *q); - -LIBLTE_API void sync_frame_set_threshold(sync_frame_t *q, - float threshold); - -LIBLTE_API uint32_t sync_frame_cell_id(sync_frame_t *q); - -LIBLTE_API uint32_t sync_frame_sfidx(sync_frame_t *q); - -/* Automatically time/freq synchronizes the input signal. Returns 1 if the signal is synched and locked, - * and fills the output buffer with the time and frequency aligned version of the signal. - * If 0 is returned, the PSS was not found. -1 is returned in case of error. - * - * The provided signal can be sampled at an integer multiple of 1.92 Mhz. - * The sampling ratio is provided when calling the sync_auto_reset() function. - * - * The buffer input must have subframe_size samples (used in sync_init) - */ -LIBLTE_API int sync_frame_push(sync_frame_t *q, - cf_t *input, - cf_t *output); - -/* Resets the automatic tracker */ -LIBLTE_API void sync_frame_reset(sync_frame_t *q); - - - - -#endif // SYNC_FRAME_ - diff --git a/lte/phy/include/liblte/phy/utils/cexptab.h b/lte/phy/include/liblte/phy/utils/cexptab.h index 058ea81c4..6922eff32 100644 --- a/lte/phy/include/liblte/phy/utils/cexptab.h +++ b/lte/phy/include/liblte/phy/utils/cexptab.h @@ -30,19 +30,28 @@ #define CEXPTAB_ #include +#include #include "liblte/config.h" typedef _Complex float cf_t; typedef struct LIBLTE_API { - int size; + uint32_t size; cf_t *tab; }cexptab_t; -LIBLTE_API int cexptab_init(cexptab_t *nco, int size); +LIBLTE_API int cexptab_init(cexptab_t *nco, + uint32_t size); + LIBLTE_API void cexptab_free(cexptab_t *nco); -LIBLTE_API void cexptab_gen(cexptab_t *nco, cf_t *x, float freq, int len); -LIBLTE_API void cexptab_gen_direct(cf_t *x, float freq, int len); +LIBLTE_API void cexptab_gen(cexptab_t *nco, + cf_t *x, + float freq, + uint32_t len); + +LIBLTE_API void cexptab_gen_direct(cf_t *x, + float freq, + uint32_t len); #endif // CEXPTAB_ diff --git a/lte/phy/include/liblte/phy/utils/convolution.h b/lte/phy/include/liblte/phy/utils/convolution.h index 99c058f02..ed9404738 100644 --- a/lte/phy/include/liblte/phy/utils/convolution.h +++ b/lte/phy/include/liblte/phy/utils/convolution.h @@ -32,23 +32,36 @@ #include "liblte/config.h" #include "liblte/phy/utils/dft.h" +typedef _Complex float cf_t; + typedef struct LIBLTE_API { - _Complex float *input_fft; - _Complex float *filter_fft; - _Complex float *output_fft; - _Complex float *output_fft2; - int input_len; - int filter_len; - int output_len; + cf_t *input_fft; + cf_t *filter_fft; + cf_t *output_fft; + cf_t *output_fft2; + uint32_t input_len; + uint32_t filter_len; + uint32_t output_len; dft_plan_t input_plan; dft_plan_t filter_plan; dft_plan_t output_plan; }conv_fft_cc_t; -LIBLTE_API int conv_fft_cc_init(conv_fft_cc_t *state, int input_len, int filter_len); -LIBLTE_API void conv_fft_cc_free(conv_fft_cc_t *state); -LIBLTE_API int conv_fft_cc_run(conv_fft_cc_t *state, _Complex float *input, _Complex float *filter, _Complex float *output); +LIBLTE_API int conv_fft_cc_init(conv_fft_cc_t *q, + uint32_t input_len, + uint32_t filter_len); + +LIBLTE_API void conv_fft_cc_free(conv_fft_cc_t *q); + +LIBLTE_API uint32_t conv_fft_cc_run(conv_fft_cc_t *q, + cf_t *input, + cf_t *filter, + cf_t *output); -LIBLTE_API int conv_cc(_Complex float *input, _Complex float *filter, _Complex float *output, int input_len, int filter_len); +LIBLTE_API uint32_t conv_cc(cf_t *input, + cf_t *filter, + cf_t *output, + uint32_t input_len, + uint32_t filter_len); #endif // CONVOLUTION_H_ diff --git a/lte/phy/include/liblte/phy/utils/vector.h b/lte/phy/include/liblte/phy/utils/vector.h index 4456f8036..1b0547cb9 100644 --- a/lte/phy/include/liblte/phy/utils/vector.h +++ b/lte/phy/include/liblte/phy/utils/vector.h @@ -30,51 +30,74 @@ #define VECTOR_ #include +#include #include "liblte/config.h" typedef _Complex float cf_t; /** Return the sum of all the elements */ -LIBLTE_API int vec_acc_ii(int *x, int len); -LIBLTE_API float vec_acc_ff(float *x, int len); -LIBLTE_API cf_t vec_acc_cc(cf_t *x, int len); +LIBLTE_API int vec_acc_ii(int *x, uint32_t len); +LIBLTE_API float vec_acc_ff(float *x, uint32_t len); +LIBLTE_API cf_t vec_acc_cc(cf_t *x, uint32_t len); -LIBLTE_API void *vec_malloc(int size); +LIBLTE_API void *vec_malloc(uint32_t size); + +LIBLTE_API void *vec_realloc(void *ptr, uint32_t old_size, uint32_t new_size); /* print vectors */ -LIBLTE_API void vec_fprint_c(FILE *stream, cf_t *x, int len); -LIBLTE_API void vec_fprint_f(FILE *stream, float *x, int len); -LIBLTE_API void vec_fprint_b(FILE *stream, char *x, int len); -LIBLTE_API void vec_fprint_i(FILE *stream, int *x, int len); +LIBLTE_API void vec_fprint_c(FILE *stream, cf_t *x, uint32_t len); +LIBLTE_API void vec_fprint_f(FILE *stream, float *x, uint32_t len); +LIBLTE_API void vec_fprint_b(FILE *stream, char *x, uint32_t len); +LIBLTE_API void vec_fprint_i(FILE *stream, int *x, uint32_t len); +LIBLTE_API void vec_fprint_hex(FILE *stream, char *x, uint32_t len); + +/* Saves a vector to a file */ +LIBLTE_API void vec_save_file(char *filename, void *buffer, uint32_t len); /* sum two vectors */ -LIBLTE_API void vec_sum_ch(char *z, char *x, char *y, int len); -LIBLTE_API void vec_sum_ccc(cf_t *z, cf_t *x, cf_t *y, int len); +LIBLTE_API void vec_sum_ch(char *x, char *y, char *z, uint32_t len); +LIBLTE_API void vec_sum_ccc(cf_t *x, cf_t *y, cf_t *z, uint32_t len); + +/* substract two vectors z=x-y */ +LIBLTE_API void vec_sub_fff(float *x, float *y, float *z, uint32_t len); /* scalar product */ -LIBLTE_API void vec_sc_prod_cfc(cf_t *x, float h, cf_t *z, int len); -LIBLTE_API void vec_sc_prod_ccc(cf_t *x, cf_t h, cf_t *z, int len); +LIBLTE_API void vec_sc_prod_cfc(cf_t *x, float h, cf_t *z, uint32_t len); +LIBLTE_API void vec_sc_prod_ccc(cf_t *x, cf_t h, cf_t *z, uint32_t len); +LIBLTE_API void vec_sc_prod_fff(float *x, float h, float *z, uint32_t len); + +LIBLTE_API void vec_convert_fi(float *x, int16_t *z, float scale, uint32_t len); + +LIBLTE_API void vec_deinterleave_cf(cf_t *x, float *real, float *imag, uint32_t len); /* vector product (element-wise) */ -LIBLTE_API void vec_prod_ccc(cf_t *x, cf_t *y, cf_t *z, int len); -LIBLTE_API void vec_prod_ccc_unalign(cf_t *x, cf_t *y, cf_t *z, int len); +LIBLTE_API void vec_prod_ccc(cf_t *x, cf_t *y, cf_t *z, uint32_t len); + +/* vector product (element-wise) */ +LIBLTE_API void vec_prod_cfc(cf_t *x, float *y, cf_t *z, uint32_t len); + +LIBLTE_API cf_t vec_dot_prod_ccc(cf_t *x, cf_t *y, uint32_t len); +LIBLTE_API float vec_dot_prod_fff(float *x, float *y, uint32_t len); /* z=x/y vector division (element-wise) */ -LIBLTE_API void vec_div_ccc(cf_t *x, cf_t *y, cf_t *z, int len); +LIBLTE_API void vec_div_ccc(cf_t *x, cf_t *y, cf_t *z, uint32_t len); /* conjugate */ -LIBLTE_API void vec_conj_cc(cf_t *x, cf_t *y, int len); +LIBLTE_API void vec_conj_cc(cf_t *x, cf_t *y, uint32_t len); /* average vector power */ -LIBLTE_API float vec_avg_power_cf(cf_t *x, int len); +LIBLTE_API float vec_avg_power_cf(cf_t *x, uint32_t len); /* return the index of the maximum value in the vector */ -LIBLTE_API int vec_max_fi(float *x, int len); +LIBLTE_API uint32_t vec_max_fi(float *x, uint32_t len); /* quantify vector of floats and convert to unsigned char */ -LIBLTE_API void vec_quant_fuc(float *in, unsigned char *out, float gain, float offset, float clip, int len); +LIBLTE_API void vec_quant_fuc(float *in, unsigned char *out, float gain, float offset, float clip, uint32_t len); /* magnitude of each vector element */ -LIBLTE_API void vec_abs_cf(cf_t *x, float *abs, int len); +LIBLTE_API void vec_abs_cf(cf_t *x, float *abs, uint32_t len); + +/* argument of each vector element */ +LIBLTE_API void vec_arg_cf(cf_t *x, float *arg, uint32_t len); #endif // VECTOR_ diff --git a/lte/phy/lib/CMakeLists.txt b/lte/phy/lib/CMakeLists.txt index ec06db805..bbb80299c 100644 --- a/lte/phy/lib/CMakeLists.txt +++ b/lte/phy/lib/CMakeLists.txt @@ -29,13 +29,13 @@ FIND_PACKAGE(FFTW3F REQUIRED) # TODO: distribute kissfft instead INCLUDE_DIRECTORIES(${FFTW3F_INCLUDE_DIRS}) IF(${DISABLE_VOLK}) - IF(${DISABLE_VOLK} EQUAL 0) - FIND_PACKAGE(Volk) - ELSE(${DISABLE_VOLK} EQUAL 0) - MESSAGE(STATUS "VOLK library disabled (DISABLE_VOLK=1)") - ENDIF(${DISABLE_VOLK} EQUAL 0) + IF(${DISABLE_VOLK} EQUAL 0) + FIND_PACKAGE(Volk) + ELSE(${DISABLE_VOLK} EQUAL 0) + MESSAGE(STATUS "VOLK library disabled (DISABLE_VOLK=1)") + ENDIF(${DISABLE_VOLK} EQUAL 0) ELSE(${DISABLE_VOLK}) - FIND_PACKAGE(Volk) + FIND_PACKAGE(Volk) ENDIF(${DISABLE_VOLK}) ######################################################################## @@ -44,10 +44,10 @@ ENDIF(${DISABLE_VOLK}) FILE(GLOB modules *) SET(SOURCES_ALL "") FOREACH (_module ${modules}) - IF(IS_DIRECTORY ${_module}) - FILE(GLOB_RECURSE tmp "${_module}/src/*.c") - LIST(APPEND SOURCES_ALL ${tmp}) - ENDIF(IS_DIRECTORY ${_module}) + IF(IS_DIRECTORY ${_module}) + FILE(GLOB_RECURSE tmp "${_module}/src/*.c") + LIST(APPEND SOURCES_ALL ${tmp}) + ENDIF(IS_DIRECTORY ${_module}) ENDFOREACH() ADD_LIBRARY(lte_phy SHARED ${SOURCES_ALL}) @@ -56,12 +56,12 @@ INSTALL(TARGETS lte_phy DESTINATION ${LIBRARY_DIR}) LIBLTE_SET_PIC(lte_phy) IF(VOLK_FOUND) - INCLUDE_DIRECTORIES(${VOLK_INCLUDE_DIRS}) - SET_TARGET_PROPERTIES(lte_phy PROPERTIES COMPILE_DEFINITIONS "${VOLK_DEFINITIONS}") - TARGET_LINK_LIBRARIES(lte_phy ${VOLK_LIBRARIES}) - MESSAGE(STATUS " Compiling with VOLK SIMD library.") + INCLUDE_DIRECTORIES(${VOLK_INCLUDE_DIRS}) + SET_TARGET_PROPERTIES(lte_phy PROPERTIES COMPILE_DEFINITIONS "${VOLK_DEFINITIONS}") + TARGET_LINK_LIBRARIES(lte_phy ${VOLK_LIBRARIES}) + MESSAGE(STATUS " Compiling with VOLK SIMD library.") ELSE(VOLK_FOUND) - MESSAGE(STATUS " VOLK SIMD library NOT found. Using generic implementation.") + MESSAGE(STATUS " VOLK SIMD library NOT found. Using generic implementation.") ENDIF(VOLK_FOUND) @@ -70,10 +70,10 @@ ENDIF(VOLK_FOUND) ######################################################################## FILE(GLOB_RECURSE cmakefiles CMakeLists.txt) FOREACH (_file ${cmakefiles}) - GET_FILENAME_COMPONENT(dir ${_file} PATH) - IF (NOT ${dir} STREQUAL ${CMAKE_CURRENT_SOURCE_DIR}) - ADD_SUBDIRECTORY(${dir}) - ENDIF () + GET_FILENAME_COMPONENT(dir ${_file} PATH) + IF (NOT ${dir} STREQUAL ${CMAKE_CURRENT_SOURCE_DIR}) + ADD_SUBDIRECTORY(${dir}) + ENDIF () ENDFOREACH() diff --git a/lte/phy/lib/ch_estimation/src/chest.c b/lte/phy/lib/ch_estimation/src/chest.c index 31332eb8f..843266d7f 100644 --- a/lte/phy/lib/ch_estimation/src/chest.c +++ b/lte/phy/lib/ch_estimation/src/chest.c @@ -32,13 +32,14 @@ #include #include "liblte/phy/ch_estimation/chest.h" -#include "liblte/phy/resampling/interp.h" #include "liblte/phy/utils/vector.h" #include "liblte/phy/utils/debug.h" #define SLOT_SZ(q) (q->nof_symbols * q->symbol_sz) #define SF_SZ(q) (2 * SLOT_SZ(q)) +//#define VOLK_INTERP + void chest_fprint(chest_t *q, FILE *stream, uint32_t nslot, uint32_t port_id) { chest_ref_fprint(q, stream, nslot, port_id); chest_recvsig_fprint(q, stream, nslot, port_id); @@ -102,6 +103,7 @@ int chest_ce_ref(chest_t *q, cf_t *input, uint32_t nslot, uint32_t port_id, uint port_id < q->nof_ports) { if (nref < q->refsignal[port_id][nslot].nof_refs) { + fidx = q->refsignal[port_id][nslot].refs[nref].freq_idx; // reference frequency index tidx = q->refsignal[port_id][nslot].refs[nref].time_idx; // reference time index @@ -153,10 +155,15 @@ int chest_ce_slot_port(chest_t *q, cf_t *input, cf_t *ce, uint32_t nslot, uint32 /* interpolate the symbols with references * in the freq domain */ for (i=0;insymbols;i++) { +#ifdef VOLK_INTERP + interp_run_offset(&q->interp_freq[port_id], + &r->ch_est[i * r->nof_refs/2], &ce[r->symbols_ref[i] * q->nof_re], + r->voffset, RE_X_RB/2-r->voffset); +#else interp_linear_offset(&r->ch_est[i * r->nof_refs/2], &ce[r->symbols_ref[i] * q->nof_re], RE_X_RB/2, r->nof_refs/2, r->voffset, RE_X_RB/2-r->voffset); - +#endif } /* now interpolate in the time domain */ for (i=0;inof_re; i++) { @@ -164,8 +171,13 @@ int chest_ce_slot_port(chest_t *q, cf_t *input, cf_t *ce, uint32_t nslot, uint32 for (j=0;jnsymbols;j++) { x[j] = ce[r->symbols_ref[j] * q->nof_re + i]; } +#ifdef VOLK_INTERP + interp_run_offset(&q->interp_time[port_id], x, y, + r->symbols_ref[0], 3); +#else interp_linear_offset(x, y, r->symbols_ref[1]-r->symbols_ref[0], 2, r->symbols_ref[0], 3); +#endif } else { for (j=0;jsymbols_ref[0] * q->nof_re + i]; @@ -225,7 +237,7 @@ int chest_ce_sf(chest_t *q, cf_t *input, cf_t *ce[MAX_PORTS], uint32_t sf_idx) { return LIBLTE_SUCCESS; } -int chest_init(chest_t *q, chest_interp_t interp, uint32_t nof_re, uint32_t nof_symbols, uint32_t nof_ports) { +int chest_init(chest_t *q, uint32_t nof_re, uint32_t nof_symbols, uint32_t nof_ports) { int ret = LIBLTE_ERROR_INVALID_INPUTS; if (q != NULL && @@ -236,12 +248,7 @@ int chest_init(chest_t *q, chest_interp_t interp, uint32_t nof_re, uint32_t nof_ q->nof_ports = nof_ports; q->nof_symbols = nof_symbols; q->nof_re = nof_re; - - switch(interp) { - case LINEAR: - q->interp = interp_linear_offset; - } - + INFO("Initializing channel estimator size %dx%d, nof_ports=%d\n", q->nof_symbols, q->nof_re, nof_ports); @@ -250,9 +257,9 @@ int chest_init(chest_t *q, chest_interp_t interp, uint32_t nof_re, uint32_t nof_ return ret; } -int chest_init_LTEDL(chest_t *q, chest_interp_t interp, lte_cell_t cell) { +int chest_init_LTEDL(chest_t *q, lte_cell_t cell) { int ret; - ret = chest_init(q, interp, cell.nof_prb * RE_X_RB, CP_NSYMB(cell.cp), cell.nof_ports); + ret = chest_init(q, cell.nof_prb * RE_X_RB, CP_NSYMB(cell.cp), cell.nof_ports); if (ret != LIBLTE_SUCCESS) { return ret; } else { @@ -268,6 +275,16 @@ int chest_ref_LTEDL_slot_port(chest_t *q, uint32_t nslot, uint32_t port_id, lte_ nslot < NSLOTS_X_FRAME) { ret = refsignal_init_LTEDL(&q->refsignal[port_id][nslot], port_id, nslot, cell); + + if (ret == LIBLTE_SUCCESS) { + if (nslot == 0) { + ret = interp_init(&q->interp_freq[port_id], LINEAR, q->refsignal[port_id][nslot].nof_refs/2, RE_X_RB/2); + if (ret == LIBLTE_SUCCESS) { + ret = interp_init(&q->interp_time[port_id], LINEAR, 2, + q->refsignal[port_id][nslot].symbols_ref[1] - q->refsignal[port_id][nslot].symbols_ref[0]); + } + } + } } return ret; } @@ -339,7 +356,7 @@ int chest_initialize(chest_hl* h) { cell.nof_prb = h->init.nof_prb; cell.cp = h->init.nof_symbols == CPNORM_NSYMB ? CPNORM : CPEXT; - if (chest_init_LTEDL(&h->obj, LINEAR, cell)) { + if (chest_init_LTEDL(&h->obj, cell)) { fprintf(stderr, "Error initializing equalizer\n"); return -1; } diff --git a/lte/phy/lib/ch_estimation/test/chest_test.c b/lte/phy/lib/ch_estimation/test/chest_test.c index 3f97e149d..b0328b4ba 100644 --- a/lte/phy/lib/ch_estimation/test/chest_test.c +++ b/lte/phy/lib/ch_estimation/test/chest_test.c @@ -162,7 +162,7 @@ int main(int argc, char **argv) { while(cid <= max_cid) { cell.id = cid; - if (chest_init_LTEDL(&eq, LINEAR, cell)) { + if (chest_init_LTEDL(&eq, cell)) { fprintf(stderr, "Error initializing equalizer\n"); goto do_exit; } diff --git a/lte/phy/lib/common/src/phy_common.c b/lte/phy/lib/common/src/phy_common.c index a4b9a314d..223d2e299 100644 --- a/lte/phy/lib/common/src/phy_common.c +++ b/lte/phy/lib/common/src/phy_common.c @@ -64,7 +64,24 @@ bool lte_cell_isvalid(lte_cell_t *cell) { return false; } } - + +bool lte_N_id_2_isvalid(uint32_t N_id_2) { + if (N_id_2 < 3) { + return true; + } else { + return false; + } +} + +bool lte_N_id_1_isvalid(uint32_t N_id_1) { + if (N_id_1 < 169) { + return true; + } else { + return false; + } +} + + /* * Returns Turbo coder interleaver size for Table 5.1.3-3 (36.212) index */ @@ -106,6 +123,14 @@ uint32_t lte_mod_bits_x_symbol(lte_mod_t mod) { } } +char *lte_cp_string(lte_cp_t cp) { + if (cp == CPNORM) { + return "Normal"; + } else { + return "Extended"; + } +} + /* * Finds index of minimum K>=long_cb in Table 5.1.3-3 of 36.212 */ @@ -130,6 +155,7 @@ int lte_sampling_freq_hz(uint32_t nof_prb) { return 15000 * n; } } + int lte_symbol_sz(uint32_t nof_prb) { if (nof_prb<=0) { return LIBLTE_ERROR; @@ -150,6 +176,18 @@ int lte_symbol_sz(uint32_t nof_prb) { return LIBLTE_ERROR; } +bool lte_symbol_sz_isvalid(uint32_t symbol_sz) { + if (symbol_sz == 128 || + symbol_sz == 256 || + symbol_sz == 512 || + symbol_sz == 1024 || + symbol_sz == 2048) { + return true; + } else { + return false; + } +} + uint32_t lte_voffset(uint32_t symbol_id, uint32_t cell_id, uint32_t nof_ports) { if (nof_ports == 1 && symbol_id==0) { return (cell_id+3) % 6; diff --git a/lte/phy/lib/phch/src/dci.c b/lte/phy/lib/phch/src/dci.c index df278efa3..5d57a28ab 100644 --- a/lte/phy/lib/phch/src/dci.c +++ b/lte/phy/lib/phch/src/dci.c @@ -61,7 +61,7 @@ int dci_msg_to_ra_dl(dci_msg_t *msg, uint16_t msg_rnti, uint16_t c_rnti, return ret; } - if (VERBOSE_ISINFO()) { + if (VERBOSE_ISDEBUG()) { dci_msg_type_fprint(stdout, type); } if (type.type == PDSCH_SCHED) { @@ -72,7 +72,7 @@ int dci_msg_to_ra_dl(dci_msg_t *msg, uint16_t msg_rnti, uint16_t c_rnti, return ret; } - if (VERBOSE_ISINFO()) { + if (VERBOSE_ISDEBUG()) { ra_pdsch_fprint(stdout, ra_dl, cell.nof_prb); } diff --git a/lte/phy/lib/phch/src/pdcch.c b/lte/phy/lib/phch/src/pdcch.c index 111420be4..99d49b4aa 100644 --- a/lte/phy/lib/phch/src/pdcch.c +++ b/lte/phy/lib/phch/src/pdcch.c @@ -50,6 +50,13 @@ #define MIN(a,b) ((a>b)?b:a) +#define NOF_COMMON_FORMATS 2 +const dci_format_t common_formats[NOF_COMMON_FORMATS] = { Format1A, Format1C }; + +#define NOF_UE_FORMATS 2 +const dci_format_t ue_formats[NOF_UE_FORMATS] = { Format0, Format1 }; // 1A has the same payload as 0 + + static void set_cfi(pdcch_t *q, uint32_t cfi) { if (cfi > 0 && cfi < 4) { q->nof_regs = (regs_pdcch_nregs(q->regs, cfi) / 9) * 9; @@ -228,7 +235,8 @@ uint32_t pdcch_ue_locations(pdcch_t *q, dci_location_t *c, uint32_t max_candidat * Returns the number of candidates saved in the array c. */ uint32_t pdcch_common_locations(pdcch_t *q, dci_location_t *c, uint32_t max_candidates, - uint32_t cfi) { + uint32_t cfi) +{ uint32_t i, l, L, k; set_cfi(q, cfi); @@ -271,8 +279,8 @@ static int dci_decode(pdcch_t *q, float *e, char *data, uint32_t E, uint32_t nof if (q != NULL && data != NULL && - E < q->max_bits && - nof_bits < DCI_MAX_BITS) + E <= q->max_bits && + nof_bits <= DCI_MAX_BITS) { /* unrate matching */ @@ -301,6 +309,7 @@ static int dci_decode(pdcch_t *q, float *e, char *data, uint32_t E, uint32_t nof } return LIBLTE_SUCCESS; } else { + fprintf(stderr, "Invalid parameters: E: %d, max_bits: %d, nof_bits: %d\n", E, q->max_bits, nof_bits); return LIBLTE_ERROR_INVALID_INPUTS; } } diff --git a/lte/phy/lib/phch/src/pdsch.c b/lte/phy/lib/phch/src/pdsch.c index 6b92c4e0b..0f5a508d4 100644 --- a/lte/phy/lib/phch/src/pdsch.c +++ b/lte/phy/lib/phch/src/pdsch.c @@ -171,7 +171,7 @@ int pdsch_get(pdsch_t *q, cf_t *sf_symbols, cf_t *pdsch_symbols, } /** Initializes the PDCCH transmitter and receiver */ -int pdsch_init(pdsch_t *q, uint16_t user_rnti, lte_cell_t cell) { +int pdsch_init(pdsch_t *q, lte_cell_t cell) { int ret = LIBLTE_ERROR_INVALID_INPUTS; int i; @@ -183,7 +183,6 @@ int pdsch_init(pdsch_t *q, uint16_t user_rnti, lte_cell_t cell) { ret = LIBLTE_ERROR; q->cell = cell; - q->rnti = user_rnti; q->max_symbols = q->cell.nof_prb * MAX_PDSCH_RE(q->cell.cp); @@ -204,13 +203,8 @@ int pdsch_init(pdsch_t *q, uint16_t user_rnti, lte_cell_t cell) { 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; - } - } + + q->rnti_is_set = false; if (tcod_init(&q->encoder, MAX_LONG_CB)) { goto clean; @@ -304,8 +298,20 @@ void pdsch_free(pdsch_t *q) { } +int pdsch_set_rnti(pdsch_t *q, uint16_t rnti) { + uint32_t i; + for (i = 0; i < NSUBFRAMES_X_FRAME; i++) { + if (sequence_pdsch(&q->seq_pdsch[i], rnti, 0, 2 * i, q->cell.id, + q->max_symbols * q->mod[3].nbits_x_symbol)) { + return LIBLTE_ERROR; + } + } + q->rnti_is_set = true; + q->rnti = rnti; + return LIBLTE_SUCCESS; +} /* Calculate Codeblock Segmentation as in Section 5.1.2 of 36.212 */ -int codeblock_segmentation(struct cb_segm *s, uint32_t tbs) { +static int codeblock_segmentation(struct cb_segm *s, uint32_t tbs) { uint32_t Bp, B, idx1; int ret; @@ -499,7 +505,7 @@ int pdsch_decode_tb(pdsch_t *q, char *data, uint32_t tbs, uint32_t nb_e, n_e = nb_e - rp; } - INFO("CB#%d: cb_len: %d, rlen: %d, wp: %d, rp: %d, F: %d, E: %d\n", i, + DEBUG("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 */ @@ -526,7 +532,7 @@ int pdsch_decode_tb(pdsch_t *q, char *data, uint32_t tbs, uint32_t nb_e, if (i < harq_process->cb_segm.C - 1) { memcpy(&data[wp], &q->cb_in[F], (rlen - F) * sizeof(char)); } else { - INFO("Last CB, appending parity: %d to %d from %d and 24 from %d\n", + DEBUG("Last CB, appending parity: %d to %d from %d and 24 from %d\n", rlen - F - 24, wp, F, rlen - 24); /* Append Transport Block parity bits to the last CB */ memcpy(&data[wp], &q->cb_in[F], (rlen - F - 24) * sizeof(char)); @@ -538,7 +544,7 @@ int pdsch_decode_tb(pdsch_t *q, char *data, uint32_t tbs, uint32_t nb_e, rp += n_e; } - INFO("END CB#%d: wp: %d, rp: %d\n", i, wp, rp); + DEBUG("END CB#%d: wp: %d, rp: %d\n", i, wp, rp); // Compute transport block CRC par_rx = crc_checksum(&q->crc_tb, data, tbs); @@ -573,11 +579,12 @@ int pdsch_decode(pdsch_t *q, cf_t *sf_symbols, cf_t *ce[MAX_PORTS], char *data, cf_t *x[MAX_LAYERS]; uint32_t nof_symbols, nof_bits, nof_bits_e; - if (q != NULL && - sf_symbols != NULL && - data != NULL && - subframe < 10 && - harq_process != NULL) + if (q != NULL && + sf_symbols != NULL && + data != NULL && + subframe < 10 && + harq_process != NULL && + harq_process->mcs.mod > 0) { nof_bits = harq_process->mcs.tbs; @@ -585,8 +592,8 @@ int pdsch_decode(pdsch_t *q, cf_t *sf_symbols, cf_t *ce[MAX_PORTS], char *data, nof_bits_e = nof_symbols * q->mod[harq_process->mcs.mod - 1].nbits_x_symbol; - INFO("Decoding PDSCH SF: %d, Mod %d, NofBits: %d, NofSymbols: %d, NofBitsE: %d\n", - subframe, harq_process->mcs.mod, nof_bits, nof_symbols, nof_bits_e); + INFO("Decoding PDSCH SF: %d, Mod %d, NofBits: %d, NofSymbols: %d, NofBitsE: %d, rv_idx: %d\n", + subframe, harq_process->mcs.mod, nof_bits, nof_symbols, nof_bits_e, rv_idx); /* number of layers equals number of ports */ for (i = 0; i < q->cell.nof_ports; i++) { @@ -651,105 +658,109 @@ int pdsch_encode_tb(pdsch_t *q, char *data, uint32_t tbs, uint32_t nb_e, uint32_t i; uint32_t cb_len, rp, wp, rlen, F, n_e; char *e_bits = q->pdsch_e; + int ret = LIBLTE_ERROR_INVALID_INPUTS; if (q != NULL && data != NULL && nb_e < q->max_symbols * q->mod[3].nbits_x_symbol) { - if (rv_idx == 0) { - /* 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); - } + if (q->rnti_is_set) { + if (rv_idx == 0) { + /* Compute transport block CRC */ + par = crc_checksum(&q->crc_tb, data, tbs); - /* Add filler bits to the new data buffer */ - for (i = 0; i < harq_process->cb_segm.F; i++) { - q->cb_in[i] = LTE_NULL_BIT; - } - } - - wp = 0; - rp = 0; - for (i = 0; i < harq_process->cb_segm.C; i++) { + /* parity bits will be appended later */ + bit_pack(par, &p_parity, 24); - /* Get read lengths */ - if (i < harq_process->cb_segm.C - harq_process->cb_segm.C2) { - cb_len = harq_process->cb_segm.K1; - } else { - cb_len = harq_process->cb_segm.K2; - } - if (harq_process->cb_segm.C > 1) { - rlen = cb_len - 24; - } else { - rlen = cb_len; - } - if (i == 0) { - F = harq_process->cb_segm.F; - } else { - F = 0; - } + if (VERBOSE_ISDEBUG()) { + DEBUG("DATA: ", 0); + vec_fprint_b(stdout, data, tbs); + DEBUG("PARITY: ", 0); + vec_fprint_b(stdout, parity, 24); + } - if (i < harq_process->cb_segm.C - 1) { - n_e = nb_e / harq_process->cb_segm.C; - } else { - n_e = nb_e - wp; + /* Add filler bits to the new data buffer */ + for (i = 0; i < harq_process->cb_segm.F; i++) { + q->cb_in[i] = LTE_NULL_BIT; + } } + + wp = 0; + rp = 0; + for (i = 0; i < harq_process->cb_segm.C; i++) { - 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); + /* Get read lengths */ + if (i < harq_process->cb_segm.C - harq_process->cb_segm.C2) { + cb_len = harq_process->cb_segm.K1; + } else { + cb_len = harq_process->cb_segm.K2; + } + if (harq_process->cb_segm.C > 1) { + rlen = cb_len - 24; + } else { + rlen = cb_len; + } + if (i == 0) { + F = harq_process->cb_segm.F; + } else { + F = 0; + } - if (rv_idx == 0) { - /* Copy data to another buffer, making space for the Codeblock CRC */ if (i < harq_process->cb_segm.C - 1) { - memcpy(&q->cb_in[F], &data[rp], (rlen - F) * sizeof(char)); + n_e = nb_e / harq_process->cb_segm.C; } else { - INFO("Last CB, appending parity: %d from %d and 24 to %d\n", - rlen - F - 24, rp, rlen - 24); - /* Append Transport Block parity bits to the last CB */ - memcpy(&q->cb_in[F], &data[rp], (rlen - F - 24) * sizeof(char)); - memcpy(&q->cb_in[rlen - 24], parity, 24 * sizeof(char)); - } - if (harq_process->cb_segm.C > 1) { - /* Attach Codeblock CRC */ - crc_attach(&q->crc_cb, q->cb_in, rlen); + n_e = nb_e - wp; } - if (VERBOSE_ISDEBUG()) { - DEBUG("CB#%d Len=%d: ", i, cb_len); - vec_fprint_b(stdout, q->cb_in, cb_len); + + INFO("CB#%d: cb_len: %d, rlen: %d, wp: %d, rp: %d, F: %d, E: %d\n", i, + cb_len, rlen - F, wp, rp, F, n_e); + + if (rv_idx == 0) { + /* Copy data to another buffer, making space for the Codeblock CRC */ + if (i < harq_process->cb_segm.C - 1) { + memcpy(&q->cb_in[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[F], &data[rp], (rlen - F - 24) * sizeof(char)); + memcpy(&q->cb_in[rlen - 24], parity, 24 * sizeof(char)); + } + if (harq_process->cb_segm.C > 1) { + /* Attach Codeblock CRC */ + crc_attach(&q->crc_cb, q->cb_in, rlen); + } + if (VERBOSE_ISDEBUG()) { + DEBUG("CB#%d Len=%d: ", i, cb_len); + vec_fprint_b(stdout, q->cb_in, cb_len); + } + /* Turbo Encoding */ + tcod_encode(&q->encoder, q->cb_in, (char*) q->cb_out, cb_len); } - /* Turbo Encoding */ - tcod_encode(&q->encoder, q->cb_in, (char*) q->cb_out, cb_len); - } - - /* Rate matching */ - if (rm_turbo_tx(harq_process->pdsch_w_buff_c[i], harq_process->w_buff_size, - (char*) q->cb_out, 3 * cb_len + 12, - &e_bits[wp], n_e, rv_idx)) - { - fprintf(stderr, "Error in rate matching\n"); - return LIBLTE_ERROR; + + /* Rate matching */ + if (rm_turbo_tx(harq_process->pdsch_w_buff_c[i], harq_process->w_buff_size, + (char*) q->cb_out, 3 * cb_len + 12, + &e_bits[wp], n_e, rv_idx)) + { + fprintf(stderr, "Error in rate matching\n"); + return LIBLTE_ERROR; + } + + /* Set read/write pointers */ + rp += (rlen - F); + wp += n_e; } - /* Set read/write pointers */ - rp += (rlen - F); - wp += n_e; + INFO("END CB#%d: wp: %d, rp: %d\n", i, wp, rp); + + ret = LIBLTE_SUCCESS; + } else { + fprintf(stderr, "Must call pdsch_set_rnti() to set the encoder/decoder RNTI\n"); } - - INFO("END CB#%d: wp: %d, rp: %d\n", i, wp, rp); - - return LIBLTE_SUCCESS; - } else { - return LIBLTE_ERROR_INVALID_INPUTS; - } + } + return ret; } /** Converts the PDSCH data bits to symbols mapped to the slot ready for transmission @@ -761,74 +772,77 @@ int pdsch_encode(pdsch_t *q, char *data, cf_t *sf_symbols[MAX_PORTS], uint32_t s uint32_t nof_symbols, nof_bits, nof_bits_e; /* Set pointers for layermapping & precoding */ cf_t *x[MAX_LAYERS]; - + int ret = LIBLTE_ERROR_INVALID_INPUTS; + if (q != NULL && data != NULL && subframe < 10 && harq_process != NULL) { - for (i=0;icell.nof_ports;i++) { - if (sf_symbols[i] == NULL) { - return LIBLTE_ERROR_INVALID_INPUTS; + if (q->rnti_is_set) { + for (i=0;icell.nof_ports;i++) { + if (sf_symbols[i] == NULL) { + return LIBLTE_ERROR_INVALID_INPUTS; + } } - } - - nof_bits = harq_process->mcs.tbs; - nof_symbols = harq_process->prb_alloc.re_sf[subframe]; - nof_bits_e = nof_symbols * q->mod[harq_process->mcs.mod - 1].nbits_x_symbol; + + nof_bits = harq_process->mcs.tbs; + nof_symbols = harq_process->prb_alloc.re_sf[subframe]; + nof_bits_e = nof_symbols * q->mod[harq_process->mcs.mod - 1].nbits_x_symbol; - if (harq_process->mcs.tbs == 0) { - return LIBLTE_ERROR_INVALID_INPUTS; - } - - if (nof_bits > nof_bits_e) { - fprintf(stderr, "Invalid code rate %.2f\n", (float) nof_bits / nof_bits_e); - return LIBLTE_ERROR_INVALID_INPUTS; - } + if (harq_process->mcs.tbs == 0) { + return LIBLTE_ERROR_INVALID_INPUTS; + } + + if (nof_bits > nof_bits_e) { + fprintf(stderr, "Invalid code rate %.2f\n", (float) nof_bits / nof_bits_e); + return LIBLTE_ERROR_INVALID_INPUTS; + } - 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->cell.nof_prb); - return LIBLTE_ERROR_INVALID_INPUTS; - } + 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->cell.nof_prb); + return LIBLTE_ERROR_INVALID_INPUTS; + } - INFO("Encoding PDSCH SF: %d, Mod %d, NofBits: %d, NofSymbols: %d, NofBitsE: %d, rv_idx: %d\n", - subframe, harq_process->mcs.mod, nof_bits, nof_symbols, nof_bits_e, rv_idx); + INFO("Encoding PDSCH SF: %d, Mod %d, NofBits: %d, NofSymbols: %d, NofBitsE: %d, rv_idx: %d\n", + subframe, harq_process->mcs.mod, nof_bits, nof_symbols, nof_bits_e, rv_idx); - /* number of layers equals number of ports */ - for (i = 0; i < q->cell.nof_ports; i++) { - x[i] = q->pdsch_x[i]; - } - memset(&x[q->cell.nof_ports], 0, sizeof(cf_t*) * (MAX_LAYERS - q->cell.nof_ports)); + /* number of layers equals number of ports */ + for (i = 0; i < q->cell.nof_ports; i++) { + x[i] = q->pdsch_x[i]; + } + memset(&x[q->cell.nof_ports], 0, sizeof(cf_t*) * (MAX_LAYERS - q->cell.nof_ports)); - if (pdsch_encode_tb(q, data, nof_bits, nof_bits_e, harq_process, rv_idx)) { - fprintf(stderr, "Error encoding TB\n"); - return LIBLTE_ERROR; - } - + if (pdsch_encode_tb(q, data, nof_bits, nof_bits_e, harq_process, rv_idx)) { + fprintf(stderr, "Error encoding TB\n"); + return LIBLTE_ERROR; + } + + scrambling_b_offset(&q->seq_pdsch[subframe], (char*) q->pdsch_e, 0, nof_bits_e); - scrambling_b_offset(&q->seq_pdsch[subframe], (char*) q->pdsch_e, 0, nof_bits_e); + mod_modulate(&q->mod[harq_process->mcs.mod - 1], (char*) q->pdsch_e, q->pdsch_d, nof_bits_e); - mod_modulate(&q->mod[harq_process->mcs.mod - 1], (char*) q->pdsch_e, q->pdsch_d, nof_bits_e); + /* TODO: only diversity supported */ + if (q->cell.nof_ports > 1) { + layermap_diversity(q->pdsch_d, x, q->cell.nof_ports, nof_symbols); + precoding_diversity(x, q->pdsch_symbols, q->cell.nof_ports, + nof_symbols / q->cell.nof_ports); + } else { + memcpy(q->pdsch_symbols[0], q->pdsch_d, nof_symbols * sizeof(cf_t)); + } - /* TODO: only diversity supported */ - if (q->cell.nof_ports > 1) { - layermap_diversity(q->pdsch_d, x, q->cell.nof_ports, nof_symbols); - precoding_diversity(x, q->pdsch_symbols, q->cell.nof_ports, - nof_symbols / q->cell.nof_ports); + /* mapping to resource elements */ + for (i = 0; i < q->cell.nof_ports; i++) { + pdsch_put(q, q->pdsch_symbols[i], sf_symbols[i], &harq_process->prb_alloc, subframe); + } + ret = LIBLTE_SUCCESS; } else { - memcpy(q->pdsch_symbols[0], q->pdsch_d, nof_symbols * sizeof(cf_t)); + fprintf(stderr, "Must call pdsch_set_rnti() to set the encoder/decoder RNTI\n"); } - - /* mapping to resource elements */ - for (i = 0; i < q->cell.nof_ports; i++) { - pdsch_put(q, q->pdsch_symbols[i], sf_symbols[i], &harq_process->prb_alloc, subframe); - } - return LIBLTE_SUCCESS; - } else { - return LIBLTE_ERROR_INVALID_INPUTS; - } + } + return ret; } - + \ No newline at end of file diff --git a/lte/phy/lib/phch/src/ue_sync.c b/lte/phy/lib/phch/src/ue_sync.c new file mode 100644 index 000000000..7a73da125 --- /dev/null +++ b/lte/phy/lib/phch/src/ue_sync.c @@ -0,0 +1,555 @@ +/** + * + * \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 "liblte/phy/phch/ue_sync.h" + +#include "liblte/phy/utils/debug.h" +#include "liblte/phy/utils/vector.h" + +#define MAX_TIME_OFFSET 128 +cf_t dummy[MAX_TIME_OFFSET]; + +#define EXPAVERAGE(data, average, nframes) ((data + average * nframes) / (nframes + 1)) + +#define CURRENT_FFTSIZE lte_symbol_sz(q->cell.nof_prb) +#define CURRENT_SFLEN SF_LEN(CURRENT_FFTSIZE, q->cell.cp) + +#define CURRENT_SLOTLEN_RE SLOT_LEN_RE(q->cell.nof_prb, q->cell.cp) +#define CURRENT_SFLEN_RE SF_LEN_RE(q->cell.nof_prb, q->cell.cp) + +#define MAXIMUM_SFLEN SF_LEN(2048, CPNORM) +#define MAXIMUM_SFLEN_RE SF_LEN_RE(110, CPNORM) + +static int mib_decoder_initialize(ue_sync_t *q); +static void mib_decoder_free(ue_sync_t *q); + +int ue_sync_init(ue_sync_t *q, + double (set_rate_callback)(void*, double), + int (recv_callback)(void*, void*, uint32_t), + void *stream_handler) +{ + int ret = LIBLTE_ERROR_INVALID_INPUTS; + + if (q != NULL && + stream_handler != NULL) + { + ret = LIBLTE_ERROR; + + bzero(q, sizeof(ue_sync_t)); + + ue_sync_reset(q); + + q->cell.nof_prb = SYNC_PBCH_NOF_PRB; + q->cell.nof_ports = SYNC_PBCH_NOF_PORTS; + q->cell.id = 0; + q->cell.cp = CPNORM; + + q->pbch_decoded = false; + q->pbch_initialized = false; + q->pbch_decoder_enabled = true; + q->pbch_decode_always = false; + q->decode_sss_on_track = false; + + q->stream = stream_handler; + q->recv_callback = recv_callback; + q->set_rate_callback = set_rate_callback; + + INFO("Setting sampling frequency 1.92 MHz\n",0); + q->set_rate_callback(q->stream, 1920000.0); + + if(sync_init(&q->s, CURRENT_SFLEN, CURRENT_FFTSIZE, CURRENT_FFTSIZE)) { + goto clean_exit; + } + + sync_pss_det_peak_to_avg(&q->s); + + if (cfo_init(&q->cfocorr, MAXIMUM_SFLEN)) { + fprintf(stderr, "Error initiating CFO\n"); + goto clean_exit; + } + + q->input_buffer = vec_malloc(3 * MAXIMUM_SFLEN * sizeof(cf_t)); + if (!q->input_buffer) { + perror("malloc"); + goto clean_exit; + } + + q->sf_symbols = vec_malloc(MAXIMUM_SFLEN_RE * sizeof(cf_t)); + if (!q->sf_symbols) { + perror("malloc"); + goto clean_exit; + } + for (int i=0;ice[i] = vec_malloc(MAXIMUM_SFLEN_RE * sizeof(cf_t)); + if (!q->ce[i]) { + perror("malloc"); + goto clean_exit; + } + } + + //float th = PAR_THRESHOLD_FIND * (1+(float) CURRENT_FFTSIZE/128/10); + sync_set_threshold(&q->s, PAR_THRESHOLD_FIND, PAR_THRESHOLD_FIND/4); + + ret = LIBLTE_SUCCESS; + } + +clean_exit: + if (ret == LIBLTE_ERROR) { + ue_sync_free(q); + } + return ret; +} + +void ue_sync_free(ue_sync_t *q) { + if (q->input_buffer) { + free(q->input_buffer); + } + if (q->sf_symbols) { + free(q->sf_symbols); + } + for (int i=0;ice[i]) { + free(q->ce[i]); + } + } + mib_decoder_free(q); + cfo_free(&q->cfocorr); + sync_free(&q->s); +} + +void ue_sync_set_threshold(ue_sync_t *q, float threshold) { + sync_set_threshold(&q->s, threshold, threshold/2); +} + +lte_cell_t ue_sync_get_cell(ue_sync_t *q) { + return q->cell; +} + +pbch_mib_t ue_sync_get_mib(ue_sync_t *q) { + return q->mib; +} + +uint32_t ue_sync_peak_idx(ue_sync_t *q) { + return q->peak_idx; +} + +ue_sync_state_t ue_sync_get_state(ue_sync_t *q) { + return q->state; +} + +static int update_srate(ue_sync_t *q) { + struct timeval t[3]; + + gettimeofday(&t[1], NULL); + if (sync_realloc(&q->s, CURRENT_SFLEN, CURRENT_FFTSIZE, CURRENT_FFTSIZE)) { + fprintf(stderr, "Error realloc'ing SYNC\n"); + return LIBLTE_ERROR; + } + gettimeofday(&t[2], NULL); + get_time_interval(t); + + if (NOF_MIB_DECODES > 1) { + mib_decoder_free(q); + if (mib_decoder_initialize(q)) { + fprintf(stderr, "Error reinitializing MIB decoder\n"); + return LIBLTE_ERROR; + } + } + + // Finally set the new sampling rate + q->set_rate_callback(q->stream, (float) lte_sampling_freq_hz(q->cell.nof_prb)); + + ue_sync_reset(q); + printf("Set sampling rate %.2f MHz, fft_size=%d, sf_len=%d Texec=%d us\n", + (float) lte_sampling_freq_hz(q->cell.nof_prb)/1000000, + CURRENT_FFTSIZE, CURRENT_SFLEN, (int) t[0].tv_usec); + + return LIBLTE_SUCCESS; +} + +uint32_t ue_sync_get_sfidx(ue_sync_t *q) { + return q->sf_idx; +} + +float ue_sync_get_cfo(ue_sync_t *q) { + return 15000 * q->cur_cfo; +} + +float ue_sync_get_sfo(ue_sync_t *q) { + return 1000*q->mean_time_offset/5; +} + +bool ue_sync_is_mib_decoded(ue_sync_t *q) { + return q->pbch_decoded; +} + +void ue_sync_pbch_enable(ue_sync_t *q, bool enabled) { + q->pbch_decoder_enabled = enabled; +} + +void ue_sync_pbch_always(ue_sync_t *q, bool enabled) { + q->pbch_decode_always = enabled; +} + +void ue_sync_decode_sss_on_track(ue_sync_t *q, bool enabled) { + q->decode_sss_on_track = enabled; +} + +static int mib_decoder_initialize(ue_sync_t *q) { + + if (lte_fft_init(&q->fft, q->cell.cp, q->cell.nof_prb)) { + fprintf(stderr, "Error initializing FFT\n"); + return -1; + } + if (chest_init_LTEDL(&q->chest, q->cell)) { + fprintf(stderr, "Error initializing reference signal\n"); + return -1; + } + if (pbch_init(&q->pbch, q->cell)) { + fprintf(stderr, "Error initiating PBCH\n"); + return -1; + } + q->pbch_initialized = 1; + DEBUG("PBCH initiated cell_id=%d\n", q->cell.id); + + return 0; +} + +static void mib_decoder_free(ue_sync_t *q) { + chest_free(&q->chest); + pbch_free(&q->pbch); + lte_fft_free(&q->fft); +} + +static int mib_decoder_run(ue_sync_t *q) { + int ret; + + /* Run FFT for the second slot */ + lte_fft_run_sf(&q->fft, q->input_buffer, q->sf_symbols); + + /* Get channel estimates of slot #1 for each port */ + chest_ce_sf(&q->chest, q->sf_symbols, q->ce, 0); + + if (q->pbch_last_trial && + (q->frame_total_cnt - q->pbch_last_trial > 2)) + { + pbch_decode_reset(&q->pbch); + INFO("Resetting PBCH decoder: last trial %d, now is %d\n", + q->pbch_last_trial, q->frame_total_cnt); + q->pbch_last_trial = 0; + } + + if (pbch_decode(&q->pbch, q->sf_symbols, q->ce, &q->mib) == 1) { + q->frame_number = q->mib.sfn; + q->cell.nof_ports = q->mib.nof_ports; + q->cell.nof_prb = q->mib.nof_prb; + + if (!q->pbch_decoded) { + printf("MIB decoded:\n"); + pbch_mib_fprint(stdout, &q->mib); + ret = update_srate(q); + } else { + INFO("MIB decoded #%d SFN: %d\n", q->pbch_decoded, q->mib.sfn); + } + q->pbch_decoded++; + + pbch_decode_reset(&q->pbch); + + } else { + INFO("MIB not decoded: %d\n", q->frame_total_cnt); + q->pbch_last_trial = q->frame_total_cnt; + } + + return ret; +} + +static int find_peak_ok(ue_sync_t *q) { + int ret; + + if (q->peak_idx < CURRENT_SFLEN) { + /* Receive the rest of the next subframe */ + if (q->recv_callback(q->stream, &q->input_buffer[CURRENT_SFLEN], q->peak_idx+CURRENT_SFLEN/2) < 0) { + return LIBLTE_ERROR; + } + } + + if (sync_sss_detected(&q->s)) { + ret = sync_get_cell_id(&q->s); + if (ret >= 0) { + q->cell.id = (uint32_t) ret; + q->cell.cp = sync_get_cp(&q->s); + } + + /* Get the subframe index (0 or 5) */ + q->sf_idx = sync_get_slot_id(&q->s)/2; + + /* Reset variables */ + q->frame_ok_cnt = 0; + q->frame_no_cnt = 0; + q->frame_total_cnt = 0; + + /* Goto Tracking state */ + q->state = SF_TRACK; + ret = LIBLTE_SUCCESS; + + INFO("Found peak %d, SF_idx: %d, Cell_id: %d CP: %s\n", + q->peak_idx, q->sf_idx, q->cell.id, lte_cp_string(q->cell.cp)); + + if (q->peak_idx < CURRENT_SFLEN) { + q->sf_idx++; + } + + return ret; + } else { + INFO("Found peak at %d, SSS not detected\n", q->peak_idx); + return 0; + } +} + +int track_peak_ok(ue_sync_t *q, uint32_t track_idx) { + int ret = LIBLTE_SUCCESS; + + /* Make sure subframe idx is what we expect */ + if ((q->sf_idx != sync_get_slot_id(&q->s)/2) && q->decode_sss_on_track) { + printf("\nWarning: Expected SF idx %d but got %d!\n", + q->sf_idx, sync_get_slot_id(&q->s)/2); + q->sf_idx = sync_get_slot_id(&q->s)/2; + } else { + q->time_offset = ((int) track_idx - (int) CURRENT_FFTSIZE); + + /* If the PSS peak is beyond the frame (we sample too slowly), + discard the offseted samples to align next frame */ + if (q->time_offset > 0 && q->time_offset < MAX_TIME_OFFSET) { + ret = q->recv_callback(q->stream, dummy, (uint32_t) q->time_offset); + } else { + ret = LIBLTE_SUCCESS; + } + + /* compute cumulative moving average CFO */ + q->cur_cfo = EXPAVERAGE(sync_get_cfo(&q->s), q->cur_cfo, q->frame_ok_cnt); + + /* compute cumulative moving average time offset */ + q->mean_time_offset = (float) EXPAVERAGE((float) q->time_offset, q->mean_time_offset, q->frame_ok_cnt); + + q->peak_idx = CURRENT_SFLEN/2 + q->time_offset; + q->frame_ok_cnt++; + q->frame_no_cnt = 0; + + + if (ret >= LIBLTE_SUCCESS) { + ret = LIBLTE_SUCCESS; + } + } + + return ret; +} + +int track_peak_no(ue_sync_t *q) { + + /* if we missed too many PSS go back to FIND */ + q->frame_no_cnt++; + if (q->frame_no_cnt >= TRACK_MAX_LOST) { + printf("\n%d frames lost. Going back to FIND\n", (int) q->frame_no_cnt); + q->state = SF_FIND; + } else { + INFO("Tracking peak not found, %d lost\n", (int) q->frame_no_cnt); + } + + return LIBLTE_SUCCESS; +} + +static int receive_samples(ue_sync_t *q) { + + /* A negative time offset means there are samples in our buffer for the next subframe, + because we are sampling too fast. + */ + if (q->time_offset < 0) { + q->time_offset = -q->time_offset; + } + /* copy last part of the last subframe (use move since there could be overlapping) */ + memmove(q->input_buffer, &q->input_buffer[CURRENT_SFLEN-q->time_offset], q->time_offset*sizeof(cf_t)); + + /* Get 1 subframe from the USRP getting more samples and keeping the previous samples, if any */ + if (q->recv_callback(q->stream, &q->input_buffer[q->time_offset], CURRENT_SFLEN - q->time_offset) < 0) { + return LIBLTE_ERROR; + } + + /* reset time offset */ + q->time_offset = 0; + + return LIBLTE_SUCCESS; +} + +int ue_sync_get_buffer(ue_sync_t *q, cf_t **sf_symbols) { + int ret = LIBLTE_ERROR_INVALID_INPUTS; + uint32_t track_idx; + struct timeval t[3]; + + if (q != NULL && + sf_symbols != NULL && + q->input_buffer != NULL) + { + + if (receive_samples(q)) { + fprintf(stderr, "Error receiving samples\n"); + return -1; + } + + switch (q->state) { + case SF_FIND: + q->s.sss_en = true; + + /* Find peak and cell id */ + ret = sync_find(&q->s, q->input_buffer, &q->peak_idx); + if (ret < 0) { + fprintf(stderr, "Error finding correlation peak (%d)\n", ret); + return -1; + } + + DEBUG("Find PAR=%.2f\n", sync_get_peak_to_avg(&q->s)); + + if (ret == 1) { + ret = find_peak_ok(q); + /* Initialize PBCH decoder */ + if (ret == LIBLTE_SUCCESS) { + if (!q->pbch_initialized && q->pbch_decoder_enabled) { + ret = mib_decoder_initialize(q); + if (ret < 0) { + fprintf(stderr, "Error initializing MIB decoder\n"); + } + } + } else if (ret < 0) { + if (ret < 0) { + fprintf(stderr, "Error processing find peak \n"); + } + } + } + break; + case SF_TRACK: + ret = LIBLTE_SUCCESS; + + q->s.sss_en = q->decode_sss_on_track; + + q->sf_idx = (q->sf_idx + 1) % 10; + + DEBUG("TRACK: SF=%d FrameCNT: %d\n", q->sf_idx, q->frame_total_cnt); + + /* Every SF idx 0 and 5, find peak around known position q->peak_idx */ + if (q->sf_idx == 0 || q->sf_idx == 5) { + + #ifdef MEASURE_EXEC_TIME + gettimeofday(&t[1], NULL); + #endif + + track_idx = 0; + + /* track pss around the middle of the subframe, where the PSS is */ + ret = sync_track(&q->s, q->input_buffer, CURRENT_SFLEN/2-CURRENT_FFTSIZE, &track_idx); + if (ret < 0) { + fprintf(stderr, "Error tracking correlation peak\n"); + return -1; + } + + #ifdef MEASURE_EXEC_TIME + gettimeofday(&t[2], NULL); + get_time_interval(t); + q->mean_exec_time = (float) EXPAVERAGE((float) t[0].tv_usec, q->mean_exec_time, q->frame_total_cnt); + #endif + + if (ret == 1) { + ret = track_peak_ok(q, track_idx); + } else { + ret = track_peak_no(q); + } + + INFO("TRACK %3d: SF=%d Track_idx=%d Offset=%d CFO: %f\n", + (int) q->frame_total_cnt, q->sf_idx, track_idx, q->time_offset, sync_get_cfo(&q->s)); + + q->frame_total_cnt++; + + if (ret == LIBLTE_ERROR) { + fprintf(stderr, "Error processing tracking peak\n"); + ue_sync_reset(q); + return LIBLTE_SUCCESS; + } + } + + /* Do CFO Correction and deliver the frame */ + cfo_correct(&q->cfocorr, q->input_buffer, q->input_buffer, -q->cur_cfo / CURRENT_FFTSIZE); + *sf_symbols = q->input_buffer; + + /* At subframe 0, try to decode PBCH if not yet decoded */ + if (q->sf_idx == 0) { + if(q->pbch_decoder_enabled && + (q->pbch_decoded < NOF_MIB_DECODES || q->pbch_decode_always)) + { + mib_decoder_run(q); + } else { + q->mib.sfn = (q->mib.sfn + 1) % 1024; + } + } + + if (ret == LIBLTE_SUCCESS) { + if (q->pbch_decoder_enabled) { + if (q->pbch_decoded >= NOF_MIB_DECODES) { + ret = 1; + } else { + ret = 0; + } + } else { + ret = 1; + } + } + break; + } + } + DEBUG("UE SYNC returns %d\n", ret); + return ret; +} + +void ue_sync_reset(ue_sync_t *q) { + q->state = SF_FIND; + + q->pbch_last_trial = 0; + q->frame_ok_cnt = 0; + q->frame_no_cnt = 0; + q->frame_total_cnt = 0; + q->cur_cfo = 0; + q->mean_time_offset = 0; + q->time_offset = 0; + #ifdef MEASURE_EXEC_TIME + q->mean_exec_time = 0; + #endif +} + diff --git a/lte/phy/lib/phch/test/CMakeLists.txt b/lte/phy/lib/phch/test/CMakeLists.txt index 328d8128a..eb8b8dd1e 100644 --- a/lte/phy/lib/phch/test/CMakeLists.txt +++ b/lte/phy/lib/phch/test/CMakeLists.txt @@ -19,6 +19,23 @@ # and at http://www.gnu.org/licenses/. # +######################################################################## +# UE SYNC TEST (Only compiled if CUHD is available) +######################################################################## +LIST(FIND OPTIONAL_LIBS cuhd CUHD_FIND) +LIST(FIND OPTIONAL_LIBS graphics GRAPHICS_FIND) +IF(${CUHD_FIND} GREATER -1) + ADD_EXECUTABLE(ue_sync_usrp ue_sync_usrp.c) + TARGET_LINK_LIBRARIES(ue_sync_usrp lte_phy cuhd) +ENDIF(${CUHD_FIND} GREATER -1) + +IF(${GRAPHICS_FIND} EQUAL -1) + SET_TARGET_PROPERTIES(ue_sync_usrp PROPERTIES COMPILE_DEFINITIONS "DISABLE_GRAPHICS") +ELSE(${GRAPHICS_FIND} EQUAL -1) + target_link_libraries(ue_sync_usrp graphics) +ENDIF(${GRAPHICS_FIND} EQUAL -1) + + ######################################################################## # PBCH TEST ######################################################################## diff --git a/lte/phy/lib/phch/test/pbch_file_test.c b/lte/phy/lib/phch/test/pbch_file_test.c index 09ed88980..92b2d8621 100644 --- a/lte/phy/lib/phch/test/pbch_file_test.c +++ b/lte/phy/lib/phch/test/pbch_file_test.c @@ -136,7 +136,7 @@ int base_init() { return -1; } - if (chest_init_LTEDL(&chest, LINEAR, cell)) { + if (chest_init_LTEDL(&chest, cell)) { fprintf(stderr, "Error initializing equalizer\n"); return -1; } diff --git a/lte/phy/lib/phch/test/pcfich_file_test.c b/lte/phy/lib/phch/test/pcfich_file_test.c index f6b5770d1..7c54203e2 100644 --- a/lte/phy/lib/phch/test/pcfich_file_test.c +++ b/lte/phy/lib/phch/test/pcfich_file_test.c @@ -141,7 +141,7 @@ int base_init() { } } - if (chest_init_LTEDL(&chest, LINEAR, cell)) { + if (chest_init_LTEDL(&chest, cell)) { fprintf(stderr, "Error initializing equalizer\n"); return -1; } diff --git a/lte/phy/lib/phch/test/pdcch_file_test.c b/lte/phy/lib/phch/test/pdcch_file_test.c index 3f400b662..189adc871 100644 --- a/lte/phy/lib/phch/test/pdcch_file_test.c +++ b/lte/phy/lib/phch/test/pdcch_file_test.c @@ -155,7 +155,7 @@ int base_init() { } } - if (chest_init_LTEDL(&chest, LINEAR, cell)) { + if (chest_init_LTEDL(&chest, cell)) { fprintf(stderr, "Error initializing equalizer\n"); return -1; } diff --git a/lte/phy/lib/phch/test/pdsch_file_test.c b/lte/phy/lib/phch/test/pdsch_file_test.c index ac2185471..d180167f2 100644 --- a/lte/phy/lib/phch/test/pdsch_file_test.c +++ b/lte/phy/lib/phch/test/pdsch_file_test.c @@ -158,7 +158,7 @@ int base_init() { } } - if (chest_init_LTEDL(&chest, LINEAR, cell)) { + if (chest_init_LTEDL(&chest, cell)) { fprintf(stderr, "Error initializing equalizer\n"); return -1; } @@ -183,10 +183,11 @@ int base_init() { exit(-1); } - if (pdsch_init(&pdsch, rnti, cell)) { + if (pdsch_init(&pdsch, cell)) { fprintf(stderr, "Error creating PDSCH object\n"); exit(-1); } + pdsch_set_rnti(&pdsch, rnti); if (pdsch_harq_init(&harq_process, &pdsch)) { fprintf(stderr, "Error initiating HARQ process\n"); diff --git a/lte/phy/lib/phch/test/pdsch_re_test.c b/lte/phy/lib/phch/test/pdsch_re_test.c index 0f772a264..2ba2c75fd 100644 --- a/lte/phy/lib/phch/test/pdsch_re_test.c +++ b/lte/phy/lib/phch/test/pdsch_re_test.c @@ -78,7 +78,8 @@ int main(int argc, char **argv) { cell.nof_ports = test_re_ports[i]; cell.cp = test_re_cp[i]; - pdsch_init(&pdsch, 0, cell); + pdsch_init(&pdsch, cell); + pdsch_set_rnti(&pdsch, 0); memset(prb_alloc.re_sf, 0, sizeof(uint32_t) * 10); prb_alloc.slot[0].nof_prb = test_re_prb[i]; diff --git a/lte/phy/lib/phch/test/pdsch_test.c b/lte/phy/lib/phch/test/pdsch_test.c index 97c54308d..271b3c471 100644 --- a/lte/phy/lib/phch/test/pdsch_test.c +++ b/lte/phy/lib/phch/test/pdsch_test.c @@ -166,11 +166,13 @@ int main(int argc, char **argv) { goto quit; } - if (pdsch_init(&pdsch, 1234, cell)) { + if (pdsch_init(&pdsch, cell)) { fprintf(stderr, "Error creating PDSCH object\n"); goto quit; } + pdsch_set_rnti(&pdsch, 1234); + if (pdsch_harq_init(&harq_process, &pdsch)) { fprintf(stderr, "Error initiating HARQ process\n"); goto quit; diff --git a/lte/phy/lib/phch/test/phich_file_test.c b/lte/phy/lib/phch/test/phich_file_test.c index 897d4172a..bf031c834 100644 --- a/lte/phy/lib/phch/test/phich_file_test.c +++ b/lte/phy/lib/phch/test/phich_file_test.c @@ -166,7 +166,7 @@ int base_init() { } } - if (chest_init_LTEDL(&chest, LINEAR, cell)) { + if (chest_init_LTEDL(&chest, cell)) { fprintf(stderr, "Error initializing equalizer\n"); return -1; } diff --git a/lte/phy/lib/resampling/src/interp.c b/lte/phy/lib/resampling/src/interp.c index 35946c5f6..f6f0f10da 100644 --- a/lte/phy/lib/resampling/src/interp.c +++ b/lte/phy/lib/resampling/src/interp.c @@ -27,12 +27,173 @@ #include #include +#include + #include "liblte/phy/resampling/interp.h" +#include "liblte/phy/utils/vector.h" #include "liblte/phy/utils/debug.h" +#define TABLE_SIZE 1024 + + +#ifdef TABLE_SIZE + #define ARG2IDX(arg) ((uint32_t) ((1+(arg)/M_PI)*TABLE_SIZE/2)) + #define MYCEXP(arg) q->cexptable[ARG2IDX(arg)] +#else + #define MYCEXP(arg) (cosf(arg) + I*sinf(arg)) +#endif + +#define MAX_OFFSET 64 + +int interp_init(interp_t *q, interp_type_t type, uint32_t len, uint32_t M) { + int ret = LIBLTE_ERROR_INVALID_INPUTS; + + if (q != NULL) { + ret = LIBLTE_ERROR; + + q->in_arg = vec_malloc(len * sizeof(float)); + if (!q->in_arg) { + goto clean_and_exit; + } + q->in_mag = vec_malloc(len * sizeof(float)); + if (!q->in_mag) { + goto clean_and_exit; + } + q->out_arg = vec_malloc((MAX_OFFSET + M * len) * sizeof(float)); + if (!q->out_arg) { + goto clean_and_exit; + } + q->out_arg2 = vec_malloc((MAX_OFFSET + M * len) * sizeof(float)); + if (!q->out_arg2) { + goto clean_and_exit; + } + q->table_idx = vec_malloc((MAX_OFFSET + M * len) * sizeof(int16_t)); + if (!q->table_idx) { + goto clean_and_exit; + } + q->out_mag = vec_malloc((MAX_OFFSET + M * len) * sizeof(float)); + if (!q->out_mag) { + goto clean_and_exit; + } + q->out_cexp = vec_malloc((MAX_OFFSET + M * len) * sizeof(cf_t)); + if (!q->out_cexp) { + goto clean_and_exit; + } + q->out_prod = vec_malloc((MAX_OFFSET + M * len) * sizeof(cf_t)); + if (!q->out_prod) { + goto clean_and_exit; + } +#ifdef TABLE_SIZE + q->cexptable = vec_malloc(TABLE_SIZE * sizeof(cf_t)); + uint32_t i; + for (i=0;icexptable[i] = cexpf(I*M_PI*(2*((float) i/TABLE_SIZE) - 1)); + } +#endif + q->M = M; + q->len = len; + ret = LIBLTE_SUCCESS; + } + +clean_and_exit: + if (ret == LIBLTE_ERROR) { + interp_free(q); + } + return ret; +} + +void interp_free(interp_t *q) { + if (q) { + if (q->in_arg) { + free(q->in_arg); + } + if (q->in_mag) { + free(q->in_mag); + } + if (q->out_arg) { + free(q->out_arg); + } + if (q->out_cexp) { + free(q->out_cexp); + } + if (q->out_mag) { + free(q->out_mag); + } + + if (q->out_prod) { + free(q->out_prod); + } +#ifdef TABLE_SIZE + if (q->cexptable) { + free(q->cexptable); + } +#endif + } +} + +void interp_run_offset(interp_t *q, cf_t *input, cf_t *output, uint32_t off_st, uint32_t off_end) { + uint32_t i, j, n; + float mag0=0, mag1=0, arg0=0, arg1=0; + float dmag, darg; + uint32_t M = q->M; + uint32_t len1 = q->len-1; + + if (off_st + off_end < MAX_OFFSET) { + vec_abs_cf(input, q->in_mag, q->len); + vec_arg_cf(input, q->in_arg, q->len); + + mag0 = q->in_mag[0]; + mag1 = q->in_mag[1]; + arg0 = q->in_arg[0]; + arg1 = q->in_arg[1]; + dmag=(mag1-mag0)/M; + darg=(arg1-arg0)/M; + for (j=0;jout_mag[j] = mag0 - (j+1)*dmag; + q->out_arg[j] = arg0 - (j+1)*darg; + } + + for (i=0;iin_mag[i]; + mag1 = q->in_mag[i+1]; + arg0 = q->in_arg[i]; + arg1 = q->in_arg[i+1]; + dmag=(mag1-mag0)/M; + darg=(arg1-arg0)/M; + for (j=0;jout_mag[i*M+j+off_st] = mag0 + j*dmag; + q->out_arg[i*M+j+off_st] = arg0 + j*darg; + } + } + if (q->len > 1) { + for (j=0;jout_mag[i*M+j+off_st] = mag1 + j*dmag; + q->out_arg[i*M+j+off_st] = arg1 + j*darg; + } + } + uint32_t len=i*M+j+off_st; +#ifdef TABLE_SIZE + vec_convert_fi(q->out_arg, q->table_idx, (float) TABLE_SIZE/2/M_PI, len); + for (n=0;nout_cexp[n] = q->cexptable[q->table_idx[n]+TABLE_SIZE/2]; + } +#else + for (n=0;nout_cexp[n] = MYCEXP(q->out_arg[n]); + } +#endif + vec_prod_cfc(q->out_cexp, q->out_mag, output, len); + } + +} + +void interp_run(interp_t *q, cf_t *input, cf_t *output) { + interp_run_offset(q, input, output, 0, 1); +} + /* Performs 1st order linear interpolation with out-of-bound interpolation */ -void interp_linear_offset(cf_t *input, cf_t *output, int M, int len, int off_st, int off_end) { - int i, j; +void interp_linear_offset(cf_t *input, cf_t *output, uint32_t M, uint32_t len, uint32_t off_st, uint32_t off_end) { + uint32_t i, j; float mag0=0, mag1=0, arg0=0, arg1=0, mag=0, arg=0; for (i=0;itab, CFO_CEXPTAB_SIZE)) { goto clean; } - h->cur_cexp = malloc(sizeof(cf_t) * nsamples); + h->cur_cexp = vec_malloc(sizeof(cf_t) * nsamples); if (!h->cur_cexp) { goto clean; } @@ -50,9 +50,9 @@ int cfo_init(cfo_t *h, int nsamples) { h->nsamples = nsamples; cexptab_gen(&h->tab, h->cur_cexp, h->last_freq, h->nsamples); - ret = 0; + ret = LIBLTE_SUCCESS; clean: - if (ret == -1) { + if (ret == LIBLTE_ERROR) { cfo_free(h); } return ret; @@ -70,11 +70,23 @@ void cfo_set_tol(cfo_t *h, float tol) { h->tol = tol; } -void cfo_correct(cfo_t *h, cf_t *x, float freq) { +int cfo_realloc(cfo_t *h, uint32_t samples) { + h->cur_cexp = realloc(h->cur_cexp, sizeof(cf_t) * samples); + if (!h->cur_cexp) { + perror("realloc"); + return LIBLTE_ERROR; + } + cexptab_gen(&h->tab, h->cur_cexp, h->last_freq, samples); + h->nsamples = samples; + + return LIBLTE_SUCCESS; +} + +void cfo_correct(cfo_t *h, cf_t *input, cf_t *output, float freq) { if (fabs(h->last_freq - freq) > h->tol) { h->last_freq = freq; cexptab_gen(&h->tab, h->cur_cexp, h->last_freq, h->nsamples); - INFO("CFO generating new table for frequency %.4f\n", freq); + DEBUG("CFO generating new table for frequency %.4f\n", freq); } - vec_prod_ccc(h->cur_cexp, x, x, h->nsamples); + vec_prod_ccc(h->cur_cexp, input, output, h->nsamples); } diff --git a/lte/phy/lib/sync/src/find_sss.c b/lte/phy/lib/sync/src/find_sss.c index 7fd47a752..7bc52d558 100644 --- a/lte/phy/lib/sync/src/find_sss.c +++ b/lte/phy/lib/sync/src/find_sss.c @@ -31,18 +31,10 @@ #include "liblte/phy/utils/vector.h" #include "liblte/phy/sync/sss.h" -cf_t corr_sz(cf_t *z, cf_t *s) { - cf_t sum; - cf_t zsprod[32]; - vec_prod_ccc(z, s, zsprod, N_SSS - 1); - sum = vec_acc_cc(zsprod, N_SSS - 1); - - return sum; -} -void corr_all_zs(cf_t *z, cf_t s[32][32], cf_t *output) { - int m; +void corr_all_zs(cf_t *z, cf_t s[N_SSS+1][N_SSS+1], cf_t *output) { + uint32_t m; for (m = 0; m < N_SSS; m++) { - output[m] = corr_sz(z, s[m]); + output[m] = vec_dot_prod_ccc(z, s[m], N_SSS - 1); } } @@ -58,54 +50,64 @@ void corr_all_zs(cf_t *z, cf_t s[32][32], cf_t *output) { * */ -void sss_synch_m0m1(sss_synch_t *q, cf_t *input, int *m0, float *m0_value, - int *m1, float *m1_value) { - - /* This is aprox 3-4 kbytes of stack. Consider moving to sss_synch_t?? */ - cf_t zdelay[N_SSS+1],zconj[N_SSS+1],zprod[N_SSS+1]; - cf_t y[2][N_SSS+1], z[N_SSS+1], tmp[N_SSS+1]; - float tmp_real[N_SSS+1]; - cf_t input_fft[SSS_DFT_LEN]; - - int i; - - dft_run_c(&q->dftp_input, input, input_fft); - - for (i = 0; i < N_SSS; i++) { - y[0][i] = input_fft[SSS_POS_SYMBOL + 2 * i]; - y[1][i] = input_fft[SSS_POS_SYMBOL + 2 * i + 1]; - } - - vec_prod_ccc(y[0], q->fc_tables[q->N_id_2].c[0], z, N_SSS); - memcpy(zdelay, &z[1], (N_SSS - 1) * sizeof(cf_t)); - vec_conj_cc(z, zconj, N_SSS - 1); - vec_prod_ccc(zdelay, zconj, zprod, N_SSS - 1); - - corr_all_zs(zprod, q->fc_tables[q->N_id_2].s, tmp); - vec_abs_cf(tmp, tmp_real, N_SSS); - *m0 = vec_max_fi(tmp_real, N_SSS); - if (m0_value) { - *m0_value = tmp_real[*m0]; - } - - vec_prod_ccc(y[1], q->fc_tables[q->N_id_2].c[1], tmp, N_SSS); - vec_prod_ccc(tmp, q->fc_tables[q->N_id_2].z1[*m0], z, N_SSS); - memcpy(zdelay, &z[1], (N_SSS - 1) * sizeof(cf_t)); - vec_conj_cc(z, zconj, N_SSS - 1); - vec_prod_ccc(zdelay, zconj, zprod, N_SSS - 1); - - corr_all_zs(zprod, q->fc_tables[q->N_id_2].s, tmp); - vec_abs_cf(tmp, tmp_real, N_SSS); - *m1 = vec_max_fi(tmp_real, N_SSS); - if (m1_value) { - *m1_value = tmp_real[*m1]; - } - +int sss_synch_m0m1(sss_synch_t *q, cf_t *input, uint32_t *m0, float *m0_value, + uint32_t *m1, float *m1_value) +{ + + int ret = LIBLTE_ERROR_INVALID_INPUTS; + + if (q != NULL && + input != NULL && + m0 != NULL && + m1 != NULL) + { + + /* Consider moving to sss_synch_t?? */ + cf_t zdelay[N_SSS+1],zconj[N_SSS+1],zprod[N_SSS+1]; + cf_t y[2][N_SSS+1], z[N_SSS+1], tmp[N_SSS+1]; + float tmp_real[N_SSS+1]; + cf_t input_fft[SSS_MAX_FFT_LEN]; + uint32_t i; + + dft_run_c(&q->dftp_input, input, input_fft); + + for (i = 0; i < N_SSS; i++) { + y[0][i] = input_fft[q->fft_size/2-N_SSS + 2 * i]; + y[1][i] = input_fft[q->fft_size/2-N_SSS + 2 * i + 1]; + } + + vec_prod_ccc(y[0], q->fc_tables[q->N_id_2].c[0], z, N_SSS); + memcpy(zdelay, &z[1], (N_SSS - 1) * sizeof(cf_t)); + vec_conj_cc(z, zconj, N_SSS - 1); + vec_prod_ccc(zdelay, zconj, zprod, N_SSS - 1); + + corr_all_zs(zprod, q->fc_tables[q->N_id_2].s, tmp); + vec_abs_cf(tmp, tmp_real, N_SSS); + *m0 = vec_max_fi(tmp_real, N_SSS); + if (m0_value) { + *m0_value = tmp_real[*m0]; + } + + vec_prod_ccc(y[1], q->fc_tables[q->N_id_2].c[1], tmp, N_SSS); + vec_prod_ccc(tmp, q->fc_tables[q->N_id_2].z1[*m0], z, N_SSS); + memcpy(zdelay, &z[1], (N_SSS - 1) * sizeof(cf_t)); + vec_conj_cc(z, zconj, N_SSS - 1); + vec_prod_ccc(zdelay, zconj, zprod, N_SSS - 1); + + corr_all_zs(zprod, q->fc_tables[q->N_id_2].s, tmp); + vec_abs_cf(tmp, tmp_real, N_SSS); + *m1 = vec_max_fi(tmp_real, N_SSS); + if (m1_value) { + *m1_value = tmp_real[*m1]; + } + ret = LIBLTE_SUCCESS; + } + return ret; } void convert_tables(struct fc_tables *fc_tables, struct sss_tables *in) { - int i, j; - bzero(fc_tables, sizeof(struct fc_tables)); + uint32_t i, j; + for (i = 0; i < N_SSS; i++) { for (j = 0; j < N_SSS; j++) { __real__ fc_tables->z1[i][j] = (float) in->z1[i][j]; diff --git a/lte/phy/lib/sync/src/gen_sss.c b/lte/phy/lib/sync/src/gen_sss.c index e68407f45..da3e895b2 100644 --- a/lte/phy/lib/sync/src/gen_sss.c +++ b/lte/phy/lib/sync/src/gen_sss.c @@ -58,19 +58,19 @@ void generate_zsc_tilde(int *z_tilde, int *s_tilde, int *c_tilde) { z_tilde[i] = 1 - 2 * x[i]; } -void generate_m0m1(int N_id_1, int *m0, int *m1) { - int q_prime = N_id_1 / (N_SSS - 1); - int q = (N_id_1 + (q_prime * (q_prime + 1) / 2)) / (N_SSS - 1); - int m_prime = N_id_1 + (q * (q + 1) / 2); +void generate_m0m1(uint32_t N_id_1, uint32_t *m0, uint32_t *m1) { + uint32_t q_prime = N_id_1 / (N_SSS - 1); + uint32_t q = (N_id_1 + (q_prime * (q_prime + 1) / 2)) / (N_SSS - 1); + uint32_t m_prime = N_id_1 + (q * (q + 1) / 2); *m0 = m_prime % N_SSS; *m1 = (*m0 + m_prime / N_SSS + 1) % N_SSS; } /* table[m0][m1-1]=N_id_1 */ -void generate_N_id_1_table(int table[30][30]) { - int m0, m1; - int N_id_1; +void generate_N_id_1_table(uint32_t table[30][30]) { + uint32_t m0, m1; + uint32_t N_id_1; for (N_id_1=0;N_id_1<168;N_id_1++) { generate_m0m1(N_id_1, &m0, &m1); table[m0][m1-1] = N_id_1; @@ -78,60 +78,60 @@ void generate_N_id_1_table(int table[30][30]) { } -void generate_s(int *s, int *s_tilde, int m0_m1) { - int i; +void generate_s(int *s, int *s_tilde, uint32_t m0_m1) { + uint32_t i; for (i = 0; i < N_SSS; i++) { s[i] = s_tilde[(i + m0_m1) % N_SSS]; } } void generate_s_all(int s[N_SSS][N_SSS], int *s_tilde) { - int i; + uint32_t i; for (i = 0; i < N_SSS; i++) { generate_s(s[i], s_tilde, i); } } -void generate_c(int *c, int *c_tilde, int N_id_2, int is_c0) { - int i; +void generate_c(int *c, int *c_tilde, uint32_t N_id_2, bool is_c0) { + uint32_t i; for (i = 0; i < N_SSS; i++) { - c[i] = c_tilde[(i + N_id_2 + (is_c0 > 0 ? 3 : 0)) % N_SSS]; + c[i] = c_tilde[(i + N_id_2 + (is_c0 ? 3 : 0)) % N_SSS]; } } -void generate_z(int *z, int *z_tilde, int m0_m1) { - int i; +void generate_z(int *z, int *z_tilde, uint32_t m0_m1) { + uint32_t i; for (i = 0; i < N_SSS; i++) { z[i] = z_tilde[(i + (m0_m1 % 8)) % N_SSS]; } } void generate_z_all(int z[N_SSS][N_SSS], int *z_tilde) { - int i; + uint32_t i; for (i = 0; i < N_SSS; i++) { generate_z(z[i], z_tilde, i); } } -void generate_sss_all_tables(struct sss_tables *tables, int N_id_2) { - int i; +void generate_sss_all_tables(struct sss_tables *tables, uint32_t N_id_2) { + uint32_t i; int s_t[N_SSS], c_t[N_SSS], z_t[N_SSS]; generate_zsc_tilde(z_t, s_t, c_t); generate_s_all(tables->s, s_t); generate_z_all(tables->z1, z_t); for (i = 0; i < 2; i++) { - generate_c(tables->c[i], c_t, N_id_2, i); + generate_c(tables->c[i], c_t, N_id_2, i > 0); } } -void sss_generate(float *signal0, float *signal5, int cell_id) { +void sss_generate(float *signal0, float *signal5, uint32_t cell_id) { - int i; - int id1 = cell_id / 3; - int id2 = cell_id % 3; - int m0; - int m1; + uint32_t i; + uint32_t id1 = cell_id / 3; + uint32_t id2 = cell_id % 3; + uint32_t m0; + uint32_t m1; int s_t[N_SSS], c_t[N_SSS], z_t[N_SSS]; int s0[N_SSS], s1[N_SSS], c0[N_SSS], c1[N_SSS], z1_0[N_SSS], z1_1[N_SSS]; diff --git a/lte/phy/lib/sync/src/pss.c b/lte/phy/lib/sync/src/pss.c index fd5f6c522..4c8da1a26 100644 --- a/lte/phy/lib/sync/src/pss.c +++ b/lte/phy/lib/sync/src/pss.c @@ -37,144 +37,142 @@ #include "liblte/phy/utils/vector.h" #include "liblte/phy/utils/convolution.h" -#define NOT_SYNC 0xF0F0F0F0 - - -int pss_synch_init_N_id_2(pss_synch_t *q, int N_id_2) { - q->N_id_2 = N_id_2; +int pss_synch_init_N_id_2(cf_t *pss_signal_freq, uint32_t N_id_2, uint32_t fft_size) { dft_plan_t plan; - cf_t pss_signal_pad[PSS_LEN_FREQ]; + cf_t pss_signal_pad[2048]; cf_t pss_signal_time[PSS_LEN]; + int ret = LIBLTE_ERROR_INVALID_INPUTS; + + if (lte_N_id_2_isvalid(N_id_2) && + fft_size < 2048) + { + + pss_generate(pss_signal_time, N_id_2); + + bzero(pss_signal_pad, fft_size * sizeof(cf_t)); + bzero(pss_signal_freq, fft_size * sizeof(cf_t)); + memcpy(&pss_signal_pad[(fft_size-PSS_LEN)/2], pss_signal_time, PSS_LEN * sizeof(cf_t)); + + if (dft_plan(&plan, fft_size, BACKWARD, COMPLEX)) { + return LIBLTE_ERROR; + } + + dft_plan_set_mirror(&plan, true); + dft_plan_set_dc(&plan, true); + dft_run_c(&plan, pss_signal_pad, pss_signal_freq); - if (N_id_2 < 0 || N_id_2 > 2) { - fprintf(stderr, "Invalid N_id_2 %d\n", N_id_2); - return -1; - } - - pss_generate(pss_signal_time, N_id_2); - - memset(pss_signal_pad, 0, PSS_LEN_FREQ * sizeof(cf_t)); - memset(q->pss_signal_freq[N_id_2], 0, PSS_LEN_FREQ * sizeof(cf_t)); - memcpy(&pss_signal_pad[33], pss_signal_time, PSS_LEN * sizeof(cf_t)); + vec_sc_prod_cfc(pss_signal_freq, (float) 1 / (fft_size), pss_signal_pad, fft_size); + vec_conj_cc(pss_signal_pad, pss_signal_freq, fft_size); - if (dft_plan(&plan, PSS_LEN_FREQ - 1, BACKWARD, COMPLEX)) { - return -1; + dft_plan_free(&plan); + + ret = LIBLTE_SUCCESS; } - dft_plan_set_mirror(&plan, true); - dft_plan_set_dc(&plan, true); - dft_run_c(&plan, pss_signal_pad, q->pss_signal_freq[q->N_id_2]); - - vec_sc_prod_cfc(q->pss_signal_freq[q->N_id_2], (float) 1 / (PSS_LEN_FREQ - 1), - pss_signal_pad, PSS_LEN_FREQ); - - vec_conj_cc(pss_signal_pad, q->pss_signal_freq[q->N_id_2], PSS_LEN_FREQ); - - dft_plan_free(&plan); - - return 0; + return ret; } -/* Initializes the object. subframe_size is the size, in samples, of the 1ms subframe - * +/* Initializes the PSS synchronization object with fft_size=128 */ -int pss_synch_init(pss_synch_t *q, int frame_size) { - int ret = -1; - int N_id_2; - bzero(q, sizeof(pss_synch_t)); - - q->conv_abs = vec_malloc((PSS_LEN_FREQ + frame_size) * sizeof(float)); - if (!q->conv_abs) { - fprintf(stderr, "Error allocating memory\n"); - goto clean_and_exit; - } - q->tmp_input = vec_malloc((PSS_LEN_FREQ + frame_size) * sizeof(cf_t)); - if (!q->tmp_input) { - fprintf(stderr, "Error allocating memory\n"); - goto clean_and_exit; - } - q->conv_output = vec_malloc((PSS_LEN_FREQ + frame_size) * sizeof(cf_t)); - if (!q->conv_output) { - fprintf(stderr, "Error allocating memory\n"); - goto clean_and_exit; - } - for (N_id_2=0;N_id_2<3;N_id_2++) { - q->pss_signal_freq[N_id_2] = vec_malloc((PSS_LEN_FREQ + frame_size) * sizeof(cf_t)); - if (!q->pss_signal_freq[N_id_2]) { +int pss_synch_init(pss_synch_t *q, uint32_t frame_size) { + return pss_synch_init_fft(q, frame_size, 128); +} +/* Initializes the PSS synchronization object. + * + * It correlates a signal of frame_size samples with the PSS sequence in the frequency + * domain. The PSS sequence is transformed using fft_size samples. + */ +int pss_synch_init_fft(pss_synch_t *q, uint32_t frame_size, uint32_t fft_size) { + int ret = LIBLTE_ERROR_INVALID_INPUTS; + + if (q != NULL) { + + uint32_t N_id_2; + uint32_t buffer_size; + bzero(q, sizeof(pss_synch_t)); + + q->N_id_2 = 10; + q->fft_size = fft_size; + q->frame_size = frame_size; + + buffer_size = fft_size + frame_size + 1; + + q->conv_abs = vec_malloc(buffer_size * sizeof(float)); + if (!q->conv_abs) { fprintf(stderr, "Error allocating memory\n"); goto clean_and_exit; } - if (pss_synch_init_N_id_2(q, N_id_2)) { - fprintf(stderr, "Error initiating PSS detector for N_id_2=%d\n", N_id_2); + q->tmp_input = vec_malloc(buffer_size * sizeof(cf_t)); + if (!q->tmp_input) { + fprintf(stderr, "Error allocating memory\n"); goto clean_and_exit; } + q->conv_output = vec_malloc(buffer_size * sizeof(cf_t)); + if (!q->conv_output) { + fprintf(stderr, "Error allocating memory\n"); + goto clean_and_exit; + } + for (N_id_2=0;N_id_2<3;N_id_2++) { + q->pss_signal_freq[N_id_2] = vec_malloc(buffer_size * sizeof(cf_t)); + if (!q->pss_signal_freq[N_id_2]) { + fprintf(stderr, "Error allocating memory\n"); + goto clean_and_exit; + } + /* The PSS is translated into the frequency domain for each N_id_2 */ + if (pss_synch_init_N_id_2(q->pss_signal_freq[N_id_2], N_id_2, fft_size)) { + fprintf(stderr, "Error initiating PSS detector for N_id_2=%d fft_size=%d\n", N_id_2, fft_size); + goto clean_and_exit; + } + } + #ifdef CONVOLUTION_FFT + if (conv_fft_cc_init(&q->conv_fft, frame_size, fft_size)) { + fprintf(stderr, "Error initiating convolution FFT\n"); + goto clean_and_exit; + } + #endif + + ret = LIBLTE_SUCCESS; } -#ifdef ENABLE_SF - q->frame_buffer = vec_malloc(4 * frame_size * sizeof(cf_t)); - if (!q->frame_buffer) { - fprintf(stderr, "Error allocating memory\n"); - goto clean_and_exit; - } - q->correlation_threshold = DEFAULT_CORRELATION_TH; - q->nosync_timeout_frames = DEFAULT_NOSYNC_TIMEOUT; - q->cfo_auto = true; - q->frame_start_idx = NOT_SYNC; - q->fb_wp = 0; -#endif - -#ifdef CONVOLUTION_FFT - if (conv_fft_cc_init(&q->conv_fft, frame_size, PSS_LEN_FREQ)) { - fprintf(stderr, "Error initiating convolution FFT\n"); - goto clean_and_exit; - } -#endif - - q->N_id_2 = -1; - q->frame_size = frame_size; - - ret = 0; - clean_and_exit: if (ret == -1) { +clean_and_exit: + if (ret == LIBLTE_ERROR) { pss_synch_free(q); } return ret; } void pss_synch_free(pss_synch_t *q) { - int i; - for (i=0;i<3;i++) { - if (q->pss_signal_freq[i]) { - free(q->pss_signal_freq[i]); + uint32_t i; + + if (q) { + for (i=0;i<3;i++) { + if (q->pss_signal_freq[i]) { + free(q->pss_signal_freq[i]); + } + } + #ifdef CONVOLUTION_FFT + conv_fft_cc_free(&q->conv_fft); + + #endif + if (q->tmp_input) { + free(q->tmp_input); + } + if (q->conv_output) { + free(q->conv_output); + } + if (q->conv_abs) { + free(q->conv_abs); } - } - if (q->conv_abs) { - free(q->conv_abs); - } - if (q->tmp_input) { - free(q->tmp_input); - } - if (q->conv_output) { - free(q->conv_output); - } -#ifdef ENABLE_SF - if (q->frame_buffer) { - free(q->frame_buffer); + bzero(q, sizeof(pss_synch_t)); } -#endif - -#ifdef CONVOLUTION_FFT - conv_fft_cc_free(&q->conv_fft); -#endif - - bzero(q, sizeof(pss_synch_t)); } /** * This function calculates the Zadoff-Chu sequence. * @param signal Output array. */ -int pss_generate(cf_t *signal, int N_id_2) { +int pss_generate(cf_t *signal, uint32_t N_id_2) { int i; float arg; const float root_value[] = { 25.0, 29.0, 34.0 }; @@ -182,7 +180,7 @@ int pss_generate(cf_t *signal, int N_id_2) { int sign = -1; - if (N_id_2 < 0 || N_id_2 > 2) { + if (N_id_2 > 2) { fprintf(stderr, "Invalid N_id_2 %d\n", N_id_2); return -1; } @@ -206,7 +204,7 @@ int pss_generate(cf_t *signal, int N_id_2) { /** 36.211 10.3 section 6.11.1.2 */ -void pss_put_slot(cf_t *pss_signal, cf_t *slot, int nof_prb, lte_cp_t cp) { +void pss_put_slot(cf_t *pss_signal, cf_t *slot, uint32_t nof_prb, lte_cp_t cp) { int k; k = (CP_NSYMB(cp) - 1) * nof_prb * RE_X_RB + nof_prb * RE_X_RB / 2 - 31; memset(&slot[k - 5], 0, 5 * sizeof(cf_t)); @@ -217,8 +215,8 @@ void pss_put_slot(cf_t *pss_signal, cf_t *slot, int nof_prb, lte_cp_t cp) { /** Sets the current N_id_2 value. Returns -1 on error, 0 otherwise */ -int pss_synch_set_N_id_2(pss_synch_t *q, int N_id_2) { - if (N_id_2 < 0 || N_id_2 > 2) { +int pss_synch_set_N_id_2(pss_synch_t *q, uint32_t N_id_2) { + if (!lte_N_id_2_isvalid((N_id_2))) { fprintf(stderr, "Invalid N_id_2 %d\n", N_id_2); return -1; } else { @@ -227,40 +225,53 @@ int pss_synch_set_N_id_2(pss_synch_t *q, int N_id_2) { } } - /** Returns the index of the PSS correlation peak in a subframe. * The frame starts at corr_peak_pos-subframe_size/2. * The value of the correlation is stored in corr_peak_value. * * Input buffer must be subframe_size long. */ -int pss_synch_find_pss(pss_synch_t *q, cf_t *input, float *corr_peak_value, - float *corr_mean_value) { - int corr_peak_pos; - int conv_output_len; - - memset(&q->pss_signal_freq[q->N_id_2][PSS_LEN_FREQ], 0, q->frame_size * sizeof(cf_t)); - memcpy(q->tmp_input, input, q->frame_size * sizeof(cf_t)); - memset(&q->tmp_input[q->frame_size], 0, PSS_LEN_FREQ * sizeof(cf_t)); - -#ifdef CONVOLUTION_FFT - conv_output_len = conv_fft_cc_run(&q->conv_fft, q->tmp_input, - q->pss_signal_freq[q->N_id_2], q->conv_output); -#else - conv_output_len = conv_cc(input, q->pss_signal_freq[q->N_id_2], q->conv_output, q->frame_size, PSS_LEN_FREQ); -#endif - - vec_abs_cf(q->conv_output, q->conv_abs, conv_output_len); - corr_peak_pos = vec_max_fi(q->conv_abs, conv_output_len); - if (corr_peak_value) { - *corr_peak_value = q->conv_abs[corr_peak_pos]; - } - if (corr_mean_value) { - *corr_mean_value = vec_acc_ff(q->conv_abs, conv_output_len) - / conv_output_len; - } +int pss_synch_find_pss(pss_synch_t *q, cf_t *input, + float *corr_peak_value, float *corr_mean_value) +{ + int ret = LIBLTE_ERROR_INVALID_INPUTS; + + if (q != NULL && + input != NULL) + { + + uint32_t corr_peak_pos; + uint32_t conv_output_len; + + if (!lte_N_id_2_isvalid(q->N_id_2)) { + fprintf(stderr, "Error finding PSS peak, N_id_2 not set\n"); + return LIBLTE_ERROR; + } + + bzero(&q->pss_signal_freq[q->N_id_2][q->fft_size], q->frame_size * sizeof(cf_t)); + memcpy(q->tmp_input, input, q->frame_size * sizeof(cf_t)); + bzero(&q->tmp_input[q->frame_size], q->fft_size * sizeof(cf_t)); + + #ifdef CONVOLUTION_FFT + conv_output_len = conv_fft_cc_run(&q->conv_fft, q->tmp_input, + q->pss_signal_freq[q->N_id_2], q->conv_output); + #else + conv_output_len = conv_cc(input, q->pss_signal_freq[q->N_id_2], q->conv_output, q->frame_size, q->fft_size); + #endif + + vec_abs_cf(q->conv_output, q->conv_abs, conv_output_len); + corr_peak_pos = vec_max_fi(q->conv_abs, conv_output_len); + if (corr_peak_value) { + *corr_peak_value = q->conv_abs[corr_peak_pos]; + } + if (corr_mean_value) { + *corr_mean_value = vec_acc_ff(q->conv_abs, conv_output_len) + / conv_output_len; + } - return (int) corr_peak_pos; + ret = (int) corr_peak_pos; + } + return ret; } /* Returns the CFO estimation given a PSS received sequence @@ -270,159 +281,12 @@ int pss_synch_find_pss(pss_synch_t *q, cf_t *input, float *corr_peak_value, */ float pss_synch_cfo_compute(pss_synch_t* q, cf_t *pss_recv) { cf_t y0, y1, yr; - cf_t y[PSS_LEN_FREQ - 1]; - vec_prod_ccc_unalign(q->pss_signal_freq[q->N_id_2], pss_recv, y, PSS_LEN_FREQ - 1); - - y0 = vec_acc_cc(y, (PSS_LEN_FREQ - 1) / 2); - y1 = vec_acc_cc(&y[(PSS_LEN_FREQ - 1) / 2], (PSS_LEN_FREQ - 1) / 2); + y0 = vec_dot_prod_ccc(q->pss_signal_freq[q->N_id_2], pss_recv, q->fft_size/2); + y1 = vec_dot_prod_ccc(&q->pss_signal_freq[q->N_id_2][q->fft_size/2], &pss_recv[q->fft_size/2], q->fft_size/2); + yr = conjf(y0) * y1; return atan2f(__imag__ yr, __real__ yr) / M_PI; } -#ifdef ENABLE_SF - -void pss_synch_set_timeout(pss_synch_t *q, int nof_frames) { - q->nosync_timeout_frames = nof_frames; -} - -void pss_synch_set_threshold(pss_synch_t *q, float threshold) { - q->correlation_threshold = threshold; -} - -void pss_synch_set_cfo_mode(pss_synch_t *q, bool cfo_auto) { - q->cfo_auto = cfo_auto; -} - -float pss_synch_get_cfo(pss_synch_t *q) { - return q->current_cfo; -} - -int pss_synch_get_frame_start_idx(pss_synch_t *q) { - return q->frame_start_idx; -} - -/** This function is designed to be called periodically on a subframe basis. - * The function finds the PSS correlation peak and computes (does not adjust) CFO automatically as defined by - * pss_synch_set_cfo_mode(). - * - * If the PSS sequence is not found, returns 0 writes nothing to the output buffer. - * If the PSS sequence is found, aligns the beginning of the subframe to the output buffer and returns the number of samples - * written to the output buffer. - * If synchronized, subsequent calls to this function align the input buffer to the subframe beginning. - */ -int pss_synch_frame(pss_synch_t *q, cf_t *input, cf_t *output, int nsamples) { - int max_idx, tmp_start_idx; - int retval; - float max_value; - - if (nsamples != q->frame_size) { - fprintf(stderr, "Configured for frame size %d but got %d samples\n", - q->frame_size, nsamples); - return -1; - } - - if (q->N_id_2 < 0) { - fprintf(stderr, - "N_id_2 must be configured before calling pss_synch()\n"); - return -1; - } - - max_idx = pss_synch_find_pss(q, input, &max_value, NULL); - if (max_value > q->correlation_threshold) { - tmp_start_idx = max_idx - nsamples / 2; - if (q->frame_start_idx != tmp_start_idx) { - printf("Re-synchronizing: new index is %d, old was %d\n", - tmp_start_idx, q->frame_start_idx); - } - q->frame_start_idx = tmp_start_idx; - } else { - if (q->nosync_timeout_frames > 0) { - q->nof_nosync_frames++; - if (q->nof_nosync_frames >= q->nosync_timeout_frames) { - q->frame_start_idx = NOT_SYNC; - } - } - } - - if (q->frame_start_idx == NOT_SYNC) { - - memcpy(q->frame_buffer, input, nsamples * sizeof(cf_t)); - retval = 0; - - } else if (q->frame_start_idx > 0) { - - if (q->fb_wp) { - memcpy(&q->frame_buffer[(nsamples - q->frame_start_idx)], input, - q->frame_start_idx * sizeof(cf_t)); - memcpy(output, q->frame_buffer, nsamples * sizeof(cf_t)); - retval = nsamples; - } else { - retval = 0; - } - memcpy(q->frame_buffer, &input[q->frame_start_idx], - (nsamples - q->frame_start_idx) * sizeof(cf_t)); - q->fb_wp = 1; - - } else { - - memcpy(output, &q->frame_buffer[nsamples + q->frame_start_idx], - (-q->frame_start_idx) * sizeof(cf_t)); - memcpy(&output[-q->frame_start_idx], input, - (nsamples + q->frame_start_idx) * sizeof(cf_t)); - memcpy(&q->frame_buffer[nsamples + q->frame_start_idx], - &input[nsamples + q->frame_start_idx], - (-q->frame_start_idx) * sizeof(cf_t)); - retval = nsamples; - } - - if (q->frame_start_idx != NOT_SYNC && q->cfo_auto && retval) { - q->current_cfo = pss_synch_cfo_compute(q, - &output[q->frame_size / 2 - PSS_LEN_FREQ + 1]); - } - - return retval; -} - -/** High-level API */ - -int pss_synch_initialize(pss_synch_hl* h) { - int fs = h->init.frame_size; - if (!fs) { - fs = DEFAULT_FRAME_SIZE; - } - if (pss_synch_init(&h->obj, fs)) { - return -1; - } - if (h->init.unsync_nof_pkts) { - pss_synch_set_timeout(&h->obj, h->init.unsync_nof_pkts); - } - - pss_synch_set_N_id_2(&h->obj, h->init.N_id_2); - if (h->init.do_cfo) { - pss_synch_set_cfo_mode(&h->obj, true); - } else { - pss_synch_set_cfo_mode(&h->obj, false); - } - return 0; -} - -int pss_synch_work(pss_synch_hl* hl) { - - if (hl->ctrl_in.correlation_threshold) { - pss_synch_set_threshold(&hl->obj, hl->ctrl_in.correlation_threshold); - } - - hl->out_len = pss_synch_frame(&hl->obj, hl->input, hl->output, hl->in_len); - - return 0; -} - -int pss_synch_stop(pss_synch_hl* hl) { - pss_synch_free(&hl->obj); - return 0; -} - -#endif - diff --git a/lte/phy/lib/sync/src/sss.c b/lte/phy/lib/sync/src/sss.c index 9d4525e83..6feef89da 100644 --- a/lte/phy/lib/sync/src/sss.c +++ b/lte/phy/lib/sync/src/sss.c @@ -35,29 +35,58 @@ #include "liblte/phy/sync/sss.h" #include "liblte/phy/utils/dft.h" #include "liblte/phy/utils/convolution.h" +#include "liblte/phy/utils/vector.h" -void generate_sss_all_tables(struct sss_tables *tables, int N_id_2); +void generate_sss_all_tables(struct sss_tables *tables, uint32_t N_id_2); void convert_tables(struct fc_tables *fc_tables, struct sss_tables *in); -void generate_N_id_1_table(int table[30][30]); - -int sss_synch_init(sss_synch_t *q) { - int N_id_2; - struct sss_tables sss_tables; - - bzero(q, sizeof(sss_synch_t)); +void generate_N_id_1_table(uint32_t table[30][30]); + +int sss_synch_init(sss_synch_t *q, uint32_t fft_size) { + + if (q != NULL && + fft_size < 2048) + { + uint32_t N_id_2; + struct sss_tables sss_tables; + + bzero(q, sizeof(sss_synch_t)); + + if (dft_plan(&q->dftp_input, fft_size, FORWARD, COMPLEX)) { + sss_synch_free(q); + return LIBLTE_ERROR; + } + q->fft_size = fft_size; + + generate_N_id_1_table(q->N_id_1_table); + dft_plan_set_mirror(&q->dftp_input, true); + dft_plan_set_dc(&q->dftp_input, true); + + for (N_id_2=0;N_id_2<3;N_id_2++) { + generate_sss_all_tables(&sss_tables, N_id_2); + convert_tables(&q->fc_tables[N_id_2], &sss_tables); + } + q->N_id_2 = 0; + return LIBLTE_SUCCESS; + } + return LIBLTE_ERROR_INVALID_INPUTS; +} - if (dft_plan(&q->dftp_input, SSS_DFT_LEN, FORWARD, COMPLEX)) { - return -1; - } - generate_N_id_1_table(q->N_id_1_table); - dft_plan_set_mirror(&q->dftp_input, true); - dft_plan_set_dc(&q->dftp_input, true); - for (N_id_2=0;N_id_2<3;N_id_2++) { - generate_sss_all_tables(&sss_tables, N_id_2); - convert_tables(&q->fc_tables[N_id_2], &sss_tables); +int sss_synch_realloc(sss_synch_t *q, uint32_t fft_size) { + if (q != NULL && + fft_size < 2048) + { + dft_plan_free(&q->dftp_input); + if (dft_plan(&q->dftp_input, fft_size, FORWARD, COMPLEX)) { + sss_synch_free(q); + return LIBLTE_ERROR; + } + dft_plan_set_mirror(&q->dftp_input, true); + dft_plan_set_dc(&q->dftp_input, true); + + q->fft_size = fft_size; + return LIBLTE_SUCCESS; } - q->N_id_2 = 0; - return 0; + return LIBLTE_ERROR_INVALID_INPUTS; } void sss_synch_free(sss_synch_t *q) { @@ -66,80 +95,40 @@ void sss_synch_free(sss_synch_t *q) { } /** Sets the N_id_2 to search for */ -int sss_synch_set_N_id_2(sss_synch_t *q, int N_id_2) { - if (N_id_2 < 0 || N_id_2 > 2) { +int sss_synch_set_N_id_2(sss_synch_t *q, uint32_t N_id_2) { + if (!lte_N_id_2_isvalid(N_id_2)) { fprintf(stderr, "Invalid N_id_2 %d\n", N_id_2); - return -1; + return LIBLTE_ERROR; } else { q->N_id_2 = N_id_2; - return 0; + return LIBLTE_SUCCESS; } } /** 36.211 10.3 section 6.11.2.2 */ -void sss_put_slot(float *sss, cf_t *slot, int nof_prb, lte_cp_t cp) { - int i, k; +void sss_put_slot(float *sss, cf_t *slot, uint32_t nof_prb, lte_cp_t cp) { + uint32_t i, k; k = (CP_NSYMB(cp) - 2) * nof_prb * RE_X_RB + nof_prb * RE_X_RB / 2 - 31; - memset(&slot[k - 5], 0, 5 * sizeof(cf_t)); - for (i = 0; i < SSS_LEN; i++) { - __real__ slot[k + i] = sss[i]; - __imag__ slot[k + i] = 0; - } - memset(&slot[k + SSS_LEN], 0, 5 * sizeof(cf_t)); -} - -/* In this function, input points to the beginning of the subframe. Saves result in subframe_idx and N_id_1 - * Return 1 if the sequence was found, 0 if the peak is not found, -1 if the subframe_sz or symbol_sz are - * invalid or not configured. - * Before calling this function, the correlation threshold and symbol size duration need to be set - * using sss_synch_set_threshold() and sss_synch_set_symbol_sz(). - */ -int sss_synch_frame(sss_synch_t *q, cf_t *input, int *subframe_idx, int *N_id_1) { - int m0, m1; - float m0_value, m1_value; - - if (q->subframe_sz <= 0 || q->symbol_sz <= 0) { - return -1; - } - - sss_synch_m0m1(q, &input[SSS_SYMBOL_ST(q->subframe_sz, q->symbol_sz)], &m0, - &m0_value, &m1, &m1_value); - - if (m0_value > q->corr_peak_threshold - && m1_value > q->corr_peak_threshold) { - if (subframe_idx) { - *subframe_idx = sss_synch_subframe(m0, m1); + + if (k > 5) { + memset(&slot[k - 5], 0, 5 * sizeof(cf_t)); + for (i = 0; i < SSS_LEN; i++) { + __real__ slot[k + i] = sss[i]; + __imag__ slot[k + i] = 0; } - if (N_id_1) { - *N_id_1 = sss_synch_N_id_1(q, m0, m1); - } - return 1; - } else { - return 0; + memset(&slot[k + SSS_LEN], 0, 5 * sizeof(cf_t)); } } -/** Used by sss_synch_frame() to compute the beginning of the SSS symbol - * symbol_sz MUST INCLUDE THE CYCLIC PREFIX SIZE - */ -void sss_synch_set_symbol_sz(sss_synch_t *q, int symbol_sz) { - q->symbol_sz = symbol_sz; -} - -/** Used by sss_synch_frame() to compute the beginning of the SSS symbol */ -void sss_synch_set_subframe_sz(sss_synch_t *q, int subframe_sz) { - q->subframe_sz = subframe_sz; -} - /** Sets the SSS correlation peak detection threshold */ void sss_synch_set_threshold(sss_synch_t *q, float threshold) { q->corr_peak_threshold = threshold; } /** Returns the subframe index based on the m0 and m1 values */ -int sss_synch_subframe(int m0, int m1) { +uint32_t sss_synch_subframe(uint32_t m0, uint32_t m1) { if (m1 > m0) { return 0; } else { @@ -148,27 +137,27 @@ int sss_synch_subframe(int m0, int m1) { } /** Returns the N_id_1 value based on the m0 and m1 values */ -int sss_synch_N_id_1(sss_synch_t *q, int m0, int m1) { - if (m0 < 0 || m0 > 29 || m1 < 0 || m1 > 29) { - return -1; +int sss_synch_N_id_1(sss_synch_t *q, uint32_t m0, uint32_t m1) { + if (m0==m1 || m0 > 29 || m1 > 29) { + return LIBLTE_ERROR; } if (m1 > m0) { return q->N_id_1_table[m0][m1 - 1]; } else { return q->N_id_1_table[m1][m0 - 1]; - } + } } /** High-level API */ int sss_synch_initialize(sss_synch_hl* h) { - if (sss_synch_init(&h->obj)) { - return -1; + if (sss_synch_init(&h->obj, 128)) { + return LIBLTE_ERROR; } sss_synch_set_N_id_2(&h->obj, h->init.N_id_2); - return 0; + return LIBLTE_SUCCESS; } int sss_synch_work(sss_synch_hl* hl) { @@ -176,20 +165,12 @@ int sss_synch_work(sss_synch_hl* hl) { if (hl->ctrl_in.correlation_threshold) { sss_synch_set_threshold(&hl->obj, hl->ctrl_in.correlation_threshold); } - if (hl->ctrl_in.subframe_sz) { - sss_synch_set_subframe_sz(&hl->obj, hl->ctrl_in.subframe_sz); - } - if (hl->ctrl_in.symbol_sz) { - sss_synch_set_symbol_sz(&hl->obj, hl->ctrl_in.symbol_sz); - } - sss_synch_frame(&hl->obj, hl->input, &hl->ctrl_out.subframe_idx, - &hl->ctrl_out.N_id_1); - - return 0; + + return LIBLTE_SUCCESS; } int sss_synch_stop(sss_synch_hl* hl) { sss_synch_free(&hl->obj); - return 0; + return LIBLTE_SUCCESS; } diff --git a/lte/phy/lib/sync/src/sync.c b/lte/phy/lib/sync/src/sync.c index 083922d99..28333e06a 100644 --- a/lte/phy/lib/sync/src/sync.c +++ b/lte/phy/lib/sync/src/sync.c @@ -25,43 +25,105 @@ * */ - - #include #include "liblte/phy/utils/debug.h" #include "liblte/phy/common/phy_common.h" #include "liblte/phy/sync/sync.h" +#include "liblte/phy/utils/vector.h" -int sync_init(sync_t *q, int frame_size) { - - bzero(q, sizeof(sync_t)); - q->threshold = 1.5; - q->pss_mode = PEAK_MEAN; - q->detect_cp = true; - q->sss_en = true; - if (pss_synch_init(&q->pss, frame_size)) { - fprintf(stderr, "Error initializing PSS object\n"); - return -1; - } - if (pss_synch_init(&q->pss_track, TRACK_LEN)) { - fprintf(stderr, "Error initializing PSS track object\n"); - return -1; - } - if (sss_synch_init(&q->sss)) { - fprintf(stderr, "Error initializing SSS object\n"); - return -1; +static bool fft_size_isvalid(uint32_t fft_size) { + if (fft_size >= FFT_SIZE_MIN && fft_size <= FFT_SIZE_MAX && (fft_size%64) == 0) { + return true; + } else { + return false; } - DEBUG("PSS and SSS initiated\n",0); +} + +int sync_init(sync_t *q, uint32_t find_frame_size, uint32_t track_frame_size, uint32_t fft_size) { + + int ret = LIBLTE_ERROR_INVALID_INPUTS; - return 0; + if (q != NULL && + find_frame_size > fft_size && + find_frame_size < 307200 && + fft_size_isvalid(fft_size)) + { + bzero(q, sizeof(sync_t)); + q->pss_mode = PEAK_MEAN; + q->detect_cp = true; + q->sss_en = true; + q->N_id_2 = 1000; + q->N_id_1 = 1000; + q->fft_size = fft_size; + q->find_frame_size = find_frame_size; + + if (pss_synch_init_fft(&q->pss_find, find_frame_size, fft_size)) { + fprintf(stderr, "Error initializing PSS object\n"); + return LIBLTE_ERROR; + } + if (sss_synch_init(&q->sss, fft_size)) { + fprintf(stderr, "Error initializing SSS object\n"); + return LIBLTE_ERROR; + } + if (pss_synch_init_fft(&q->pss_track, track_frame_size, fft_size)) { + fprintf(stderr, "Error initializing PSS track object\n"); + return LIBLTE_ERROR; + } + + DEBUG("SYNC init with find_frame_size=%d and fft_size=%d\n", find_frame_size, fft_size); + + ret = LIBLTE_SUCCESS; + } + return ret; +} + +int sync_realloc(sync_t *q, uint32_t find_frame_size, uint32_t track_frame_size, + uint32_t fft_size) +{ + int ret = LIBLTE_ERROR_INVALID_INPUTS; + + if (q != NULL && + find_frame_size > fft_size && + find_frame_size < 307200 && + fft_size_isvalid(fft_size)) + { + q->N_id_2 = 1000; + q->N_id_1 = 1000; + q->fft_size = fft_size; + q->find_frame_size = find_frame_size; + + pss_synch_free(&q->pss_find); + if (pss_synch_init_fft(&q->pss_find, find_frame_size, fft_size)) { + fprintf(stderr, "Error initializing PSS object\n"); + return LIBLTE_ERROR; + } + + pss_synch_free(&q->pss_track); + if (pss_synch_init_fft(&q->pss_track, track_frame_size, fft_size)) { + fprintf(stderr, "Error initializing PSS track object\n"); + return LIBLTE_ERROR; + } + + if (sss_synch_realloc(&q->sss, fft_size)) { + fprintf(stderr, "Error realloc'ing SSS object\n"); + return LIBLTE_ERROR; + } + + DEBUG("SYNC init with find_frame_size=%d and fft_size=%d\n", find_frame_size, fft_size); + + ret = LIBLTE_SUCCESS; + } + return ret; } void sync_free(sync_t *q) { - pss_synch_free(&q->pss); - pss_synch_free(&q->pss_track); - sss_synch_free(&q->sss); + if (q) { + pss_synch_free(&q->pss_track); + pss_synch_free(&q->pss_find); + sss_synch_free(&q->sss); + } } void sync_pss_det_absolute(sync_t *q) { @@ -71,31 +133,42 @@ void sync_pss_det_peak_to_avg(sync_t *q) { q->pss_mode = PEAK_MEAN; } -void sync_set_threshold(sync_t *q, float threshold) { - q->threshold = threshold; +void sync_set_threshold(sync_t *q, float find_threshold, float track_threshold) { + q->find_threshold = find_threshold; + q->track_threshold = track_threshold; } void sync_sss_en(sync_t *q, bool enabled) { q->sss_en = enabled; } +bool sync_sss_detected(sync_t *q) { + return lte_N_id_1_isvalid(q->N_id_1); +} + int sync_get_cell_id(sync_t *q) { - if (q->N_id_1 >=0 && q->N_id_2 >= 0) { - return q->N_id_1*3 + q->N_id_2; + if (q->N_id_2 != 10) { + if (lte_N_id_2_isvalid(q->N_id_2) && lte_N_id_1_isvalid(q->N_id_1)) { + return q->N_id_1*3 + q->N_id_2; + } else { + fprintf(stderr, "Error getting cell_id, invalid N_id_1 or N_id_2\n"); + return LIBLTE_ERROR; + } } else { - return -1; + fprintf(stderr, "Error getting cell_id, N_id_2 not set\n"); + return LIBLTE_ERROR; } } -int sync_get_N_id_1(sync_t *q) { +uint32_t sync_get_N_id_1(sync_t *q) { return q->N_id_1; } -int sync_get_N_id_2(sync_t *q) { +uint32_t sync_get_N_id_2(sync_t *q) { return q->N_id_2; } -int sync_get_slot_id(sync_t *q) { +uint32_t sync_get_slot_id(sync_t *q) { return q->slot_id; } @@ -115,57 +188,66 @@ lte_cp_t sync_get_cp(sync_t *q) { return q->cp; } -int sync_sss(sync_t *q, cf_t *input, int N_id_2, int peak_pos, bool en_cp) { - int m0, m1, sss_idx_n, sss_idx_e; +int sync_sss(sync_t *q, cf_t *input, uint32_t peak_pos, bool en_cp) { + uint32_t m0, m1; + int sss_idx_n, sss_idx_e, ret; float m0_value_e, m1_value_e,m0_value_n, m1_value_n; - int slot_id_e, N_id_1_e, slot_id_n, N_id_1_n; + uint32_t slot_id_e, N_id_1_e, slot_id_n, N_id_1_n; - sss_synch_set_N_id_2(&q->sss, N_id_2); + sss_synch_set_N_id_2(&q->sss, q->N_id_2); /* Make sure we have enough room to find SSS sequence */ - sss_idx_n = peak_pos-2*(128+CP(128,CPNORM_LEN)); - sss_idx_e = peak_pos-2*(128+CP(128,CPEXT_LEN)); + sss_idx_n = (int) peak_pos - 2*(q->fft_size + CP(q->fft_size, CPNORM_LEN)); + sss_idx_e = (int) peak_pos - 2*(q->fft_size + CP(q->fft_size, CPEXT_LEN)); if (en_cp) { if (sss_idx_n < 0 || sss_idx_e < 0) { INFO("Not enough room to decode SSS (%d, %d)\n", sss_idx_n, sss_idx_e); - return -1; + return LIBLTE_SUCCESS; } } else { if (CP_ISNORM(q->cp)) { if (sss_idx_n < 0) { - INFO("Not enough room to decode SSS (%d)\n", sss_idx_n); - return -1; + INFO("Not enough room to decode normal CP SSS (sss_idx=%d, peak_pos=%d)\n", sss_idx_n, peak_pos); + return LIBLTE_SUCCESS; } } else { if (sss_idx_e < 0) { - INFO("Not enough room to decode SSS (%d)\n", sss_idx_e); - return -1; + INFO("Not enough room to decode extended CP SSS (sss_idx=%d, peak_pos=%d)\n", sss_idx_e, peak_pos); + return LIBLTE_SUCCESS; } } } - - N_id_1_e = -1; - N_id_1_n = -1; - slot_id_e = -1; - slot_id_n = -1; + + slot_id_n = 0; + slot_id_e = 0; + N_id_1_n = 0; + N_id_1_e = 0; /* try Normal CP length */ if (en_cp || CP_ISNORM(q->cp)) { - sss_synch_m0m1(&q->sss, &input[sss_idx_n], - &m0, &m0_value_n, &m1, &m1_value_n); + sss_synch_m0m1(&q->sss, &input[sss_idx_n], &m0, &m0_value_n, &m1, &m1_value_n); slot_id_n = 2 * sss_synch_subframe(m0, m1); - N_id_1_n = sss_synch_N_id_1(&q->sss, m0, m1); + ret = sss_synch_N_id_1(&q->sss, m0, m1); + if (ret >= 0) { + N_id_1_n = (uint32_t) ret; + } else { + N_id_1_n = 1000; + } } if (en_cp || CP_ISEXT(q->cp)) { /* Now try Extended CP length */ - sss_synch_m0m1(&q->sss, &input[sss_idx_e], - &m0, &m0_value_e, &m1, &m1_value_e); + sss_synch_m0m1(&q->sss, &input[sss_idx_e], &m0, &m0_value_e, &m1, &m1_value_e); slot_id_e = 2 * sss_synch_subframe(m0, m1); - N_id_1_e = sss_synch_N_id_1(&q->sss, m0, m1); + ret = sss_synch_N_id_1(&q->sss, m0, m1); + if (ret >= 0) { + N_id_1_e = (uint32_t) ret; + } else { + N_id_1_e = 1000; + } } /* Correlation with extended CP hypoteshis is greater than with normal? */ @@ -174,56 +256,93 @@ int sync_sss(sync_t *q, cf_t *input, int N_id_2, int peak_pos, bool en_cp) { q->cp = CPEXT; q->slot_id = slot_id_e; q->N_id_1 = N_id_1_e; - /* then is normal CP */ + /* otherwise is normal CP */ } else { q->cp = CPNORM; q->slot_id = slot_id_n; q->N_id_1 = N_id_1_n; } - INFO("SSS detected N_id_1=%d, slot_idx=%d, %s CP\n", - q->N_id_1, q->slot_id, CP_ISNORM(q->cp)?"Normal":"Extended"); + DEBUG("SSS detected N_id_1=%d, slot_idx=%d, position=%d/%d %s CP\n", + q->N_id_1, q->slot_id, sss_idx_n, sss_idx_e, CP_ISNORM(q->cp)?"Normal":"Extended"); - return 0; + return 1; } -int sync_track(sync_t *q, cf_t *input) { - float peak_value, mean_value; - int peak_detected = 0; - pss_synch_set_N_id_2(&q->pss_track, q->N_id_2); +int sync_track(sync_t *q, cf_t *input, uint32_t offset, uint32_t *peak_position) { - int peak_pos = pss_synch_find_pss(&q->pss, input, &peak_value, &mean_value); + int ret = LIBLTE_ERROR_INVALID_INPUTS; - if (q->peak_to_avg > TRACK_THRESHOLD) { - peak_detected = 1; - } - if (peak_detected) { - - q->cfo = pss_synch_cfo_compute(&q->pss, &input[peak_pos-128]); + if (q != NULL && + input != NULL && + fft_size_isvalid(q->fft_size)) + { + float peak_value, mean_value, *mean_ptr; + bool peak_detected; + uint32_t peak_pos; + + pss_synch_set_N_id_2(&q->pss_track, q->N_id_2); + + if (q->pss_mode == ABSOLUTE) { + mean_ptr = NULL; + } else { + mean_ptr = &mean_value; + } + + peak_pos = pss_synch_find_pss(&q->pss_track, &input[offset], &peak_value, mean_ptr); - if (q->sss_en) { - if (sync_sss(q, input, q->N_id_2, peak_pos, false)) { - return -1; + peak_detected = false; + if (q->pss_mode == ABSOLUTE) { + if (peak_value > q->track_threshold) { + peak_detected = true; + } + } else { + q->peak_to_avg = peak_value / mean_value; + if (q->peak_to_avg > q->track_threshold) { + peak_detected = true; } } - - return peak_pos; - } else { - return -1; + DEBUG("PSS possible tracking peak pos=%d peak=%.2f par=%.2f threshold=%.2f\n", + peak_pos, peak_value, q->peak_to_avg, q->track_threshold); + if (peak_detected) { + q->cfo = pss_synch_cfo_compute(&q->pss_track, &input[offset+peak_pos-q->fft_size]); + + if (q->sss_en) { + if (sync_sss(q, input, offset + peak_pos, false) < 0) { + fprintf(stderr, "Error synchronizing with SSS\n"); + return LIBLTE_ERROR; + } + } + + if (peak_position) { + *peak_position = peak_pos; + } + ret = 1; + } else { + ret = LIBLTE_SUCCESS; + } } + return ret; } -int sync_find(sync_t *q, cf_t *input) { - int N_id_2, peak_pos[3]; +int sync_find(sync_t *q, cf_t *input, uint32_t *peak_position) { + uint32_t N_id_2, peak_pos[3]; float peak_value[3]; float mean_value[3]; float max=-999; - int i; - int peak_detected; + uint32_t i; + int ret; + bool peak_detected; for (N_id_2=0;N_id_2<3;N_id_2++) { - pss_synch_set_N_id_2(&q->pss, N_id_2); - peak_pos[N_id_2] = pss_synch_find_pss(&q->pss, input, &peak_value[N_id_2], &mean_value[N_id_2]); + pss_synch_set_N_id_2(&q->pss_find, N_id_2); + ret = pss_synch_find_pss(&q->pss_find, input, &peak_value[N_id_2], &mean_value[N_id_2]); + if (ret < 0) { + fprintf(stderr, "Error finding PSS for N_id_2=%d\n", N_id_2); + return LIBLTE_ERROR; + } + peak_pos[N_id_2] = (uint32_t) ret; + } for (i=0;i<3;i++) { if (peak_value[i] > max) { @@ -235,38 +354,43 @@ int sync_find(sync_t *q, cf_t *input) { q->peak_to_avg = peak_value[N_id_2] / mean_value[N_id_2]; DEBUG("PSS possible peak N_id_2=%d, pos=%d peak=%.2f par=%.2f threshold=%.2f\n", - N_id_2, peak_pos[N_id_2], peak_value[N_id_2], q->peak_to_avg, q->threshold); + N_id_2, peak_pos[N_id_2], peak_value[N_id_2], q->peak_to_avg, q->find_threshold); /* If peak detected */ - peak_detected = 0; - if (peak_pos[N_id_2] - 128 >= 0) { + peak_detected = false; + if (peak_pos[N_id_2] > q->fft_size) { if (q->pss_mode == ABSOLUTE) { - if (peak_value[N_id_2] > q->threshold) { - peak_detected = 1; + if (peak_value[N_id_2] > q->find_threshold) { + peak_detected = true; } } else { - if (q->peak_to_avg > q->threshold) { - peak_detected = 1; + if (q->peak_to_avg > q->find_threshold) { + peak_detected = true; } } } + if (peak_detected) { q->N_id_2 = N_id_2; - pss_synch_set_N_id_2(&q->pss, q->N_id_2); - q->cfo = pss_synch_cfo_compute(&q->pss, &input[peak_pos[q->N_id_2]-128]); + pss_synch_set_N_id_2(&q->pss_find, q->N_id_2); + q->cfo = pss_synch_cfo_compute(&q->pss_find, &input[peak_pos[N_id_2]-q->fft_size]); - INFO("PSS peak detected N_id_2=%d, pos=%d peak=%.2f par=%.2f th=%.2f cfo=%.4f\n", N_id_2, - peak_pos[N_id_2], peak_value[N_id_2], q->peak_to_avg, q->threshold, q->cfo); + DEBUG("PSS peak detected N_id_2=%d, pos=%d peak=%.2f par=%.2f th=%.2f cfo=%.4f\n", N_id_2, + peak_pos[N_id_2], peak_value[N_id_2], q->peak_to_avg, q->find_threshold, q->cfo); if (q->sss_en) { - if (sync_sss(q, input, q->N_id_2, peak_pos[q->N_id_2], q->detect_cp)) { - return -1; + if (sync_sss(q, input, peak_pos[q->N_id_2], q->detect_cp) < 0) { + fprintf(stderr, "Error synchronizing with SSS\n"); + return LIBLTE_ERROR; } } + + if (peak_position) { + *peak_position = peak_pos[N_id_2]; + } - return peak_pos[N_id_2]; - + return 1; } else { - return -1; + return LIBLTE_SUCCESS; } } diff --git a/lte/phy/lib/sync/src/sync_frame.c b/lte/phy/lib/sync/src/sync_frame.c deleted file mode 100644 index 56b9de863..000000000 --- a/lte/phy/lib/sync/src/sync_frame.c +++ /dev/null @@ -1,244 +0,0 @@ -/** - * - * \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 "liblte/phy/resampling/decim.h" -#include "liblte/phy/resampling/resample_arb.h" -#include "liblte/phy/utils/debug.h" -#include "liblte/phy/sync/sync_frame.h" - - -int sync_frame_init(sync_frame_t *q, uint32_t downsampling) { - int ret = -1; - bzero(q, sizeof(sync_frame_t)); - - if(sync_init(&q->s, SYNC_SF_LEN)) { - goto clean_exit; - } - sync_pss_det_peak_to_avg(&q->s); - - if (cfo_init(&q->cfocorr, SYNC_SF_LEN * downsampling)) { - fprintf(stderr, "Error initiating CFO\n"); - goto clean_exit; - } - - q->input_buffer = malloc(2 * SYNC_SF_LEN * downsampling * sizeof(cf_t)); - if (!q->input_buffer) { - perror("malloc"); - goto clean_exit; - } - - q->input_downsampled = malloc(SYNC_SF_LEN * sizeof(cf_t)); - if (!q->input_downsampled) { - perror("malloc"); - goto clean_exit; - } - - resample_arb_init(&q->resample, (float) 1/downsampling); - - q->downsampling = downsampling; - sync_frame_reset(q); - ret = 0; - -clean_exit: - if (ret == -1) { - sync_frame_free(q); - } - return ret; -} - -void sync_frame_free(sync_frame_t *q) { - if (q->input_buffer) { - free(q->input_buffer); - } - if (q->input_downsampled) { - free(q->input_downsampled); - } - - cfo_free(&q->cfocorr); - sync_free(&q->s); -} - -void sync_frame_run(sync_frame_t *q, cf_t *input) { - uint32_t track_idx; - - switch (q->state) { - - case SF_FIND: - q->peak_idx = sync_find(&q->s, input); - q->cell_id = sync_get_cell_id(&q->s); - - INFO("FIND %3d:\tPAR=%.2f\n", (int) q->frame_cnt, sync_get_peak_to_avg(&q->s)); - - if (q->peak_idx != -1 && q->cell_id != -1) { - - /* Get the subframe index (0 or 5) */ - q->sf_idx = sync_get_slot_id(&q->s)/2; - - /* Reset variables */ - q->last_found = 0; - q->timeoffset = 0; - q->frame_cnt = 0; - - /* Goto Tracking state */ - q->state = SF_TRACK; - } - break; - case SF_TRACK: - - q->sf_idx = (q->sf_idx + 1) % 10; - - /* Every SF idx 0 and 5, find peak around known position q->peak_idx */ - if (q->sf_idx != 0 && q->sf_idx != 5) { - break; - } - - assert(q->peak_idx < TRACK_LEN); - - track_idx = sync_track(&q->s, &input[q->peak_idx - TRACK_LEN]); - - INFO("TRACK %3d: SF=%d. Previous idx is %d New Offset is %d\n", - (int) q->frame_cnt, q->sf_idx, q->peak_idx, track_idx - TRACK_LEN); - - if (track_idx != -1) { - INFO("Expected SF idx %d but got %d. Going back to FIND\n", q->sf_idx, - sync_get_slot_id(&q->s)/2); - - /* Make sure subframe idx is what we expect */ - if (q->sf_idx != sync_get_slot_id(&q->s)/2) { - INFO("Expected SF idx %d but got %d. Going back to FIND\n", q->sf_idx, - sync_get_slot_id(&q->s)/2); - q->state = SF_FIND; - } - - /* compute cumulative moving average CFO */ - q->cur_cfo = (sync_get_cfo(&q->s) + q->frame_cnt * q->cur_cfo) / (q->frame_cnt + 1); - - /* compute cumulative moving average time offset */ - q->timeoffset = (float) ((float) track_idx - TRACK_LEN + q->timeoffset * q->frame_cnt) - / (q->frame_cnt + 1); - - q->last_found = q->frame_cnt; - q->peak_idx = (q->peak_idx + track_idx - TRACK_LEN) % SYNC_SF_LEN; - - if (q->peak_idx < 0) { - INFO("PSS lost (peak_idx=%d). Going back to FIND\n", q->peak_idx); - q->state = SF_FIND; - } - } else { - /* if sync not found, adjust time offset with the averaged value */ - q->peak_idx = (q->peak_idx + (uint32_t) q->timeoffset) % SYNC_SF_LEN; - - /* if we missed too many PSS go back to FIND */ - if (q->frame_cnt - q->last_found > TRACK_MAX_LOST) { - INFO("%d frames lost. Going back to FIND", (int) q->frame_cnt - q->last_found); - q->state = SF_FIND; - } - } - q->frame_cnt++; - break; - } -} - -void sync_frame_set_threshold(sync_frame_t *q, float threshold) { - sync_set_threshold(&q->s, threshold); -} - -uint32_t sync_frame_cell_id(sync_frame_t *q) { - return q->cell_id; -} - -uint32_t sync_frame_sfidx(sync_frame_t *q) { - return q->sf_idx; -} - - -int sync_frame_push(sync_frame_t *q, cf_t *input, cf_t *output) { - int retval = 0; - int frame_start; - cf_t *input_ds; - uint32_t sf_len; - - if (q->downsampling == 1) { - input_ds = input; - } else { - //resample_arb_compute(&q->resample, input, q->input_downsampled, SYNC_SF_LEN * q->downsampling); - decim_c(input, q->input_downsampled, q->downsampling, SYNC_SF_LEN * q->downsampling); - input_ds = q->input_downsampled; - } - - sync_frame_run(q, input_ds); - - sf_len = q->downsampling * SYNC_SF_LEN; - - if (q->state == SF_FIND) { - memcpy(q->input_buffer, input, sf_len * sizeof(cf_t)); - } else { - frame_start = q->downsampling * q->peak_idx - sf_len/2; - - DEBUG("Peak_idx=%d, frame_start=%d cfo=%.3f\n",q->peak_idx, - frame_start, q->cur_cfo); - - if (frame_start > 0) { - if (q->fb_wp) { - memcpy(&q->input_buffer[(sf_len - frame_start)], input, frame_start * sizeof(cf_t)); - memcpy(output, q->input_buffer, sf_len * sizeof(cf_t)); - retval = 1; - } - memcpy(q->input_buffer, &input[frame_start], (sf_len - frame_start) * sizeof(cf_t)); - q->fb_wp = true; - } else { - memcpy(output, &q->input_buffer[sf_len + frame_start], (-frame_start) * sizeof(cf_t)); - memcpy(&output[-frame_start], input, (sf_len + frame_start) * sizeof(cf_t)); - memcpy(&q->input_buffer[sf_len + frame_start], &input[sf_len + frame_start], (-frame_start) * sizeof(cf_t)); - retval = 1; - } - } - - /* Frequency Synchronization */ - if (retval) { - cfo_correct(&q->cfocorr, output, -q->cur_cfo / 128); - } - - if (!retval) { - DEBUG("Frame Buffered\n",0); - } - - return retval; -} - -void sync_frame_reset(sync_frame_t *q) { - q->state = SF_FIND; - q->frame_cnt = 0; - q->fb_wp = false; - q->cur_cfo = 0; -} - diff --git a/lte/phy/lib/sync/test/CMakeLists.txt b/lte/phy/lib/sync/test/CMakeLists.txt index 2c5b29c3b..72b2ccb6a 100644 --- a/lte/phy/lib/sync/test/CMakeLists.txt +++ b/lte/phy/lib/sync/test/CMakeLists.txt @@ -19,6 +19,7 @@ # and at http://www.gnu.org/licenses/. # + ######################################################################## # SYNC TEST ######################################################################## diff --git a/lte/phy/lib/sync/test/cfo_test.c b/lte/phy/lib/sync/test/cfo_test.c index 1ccb17cc2..5c6086c15 100644 --- a/lte/phy/lib/sync/test/cfo_test.c +++ b/lte/phy/lib/sync/test/cfo_test.c @@ -96,8 +96,8 @@ int main(int argc, char **argv) { return -1; } - cfo_correct(&cfocorr, output, freq); - cfo_correct(&cfocorr, output, -freq); + cfo_correct(&cfocorr, output, output, freq); + cfo_correct(&cfocorr, output, output, -freq); mse = 0; for (i=0;isize = size; h->tab = malloc(sizeof(cf_t) * size); @@ -42,9 +42,9 @@ int cexptab_init(cexptab_t *h, int size) { for (i = 0; i < size; i++) { h->tab[i] = cexpf(_Complex_I * 2 * M_PI * (float) i / size); } - return 0; + return LIBLTE_SUCCESS; } else { - return -1; + return LIBLTE_ERROR; } } @@ -55,9 +55,9 @@ void cexptab_free(cexptab_t *h) { bzero(h, sizeof(cexptab_t)); } -void cexptab_gen(cexptab_t *h, cf_t *x, float freq, int len) { - int i; - unsigned int idx; +void cexptab_gen(cexptab_t *h, cf_t *x, float freq, uint32_t len) { + uint32_t i; + uint32_t idx; float phase_inc = freq * h->size; float phase=0; @@ -68,15 +68,15 @@ void cexptab_gen(cexptab_t *h, cf_t *x, float freq, int len) { while (phase < 0) { phase += (float) h->size; } - idx = (unsigned int) phase; + idx = (uint32_t) phase; x[i] = h->tab[idx]; phase += phase_inc; } } -void cexptab_gen_direct(cf_t *x, float freq, int len) { - int i; +void cexptab_gen_direct(cf_t *x, float freq, uint32_t len) { + uint32_t i; for (i = 0; i < len; i++) { x[i] = cexpf(_Complex_I * 2 * M_PI * freq * i); } diff --git a/lte/phy/lib/utils/src/convolution.c b/lte/phy/lib/utils/src/convolution.c index 2ab27e041..721595f80 100644 --- a/lte/phy/lib/utils/src/convolution.c +++ b/lte/phy/lib/utils/src/convolution.c @@ -34,61 +34,61 @@ #include "liblte/phy/utils/convolution.h" -int conv_fft_cc_init(conv_fft_cc_t *state, int input_len, int filter_len) { - state->input_len = input_len; - state->filter_len = filter_len; - state->output_len = input_len+filter_len-1; - state->input_fft = vec_malloc(sizeof(_Complex float)*state->output_len); - state->filter_fft = vec_malloc(sizeof(_Complex float)*state->output_len); - state->output_fft = vec_malloc(sizeof(_Complex float)*state->output_len); - if (!state->input_fft || !state->filter_fft || !state->output_fft) { - return -1; +int conv_fft_cc_init(conv_fft_cc_t *q, uint32_t input_len, uint32_t filter_len) { + q->input_len = input_len; + q->filter_len = filter_len; + q->output_len = input_len+filter_len; + q->input_fft = vec_malloc(sizeof(cf_t)*q->output_len); + q->filter_fft = vec_malloc(sizeof(cf_t)*q->output_len); + q->output_fft = vec_malloc(sizeof(cf_t)*q->output_len); + if (!q->input_fft || !q->filter_fft || !q->output_fft) { + return LIBLTE_ERROR; } - if (dft_plan(&state->input_plan,state->output_len,FORWARD,COMPLEX)) { - return -2; + if (dft_plan(&q->input_plan,q->output_len,FORWARD,COMPLEX)) { + return LIBLTE_ERROR; } - if (dft_plan(&state->filter_plan,state->output_len,FORWARD,COMPLEX)) { - return -3; + if (dft_plan(&q->filter_plan,q->output_len,FORWARD,COMPLEX)) { + return LIBLTE_ERROR; } - if (dft_plan(&state->output_plan,state->output_len,BACKWARD,COMPLEX)) { - return -4; + if (dft_plan(&q->output_plan,q->output_len,BACKWARD,COMPLEX)) { + return LIBLTE_ERROR; } - return 0; + return LIBLTE_SUCCESS; } -void conv_fft_cc_free(conv_fft_cc_t *state) { - if (state->input_fft) { - free(state->input_fft); +void conv_fft_cc_free(conv_fft_cc_t *q) { + if (q->input_fft) { + free(q->input_fft); } - if (state->filter_fft) { - free(state->filter_fft); + if (q->filter_fft) { + free(q->filter_fft); } - if (state->output_fft) { - free(state->output_fft); + if (q->output_fft) { + free(q->output_fft); } - dft_plan_free(&state->input_plan); - dft_plan_free(&state->filter_plan); - dft_plan_free(&state->output_plan); + dft_plan_free(&q->input_plan); + dft_plan_free(&q->filter_plan); + dft_plan_free(&q->output_plan); } -int conv_fft_cc_run(conv_fft_cc_t *state, _Complex float *input, _Complex float *filter, _Complex float *output) { +uint32_t conv_fft_cc_run(conv_fft_cc_t *q, cf_t *input, cf_t *filter, cf_t *output) { - dft_run_c(&state->input_plan, input, state->input_fft); - dft_run_c(&state->filter_plan, filter, state->filter_fft); + dft_run_c(&q->input_plan, input, q->input_fft); + dft_run_c(&q->filter_plan, filter, q->filter_fft); - vec_prod_ccc(state->input_fft,state->filter_fft,state->output_fft,state->output_len); + vec_prod_ccc(q->input_fft,q->filter_fft,q->output_fft,q->output_len); - dft_run_c(&state->output_plan, state->output_fft, output); + dft_run_c(&q->output_plan, q->output_fft, output); - return state->output_len; + return q->output_len; } -int conv_cc(_Complex float *input, _Complex float *filter, _Complex float *output, int input_len, int filter_len) { - int i,j; - int output_len; +uint32_t conv_cc(cf_t *input, cf_t *filter, cf_t *output, uint32_t input_len, uint32_t filter_len) { + uint32_t i,j; + uint32_t output_len; output_len=input_len+filter_len-1; - memset(output,0,output_len*sizeof(_Complex float)); + memset(output,0,output_len*sizeof(cf_t)); for (i=0;i #include #include +#include + +#include "liblte/phy/utils/vector.h" +#include "liblte/phy/utils/bit.h" #ifdef HAVE_VOLK #include "volk/volk.h" #endif -int vec_acc_ii(int *x, int len) { +int vec_acc_ii(int *x, uint32_t len) { int i; int z=0; for (i=0;im) { m=x[i]; @@ -244,7 +386,7 @@ int vec_max_fi(float *x, int len) { #endif } -void vec_quant_fuc(float *in, unsigned char *out, float gain, float offset, float clip, int len) { +void vec_quant_fuc(float *in, unsigned char *out, float gain, float offset, float clip, uint32_t len) { int i; int tmp; for (i=0;i 128 && i threshold) - y=ccf.*x(i-128:i-1); - - y0=y(1:64); - y1=y(65:length(y)); - - eps=angle(conj(sum(y0))*sum(y1))/pi; - else - eps = NaN; - fs = NaN; - end end diff --git a/matlab/sync/lte_generate_sss.m b/matlab/sync/lte_generate_sss.m deleted file mode 100644 index d8b45e914..000000000 --- a/matlab/sync/lte_generate_sss.m +++ /dev/null @@ -1,123 +0,0 @@ -% -% Copyright 2011-2012 Ben Wojtowicz -% -% This program is free software: you can redistribute it and/or modify -% it under the terms of the GNU Affero General Public License as published by -% the Free Software Foundation, either version 3 of the License, or -% (at your option) any later version. -% -% This program 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 Affero General Public License for more details. -% -% You should have received a copy of the GNU Affero General Public License -% along with this program. If not, see . -% -% Function: lte_generate_sss -% Description: Generates LTE secondary synchronization signals -% Inputs: N_id_1 - Physical layer cell identity group -% N_id_2 - Physical layer identity -% Outputs: sss_d_u_0 - The sequence d(n) used for the secondary -% synchronization signal, an interleaved -% concatenation of two length-31 binary -% sequences for subframe 0 -% Outputs: sss_d_u_5 - The sequence d(n) used for the secondary -% synchronization signal, an interleaved -% concatenation of two length-31 binary -% sequences for subframe 5 -% Spec: 3GPP TS 36.211 section 6.11.2.1 v10.1.0 -% Notes: None -% Rev History: Ben Wojtowicz 10/28/2011 Created -% Ben Wojtowicz 01/29/2012 Fixed license statement -% -function [sss_d_u_0, sss_d_u_5 c0 c1 m0 m1] = lte_generate_sss(N_id_1, N_id_2) - % Validate N_id_1 - if(~(N_id_1 >= 0 && N_id_1 <= 167)) - fprintf('ERROR: Invalid N_id_1 (%u)\n', N_id_1); - sss_d_u_0 = 0; - sss_d_u_5 = 0; - return; - end - - % Validate N_id_2 - if(~(N_id_2 >= 0 && N_id_2 <= 2)) - fprintf('ERROR: Invalid N_id_2 (%u)\n', N_id_2); - sss_d_u_0 = 0; - sss_d_u_5 = 0; - return; - end - - % Generate m0 and m1 - q_prime = floor(N_id_1/30); - q = floor((N_id_1 + (q_prime*(q_prime+1)/2))/30); - m_prime = N_id_1 + (q*(q+1)/2); - m0 = mod(m_prime, 31); - m1 = mod((m0 + floor(m_prime/31) + 1), 31); - - % Generate s_tilda - x_s_tilda(0+1) = 0; - x_s_tilda(1+1) = 0; - x_s_tilda(2+1) = 0; - x_s_tilda(3+1) = 0; - x_s_tilda(4+1) = 1; - for(i_hat=0:25) - x_s_tilda(i_hat+5+1) = mod((x_s_tilda(i_hat+2+1) + x_s_tilda(i_hat+1)), 2); - end - for(idx=0:30) - s_tilda(idx+1) = 1 - 2*x_s_tilda(idx+1); - end - - % Generate c_tilda - x_c_tilda(0+1) = 0; - x_c_tilda(1+1) = 0; - x_c_tilda(2+1) = 0; - x_c_tilda(3+1) = 0; - x_c_tilda(4+1) = 1; - for(i_hat=0:25) - x_c_tilda(i_hat+5+1) = mod((x_c_tilda(i_hat+3+1) + x_c_tilda(i_hat+1)), 2); - end - for(idx=0:30) - c_tilda(idx+1) = 1 - 2*x_c_tilda(idx+1); - end - - % Generate z_tilda - x_z_tilda(0+1) = 0; - x_z_tilda(1+1) = 0; - x_z_tilda(2+1) = 0; - x_z_tilda(3+1) = 0; - x_z_tilda(4+1) = 1; - for(i_hat=0:25) - x_z_tilda(i_hat+5+1) = mod((x_z_tilda(i_hat+4+1) + x_z_tilda(i_hat+2+1) + x_z_tilda(i_hat+1+1) + x_z_tilda(i_hat+1)), 2); - end - for(idx=0:30) - z_tilda(idx+1) = 1 - 2*x_z_tilda(idx+1); - end - - % Generate s0_m0 and s1_m1 - for(n=0:30) - s0_m0(n+1) = s_tilda(mod(n + m0, 31)+1); - s1_m1(n+1) = s_tilda(mod(n + m1, 31)+1); - end - - % Generate c0 and c1 - for(n=0:30) - c0(n+1) = c_tilda(mod(n + N_id_2, 31)+1); - c1(n+1) = c_tilda(mod(n + N_id_2 + 3, 31)+1); - end - - % Generate z1_m0 and z1_m1 - for(n=0:30) - z1_m0(n+1) = z_tilda(mod(n + mod(m0, 8), 31)+1); - z1_m1(n+1) = z_tilda(mod(n + mod(m1, 8), 31)+1); - end - - % Generate SSS - for(n=0:30) - sss_d_u_0(2*n+1) = s0_m0(n+1) * c0(n+1); - sss_d_u_5(2*n+1) = s1_m1(n+1) * c0(n+1); - - sss_d_u_0(2*n+1+1) = s1_m1(n+1) * c1(n+1) * z1_m0(n+1); - sss_d_u_5(2*n+1+1) = s0_m0(n+1) * c1(n+1) * z1_m1(n+1); - end -end diff --git a/matlab/sync/test.m b/matlab/sync/test.m deleted file mode 100644 index 33d3d6e92..000000000 --- a/matlab/sync/test.m +++ /dev/null @@ -1,35 +0,0 @@ -N=128; %128 subcarries -M=16; %QAM order -cp=9; %length of the cyclic prefix... Is increasing the cyclic prefix size gonna increase the efficiency? -scale = 1/sqrt(10); -hMod = modem.qammod(M); %QAM Modulator -hDemod = modem.qamdemod(hMod); %QAM demodulator -loops = 10; -SNR =0:5:35; -t1= cputime ; -% transmited signal. Contains N data points ranging from 0 to M-1 -ber=zeros(5,length(SNR)); -%% Creating the Rayleigh Multipath Channels -Ch = rayleighchan(1/1000,10); -Ch.ResetBeforeFiltering = 0; -sig = 1i*ones(loops,1); -h1 = filter(Ch,sig); -h2 = 0.1072*filter(Ch,sig); -h3 = 0.0120*filter(Ch,sig); -h4 = 0.0052*filter(Ch,sig); -% Delay Values -l1 = 4; -l2 = 7; -l3= 16; -%% -ofdm_cp=[]; - %tx=transmited_data; - for ik=1:loops%number of loops - tx = randi([0 M-1],1,N); % generate random data - sig=modulate(hMod, tx)*scale; % Modulate QAM modulated signal, devide by the square root of 10 to bring the average power of the signal to 1 - ofdm=sqrt(N).*ifft(sig,N); % generate OFDM signal IFFT on the parrellel data,multiply by sqrt(N) to adjust to the matlab computation , - ofdm_cp = [ofdm_cp ofdm(N-cp+1:N) ofdm]; % Add cyclic prefix - - end - - \ No newline at end of file From d99e4f5988fde8ad9fc6517d3debd2226c9e3986 Mon Sep 17 00:00:00 2001 From: ismagom Date: Mon, 21 Jul 2014 16:19:50 +0200 Subject: [PATCH 13/14] ue_dl --- lte/phy/examples/iodev.c | 167 ++++++++++++ lte/phy/examples/iodev.h | 90 ++++++ lte/phy/include/liblte/phy/phch/ue_dl.h | 95 +++++++ lte/phy/lib/phch/src/ue_dl.c | 255 +++++++++++++++++ lte/phy/lib/phch/test/ue_sync_usrp.c | 257 ++++++++++++++++++ .../lib/resampling/test/interp_test_volk.c | 92 +++++++ matlab/sync/find_pss2.m | 18 ++ 7 files changed, 974 insertions(+) create mode 100644 lte/phy/examples/iodev.c create mode 100644 lte/phy/examples/iodev.h create mode 100644 lte/phy/include/liblte/phy/phch/ue_dl.h create mode 100644 lte/phy/lib/phch/src/ue_dl.c create mode 100644 lte/phy/lib/phch/test/ue_sync_usrp.c create mode 100644 lte/phy/lib/resampling/test/interp_test_volk.c create mode 100644 matlab/sync/find_pss2.m diff --git a/lte/phy/examples/iodev.c b/lte/phy/examples/iodev.c new file mode 100644 index 000000000..056c64f16 --- /dev/null +++ b/lte/phy/examples/iodev.c @@ -0,0 +1,167 @@ +/** + * + * \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 "iodev.h" + +#include "liblte/phy/io/filesource.h" +#include "liblte/phy/phch/ue_sync.h" +#include "liblte/phy/utils/debug.h" +#include "liblte/phy/utils/vector.h" + +#ifndef DISABLE_UHD +#include "liblte/cuhd/cuhd.h" +#endif + + +int cuhd_recv_wrapper(void *h, void *data, uint32_t nsamples) { + DEBUG(" ---- Receive %d samples ---- \n", nsamples); + return cuhd_recv(h, data, nsamples, 1); +} + +/* Setup USRP or input file */ +int iodev_init(iodev_t *q, iodev_cfg_t *config) { + + if (config->input_file_name) { + if (filesource_init(&q->fsrc, config->input_file_name, COMPLEX_FLOAT_BIN)) { + return LIBLTE_ERROR; + } + q->input_buffer_file = vec_malloc(SF_LEN_MAX * sizeof(cf_t)); + if (!q->input_buffer_file) { + perror("malloc"); + return LIBLTE_ERROR; + } + + q->mode = FILESOURCE; + q->sf_len = 1920; + + } else { +#ifndef DISABLE_UHD + printf("Opening UHD device...\n"); + if (cuhd_open(config->uhd_args, &q->uhd)) { + fprintf(stderr, "Error opening uhd\n"); + return LIBLTE_ERROR; + } + + /* set uhd_freq */ + cuhd_set_rx_gain(q->uhd, config->uhd_gain); + cuhd_set_rx_freq(q->uhd, (double) config->uhd_freq); + + cuhd_rx_wait_lo_locked(q->uhd); + DEBUG("Set uhd_freq to %.3f MHz\n", (double ) config->uhd_freq); + + DEBUG("Starting receiver...\n", 0); + cuhd_start_rx_stream(q->uhd); + + if (config->find_threshold > 0.0) { + ue_sync_set_threshold(&q->sframe, config->find_threshold); + } + + ue_sync_init(&q->sframe, cuhd_set_rx_srate, cuhd_recv_wrapper, q->uhd); + + // Here, the subframe length and input buffer is managed by ue_sync + q->mode = UHD; + +#else + printf("Error UHD not available. Select an input file\n"); + return LIBLTE_ERROR; +#endif + } + + memcpy(&q->config, config, sizeof(iodev_cfg_t)); + + return LIBLTE_SUCCESS; +} + + + +void iodev_free(iodev_t *q) { + + if (q->mode == FILESOURCE) { + filesource_free(&q->fsrc); + } else { +#ifndef DISABLE_UHD + cuhd_close(q->uhd); +#endif + } +} +/* Receive samples from the USRP or read from file */ +int iodev_receive(iodev_t *q, cf_t **buffer) { + int n; + if (q->mode == FILESOURCE) { + DEBUG(" ----- READING %d SAMPLES ---- \n", q->sf_len); + n = filesource_read(&q->fsrc, q->input_buffer_file, q->sf_len); + *buffer = q->input_buffer_file; + if (n == -1) { + fprintf(stderr, "Error reading file\n"); + /* wrap file if arrive to end */ + } else if (n < q->sf_len) { + DEBUG("Read %d from file. Seeking to 0\n",n); + filesource_seek(&q->fsrc, 0); + n = filesource_read(&q->fsrc, q->input_buffer_file, q->sf_len); + if (n == -1) { + fprintf(stderr, "Error reading file\n"); + /* wrap file if arrive to end */ + } else { + n = 1; + } + } else { + n = 1; + } + } else { + /* Use ue_sync_work which returns a synchronized buffer of subframe samples */ +#ifndef DISABLE_UHD + n = ue_sync_get_buffer(&q->sframe, buffer); + if (n < 0) { + fprintf(stderr, "Error calling ue_sync_work()\n"); + } +#endif + } + return n; +} + +void* iodev_get_cuhd(iodev_t *q) { + if (q->mode == UHD) { + return q->uhd; + } else { + return NULL; + } +} + +bool iodev_isfile(iodev_t *q) { + return q->mode == FILESOURCE; +} + +bool iodev_isUSRP(iodev_t *q) { + return q->mode == UHD; +} + + diff --git a/lte/phy/examples/iodev.h b/lte/phy/examples/iodev.h new file mode 100644 index 000000000..87264eda6 --- /dev/null +++ b/lte/phy/examples/iodev.h @@ -0,0 +1,90 @@ +/** + * + * \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/. + * + */ + +#ifndef IODEF_H +#define IODEF_H + +#include "liblte/config.h" + +#include "liblte/phy/phch/ue_sync.h" +#include "liblte/phy/io/filesource.h" + +#ifndef DISABLE_UHD +#include "liblte/cuhd/cuhd.h" +#endif + +/********* + * + * This component is a wrapper to the cuhd or filesource modules. It uses + * sync_frame_t to read aligned subframes from the USRP or filesource to read + * subframes from a file. + * + * When created, it starts receiving/reading at 1.92 MHz. The sampling frequency + * can then be changed using iodev_set_srate() + */ + + +typedef enum LIBLTE_API {FILESOURCE, UHD} iodev_mode_t; + +typedef _Complex float cf_t; + +typedef struct LIBLTE_API { + char *input_file_name; + float uhd_freq; + float uhd_gain; + char *uhd_args; + float find_threshold; +} iodev_cfg_t; + +typedef struct LIBLTE_API { + #ifndef DISABLE_UHD + void *uhd; + ue_sync_t sframe; + #endif + uint32_t sf_len; + cf_t *input_buffer_file; // for UHD mode, the input buffer is managed by sync_frame_t + filesource_t fsrc; + iodev_cfg_t config; + iodev_mode_t mode; +} iodev_t; + + +LIBLTE_API int iodev_init(iodev_t *q, + iodev_cfg_t *config); + +LIBLTE_API void iodev_free(iodev_t *q); + +LIBLTE_API int iodev_receive(iodev_t *q, + cf_t **buffer); + +LIBLTE_API void* iodev_get_cuhd(iodev_t *q); + +LIBLTE_API bool iodev_isfile(iodev_t *q); + +LIBLTE_API bool iodev_isUSRP(iodev_t *q); + +#endif \ No newline at end of file diff --git a/lte/phy/include/liblte/phy/phch/ue_dl.h b/lte/phy/include/liblte/phy/phch/ue_dl.h new file mode 100644 index 000000000..b6ca44bab --- /dev/null +++ b/lte/phy/include/liblte/phy/phch/ue_dl.h @@ -0,0 +1,95 @@ +/** + * + * \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/. + * + */ + +#ifndef UEDL_H +#define UEDL_H + +/******************************************************* + * + * This module is a frontend to all the data and control channels processing + * modules. + ********************************************************/ + + + +#include "liblte/phy/ch_estimation/chest.h" +#include "liblte/phy/common/fft.h" +#include "liblte/phy/common/phy_common.h" + +#include "liblte/phy/phch/dci.h" +#include "liblte/phy/phch/pbch.h" +#include "liblte/phy/phch/pcfich.h" +#include "liblte/phy/phch/pdcch.h" +#include "liblte/phy/phch/pdsch.h" +#include "liblte/phy/phch/phich.h" +#include "liblte/phy/phch/ra.h" +#include "liblte/phy/phch/regs.h" + +#include "liblte/phy/utils/vector.h" +#include "liblte/phy/utils/debug.h" + +#include "liblte/config.h" + +#define NOF_HARQ_PROCESSES 8 + +typedef struct LIBLTE_API { + pcfich_t pcfich; + pdcch_t pdcch; + pdsch_t pdsch; + pdsch_harq_t harq_process[NOF_HARQ_PROCESSES]; + regs_t regs; + lte_fft_t fft; + chest_t chest; + + lte_cell_t cell; + + cf_t *sf_symbols; + cf_t *ce[MAX_PORTS]; + + uint64_t pkt_errors; + uint64_t pkts_total; + uint64_t nof_trials; + + uint16_t user_rnti; +}ue_dl_t; + +/* This function shall be called just after the initial synchronization */ +LIBLTE_API int ue_dl_init(ue_dl_t *q, + lte_cell_t cell, + phich_resources_t phich_resources, + phich_length_t phich_length, + uint16_t user_rnti); + +LIBLTE_API void ue_dl_free(ue_dl_t *q); + +LIBLTE_API int ue_dl_process(ue_dl_t *q, + cf_t *sf_buffer, + uint32_t sf_idx, + uint32_t sfn, + uint16_t rnti); + +#endif \ No newline at end of file diff --git a/lte/phy/lib/phch/src/ue_dl.c b/lte/phy/lib/phch/src/ue_dl.c new file mode 100644 index 000000000..707f89917 --- /dev/null +++ b/lte/phy/lib/phch/src/ue_dl.c @@ -0,0 +1,255 @@ +/** + * + * \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 "liblte/phy/phch/ue_dl.h" + + +#define EXPAVERAGE(data, average, nframes) ((data + average * nframes) / (nframes + 1)) + +#define CURRENT_FFTSIZE lte_symbol_sz(q->cell.nof_prb) +#define CURRENT_SFLEN SF_LEN(CURRENT_FFTSIZE, q->cell.cp) + +#define CURRENT_SLOTLEN_RE SLOT_LEN_RE(q->cell.nof_prb, q->cell.cp) +#define CURRENT_SFLEN_RE SF_LEN_RE(q->cell.nof_prb, q->cell.cp) + + +int ue_dl_init(ue_dl_t *q, + lte_cell_t cell, + phich_resources_t phich_resources, phich_length_t phich_length, + uint16_t user_rnti) +{ + int ret = LIBLTE_ERROR_INVALID_INPUTS; + + if (q != NULL && + lte_cell_isvalid(&cell)) + { + ret = LIBLTE_ERROR; + + q->cell = cell; + q->user_rnti = user_rnti; + q->pkt_errors = 0; + q->pkts_total = 0; + + if (lte_fft_init(&q->fft, q->cell.cp, q->cell.nof_prb)) { + fprintf(stderr, "Error initiating FFT\n"); + goto clean_exit; + } + if (chest_init_LTEDL(&q->chest, cell)) { + fprintf(stderr, "Error initiating channel estimator\n"); + goto clean_exit; + } + if (regs_init(&q->regs, phich_resources, phich_length, q->cell)) { + fprintf(stderr, "Error initiating REGs\n"); + goto clean_exit; + } + + if (pcfich_init(&q->pcfich, &q->regs, q->cell)) { + fprintf(stderr, "Error creating PCFICH object\n"); + goto clean_exit; + } + + if (pdcch_init(&q->pdcch, &q->regs, q->cell)) { + fprintf(stderr, "Error creating PDCCH object\n"); + goto clean_exit; + } + + if (pdsch_init(&q->pdsch, q->cell)) { + fprintf(stderr, "Error creating PDSCH object\n"); + goto clean_exit; + } + for (uint32_t i=0;iharq_process[i], &q->pdsch)) { + fprintf(stderr, "Error initiating HARQ process\n"); + goto clean_exit; + } + } + q->sf_symbols = vec_malloc(CURRENT_SFLEN_RE * sizeof(cf_t)); + if (!q->sf_symbols) { + perror("malloc"); + goto clean_exit; + } + for (uint32_t i=0;icell.nof_ports;i++) { + q->ce[i] = vec_malloc(CURRENT_SFLEN_RE * sizeof(cf_t)); + if (!q->ce[i]) { + perror("malloc"); + goto clean_exit; + } + } + + ret = LIBLTE_SUCCESS; + } else { + fprintf(stderr, "Invalid cell properties: Id=%d, Ports=%d, PRBs=%d\n", + cell.id, cell.nof_ports, cell.nof_prb); + } + +clean_exit: + if (ret == LIBLTE_ERROR) { + ue_dl_free(q); + } + return ret; +} + +void ue_dl_free(ue_dl_t *q) { + if (q) { + lte_fft_free(&q->fft); + chest_free(&q->chest); + regs_free(&q->regs); + pcfich_free(&q->pcfich); + pdcch_free(&q->pdcch); + pdsch_free(&q->pdsch); + for (uint32_t i=0;iharq_process[i]); + } + if (q->sf_symbols) { + free(q->sf_symbols); + } + for (uint32_t i=0;icell.nof_ports;i++) { + if (q->ce[i]) { + free(q->ce[i]); + } + } + } +} + +/* TODO: Do something with the output data */ +char data[10000]; + +int ue_dl_process(ue_dl_t *q, cf_t *input, uint32_t sf_idx, uint32_t sfn, uint16_t rnti) +{ + uint32_t cfi, cfi_distance, i; + ra_pdsch_t ra_dl; + dci_location_t locations[10]; + dci_msg_t dci_msg; + uint32_t nof_locations; + uint16_t crc_rem; + dci_format_t format; + + /* If we are looking for SI Blocks, search only in appropiate places */ + if ((rnti == SIRNTI && (sfn % 2) == 0 && sf_idx == 5) || + rnti != SIRNTI) + { + + /* Run FFT for all subframe data */ + lte_fft_run_sf(&q->fft, input, q->sf_symbols); + + /* Get channel estimates for each port */ + chest_ce_sf(&q->chest, q->sf_symbols, q->ce, sf_idx); + + /* First decode PCFICH and obtain CFI */ + if (pcfich_decode(&q->pcfich, q->sf_symbols, q->ce, sf_idx, &cfi, &cfi_distance)<0) { + fprintf(stderr, "Error decoding PCFICH\n"); + return LIBLTE_ERROR; + } + + INFO("Decoded CFI=%d with distance %d\n", cfi, cfi_distance); + + if (regs_set_cfi(&q->regs, cfi)) { + fprintf(stderr, "Error setting CFI\n"); + return LIBLTE_ERROR; + } + + /* Generate PDCCH candidates */ + if (rnti == SIRNTI) { + nof_locations = pdcch_common_locations(&q->pdcch, locations, 10, cfi); + format = Format1A; + } else { + nof_locations = pdcch_ue_locations(&q->pdcch, locations, 10, sf_idx, cfi, q->user_rnti); + format = Format1; + } + + crc_rem = 0; + for (i=0;ipdcch, q->sf_symbols, q->ce, locations[i], sf_idx, cfi)) { + fprintf(stderr, "Error extracting LLRs\n"); + return -1; + } + if (pdcch_decode_msg(&q->pdcch, &dci_msg, format, &crc_rem)) { + fprintf(stderr, "Error decoding DCI msg\n"); + return -1; + } + INFO("Decoded DCI message RNTI: 0x%x\n", crc_rem); + } + + + if (crc_rem == rnti) { + if (dci_msg_to_ra_dl(&dci_msg, rnti, q->user_rnti, q->cell, cfi, &ra_dl)) { + fprintf(stderr, "Error unpacking PDSCH scheduling DCI message\n"); + return -1; + } + + uint32_t rvidx; + if (rnti == SIRNTI) { + switch((sfn%8)/2) { + case 0: + rvidx = 0; + break; + case 1: + rvidx = 2; + break; + case 2: + rvidx = 3; + break; + case 3: + rvidx = 1; + break; + } + } else { + rvidx = ra_dl.rv_idx; + } + + if (rvidx == 0) { + if (pdsch_harq_setup(&q->harq_process[0], ra_dl.mcs, &ra_dl.prb_alloc)) { + fprintf(stderr, "Error configuring HARQ process\n"); + return -1; + } + } + if (q->harq_process[0].mcs.mod > 0) { + if (pdsch_decode(&q->pdsch, q->sf_symbols, q->ce, data, sf_idx, + &q->harq_process[0], rvidx)) { + if (rnti == SIRNTI && rvidx == 1) { + q->pkt_errors++; + } else { + q->pkt_errors++; + } + } else { + if (VERBOSE_ISINFO()) { + INFO("Decoded Message: ", 0); + vec_fprint_hex(stdout, data, ra_dl.mcs.tbs); + } + } + if (rnti == SIRNTI && rvidx == 1) { + q->pkts_total++; + } + } + } + if (rnti == SIRNTI && (sfn%8) == 0) { + q->nof_trials++; + } + } + + return 0; +} diff --git a/lte/phy/lib/phch/test/ue_sync_usrp.c b/lte/phy/lib/phch/test/ue_sync_usrp.c new file mode 100644 index 000000000..752c4d236 --- /dev/null +++ b/lte/phy/lib/phch/test/ue_sync_usrp.c @@ -0,0 +1,257 @@ +/** + * + * \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 +#include +#include + +#include "liblte/phy/phy.h" + +#include "liblte/cuhd/cuhd.h" +void *uhd; + +#ifndef DISABLE_GRAPHICS +#include "liblte/graphics/plot.h" +plot_real_t poutfft; +#endif + +int nof_frames = -1; +float threshold = -1.0; + +float uhd_freq = 0.0, uhd_gain = 20.0; +char *uhd_args = ""; +int disable_plots = 0; + +void usage(char *prog) { + printf("Usage: %s [agntdv] -f uhd_freq\n", prog); + printf("\t-a UHD args [Default %s]\n", uhd_args); + printf("\t-g UHD RX gain [Default %.2f dB]\n", uhd_gain); + printf("\t-n nof_frames [Default infinite]\n"); + printf("\t-t threshold [Default %.2f]\n",threshold); + +#ifndef DISABLE_GRAPHICS + printf("\t-d disable plots [Default enabled]\n"); +#endif + printf("\t-v [set verbose to debug, default none]\n"); +} + +void parse_args(int argc, char **argv) { + int opt; + while ((opt = getopt(argc, argv, "agntdvf")) != -1) { + switch (opt) { + case 'n': + nof_frames = atoi(argv[optind]); + break; + case 'a': + uhd_args = argv[optind]; + break; + case 'g': + uhd_gain = atof(argv[optind]); + break; + case 'f': + uhd_freq = atof(argv[optind]); + break; + case 't': + threshold = atof(argv[optind]); + break; + case 'd': + disable_plots = 1; + break; + case 'v': + verbose++; + break; + default: + usage(argv[0]); + exit(-1); + } + } + if (uhd_freq == 0.0) { + usage(argv[0]); + exit(-1); + } +} + +void input_init() { + + printf("Opening UHD device...\n"); + if (cuhd_open(uhd_args, &uhd)) { + fprintf(stderr, "Error opening uhd\n"); + exit(-1); + } + cuhd_set_rx_gain(uhd, uhd_gain); + + /* set uhd_freq */ + cuhd_set_rx_freq(uhd, (double) uhd_freq); + cuhd_rx_wait_lo_locked(uhd); + DEBUG("Set uhd_freq to %.3f MHz\n", (double ) uhd_freq/1000000); + + DEBUG("Starting receiver...\n", 0); + cuhd_start_rx_stream(uhd); + +} + +int cuhd_recv_wrapper(void *h, void *data, uint32_t nsamples) { + DEBUG(" ---- Receive %d samples ---- \n", nsamples); + return cuhd_recv(h, data, nsamples, 1); +} + +#ifndef DISABLE_GRAPHICS + +void init_plots() { + plot_init(); + + plot_real_init(&poutfft); + plot_real_setTitle(&poutfft, "Output FFT - Magnitude"); + plot_real_setLabels(&poutfft, "Index", "dB"); + plot_real_setYAxisScale(&poutfft, -60, 0); + +} + +#endif + +float tmp_plot[100000]; + +int main(int argc, char **argv) { + cf_t *input_buffer, *sf_symbols = NULL; + int frame_cnt; + ue_sync_t s; + int pos; + pss_synch_t pss; + float peak; + struct timeval t[3]; + float mean_ce_time=0; + bool signal_detected; + lte_fft_t fft; + lte_cell_t cell; + + bzero(&cell, sizeof(lte_cell_t)); + + parse_args(argc, argv); + + #ifndef DISABLE_GRAPHICS + if (!disable_plots) { + init_plots(); + } + #endif + + input_init(); + + if (ue_sync_init(&s, cuhd_set_rx_srate, cuhd_recv_wrapper, uhd)) { + fprintf(stderr, "Error initiating UE sync module\n"); + exit(-1); + } + + if (threshold > 0.0) { + ue_sync_set_threshold(&s, threshold); + } + + ue_sync_pbch_enable(&s, true); +// ue_sync_pbch_always(&s, true); +// ue_sync_decode_sss_on_track(&s, true); + + signal_detected = true; + frame_cnt = 0; + mean_ce_time=0; + uint32_t valid_frames=0; + //uint32_t unaligned = 0; + while (frame_cnt < nof_frames || nof_frames == -1) { + + int n = ue_sync_get_buffer(&s, &input_buffer); + if (n < 0) { + fprintf(stderr, "Error calling sync work()\n"); + exit(-1); + } + + if (n == 1 && ue_sync_get_sfidx(&s) == 0) { + + if (signal_detected) { + cell = ue_sync_get_cell(&s); + pss_synch_init_fft(&pss, + SF_LEN(lte_symbol_sz(cell.nof_prb), cell.cp), + lte_symbol_sz(cell.nof_prb)); + pss_synch_set_N_id_2(&pss, cell.id%3); + + sf_symbols = vec_malloc(SLOT_LEN_RE(cell.nof_prb, cell.cp) * sizeof(cf_t)); + if (!sf_symbols) { + perror("malloc"); + exit(-1); + } + lte_fft_init(&fft, cell.cp, cell.nof_prb); + signal_detected = false; + } + + mean_ce_time = (float) (mean_ce_time + (float) t[0].tv_usec * valid_frames) / (valid_frames+1); + valid_frames++; + + #ifndef DISABLE_GRAPHICS + if (!disable_plots && !(valid_frames % 5) && sf_symbols) { + + /* Run FFT for the second slot */ + lte_fft_run_slot(&fft, input_buffer, sf_symbols); + + int i; + int nof_re = SLOT_LEN_RE(cell.nof_prb, cell.cp); + for (i = 0; i < nof_re; i++) { + tmp_plot[i] = 10 * log10f(cabsf(sf_symbols[i])); + if (isinf(tmp_plot[i])) { + tmp_plot[i] = -80; + } + } + plot_real_setNewData(&poutfft, tmp_plot, nof_re); + } + #endif + + pos = pss_synch_find_pss(&pss, input_buffer, &peak, NULL); + /*if (pos > 962 || pos < 958) { + unaligned++; + } + */ + printf("CELL_ID: %3d CFO: %+.4f KHz, SFO: %+.4f Khz, TimeOffset: %4d, Exec: %3.2f\r", + cell.id, ue_sync_get_cfo(&s)/1000, ue_sync_get_sfo(&s)/1000, pos, + s.mean_exec_time); + fflush(stdout); + if (VERBOSE_ISINFO()) { + printf("\n"); + } + } + + frame_cnt++; + } + + printf("\nBye\n"); + exit(0); +} + + diff --git a/lte/phy/lib/resampling/test/interp_test_volk.c b/lte/phy/lib/resampling/test/interp_test_volk.c new file mode 100644 index 000000000..cc97f3cef --- /dev/null +++ b/lte/phy/lib/resampling/test/interp_test_volk.c @@ -0,0 +1,92 @@ +#include +#include +#include +#include +#include +#include + +#include "liblte/phy/phy.h" + +typedef _Complex float cf_t; + +int main(int argc, char **argv) { + uint32_t N = 1000; // Number of sinwave samples + interp_t interp; + struct timeval t[3]; + + if (argc < 3) { + printf("usage: %s upsampling_rate nof_trials\n", argv[0]); + exit(-1); + } + + uint32_t M = atoi(argv[1]); + uint32_t nof_trials = atoi(argv[2]); + + if (interp_init(&interp, LINEAR, N, M)) { + exit(-1); + } + + cf_t *in = vec_malloc(N*sizeof(cf_t)); + if(!in) { + perror("malloc"); + exit(-1); + } + cf_t *out = vec_malloc(M * N*sizeof(cf_t)); + if(!out) { + perror("malloc"); + exit(-1); + } + cf_t *out_volk = vec_malloc(M * N*sizeof(cf_t)); + if(!out_volk) { + perror("malloc"); + exit(-1); + } + + srand(time(NULL)); + for(uint32_t i=0;i Date: Mon, 21 Jul 2014 17:54:25 +0200 Subject: [PATCH 14/14] Added AGC module --- cmake/modules/FindVolk.cmake | 8 +++ lte/phy/examples/pdsch_ue.c | 43 ++++++------ lte/phy/examples/scan_mib.c | 6 +- lte/phy/examples/scan_pss.c | 6 +- lte/phy/include/liblte/phy/agc/agc.h | 69 ++++++++++++++++++++ lte/phy/include/liblte/phy/phch/ue_dl.h | 3 +- lte/phy/include/liblte/phy/phch/ue_sync.h | 5 +- lte/phy/include/liblte/phy/sync/sync.h | 4 +- lte/phy/include/liblte/phy/utils/vector.h | 5 ++ lte/phy/lib/agc/src/agc.c | 79 +++++++++++++++++++++++ lte/phy/lib/phch/src/ue_dl.c | 20 +++--- lte/phy/lib/phch/src/ue_sync.c | 27 ++++++-- lte/phy/lib/sync/src/pss.c | 2 +- lte/phy/lib/sync/src/sync.c | 57 +++++++--------- lte/phy/lib/utils/src/vector.c | 28 ++++++++ 15 files changed, 286 insertions(+), 76 deletions(-) create mode 100644 lte/phy/include/liblte/phy/agc/agc.h create mode 100644 lte/phy/lib/agc/src/agc.c diff --git a/cmake/modules/FindVolk.cmake b/cmake/modules/FindVolk.cmake index d9e90e9e4..7a3660f18 100644 --- a/cmake/modules/FindVolk.cmake +++ b/cmake/modules/FindVolk.cmake @@ -31,11 +31,13 @@ CHECK_FUNCTION_EXISTS_MATH(volk_32f_accumulator_s32f HAVE_VOLK_ACC_FUNCTION) CHECK_FUNCTION_EXISTS_MATH(volk_32fc_s32fc_multiply_32fc HAVE_VOLK_MULT_FUNCTION) CHECK_FUNCTION_EXISTS_MATH(volk_32fc_conjugate_32fc HAVE_VOLK_CONJ_FUNCTION) CHECK_FUNCTION_EXISTS_MATH(volk_32fc_x2_multiply_32fc HAVE_VOLK_MULT2_FUNCTION) +CHECK_FUNCTION_EXISTS_MATH(volk_32fc_x2_multiply_conjugate_32fc HAVE_VOLK_MULT2_CONJ_FUNCTION) CHECK_FUNCTION_EXISTS_MATH(volk_32fc_32f_multiply_32fc HAVE_VOLK_MULT_REAL_FUNCTION) CHECK_FUNCTION_EXISTS_MATH(volk_32f_s32f_multiply_32f HAVE_VOLK_MULT_FLOAT_FUNCTION) CHECK_FUNCTION_EXISTS_MATH(volk_32fc_magnitude_32f HAVE_VOLK_MAG_FUNCTION) CHECK_FUNCTION_EXISTS_MATH(volk_32f_x2_divide_32f HAVE_VOLK_DIVIDE_FUNCTION) CHECK_FUNCTION_EXISTS_MATH(volk_32fc_32f_dot_prod_32fc HAVE_VOLK_DOTPROD_FC_FUNCTION) +CHECK_FUNCTION_EXISTS_MATH(volk_32fc_x2_conjugate_dot_prod_32fc HAVE_VOLK_DOTPROD_CONJ_FC_FUNCTION) CHECK_FUNCTION_EXISTS_MATH(volk_32f_x2_dot_prod_32f HAVE_VOLK_DOTPROD_F_FUNCTION) CHECK_FUNCTION_EXISTS_MATH(volk_32fc_s32f_atan2_32f HAVE_VOLK_ATAN_FUNCTION) CHECK_FUNCTION_EXISTS_MATH(volk_32f_s32f_convert_16i HAVE_VOLK_CONVERT_FI_FUNCTION) @@ -45,9 +47,15 @@ CHECK_FUNCTION_EXISTS_MATH(volk_32f_x2_subtract_32f HAVE_VOLK_SUB_FLOAT_FUNCTION SET(VOLK_DEFINITIONS "HAVE_VOLK") +IF(${HAVE_VOLK_DOTPROD_CONJ_FC_FUNCTION}) + SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_DOTPROD_CONJ_FC_FUNCTION") +ENDIF() IF(${HAVE_VOLK_SUB_FLOAT_FUNCTION}) SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_SUB_FLOAT_FUNCTION") ENDIF() +IF(${HAVE_VOLK_MULT2_CONJ_FUNCTION}) + SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_MULT2_CONJ_FUNCTION") +ENDIF() IF(${HAVE_VOLK_DEINTERLEAVE_FUNCTION}) SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_DEINTERLEAVE_FUNCTION") ENDIF() diff --git a/lte/phy/examples/pdsch_ue.c b/lte/phy/examples/pdsch_ue.c index 70b6cb121..75d497fe7 100644 --- a/lte/phy/examples/pdsch_ue.c +++ b/lte/phy/examples/pdsch_ue.c @@ -58,7 +58,6 @@ typedef struct { uint16_t rnti; int nof_subframes; bool disable_plots; - bool pbch_only; iodev_cfg_t io_config; }prog_args_t; @@ -68,7 +67,6 @@ void args_default(prog_args_t *args) { args->rnti = SIRNTI; args->nof_subframes = -1; args->disable_plots = false; - args->pbch_only = false; args->io_config.find_threshold = -1.0; args->io_config.input_file_name = NULL; args->io_config.uhd_args = ""; @@ -121,10 +119,7 @@ void parse_args(prog_args_t *args, int argc, char **argv) { case 'f': args->io_config.uhd_freq = atof(argv[optind]); break; - case 'b': - args->pbch_only = true; - break; - case 't': + case 't': args->io_config.find_threshold = atof(argv[optind]); break; case 'n': @@ -151,6 +146,9 @@ void sigintHandler(int x) { go_exit = 1; } +/* TODO: Do something with the output data */ +char data[10000]; + int main(int argc, char **argv) { int ret; cf_t *sf_buffer; @@ -162,6 +160,8 @@ int main(int argc, char **argv) { int64_t sf_cnt; uint32_t sf_idx; pbch_mib_t mib; + bool printed_sib = false; + uint32_t rlen; parse_args(&prog_args, argc, argv); @@ -215,14 +215,21 @@ int main(int argc, char **argv) { if (iodev_isUSRP(&iodev)) { sf_idx = ue_sync_get_sfidx(&iodev.sframe); } - if (ue_dl_process(&ue_dl, sf_buffer, sf_idx, ue_sync_get_mib(&iodev.sframe).sfn, prog_args.rnti)) { + rlen = ue_dl_receive(&ue_dl, sf_buffer, data, sf_idx, ue_sync_get_mib(&iodev.sframe).sfn, prog_args.rnti); + if (rlen < 0) { fprintf(stderr, "\nError running receiver\n");fflush(stdout); exit(-1); } + if (prog_args.rnti == SIRNTI && !printed_sib && rlen > 0) { + printf("\n\nDecoded SIB1 Message: "); + vec_fprint_hex(stdout, data, rlen); + printf("\n");fflush(stdout); + printed_sib = true; + } if (!(sf_cnt % 10)) { - printf("Cell ID: %3d, CFO: %+.4f KHz, SFO: %+.4f Khz, TimeOffset: %4d, Errors: %4d/%4d/%d, BLER: %.1e\r", - cell.id, iodev.sframe.cur_cfo * 15, iodev.sframe.mean_time_offset / 5, iodev.sframe.peak_idx, - (int) ue_dl.pkt_errors, (int) ue_dl.pkts_total, (int) ue_dl.nof_trials, (float) ue_dl.pkt_errors / ue_dl.pkts_total); + printf("Cell ID: %3d, RSSI: %+.2f dBm, CFO: %+.4f KHz, SFO: %+.4f Khz, TimeOffset: %4d, Errors: %4d/%4d, BLER: %.1e\r", + cell.id, 20*log10f(agc_get_rssi(&iodev.sframe.agc)), iodev.sframe.cur_cfo * 15, iodev.sframe.mean_time_offset / 5, iodev.sframe.peak_idx, + (int) ue_dl.pkt_errors, (int) ue_dl.pkts_total, (float) ue_dl.pkt_errors / ue_dl.pkts_total); fflush(stdout); if (VERBOSE_ISINFO()) { printf("\n"); @@ -277,24 +284,24 @@ void init_plots() { plot_real_init(&poutfft); plot_real_setTitle(&poutfft, "Output FFT - Magnitude"); plot_real_setLabels(&poutfft, "Index", "dB"); - plot_real_setYAxisScale(&poutfft, -60, 0); + plot_real_setYAxisScale(&poutfft, -30, 20); plot_complex_init(&pce); plot_complex_setTitle(&pce, "Channel Estimates"); - plot_complex_setYAxisScale(&pce, Ip, -0.01, 0.01); - plot_complex_setYAxisScale(&pce, Q, -0.01, 0.01); - plot_complex_setYAxisScale(&pce, Magnitude, 0, 0.01); + plot_complex_setYAxisScale(&pce, Ip, -3, 3); + plot_complex_setYAxisScale(&pce, Q, -3, 3); + plot_complex_setYAxisScale(&pce, Magnitude, 0, 4); plot_complex_setYAxisScale(&pce, Phase, -M_PI, M_PI); plot_scatter_init(&pscatrecv); plot_scatter_setTitle(&pscatrecv, "Received Symbols"); - plot_scatter_setXAxisScale(&pscatrecv, -0.01, 0.01); - plot_scatter_setYAxisScale(&pscatrecv, -0.01, 0.01); + plot_scatter_setXAxisScale(&pscatrecv, -4, 4); + plot_scatter_setYAxisScale(&pscatrecv, -4, 4); plot_scatter_init(&pscatequal); plot_scatter_setTitle(&pscatequal, "Equalized Symbols"); - plot_scatter_setXAxisScale(&pscatequal, -1, 1); - plot_scatter_setYAxisScale(&pscatequal, -1, 1); + plot_scatter_setXAxisScale(&pscatequal, -2, 2); + plot_scatter_setYAxisScale(&pscatequal, -2, 2); } void do_plots(ue_dl_t *q, uint32_t sf_idx) { diff --git a/lte/phy/examples/scan_mib.c b/lte/phy/examples/scan_mib.c index 94782c308..d92b06aea 100644 --- a/lte/phy/examples/scan_mib.c +++ b/lte/phy/examples/scan_mib.c @@ -442,7 +442,7 @@ int main(int argc, char **argv) { case FIND: /* find peak in all frame */ ret = sync_find(&ssync, &input_buffer[FLEN], &find_idx); - DEBUG("[%3d/%d]: PAR=%.2f\n", freq, nof_bands, sync_get_peak_to_avg(&ssync)); + DEBUG("[%3d/%d]: PAR=%.2f\n", freq, nof_bands, sync_get_peak_value(&ssync)); if (ret == 1) { /* if found peak, go to track and set lower threshold */ frame_cnt = -1; @@ -453,7 +453,7 @@ int main(int argc, char **argv) { state = TRACK; INFO("[%3d/%d]: EARFCN %d Freq. %.2f MHz PSS found PAR %.2f dB\n", freq, nof_bands, channels[freq].id, channels[freq].fd, - 10*log10f(sync_get_peak_to_avg(&ssync))); + 10*log10f(sync_get_peak_value(&ssync))); } else { if (frame_cnt >= nof_frames_find) { state = INIT; @@ -465,7 +465,7 @@ int main(int argc, char **argv) { INFO("Tracking PSS find_idx %d offset %d\n", find_idx, find_idx - track_len); ret = sync_track(&ssync, input_buffer, FLEN + find_idx - track_len, &track_idx); - p2a_v[frame_cnt] = sync_get_peak_to_avg(&ssync); + p2a_v[frame_cnt] = sync_get_peak_value(&ssync); /* save cell id for the best peak-to-avg */ if (p2a_v[frame_cnt] > max_peak_to_avg) { diff --git a/lte/phy/examples/scan_pss.c b/lte/phy/examples/scan_pss.c index e6e052cd6..0e0868b2e 100644 --- a/lte/phy/examples/scan_pss.c +++ b/lte/phy/examples/scan_pss.c @@ -356,7 +356,7 @@ int main(int argc, char **argv) { case FIND: /* find peak in all frame */ ret = sync_find(&sfind, &input_buffer[FLEN], &find_idx); - DEBUG("[%3d/%d]: PAR=%.2f\n", freq, nof_bands, sync_get_peak_to_avg(&sfind)); + DEBUG("[%3d/%d]: PAR=%.2f\n", freq, nof_bands, sync_get_peak_value(&sfind)); if (ret == 1) { /* if found peak, go to track and set lower threshold */ frame_cnt = -1; @@ -364,7 +364,7 @@ int main(int argc, char **argv) { state = TRACK; INFO("[%3d/%d]: EARFCN %d Freq. %.2f MHz PSS found PAR %.2f dB\n", freq, nof_bands, channels[freq].id, channels[freq].fd, - 10*log10f(sync_get_peak_to_avg(&sfind))); + 10*log10f(sync_get_peak_value(&sfind))); } else { if (frame_cnt >= nof_frames_find) { state = INIT; @@ -383,7 +383,7 @@ int main(int argc, char **argv) { filesink_write(&fs, &input_buffer[FLEN+find_idx+track_len], track_len); ret = sync_find(&strack, &input_buffer[FLEN + find_idx - track_len], &track_idx); - p2a_v[frame_cnt] = sync_get_peak_to_avg(&strack); + p2a_v[frame_cnt] = sync_get_peak_value(&strack); /* save cell id for the best peak-to-avg */ if (p2a_v[frame_cnt] > max_peak_to_avg) { diff --git a/lte/phy/include/liblte/phy/agc/agc.h b/lte/phy/include/liblte/phy/agc/agc.h new file mode 100644 index 000000000..f28e7a09b --- /dev/null +++ b/lte/phy/include/liblte/phy/agc/agc.h @@ -0,0 +1,69 @@ +/** + * + * \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/. + * + */ + + + +#ifndef AGC_ +#define AGC_ + +#include +#include +#include + +#include "liblte/config.h" + +/* Automatic Gain Control + * + */ +typedef _Complex float cf_t; + +#define AGC_DEFAULT_BW (1e-2f) + +typedef struct LIBLTE_API{ + float bandwidth; + float gain; + float y_out; + bool lock; +} agc_t; + +LIBLTE_API int agc_init (agc_t *q); + +LIBLTE_API void agc_free(agc_t *q); + +LIBLTE_API void agc_set_bandwidth(agc_t *q, + float bandwidth); + +LIBLTE_API float agc_get_rssi(agc_t *q); + +LIBLTE_API void agc_lock(agc_t *q, bool enable); + +LIBLTE_API void agc_push(agc_t *q, + cf_t *input, + cf_t *output, + uint32_t len); + +#endif // AGC_ diff --git a/lte/phy/include/liblte/phy/phch/ue_dl.h b/lte/phy/include/liblte/phy/phch/ue_dl.h index b6ca44bab..22ecd718d 100644 --- a/lte/phy/include/liblte/phy/phch/ue_dl.h +++ b/lte/phy/include/liblte/phy/phch/ue_dl.h @@ -86,8 +86,9 @@ LIBLTE_API int ue_dl_init(ue_dl_t *q, LIBLTE_API void ue_dl_free(ue_dl_t *q); -LIBLTE_API int ue_dl_process(ue_dl_t *q, +LIBLTE_API int ue_dl_receive(ue_dl_t *q, cf_t *sf_buffer, + char *data, uint32_t sf_idx, uint32_t sfn, uint16_t rnti); diff --git a/lte/phy/include/liblte/phy/phch/ue_sync.h b/lte/phy/include/liblte/phy/phch/ue_sync.h index cf1e2f7a2..dc374e238 100644 --- a/lte/phy/include/liblte/phy/phch/ue_sync.h +++ b/lte/phy/include/liblte/phy/phch/ue_sync.h @@ -36,6 +36,7 @@ #include "liblte/phy/ch_estimation/chest.h" #include "liblte/phy/phch/pbch.h" #include "liblte/phy/common/fft.h" +#include "liblte/phy/agc/agc.h" /************************************************************** * @@ -66,7 +67,7 @@ typedef enum LIBLTE_API { SF_FIND, SF_TRACK} ue_sync_state_t; #define SYNC_PBCH_NOF_PORTS 2 #define TRACK_MAX_LOST 10 -#define PAR_THRESHOLD_FIND 20 +#define PSS_THRESHOLD 1 #define NOF_MIB_DECODES 10 @@ -82,6 +83,7 @@ typedef struct LIBLTE_API { ue_sync_state_t state; cf_t *input_buffer; + cf_t *receive_buffer; cf_t *sf_symbols; cf_t *ce[SYNC_PBCH_NOF_PORTS]; @@ -100,6 +102,7 @@ typedef struct LIBLTE_API { float cur_cfo; /* Variables for PBCH decoding */ + agc_t agc; pbch_mib_t mib; lte_fft_t fft; chest_t chest; diff --git a/lte/phy/include/liblte/phy/sync/sync.h b/lte/phy/include/liblte/phy/sync/sync.h index 6f40777dd..8dddbc7b5 100644 --- a/lte/phy/include/liblte/phy/sync/sync.h +++ b/lte/phy/include/liblte/phy/sync/sync.h @@ -60,7 +60,7 @@ typedef struct LIBLTE_API { enum sync_pss_det pss_mode; float find_threshold; float track_threshold; - float peak_to_avg; + float peak_value; uint32_t N_id_2; uint32_t N_id_1; uint32_t slot_id; @@ -113,7 +113,7 @@ LIBLTE_API void sync_pss_det_peak_to_avg(sync_t *q); LIBLTE_API uint32_t sync_get_slot_id(sync_t *q); /* Gets the last peak-to-average ratio */ -LIBLTE_API float sync_get_peak_to_avg(sync_t *q); +LIBLTE_API float sync_get_peak_value(sync_t *q); /* Gets the N_id_2 from the last call to synch_run() */ LIBLTE_API uint32_t sync_get_N_id_2(sync_t *q); diff --git a/lte/phy/include/liblte/phy/utils/vector.h b/lte/phy/include/liblte/phy/utils/vector.h index 1b0547cb9..369428fb9 100644 --- a/lte/phy/include/liblte/phy/utils/vector.h +++ b/lte/phy/include/liblte/phy/utils/vector.h @@ -76,7 +76,12 @@ LIBLTE_API void vec_prod_ccc(cf_t *x, cf_t *y, cf_t *z, uint32_t len); /* vector product (element-wise) */ LIBLTE_API void vec_prod_cfc(cf_t *x, float *y, cf_t *z, uint32_t len); +/* conjugate vector product (element-wise) */ +LIBLTE_API void vec_prod_conj_ccc(cf_t *x, cf_t *y, cf_t *z, uint32_t len); + +/* Dot-product */ LIBLTE_API cf_t vec_dot_prod_ccc(cf_t *x, cf_t *y, uint32_t len); +LIBLTE_API cf_t vec_dot_prod_conj_ccc(cf_t *x, cf_t *y, uint32_t len); LIBLTE_API float vec_dot_prod_fff(float *x, float *y, uint32_t len); /* z=x/y vector division (element-wise) */ diff --git a/lte/phy/lib/agc/src/agc.c b/lte/phy/lib/agc/src/agc.c new file mode 100644 index 000000000..e377ac1be --- /dev/null +++ b/lte/phy/lib/agc/src/agc.c @@ -0,0 +1,79 @@ +/** + * + * \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 "liblte/phy/utils/debug.h" + +#include "liblte/phy/agc/agc.h" +#include "liblte/phy/utils/vector.h" +#include "liblte/phy/utils/debug.h" + + +int agc_init (agc_t *q) { + bzero(q, sizeof(agc_t)); + q->bandwidth = AGC_DEFAULT_BW; + q->lock = false; + q->gain = 1.0; + q->y_out = 1.0; + return LIBLTE_SUCCESS; +} + +void agc_free(agc_t *q) { + bzero(q, sizeof(agc_t)); +} + +void agc_set_bandwidth(agc_t *q, float bandwidth) { + q->bandwidth = bandwidth; +} + +float agc_get_rssi(agc_t *q) { + return 1.0/q->gain; +} + +void agc_lock(agc_t *q, bool enable) { + q->lock = enable; +} + +void agc_push(agc_t *q, cf_t *input, cf_t *output, uint32_t len) { + + // Apply current gain to input signal + vec_sc_prod_cfc(input, q->gain, output, len); + + // compute output energy estimate + float y = sqrtf(crealf(vec_dot_prod_conj_ccc(output, output, len))/len); + + q->y_out = (1-q->bandwidth) * q->y_out + q->bandwidth * y; + if (!q->lock) { + q->gain *= expf(-0.5*q->bandwidth*logf(q->y_out)); + } +} diff --git a/lte/phy/lib/phch/src/ue_dl.c b/lte/phy/lib/phch/src/ue_dl.c index 707f89917..e48b28f62 100644 --- a/lte/phy/lib/phch/src/ue_dl.c +++ b/lte/phy/lib/phch/src/ue_dl.c @@ -53,6 +53,7 @@ int ue_dl_init(ue_dl_t *q, q->user_rnti = user_rnti; q->pkt_errors = 0; q->pkts_total = 0; + q->nof_trials = 0; if (lte_fft_init(&q->fft, q->cell.cp, q->cell.nof_prb)) { fprintf(stderr, "Error initiating FFT\n"); @@ -135,10 +136,7 @@ void ue_dl_free(ue_dl_t *q) { } } -/* TODO: Do something with the output data */ -char data[10000]; - -int ue_dl_process(ue_dl_t *q, cf_t *input, uint32_t sf_idx, uint32_t sfn, uint16_t rnti) +int ue_dl_receive(ue_dl_t *q, cf_t *input, char *data, uint32_t sf_idx, uint32_t sfn, uint16_t rnti) { uint32_t cfi, cfi_distance, i; ra_pdsch_t ra_dl; @@ -185,11 +183,11 @@ int ue_dl_process(ue_dl_t *q, cf_t *input, uint32_t sf_idx, uint32_t sfn, uint16 for (i=0;ipdcch, q->sf_symbols, q->ce, locations[i], sf_idx, cfi)) { fprintf(stderr, "Error extracting LLRs\n"); - return -1; + return LIBLTE_ERROR; } if (pdcch_decode_msg(&q->pdcch, &dci_msg, format, &crc_rem)) { fprintf(stderr, "Error decoding DCI msg\n"); - return -1; + return LIBLTE_ERROR; } INFO("Decoded DCI message RNTI: 0x%x\n", crc_rem); } @@ -198,7 +196,7 @@ int ue_dl_process(ue_dl_t *q, cf_t *input, uint32_t sf_idx, uint32_t sfn, uint16 if (crc_rem == rnti) { if (dci_msg_to_ra_dl(&dci_msg, rnti, q->user_rnti, q->cell, cfi, &ra_dl)) { fprintf(stderr, "Error unpacking PDSCH scheduling DCI message\n"); - return -1; + return LIBLTE_ERROR; } uint32_t rvidx; @@ -224,7 +222,7 @@ int ue_dl_process(ue_dl_t *q, cf_t *input, uint32_t sf_idx, uint32_t sfn, uint16 if (rvidx == 0) { if (pdsch_harq_setup(&q->harq_process[0], ra_dl.mcs, &ra_dl.prb_alloc)) { fprintf(stderr, "Error configuring HARQ process\n"); - return -1; + return LIBLTE_ERROR; } } if (q->harq_process[0].mcs.mod > 0) { @@ -251,5 +249,9 @@ int ue_dl_process(ue_dl_t *q, cf_t *input, uint32_t sf_idx, uint32_t sfn, uint16 } } - return 0; + if (crc_rem == rnti) { + return ra_dl.mcs.tbs; + } else { + return 0; + } } diff --git a/lte/phy/lib/phch/src/ue_sync.c b/lte/phy/lib/phch/src/ue_sync.c index 7a73da125..bf19c5516 100644 --- a/lte/phy/lib/phch/src/ue_sync.c +++ b/lte/phy/lib/phch/src/ue_sync.c @@ -88,11 +88,15 @@ int ue_sync_init(ue_sync_t *q, INFO("Setting sampling frequency 1.92 MHz\n",0); q->set_rate_callback(q->stream, 1920000.0); + if (agc_init(&q->agc)) { + goto clean_exit; + } + if(sync_init(&q->s, CURRENT_SFLEN, CURRENT_FFTSIZE, CURRENT_FFTSIZE)) { goto clean_exit; } - sync_pss_det_peak_to_avg(&q->s); + sync_pss_det_absolute(&q->s); if (cfo_init(&q->cfocorr, MAXIMUM_SFLEN)) { fprintf(stderr, "Error initiating CFO\n"); @@ -104,6 +108,12 @@ int ue_sync_init(ue_sync_t *q, perror("malloc"); goto clean_exit; } + + q->receive_buffer = vec_malloc(3 * MAXIMUM_SFLEN * sizeof(cf_t)); + if (!q->receive_buffer) { + perror("malloc"); + goto clean_exit; + } q->sf_symbols = vec_malloc(MAXIMUM_SFLEN_RE * sizeof(cf_t)); if (!q->sf_symbols) { @@ -118,8 +128,7 @@ int ue_sync_init(ue_sync_t *q, } } - //float th = PAR_THRESHOLD_FIND * (1+(float) CURRENT_FFTSIZE/128/10); - sync_set_threshold(&q->s, PAR_THRESHOLD_FIND, PAR_THRESHOLD_FIND/4); + sync_set_threshold(&q->s, PSS_THRESHOLD, PSS_THRESHOLD); ret = LIBLTE_SUCCESS; } @@ -135,6 +144,9 @@ void ue_sync_free(ue_sync_t *q) { if (q->input_buffer) { free(q->input_buffer); } + if (q->receive_buffer) { + free(q->receive_buffer); + } if (q->sf_symbols) { free(q->sf_symbols); } @@ -146,6 +158,7 @@ void ue_sync_free(ue_sync_t *q) { mib_decoder_free(q); cfo_free(&q->cfocorr); sync_free(&q->s); + agc_free(&q->agc); } void ue_sync_set_threshold(ue_sync_t *q, float threshold) { @@ -398,10 +411,10 @@ static int receive_samples(ue_sync_t *q) { q->time_offset = -q->time_offset; } /* copy last part of the last subframe (use move since there could be overlapping) */ - memmove(q->input_buffer, &q->input_buffer[CURRENT_SFLEN-q->time_offset], q->time_offset*sizeof(cf_t)); + memcpy(q->receive_buffer, &q->input_buffer[CURRENT_SFLEN-q->time_offset], q->time_offset*sizeof(cf_t)); /* Get 1 subframe from the USRP getting more samples and keeping the previous samples, if any */ - if (q->recv_callback(q->stream, &q->input_buffer[q->time_offset], CURRENT_SFLEN - q->time_offset) < 0) { + if (q->recv_callback(q->stream, &q->receive_buffer[q->time_offset], CURRENT_SFLEN - q->time_offset) < 0) { return LIBLTE_ERROR; } @@ -426,6 +439,8 @@ int ue_sync_get_buffer(ue_sync_t *q, cf_t **sf_symbols) { return -1; } + agc_push(&q->agc, q->receive_buffer, q->input_buffer, CURRENT_SFLEN); + switch (q->state) { case SF_FIND: q->s.sss_en = true; @@ -437,7 +452,7 @@ int ue_sync_get_buffer(ue_sync_t *q, cf_t **sf_symbols) { return -1; } - DEBUG("Find PAR=%.2f\n", sync_get_peak_to_avg(&q->s)); + DEBUG("Find PAR=%.2f\n", sync_get_peak_value(&q->s)); if (ret == 1) { ret = find_peak_ok(q); diff --git a/lte/phy/lib/sync/src/pss.c b/lte/phy/lib/sync/src/pss.c index 4c8da1a26..29ca1608c 100644 --- a/lte/phy/lib/sync/src/pss.c +++ b/lte/phy/lib/sync/src/pss.c @@ -262,7 +262,7 @@ int pss_synch_find_pss(pss_synch_t *q, cf_t *input, vec_abs_cf(q->conv_output, q->conv_abs, conv_output_len); corr_peak_pos = vec_max_fi(q->conv_abs, conv_output_len); if (corr_peak_value) { - *corr_peak_value = q->conv_abs[corr_peak_pos]; + *corr_peak_value = q->conv_abs[corr_peak_pos] / conv_output_len; } if (corr_mean_value) { *corr_mean_value = vec_acc_ff(q->conv_abs, conv_output_len) diff --git a/lte/phy/lib/sync/src/sync.c b/lte/phy/lib/sync/src/sync.c index 28333e06a..bb62a806f 100644 --- a/lte/phy/lib/sync/src/sync.c +++ b/lte/phy/lib/sync/src/sync.c @@ -176,8 +176,8 @@ float sync_get_cfo(sync_t *q) { return q->cfo; } -float sync_get_peak_to_avg(sync_t *q) { - return q->peak_to_avg; +float sync_get_peak_value(sync_t *q) { + return q->peak_value; } void sync_cp_en(sync_t *q, bool enabled) { @@ -278,7 +278,6 @@ int sync_track(sync_t *q, cf_t *input, uint32_t offset, uint32_t *peak_position) fft_size_isvalid(q->fft_size)) { float peak_value, mean_value, *mean_ptr; - bool peak_detected; uint32_t peak_pos; pss_synch_set_N_id_2(&q->pss_track, q->N_id_2); @@ -291,20 +290,16 @@ int sync_track(sync_t *q, cf_t *input, uint32_t offset, uint32_t *peak_position) peak_pos = pss_synch_find_pss(&q->pss_track, &input[offset], &peak_value, mean_ptr); - peak_detected = false; if (q->pss_mode == ABSOLUTE) { - if (peak_value > q->track_threshold) { - peak_detected = true; - } + q->peak_value = peak_value; } else { - q->peak_to_avg = peak_value / mean_value; - if (q->peak_to_avg > q->track_threshold) { - peak_detected = true; - } + q->peak_value = peak_value / mean_value; } - DEBUG("PSS possible tracking peak pos=%d peak=%.2f par=%.2f threshold=%.2f\n", - peak_pos, peak_value, q->peak_to_avg, q->track_threshold); - if (peak_detected) { + + DEBUG("PSS possible tracking peak pos=%d peak=%.2f threshold=%.2f\n", + peak_pos, peak_value, q->track_threshold); + + if (peak_value > q->track_threshold) { q->cfo = pss_synch_cfo_compute(&q->pss_track, &input[offset+peak_pos-q->fft_size]); if (q->sss_en) { @@ -332,11 +327,16 @@ int sync_find(sync_t *q, cf_t *input, uint32_t *peak_position) { float max=-999; uint32_t i; int ret; - bool peak_detected; - + float *mean_ptr; + for (N_id_2=0;N_id_2<3;N_id_2++) { + if (q->pss_mode == ABSOLUTE) { + mean_ptr = NULL; + } else { + mean_ptr = &mean_value[N_id_2]; + } pss_synch_set_N_id_2(&q->pss_find, N_id_2); - ret = pss_synch_find_pss(&q->pss_find, input, &peak_value[N_id_2], &mean_value[N_id_2]); + ret = pss_synch_find_pss(&q->pss_find, input, &peak_value[N_id_2], mean_ptr); if (ret < 0) { fprintf(stderr, "Error finding PSS for N_id_2=%d\n", N_id_2); return LIBLTE_ERROR; @@ -351,32 +351,25 @@ int sync_find(sync_t *q, cf_t *input, uint32_t *peak_position) { } } - q->peak_to_avg = peak_value[N_id_2] / mean_value[N_id_2]; - - DEBUG("PSS possible peak N_id_2=%d, pos=%d peak=%.2f par=%.2f threshold=%.2f\n", - N_id_2, peak_pos[N_id_2], peak_value[N_id_2], q->peak_to_avg, q->find_threshold); - - /* If peak detected */ - peak_detected = false; if (peak_pos[N_id_2] > q->fft_size) { if (q->pss_mode == ABSOLUTE) { - if (peak_value[N_id_2] > q->find_threshold) { - peak_detected = true; - } + q->peak_value = peak_value[N_id_2]; } else { - if (q->peak_to_avg > q->find_threshold) { - peak_detected = true; - } + q->peak_value = peak_value[N_id_2] / mean_value[N_id_2]; } } - if (peak_detected) { + DEBUG("PSS possible peak N_id_2=%d, pos=%d peak=%.2f threshold=%.2f\n", + N_id_2, peak_pos[N_id_2], peak_value[N_id_2], q->find_threshold); + + /* If peak detected */ + if (q->peak_value > q->find_threshold) { q->N_id_2 = N_id_2; pss_synch_set_N_id_2(&q->pss_find, q->N_id_2); q->cfo = pss_synch_cfo_compute(&q->pss_find, &input[peak_pos[N_id_2]-q->fft_size]); DEBUG("PSS peak detected N_id_2=%d, pos=%d peak=%.2f par=%.2f th=%.2f cfo=%.4f\n", N_id_2, - peak_pos[N_id_2], peak_value[N_id_2], q->peak_to_avg, q->find_threshold, q->cfo); + peak_pos[N_id_2], peak_value[N_id_2], q->peak_value, q->find_threshold, q->cfo); if (q->sss_en) { if (sync_sss(q, input, peak_pos[q->N_id_2], q->detect_cp) < 0) { diff --git a/lte/phy/lib/utils/src/vector.c b/lte/phy/lib/utils/src/vector.c index 61ba4313c..1c7ad6275 100644 --- a/lte/phy/lib/utils/src/vector.c +++ b/lte/phy/lib/utils/src/vector.c @@ -281,6 +281,18 @@ void vec_prod_ccc(cf_t *x,cf_t *y, cf_t *z, uint32_t len) { #endif } + +void vec_prod_conj_ccc(cf_t *x,cf_t *y, cf_t *z, uint32_t len) { +#ifndef HAVE_VOLK_MULT2_CONJ_FUNCTION + int i; + for (i=0;i