diff --git a/README.md b/README.md index b7a2d5dd3..7141628b7 100644 --- a/README.md +++ b/README.md @@ -25,9 +25,9 @@ The library currently uses Ettus Universal Hardware Driver (UHD). Thus, any hard Download & Install Instructions ================================= -* Requirements: Currently, the library requires libfftw, although we plan make this dependency optional in the future. Also, QT4 is needed for graphics visualization. Compilation is possible without QT4, although graphics will be disabled. +* Requirements: Currently, the library requires libfftw, although we plan make this dependency optional in the future. Also, QT4 and Qwt6 are needed for graphics visualization. Compilation is possible without QT4, although graphics will be disabled. -To install QT4 and libfftw use your distribution packet management system, for instance in ubuntu you can run: `sudo apt-get install libfftw3-dev libqt4-dev` to install all requirements. +To install QT4, Qwt6 and libfftw use your distribution packet management system, for instance in ubuntu you can run: `sudo apt-get install libfftw3-dev libqwt-dev libqt4-dev` to install all requirements. Finally, to download and build libLTE, just run: diff --git a/cmake/modules/CheckFunctionExists.c b/cmake/modules/CheckFunctionExists.c new file mode 100644 index 000000000..9fdea2866 --- /dev/null +++ b/cmake/modules/CheckFunctionExists.c @@ -0,0 +1,25 @@ +#ifdef CHECK_FUNCTION_EXISTS + +char CHECK_FUNCTION_EXISTS(); +#ifdef __CLASSIC_C__ +int main(){ + int ac; + char*av[]; +#else +int main(int ac, char*av[]){ + +#endif + float ac2 = sqrtf(rand()); + CHECK_FUNCTION_EXISTS(); + if(ac2 * ac > 1000) + { + return *av[0]; + } + return 0; +} + +#else /* CHECK_FUNCTION_EXISTS */ + +# error "CHECK_FUNCTION_EXISTS has to specify the function" + +#endif /* CHECK_FUNCTION_EXISTS */ diff --git a/cmake/modules/CheckFunctionExistsMath.cmake b/cmake/modules/CheckFunctionExistsMath.cmake new file mode 100644 index 000000000..0fbccb836 --- /dev/null +++ b/cmake/modules/CheckFunctionExistsMath.cmake @@ -0,0 +1,57 @@ +# - Check if a C function can be linked +# CHECK_FUNCTION_EXISTS( ) +# +# Check that the is provided by libraries on the system and +# store the result in a . This does not verify that any +# system header file declares the function, only that it can be found +# at link time (considure using CheckSymbolExists). +# +# The following variables may be set before calling this macro to +# modify the way the check is run: +# +# CMAKE_REQUIRED_FLAGS = string of compile command line flags +# CMAKE_REQUIRED_DEFINITIONS = list of macros to define (-DFOO=bar) +# CMAKE_REQUIRED_INCLUDES = list of include directories +# CMAKE_REQUIRED_LIBRARIES = list of libraries to link + + +MACRO(CHECK_FUNCTION_EXISTS_MATH FUNCTION VARIABLE) + IF("${VARIABLE}" MATCHES "^${VARIABLE}$") + SET(MACRO_CHECK_FUNCTION_DEFINITIONS + "-DCHECK_FUNCTION_EXISTS=${FUNCTION} ${CMAKE_REQUIRED_FLAGS}") + MESSAGE(STATUS "Looking for ${FUNCTION}") + IF(CMAKE_REQUIRED_LIBRARIES) + SET(CHECK_FUNCTION_EXISTS_ADD_LIBRARIES + "-DLINK_LIBRARIES:STRING=${CMAKE_REQUIRED_LIBRARIES}") + ELSE(CMAKE_REQUIRED_LIBRARIES) + SET(CHECK_FUNCTION_EXISTS_ADD_LIBRARIES) + ENDIF(CMAKE_REQUIRED_LIBRARIES) + IF(CMAKE_REQUIRED_INCLUDES) + SET(CHECK_FUNCTION_EXISTS_ADD_INCLUDES + "-DINCLUDE_DIRECTORIES:STRING=${CMAKE_REQUIRED_INCLUDES}") + ELSE(CMAKE_REQUIRED_INCLUDES) + SET(CHECK_FUNCTION_EXISTS_ADD_INCLUDES) + ENDIF(CMAKE_REQUIRED_INCLUDES) + TRY_COMPILE(${VARIABLE} + ${CMAKE_BINARY_DIR} + ${CMAKE_SOURCE_DIR}/cmake/modules/CheckFunctionExists.c + COMPILE_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS} + CMAKE_FLAGS -DCOMPILE_DEFINITIONS:STRING=${MACRO_CHECK_FUNCTION_DEFINITIONS} + "${CHECK_FUNCTION_EXISTS_ADD_LIBRARIES}" + "${CHECK_FUNCTION_EXISTS_ADD_INCLUDES}" + OUTPUT_VARIABLE OUTPUT) + IF(${VARIABLE}) + SET(${VARIABLE} 1 CACHE INTERNAL "Have function ${FUNCTION}") + MESSAGE(STATUS "Looking for ${FUNCTION} - found") + FILE(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log + "Determining if the function ${FUNCTION} exists passed with the following output:\n" + "${OUTPUT}\n\n") + ELSE(${VARIABLE}) + MESSAGE(STATUS "Looking for ${FUNCTION} - not found") + SET(${VARIABLE} "" CACHE INTERNAL "Have function ${FUNCTION}") + FILE(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log + "Determining if the function ${FUNCTION} exists failed with the following output:\n" + "${OUTPUT}\n\n") + ENDIF(${VARIABLE}) + ENDIF("${VARIABLE}" MATCHES "^${VARIABLE}$") +ENDMACRO(CHECK_FUNCTION_EXISTS_MATH) diff --git a/cmake/modules/FindVolk.cmake b/cmake/modules/FindVolk.cmake index 3da43592d..7a9cb5349 100644 --- a/cmake/modules/FindVolk.cmake +++ b/cmake/modules/FindVolk.cmake @@ -24,6 +24,36 @@ FIND_LIBRARY( /usr/lib64 ) +# Some functions are not defined in old volk versions +SET(CMAKE_REQUIRED_LIBRARIES volk 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_magnitude_32f HAVE_VOLK_MAG_FUNCTION) + + +SET(VOLK_DEFINITIONS "HAVE_VOLK") +IF(${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") +ENDIF() +IF(${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") +ENDIF() +IF(${HAVE_VOLK_MULT2_FUNCTION}) + SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_MULT2_FUNCTION") +ENDIF() +IF(${HAVE_VOLK_MAG_FUNCTION}) + SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_MAG_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) +MARK_AS_ADVANCED(VOLK_LIBRARIES VOLK_INCLUDE_DIRS VOLK_DEFINITIONS) diff --git a/examples/pbch_enodeb.c b/examples/pbch_enodeb.c index be6dbbb11..21a10b514 100644 --- a/examples/pbch_enodeb.c +++ b/examples/pbch_enodeb.c @@ -152,7 +152,7 @@ void base_init() { fprintf(stderr, "Error creating iFFT object\n"); exit(-1); } - if (pbch_init(&pbch, cell_id, CPNORM)) { + if (pbch_init(&pbch, 6, cell_id, CPNORM)) { fprintf(stderr, "Error creating PBCH object\n"); exit(-1); } @@ -249,7 +249,7 @@ int main(int argc, char **argv) { sss_put_slot(ns?sss_signal5:sss_signal0, slot_buffer, nof_prb, CPNORM); break; case 1: // tx pbch - pbch_encode(&pbch, &mib, slot1_symbols, nof_prb, 1); + pbch_encode(&pbch, &mib, slot1_symbols, 1); break; default: // transmit zeros break; diff --git a/examples/pbch_ue.c b/examples/pbch_ue.c index c63a5f9c4..c07c769a0 100644 --- a/examples/pbch_ue.c +++ b/examples/pbch_ue.c @@ -274,7 +274,7 @@ int mib_decoder_init(int cell_id) { return -1; } - if (pbch_init(&pbch, cell_id, CPNORM)) { + if (pbch_init(&pbch, 6, cell_id, CPNORM)) { fprintf(stderr, "Error initiating PBCH\n"); return -1; } @@ -292,7 +292,7 @@ int mib_decoder_run(cf_t *input, pbch_mib_t *mib) { } DEBUG("Decoding PBCH\n", 0); - n = pbch_decode(&pbch, fft_buffer, ce, 6, 1, mib); + n = pbch_decode(&pbch, fft_buffer, ce, 1, mib); #ifndef DISABLE_GRAPHICS diff --git a/examples/scan_mib.c b/examples/scan_mib.c index e94ad6c18..f092c046e 100644 --- a/examples/scan_mib.c +++ b/examples/scan_mib.c @@ -325,7 +325,7 @@ int mib_decoder_init(int cell_id) { return -1; } - if (pbch_init(&pbch, cell_id, CPNORM)) { + if (pbch_init(&pbch, 6, cell_id, CPNORM)) { fprintf(stderr, "Error initiating PBCH\n"); return -1; } @@ -343,7 +343,7 @@ int mib_decoder_run(cf_t *input, pbch_mib_t *mib) { } DEBUG("Decoding PBCH\n", 0); - return pbch_decode(&pbch, fft_buffer, ce, 6, 1, mib); + return pbch_decode(&pbch, fft_buffer, ce, 1, mib); } int main(int argc, char **argv) { diff --git a/lte/include/lte.h b/lte/include/lte.h index 53415a8ef..b41d55122 100644 --- a/lte/include/lte.h +++ b/lte/include/lte.h @@ -72,6 +72,8 @@ #include "lte/mimo/layermap.h" #include "lte/phch/regs.h" +#include "lte/phch/dci.h" +#include "lte/phch/pdcch.h" #include "lte/phch/pbch.h" #include "lte/phch/pcfich.h" #include "lte/phch/phich.h" diff --git a/lte/include/lte/common/base.h b/lte/include/lte/common/base.h index 5592c3d5b..ef8c33519 100644 --- a/lte/include/lte/common/base.h +++ b/lte/include/lte/common/base.h @@ -32,6 +32,8 @@ #define NSUBFRAMES_X_FRAME 10 #define NSLOTS_X_FRAME (2*NSUBFRAMES_X_FRAME) +#define LTE_NIL_SYMBOL 2 + #define MAX_PORTS 4 #define MAX_PORTS_CTRL 4 #define MAX_LAYERS 8 @@ -39,6 +41,9 @@ typedef enum {CPNORM, CPEXT} lte_cp_t; +#define SIRNTI 0xFFFF +#define PRNTI 0xFFFE + #define MAX_NSYMB 7 #define CPNORM_NSYMB 7 diff --git a/lte/include/lte/common/sequence.h b/lte/include/lte/common/sequence.h index c52f44602..e4fcca153 100644 --- a/lte/include/lte/common/sequence.h +++ b/lte/include/lte/common/sequence.h @@ -44,5 +44,6 @@ int sequence_LTEPRS(sequence_t *q, int len, int seed); int sequence_pbch(sequence_t *seq, lte_cp_t cp, int cell_id); int sequence_pcfich(sequence_t *seq, int nslot, int cell_id); int sequence_phich(sequence_t *seq, int nslot, int cell_id); +int sequence_pdcch(sequence_t *seq, int nslot, int cell_id, int len); #endif diff --git a/lte/include/lte/fec/convcoder.h b/lte/include/lte/fec/convcoder.h index ac62a358e..54f9eb723 100644 --- a/lte/include/lte/fec/convcoder.h +++ b/lte/include/lte/fec/convcoder.h @@ -38,11 +38,10 @@ typedef struct { int R; int K; int poly[3]; - int framelength; bool tail_biting; }convcoder_t; -int convcoder_encode(convcoder_t *q, char *input, char *output); +int convcoder_encode(convcoder_t *q, char *input, char *output, int frame_length); /* High-level API */ diff --git a/lte/include/lte/fec/crc.h b/lte/include/lte/fec/crc.h index dd29d8868..5cc24ad23 100644 --- a/lte/include/lte/fec/crc.h +++ b/lte/include/lte/fec/crc.h @@ -30,6 +30,11 @@ #ifndef CRC_ #define CRC_ +#define LTE_CRC24A 0x1864CFB +#define LTE_CRC24B 0X1800063 +#define LTE_CRC16 0x11021 +#define LTE_CRC8 0x19B + unsigned int crc(unsigned int crc, char *bufptr, int len, int long_crc,unsigned int poly, int paste_word); diff --git a/lte/include/lte/fec/viterbi.h b/lte/include/lte/fec/viterbi.h index 9cf2cbb88..02bbe4383 100644 --- a/lte/include/lte/fec/viterbi.h +++ b/lte/include/lte/fec/viterbi.h @@ -42,16 +42,16 @@ typedef struct { unsigned int framebits; bool tail_biting; int poly[3]; - int (*decode) (void*, unsigned char*, char*); + int (*decode) (void*, unsigned char*, char*, int); void (*free) (void*); unsigned char *tmp; unsigned char *symbols_uc; }viterbi_t; -int viterbi_init(viterbi_t *q, viterbi_type_t type, int poly[3], int framebits, bool tail_bitting); +int viterbi_init(viterbi_t *q, viterbi_type_t type, int poly[3], int max_frame_length, bool tail_bitting); void viterbi_free(viterbi_t *q); -int viterbi_decode_f(viterbi_t *q, float *symbols, char *data); -int viterbi_decode_uc(viterbi_t *q, unsigned char *symbols, char *data); +int viterbi_decode_f(viterbi_t *q, float *symbols, char *data, int frame_length); +int viterbi_decode_uc(viterbi_t *q, unsigned char *symbols, char *data, int frame_length); /* High-level API */ diff --git a/lte/include/lte/phch/dci.h b/lte/include/lte/phch/dci.h new file mode 100644 index 000000000..ee9224687 --- /dev/null +++ b/lte/include/lte/phch/dci.h @@ -0,0 +1,113 @@ +/** + * + * \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 DCI_ +#define DCI_ + +#include "lte/common/base.h" + +typedef _Complex float cf_t; + +/** + * DCI message generation according to the formats, as specified in + * 36.212 Section 5.3.3.1 + * + * Call the function dci_init(&q) to generate a collection of DCI messages + * to be transmitted in a subframe. Each subsequent call to + * dci_add_formatXX(&q, ...) generates the DCI message and appends the data + * to the collection "q". + * + */ + +#define DCI_MAX_BITS 45 + +typedef enum { + FORMAT0, + FORMAT1, + FORMAT1A, + /* ... */ +}dci_format_t; + +typedef enum { + DCI_COMMON=0, DCI_UE=1 +}dci_spec_t; + +/** TODO: this is Release 8 */ +typedef struct { + /* 36.213 Table 8.4-2: hop_half is 0 for < 10 Mhz and 10 for > 10 Mh. + * hop_quart is 00 for > 10 Mhz and hop_quart_neg is 01 for > 10 Mhz. + */ + enum {hop_disabled, hop_half, hop_quart, hop_quart_neg, hop_type_2} freq_hop_fl; + int n_rb_ul; // number of resource blocks + int riv; // Resource Indication Value (36.213 8.1) + int mcs_and_rv; // MCS and RV value + enum {ndi_true=1, ndi_false=0} ndi; // New Data Indicator + int tpc; // Transmit Power Control + int dm_rs; // DM RS + enum {cqi_true=0, cqi_false=1} cqi_request; +}dci_format0_t; + +typedef struct { + +}dci_format1_t; + +typedef struct { + unsigned char nof_bits; + unsigned char L; // Aggregation level + unsigned char ncce; // Position of first CCE of the dci + unsigned short rnti; +}dci_candidate_t; + +typedef struct { + char data[DCI_MAX_BITS]; + dci_candidate_t location; +}dci_msg_t; + +typedef struct { + dci_msg_t *msg; + int nof_dcis; +}dci_t; + + +int dci_init(dci_t *q, int nof_dci); +void dci_free(dci_t *q); +void dci_candidate_fprint(FILE *f, dci_candidate_t *q); + +int dci_format0_add(dci_t *q, dci_format0_t *msg, int L, int nCCE, unsigned short rnti); +int dci_format0_sizeof(int nof_prb); + +int dci_format1_add(dci_t *q, dci_format1_t *msg, int L, int nCCE, unsigned short rnti); +int dci_format1_sizeof(int nof_prb, int P); + +int dci_format1A_add(dci_t *q, dci_format1_t *msg); +int dci_format1A_sizeof(int nof_prb, bool random_access_initiated); + +int dci_format1C_add(dci_t *q, dci_format1_t *msg); +int dci_format1C_sizeof(); + +#endif diff --git a/lte/include/lte/phch/pbch.h b/lte/include/lte/phch/pbch.h index 081388289..9cb3ae113 100644 --- a/lte/include/lte/phch/pbch.h +++ b/lte/include/lte/phch/pbch.h @@ -57,6 +57,7 @@ typedef struct { typedef struct { int cell_id; lte_cp_t cp; + int nof_prb; int nof_symbols; /* buffers */ @@ -82,11 +83,10 @@ typedef struct { }pbch_t; -int pbch_init(pbch_t *q, int cell_id, lte_cp_t cp); +int pbch_init(pbch_t *q, int nof_prb, int cell_id, lte_cp_t cp); void pbch_free(pbch_t *q); -int pbch_decode(pbch_t *q, cf_t *slot1_symbols, cf_t *ce[MAX_PORTS_CTRL], int nof_prb, float ebno, pbch_mib_t *mib); -void pbch_encode(pbch_t *q, pbch_mib_t *mib, cf_t *slot1_symbols[MAX_PORTS_CTRL], - int nof_prb, int nof_ports); +int pbch_decode(pbch_t *q, cf_t *slot1_symbols, cf_t *ce[MAX_PORTS_CTRL], float ebno, pbch_mib_t *mib); +void pbch_encode(pbch_t *q, pbch_mib_t *mib, cf_t *slot1_symbols[MAX_PORTS_CTRL], int nof_ports); void pbch_decode_reset(pbch_t *q); void pbch_mib_fprint(FILE *stream, pbch_mib_t *mib); diff --git a/lte/include/lte/phch/pdcch.h b/lte/include/lte/phch/pdcch.h new file mode 100644 index 000000000..75c8e768c --- /dev/null +++ b/lte/include/lte/phch/pdcch.h @@ -0,0 +1,126 @@ +/** + * + * \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 PDCCH_ +#define PDCCH_ + +#include "lte/common/base.h" +#include "lte/mimo/precoding.h" +#include "lte/mimo/layermap.h" +#include "lte/modem/mod.h" +#include "lte/modem/demod_soft.h" +#include "lte/scrambling/scrambling.h" +#include "lte/ratematching/rm_conv.h" +#include "lte/fec/convcoder.h" +#include "lte/fec/viterbi.h" +#include "lte/fec/crc.h" +#include "lte/phch/dci.h" +#include "lte/phch/regs.h" + +typedef _Complex float cf_t; + +#define PDCCH_NOF_SEARCH_MODES 3 + +typedef enum { + SEARCH_NONE=3, SEARCH_SI=0, SEARCH_RA=1, SEARCH_UE=2 +}pdcch_search_mode_t; + +/* + * A search mode is indicated by higher layers to look for SI/C/RA-RNTI + * DCI messages as defined in Section 7.1 of 36.213 + */ +typedef struct { + int nof_candidates; + dci_candidate_t *candidates[NSUBFRAMES_X_FRAME]; +}pdcch_search_t; + +/* PDCCH object */ +typedef struct { + 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; + + pdcch_search_t search_mode[PDCCH_NOF_SEARCH_MODES]; + pdcch_search_mode_t current_search_mode; + + 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 *pdcch_d; + char *pdcch_e; + float *pdcch_llr; + + /* tx & rx objects */ + modem_table_t mod; + demod_soft_t demod; + sequence_t seq_pdcch[NSUBFRAMES_X_FRAME]; + viterbi_t decoder; + +}pdcch_t; + +int pdcch_init(pdcch_t *q, regs_t *regs, int nof_prb, int nof_ports, int cell_id, lte_cp_t cp); +void pdcch_free(pdcch_t *q); + +/* Encoding functions */ +int pdcch_encode(pdcch_t *q, dci_t *dci, cf_t *slot1_symbols[MAX_PORTS_CTRL], int nsubframe); + + +/* Decoding functions */ + +/* There are two ways to decode the DCI messages: + * a) call pdcch_set_search_si/ue/ra and then call pdcch_decode() + * b) call pdcch_extract_llr() and then call pdcch_decode_si/ue/ra + */ + +int pdcch_decode(pdcch_t *q, cf_t *slot1_symbols, cf_t *ce[MAX_PORTS_CTRL], + dci_t *dci, int nsubframe, float ebno); +int pdcch_extract_llr(pdcch_t *q, cf_t *slot1_symbols, cf_t *ce[MAX_PORTS_CTRL], float *llr, + int nsubframe, float ebno); + +void pdcch_init_search_si(pdcch_t *q); +void pdcch_set_search_si(pdcch_t *q); +int pdcch_decode_si(pdcch_t *q, float *llr, dci_t *dci); + +void pdcch_init_search_ue(pdcch_t *q, unsigned short c_rnti); +void pdcch_set_search_ue(pdcch_t *q); +int pdcch_decode_ue(pdcch_t *q, float *llr, dci_t *dci, int nsubframe); + +void pdcch_init_search_ra(pdcch_t *q, unsigned short ra_rnti); +void pdcch_set_search_ra(pdcch_t *q); +int pdcch_decode_ra(pdcch_t *q, float *llr, dci_t *dci); + + +#endif diff --git a/lte/include/lte/phch/regs.h b/lte/include/lte/phch/regs.h index 1f7eef0ff..a439e2e61 100644 --- a/lte/include/lte/phch/regs.h +++ b/lte/include/lte/phch/regs.h @@ -89,5 +89,6 @@ int regs_phich_get(regs_t *h, cf_t *slot_symbols, cf_t phich_symbols[REGS_PHICH_ int regs_phich_ngroups(regs_t *h); int regs_phich_reset(regs_t *h, cf_t *slot_symbols); +int regs_pdcch_nregs(regs_t *h); #endif diff --git a/lte/lib/CMakeLists.txt b/lte/lib/CMakeLists.txt index f4d09f9a2..9efebe36f 100644 --- a/lte/lib/CMakeLists.txt +++ b/lte/lib/CMakeLists.txt @@ -23,6 +23,7 @@ ######################################################################## # Find Dependencies ######################################################################## +include(CheckFunctionExistsMath) FIND_PACKAGE(FFTW3F REQUIRED) # TODO: distribute kissfft instead INCLUDE_DIRECTORIES(${FFTW3F_INCLUDE_DIRS}) @@ -57,9 +58,9 @@ LIBLTE_SET_PIC(lte) IF(VOLK_FOUND) INCLUDE_DIRECTORIES(${VOLK_INCLUDE_DIRS}) - SET_TARGET_PROPERTIES(lte PROPERTIES COMPILE_DEFINITIONS "HAVE_VOLK") + SET_TARGET_PROPERTIES(lte PROPERTIES COMPILE_DEFINITIONS "${VOLK_DEFINITIONS}") TARGET_LINK_LIBRARIES(lte ${VOLK_LIBRARIES}) - MESSAGE(STATUS " Compiling with VOLK SIMD library.") + MESSAGE(STATUS " Compiling with VOLK SIMD library.") ELSE(VOLK_FOUND) MESSAGE(STATUS " VOLK SIMD library NOT found. Using generic implementation.") ENDIF(VOLK_FOUND) diff --git a/lte/lib/fec/src/convcoder.c b/lte/lib/fec/src/convcoder.c index 183afeee3..4fbd3e203 100644 --- a/lte/lib/fec/src/convcoder.c +++ b/lte/lib/fec/src/convcoder.c @@ -33,27 +33,25 @@ #include "lte/fec/convcoder.h" #include "parity.h" -int convcoder_encode(convcoder_t *q, char *input, char *output) { +int convcoder_encode(convcoder_t *q, char *input, char *output, int frame_length) { unsigned int sr; int i,j; - int len = q->tail_biting ? q->framelength : (q->framelength + q->K - 1); + int len = q->tail_biting ? frame_length : (frame_length + q->K - 1); if (q->tail_biting) { sr = 0; - for (i=q->framelength - q->K + 1; iframelength; i++) { + for (i=frame_length - q->K + 1; iframelength) ? (input[i] & 1) : 0; + int 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]); } - //printf("%3d - sr=%u\n", i, sr%64); } return q->R*len; @@ -69,12 +67,11 @@ int convcoder_work(convcoder_hl* hl) { hl->obj.K = hl->ctrl_in.constraint_length; hl->obj.R = hl->ctrl_in.rate; - hl->obj.framelength = hl->in_len; hl->obj.poly[0] = hl->ctrl_in.generator_0; hl->obj.poly[1] = hl->ctrl_in.generator_1; hl->obj.poly[2] = hl->ctrl_in.generator_2; hl->obj.tail_biting = hl->ctrl_in.tail_bitting?true:false; - hl->out_len = convcoder_encode(&hl->obj, hl->input, hl->output); + hl->out_len = convcoder_encode(&hl->obj, hl->input, hl->output, hl->in_len); return 0; } diff --git a/lte/lib/fec/src/viterbi.c b/lte/lib/fec/src/viterbi.c index 0b7351a10..98bfe7289 100644 --- a/lte/lib/fec/src/viterbi.c +++ b/lte/lib/fec/src/viterbi.c @@ -38,49 +38,62 @@ #define DEB 0 -int decode37(void *o, unsigned char *symbols, char *data) { +int decode37(void *o, unsigned char *symbols, char *data, int frame_length) { viterbi_t *q = o; int i; int best_state; + if (frame_length > q->framebits) { + fprintf(stderr, "Initialized decoder for max frame length %d bits\n", + q->framebits); + return -1; + } + /* Initialize Viterbi decoder */ - init_viterbi37_port(q->ptr, q->tail_biting?-1:0); + init_viterbi37_port(q->ptr, q->tail_biting ? -1 : 0); /* Decode block */ if (q->tail_biting) { - memcpy(q->tmp, symbols, 3 * q->framebits * sizeof(char)); - for (i=0;i<3*(q->K-1);i++) { - q->tmp[i+3*q->framebits] = q->tmp[i]; + memcpy(q->tmp, symbols, 3 * frame_length * sizeof(char)); + for (i = 0; i < 3 * (q->K - 1); i++) { + q->tmp[i + 3 * frame_length] = q->tmp[i]; } } else { q->tmp = symbols; } - update_viterbi37_blk_port(q->ptr, q->tmp, q->framebits + q->K - 1, q->tail_biting?&best_state:NULL); + update_viterbi37_blk_port(q->ptr, q->tmp, frame_length + q->K - 1, + q->tail_biting ? &best_state : NULL); /* Do Viterbi chainback */ - chainback_viterbi37_port(q->ptr, data, q->framebits, q->tail_biting?best_state:0); + chainback_viterbi37_port(q->ptr, data, frame_length, + q->tail_biting ? best_state : 0); return q->framebits; } -int decode39(void *o, unsigned char *symbols, char *data) { +int decode39(void *o, unsigned char *symbols, char *data, int frame_length) { viterbi_t *q = o; + if (frame_length > q->framebits) { + fprintf(stderr, "Initialized decoder for max frame length %d bits\n", + q->framebits); + return -1; + } + /* Initialize Viterbi decoder */ init_viterbi39_port(q->ptr, 0); /* Decode block */ - update_viterbi39_blk_port(q->ptr, symbols,q->framebits + q->K - 1); + update_viterbi39_blk_port(q->ptr, symbols, frame_length + q->K - 1); /* Do Viterbi chainback */ - chainback_viterbi39_port(q->ptr, data, q->framebits, 0); + chainback_viterbi39_port(q->ptr, data, frame_length, 0); return q->framebits; } - void free37(void *o) { viterbi_t *q = o; if (q->symbols_uc) { @@ -107,13 +120,13 @@ int init37(viterbi_t *q, int poly[3], int framebits, bool tail_biting) { q->tail_biting = tail_biting; q->decode = decode37; q->free = free37; - q->symbols_uc = malloc(3 * (q->framebits + q->K -1) * sizeof(char)); + q->symbols_uc = malloc(3 * (q->framebits + q->K - 1) * sizeof(char)); if (!q->symbols_uc) { perror("malloc"); return -1; } if (q->tail_biting) { - q->tmp = malloc(3 * (q->framebits + q->K -1) * sizeof(char)); + q->tmp = malloc(3 * (q->framebits + q->K - 1) * sizeof(char)); if (!q->tmp) { perror("malloc"); free37(q); @@ -140,10 +153,11 @@ int init39(viterbi_t *q, int poly[3], int framebits, bool tail_biting) { q->decode = decode39; q->free = free39; if (q->tail_biting) { - fprintf(stderr, "Error: Tailbitting not supported in 1/3 K=9 decoder\n"); + fprintf(stderr, + "Error: Tailbitting not supported in 1/3 K=9 decoder\n"); return -1; } - q->symbols_uc = malloc(3 * (q->framebits + q->K -1) * sizeof(char)); + q->symbols_uc = malloc(3 * (q->framebits + q->K - 1) * sizeof(char)); if (!q->symbols_uc) { perror("malloc"); return -1; @@ -157,12 +171,13 @@ 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 framebits, bool tail_bitting) { - switch(type) { +int viterbi_init(viterbi_t *q, viterbi_type_t type, int poly[3], + int max_frame_length, bool tail_bitting) { + switch (type) { case viterbi_37: - return init37(q, poly, framebits, tail_bitting); + return init37(q, poly, max_frame_length, tail_bitting); case viterbi_39: - return init39(q, poly, framebits, tail_bitting); + return init39(q, poly, max_frame_length, tail_bitting); default: fprintf(stderr, "Decoder not implemented\n"); return -1; @@ -174,22 +189,27 @@ void viterbi_free(viterbi_t *q) { } /* symbols are real-valued */ -int viterbi_decode_f(viterbi_t *q, float *symbols, char *data) { +int viterbi_decode_f(viterbi_t *q, float *symbols, char *data, int frame_length) { int len; + if (frame_length > q->framebits) { + fprintf(stderr, "Initialized decoder for max frame length %d bits\n", + q->framebits); + return -1; + } if (q->tail_biting) { - len = 3 * q->framebits; + len = 3 * frame_length; } else { - len = 3 * (q->framebits + q->K - 1); + len = 3 * (frame_length + q->K - 1); } vec_quant_fuc(symbols, q->symbols_uc, 32, 127.5, 255, len); - return q->decode(q, q->symbols_uc, data); + return q->decode(q, q->symbols_uc, data, frame_length); } -int viterbi_decode_uc(viterbi_t *q, unsigned char *symbols, char *data) { - return q->decode(q, symbols, data); +int viterbi_decode_uc(viterbi_t *q, unsigned char *symbols, char *data, + int frame_length) { + return q->decode(q, symbols, data, frame_length); } - int viterbi_initialize(viterbi_hl* h) { int poly[3]; viterbi_type_t type; @@ -222,15 +242,16 @@ int viterbi_initialize(viterbi_hl* h) { poly[1] = h->init.generator_1; poly[2] = h->init.generator_2; return viterbi_init(&h->obj, type, poly, h->init.frame_length, - h->init.tail_bitting?true:false); + h->init.tail_bitting ? true : false); } int viterbi_work(viterbi_hl* hl) { if (hl->in_len != hl->init.frame_length) { - fprintf(stderr, "Expected input length %d but got %d\n", hl->init.frame_length, hl->in_len); + fprintf(stderr, "Expected input length %d but got %d\n", + hl->init.frame_length, hl->in_len); return -1; } - return viterbi_decode_f(&hl->obj, hl->input, hl->output); + return viterbi_decode_f(&hl->obj, hl->input, hl->output, hl->init.frame_length); } int viterbi_stop(viterbi_hl* h) { diff --git a/lte/lib/fec/test/crc_test.h b/lte/lib/fec/test/crc_test.h index b55f15b39..926e79426 100644 --- a/lte/lib/fec/test/crc_test.h +++ b/lte/lib/fec/test/crc_test.h @@ -27,6 +27,8 @@ #include +#include "lte/fec/crc.h" + typedef struct { int n; int l; @@ -37,10 +39,10 @@ typedef struct { static expected_word_t expected_words[] = { - {5000, 24, 0x1864CFB, 1, 0x4D0836}, // LTE CRC24A (36.212 Sec 5.1.1) - {5000, 24, 0X1800063, 1, 0x9B68F8}, // LTE CRC24B - {5000, 16, 0x11021, 1, 0xBFFA}, // LTE CRC16 - {5000, 8, 0x19B, 1, 0xF8}, // LTE CRC8 + {5000, 24, LTE_CRC24A, 1, 0x4D0836}, // LTE CRC24A (36.212 Sec 5.1.1) + {5000, 24, LTE_CRC24B, 1, 0x9B68F8}, // LTE CRC24B + {5000, 16, LTE_CRC16, 1, 0xBFFA}, // LTE CRC16 + {5000, 8, LTE_CRC8, 1, 0xF8}, // LTE CRC8 {-1, -1, 0, 0, 0} }; diff --git a/lte/lib/fec/test/viterbi_test.c b/lte/lib/fec/test/viterbi_test.c index 43180f9e5..e7ee9e92c 100644 --- a/lte/lib/fec/test/viterbi_test.c +++ b/lte/lib/fec/test/viterbi_test.c @@ -187,7 +187,6 @@ int main(int argc, char **argv) { max_coded_length = 0; for (i=0;i max_coded_length) { max_coded_length = coded_length[i]; @@ -273,7 +272,7 @@ int main(int argc, char **argv) { /* coded BER */ for (n=0;n +#include +#include +#include +#include +#include +#include +#include + +#include "lte/phch/dci.h" +#include "lte/common/base.h" +#include "lte/utils/bit.h" +#include "lte/utils/vector.h" +#include "lte/utils/debug.h" + + +int dci_init(dci_t *q, int nof_dcis) { + q->msg = calloc(sizeof(dci_msg_t), nof_dcis); + if (!q->msg) { + perror("malloc"); + return -1; + } + q->nof_dcis = nof_dcis; + return 0; +} + +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_format1_add(dci_t *q, dci_format1_t *msg, int L, int nCCE, unsigned short rnti) { + int i, j; + i=0; + while(inof_dcis && q->msg[i].location.nof_bits) + i++; + if (i == q->nof_dcis) { + fprintf(stderr, "No more space in DCI container\n"); + return -1; + } + q->msg[i].location.L = L; + q->msg[i].location.ncce = nCCE; + q->msg[i].location.nof_bits = dci_format1_sizeof(6, 1); + q->msg[i].location.rnti = rnti; + for (j=0;jmsg[i].location.nof_bits;j++) { + q->msg[i].data[j] = rand()%2; + } + return 0; +} + +int dci_format0_add(dci_t *q, dci_format0_t *msg, int L, int nCCE, unsigned short rnti) { + int i, j; + i=0; + while(inof_dcis && q->msg[i].location.nof_bits) + i++; + if (i == q->nof_dcis) { + fprintf(stderr, "No more space in DCI container\n"); + return -1; + } + q->msg[i].location.L = L; + q->msg[i].location.ncce = nCCE; + q->msg[i].location.nof_bits = dci_format0_sizeof(msg->n_rb_ul); + q->msg[i].location.rnti = rnti; + for (j=0;jmsg[i].location.nof_bits;j++) { + q->msg[i].data[j] = rand()%2; + } + return 0; +} + +int dci_format0_sizeof(int nof_prb) { + return 1+1+(int) ceilf(log2f(nof_prb*(nof_prb+1)/2))+2+3+1; +} + +int dci_format1_sizeof(int nof_prb, int P) { + return (nof_prb>10)?1:0+(int) ceilf(log2f(nof_prb/P))+5+3+1+2+2; +} + +int dci_format1A_sizeof(int nof_prb, bool random_access_initiated) { + if (random_access_initiated) { + return 1+(int) ceilf(log2f(nof_prb*(nof_prb+1)/2))+6+4; + } else { + return 1+(int) ceilf(log2f(nof_prb*(nof_prb+1)/2))+5+3+1+2+2; + } +} + +int dci_format1C_sizeof() { + return 10; +} diff --git a/lte/lib/phch/src/pbch.c b/lte/lib/phch/src/pbch.c index 4158cf855..a20684380 100644 --- a/lte/lib/phch/src/pbch.c +++ b/lte/lib/phch/src/pbch.c @@ -109,7 +109,7 @@ int pbch_get(cf_t *slot1_data, cf_t *pbch, int nof_prb, lte_cp_t cp, int cell_id } /** Initializes the PBCH transmitter and receiver */ -int pbch_init(pbch_t *q, int cell_id, lte_cp_t cp) { +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; @@ -117,6 +117,7 @@ int pbch_init(pbch_t *q, int cell_id, lte_cp_t cp) { bzero(q, sizeof(pbch_t)); q->cell_id = cell_id; q->cp = cp; + q->nof_prb = nof_prb; if (modem_table_std(&q->mod, LTE_QPSK, true)) { goto clean; @@ -134,7 +135,6 @@ int pbch_init(pbch_t *q, int cell_id, lte_cp_t cp) { } q->encoder.K = 7; q->encoder.R = 3; - q->encoder.framelength = 40; q->encoder.tail_biting = true; memcpy(q->encoder.poly, poly, 3 * sizeof(int)); @@ -360,7 +360,7 @@ int pbch_crc_check(char *bits, int nof_ports) { char data[40]; memcpy(data, bits, 40 * sizeof(char)); crc_set_mask(data, nof_ports); - return crc(0, data, 40, 16, 0x11021, 0); + return crc(0, data, 40, 16, LTE_CRC16, 0); } int pbch_decode_frame(pbch_t *q, pbch_mib_t *mib, int src, int dst, int n, int nof_bits, int nof_ports) { @@ -389,7 +389,7 @@ int pbch_decode_frame(pbch_t *q, pbch_mib_t *mib, int src, int dst, int n, int n } /* decode */ - viterbi_decode_f(&q->decoder, q->pbch_rm_f, q->data); + viterbi_decode_f(&q->decoder, q->pbch_rm_f, q->data, 40); int c=0; for (j=0;j<40;j++) { @@ -420,7 +420,7 @@ int pbch_decode_frame(pbch_t *q, pbch_mib_t *mib, int src, int dst, int n, int n * * Returns 1 if successfully decoded MIB, 0 if not and -1 on error */ -int pbch_decode(pbch_t *q, cf_t *slot1_symbols, cf_t *ce[MAX_PORTS_CTRL], int nof_prb, float ebno, pbch_mib_t *mib) { +int pbch_decode(pbch_t *q, cf_t *slot1_symbols, cf_t *ce[MAX_PORTS_CTRL], float ebno, pbch_mib_t *mib) { int src, dst, res, nb; int nant_[3] = {1, 2, 4}; int na, nant; @@ -437,7 +437,7 @@ int pbch_decode(pbch_t *q, cf_t *slot1_symbols, cf_t *ce[MAX_PORTS_CTRL], int no memset(&x[MAX_PORTS_CTRL], 0, sizeof(cf_t*) * (MAX_LAYERS - MAX_PORTS_CTRL)); /* extract symbols */ - if (q->nof_symbols != pbch_get(slot1_symbols, q->pbch_symbols[0], nof_prb, + 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; @@ -445,7 +445,7 @@ int pbch_decode(pbch_t *q, cf_t *slot1_symbols, cf_t *ce[MAX_PORTS_CTRL], int no /* extract channel estimates */ for (i=0;inof_symbols != pbch_get(ce[i], q->ce[i], nof_prb, + if (q->nof_symbols != pbch_get(ce[i], q->ce[i], q->nof_prb, q->cp, q->cell_id)) { fprintf(stderr, "There was an error getting the PBCH symbols\n"); return -1; @@ -503,8 +503,7 @@ int pbch_decode(pbch_t *q, cf_t *slot1_symbols, cf_t *ce[MAX_PORTS_CTRL], int no /** 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_prb, int nof_ports) { +void pbch_encode(pbch_t *q, pbch_mib_t *mib, cf_t *slot1_symbols[MAX_PORTS_CTRL], int nof_ports) { int i; int nof_bits = 2 * q->nof_symbols; @@ -527,7 +526,7 @@ void pbch_encode(pbch_t *q, pbch_mib_t *mib, cf_t *slot1_symbols[MAX_PORTS_CTRL] crc(0, q->data, 24, 16, 0x11021, 1); crc_set_mask(q->data, nof_ports); - convcoder_encode(&q->encoder, q->data, q->data_enc); + convcoder_encode(&q->encoder, q->data, q->data_enc, 40); rm_conv_tx(q->data_enc, q->pbch_rm_b, 120, 4 * nof_bits); @@ -549,7 +548,7 @@ void pbch_encode(pbch_t *q, pbch_mib_t *mib, cf_t *slot1_symbols[MAX_PORTS_CTRL] /* mapping to resource elements */ for (i=0;ipbch_symbols[i], slot1_symbols[i], nof_prb, q->cp, q->cell_id); + 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) { diff --git a/lte/lib/phch/src/pdcch.c b/lte/lib/phch/src/pdcch.c new file mode 100644 index 000000000..1dc8463ca --- /dev/null +++ b/lte/lib/phch/src/pdcch.c @@ -0,0 +1,585 @@ +/** + * + * \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 "lte/phch/dci.h" +#include "lte/phch/regs.h" +#include "lte/phch/pdcch.h" +#include "lte/common/base.h" +#include "lte/utils/bit.h" +#include "lte/utils/vector.h" +#include "lte/utils/debug.h" + +#define PDCCH_NOF_FORMATS 4 +#define PDCCH_FORMAT_NOF_CCE(i) (1<b)?b:a) + +/** + * 36.213 9.1 + */ +int gen_common_search(dci_candidate_t *c, int nof_cce, int nof_bits, unsigned short rnti) { + int i, L, k; + k = 0; + for (L = 2; L > 0; L--) { + for (i = 0; i < MIN(nof_cce,16) / (4 * L); i++) { + c[k].L = 4 * L; + c[k].nof_bits = nof_bits; + c[k].rnti = rnti; + c[k].ncce = (4 * L) * (i % (nof_cce / (4 * L))); + k++; + 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); + } + } + return k; +} + +/** + * 36.213 9.1 + */ +int gen_ue_search(dci_candidate_t *c, int nof_cce, int nof_bits, unsigned short rnti, int subframe) { + int i, l, L, k, m; + unsigned int Yk; + const int S[4] = { 6, 12, 8, 16 }; + k = 0; + 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)); + INFO("UE-specific SS Candidate %d: SF: %d, RNTI: 0x%x, nCCE: %d, Nbits: %d, L: %d\n", + k, subframe, c[k].rnti, c[k].ncce, c[k].nof_bits, c[k].L); + k++; + } + } + return k; +} +void pdcch_init_common(pdcch_t *q, pdcch_search_t *s, unsigned short rnti) { + int k; + s->nof_candidates = 2*(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]; + + if (c) { + // Format 1A and 1C L=4 and L=8, 4 and 2 candidates, only if nof_cce > 16 + k = 0; + k += gen_common_search(&c[k], q->nof_cce, + dci_format1A_sizeof(q->nof_prb, true), SIRNTI); + k += gen_common_search(&c[k], q->nof_cce, + dci_format1C_sizeof(q->nof_prb), SIRNTI); + } + } +} + +/** 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 l, n, k; + pdcch_search_t *s = &q->search_mode[SEARCH_UE]; + s->nof_candidates = 0; + for (l=0;l<3;l++) { + s->nof_candidates += 3*(MIN(q->nof_cce,16) / (1<nof_candidates, c_rnti); + if (s->nof_candidates) { + for (n=0;ncandidates[n] = malloc(sizeof(dci_candidate_t) * s->nof_candidates); + dci_candidate_t *c = s->candidates[n]; + + if (c) { + // Expect Formats 1, 1A, 0 + k = 0; + k += gen_ue_search(&c[k], q->nof_cce, + dci_format0_sizeof(q->nof_prb), c_rnti, n); + k += gen_ue_search(&c[k], q->nof_cce, + dci_format1_sizeof(q->nof_prb, 1), c_rnti, n); + k += gen_ue_search(&c[k], q->nof_cce, + dci_format1A_sizeof(q->nof_prb, true), c_rnti, n); + } + } + } + q->current_search_mode = SEARCH_UE; +} + +/** 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; +} + +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; +} + +/** 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 i; + + if (cell_id < 0) { + return -1; + } + if (nof_ports > MAX_PORTS_CTRL) { + 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->current_search_mode = SEARCH_NONE; + + q->nof_regs = regs_pdcch_nregs(q->regs); + q->nof_cce = q->nof_regs / 9; + q->nof_symbols = 4 * q->nof_regs; + q->nof_bits = 2 * q->nof_symbols; + + INFO("Init PDCCH: %d REGs, %d bits, %d symbols, %d ports\n", q->nof_regs, + q->nof_bits, q->nof_symbols, q->nof_ports); + + 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); + + 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; + } + } + + 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; + } + + q->pdcch_llr = malloc(sizeof(float) * q->nof_bits); + if (!q->pdcch_llr) { + goto clean; + } + + q->pdcch_d = malloc(sizeof(cf_t) * q->nof_symbols); + if (!q->pdcch_d) { + goto clean; + } + + for (i = 0; i < MAX_PORTS_CTRL; 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) { + pdcch_free(q); + } + return ret; +} + +void pdcch_free(pdcch_t *q) { + int i, j; + + for (i=0;isearch_mode[i].candidates[j]) { + free(q->search_mode[i].candidates[j]); + } + } + } + if (q->pdcch_e) { + free(q->pdcch_e); + } + if (q->pdcch_llr) { + free(q->pdcch_llr); + } + if (q->pdcch_d) { + free(q->pdcch_d); + } + for (i = 0; i < MAX_PORTS_CTRL; i++) { + if (q->ce[i]) { + free(q->ce[i]); + } + if (q->pdcch_x[i]) { + free(q->pdcch_x[i]); + } + if (q->pdcch_symbols[i]) { + free(q->pdcch_symbols[i]); + } + } + + for (i = 0; i < NSUBFRAMES_X_FRAME; i++) { + sequence_free(&q->seq_pdcch[i]); + } + + modem_table_free(&q->mod); + viterbi_free(&q->decoder); +} + +/** 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 + */ +unsigned short dci_decode(viterbi_t *decoder, float *e, char *data, int E, + int nof_bits) { + + float tmp[3 * (DCI_MAX_BITS + 16)]; + unsigned short p_bits; + char *x; + + assert(nof_bits < DCI_MAX_BITS); + + /* unrate matching */ + rm_conv_rx(e, tmp, E, 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(decoder, tmp, data, nof_bits + 16); + + x = &data[nof_bits]; + p_bits = (unsigned short) bit_unpack(&x, 16); + + return (p_bits + ^ ((unsigned short) crc(0, data, nof_bits, 16, LTE_CRC16, 0) + & 0xffff)); +} + +int pdcch_decode_candidate(pdcch_t *q, float *llr, dci_candidate_t *c, + dci_msg_t *msg) { + unsigned short crc_res; + crc_res = dci_decode(&q->decoder, &llr[72 * c->ncce], msg->data, + PDCCH_FORMAT_NOF_BITS(c->L), c->nof_bits); + + if (c->rnti == crc_res) { + memcpy(&msg->location, c, sizeof(dci_candidate_t)); + INFO( + "FOUND CAND: Nbits: %d, E: %d, nCCE: %d, L: %d, RNTI: 0x%x\n", + c->nof_bits, PDCCH_FORMAT_NOF_BITS(c->L), c->ncce, c->L, + c->rnti); + return 1; + } + return 0; +} + +int pdcch_extract_llr(pdcch_t *q, cf_t *slot1_symbols, cf_t *ce[MAX_PORTS_CTRL], + float *llr, int nsubframe, float ebno) { + + /* 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); + return -1; + } + + if (ebno == 0.0) { + fprintf(stderr, "EbNo is Zero\n"); + 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 */ + if (q->nof_symbols + != pdcch_get(slot1_symbols, q->pdcch_symbols[0], q->nof_symbols)) { + fprintf(stderr, "There was an error getting the PDCCH symbols\n"); + return -1; + } + + /* extract channel estimates */ + for (i = 0; i < q->nof_ports; i++) { + if (q->nof_symbols != pdcch_get(ce[i], q->ce[i], q->nof_symbols)) { + fprintf(stderr, "There was an error getting the PDCCH symbols\n"); + return -1; + } + } + + DEBUG("pdcch_symbols: ", 0); + if (VERBOSE_ISDEBUG()) { + vec_fprint_c(stdout, q->pdcch_symbols[0], q->nof_symbols); + } + + /* 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, q->ce, x, q->nof_ports, + q->nof_symbols); + layerdemap_diversity(x, q->pdcch_d, q->nof_ports, + q->nof_symbols / q->nof_ports); + } + + /* demodulate symbols */ + demod_soft_sigma_set(&q->demod, ebno); + 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_symbols); + } + + /* descramble */ + scrambling_f_offset(&q->seq_pdcch[nsubframe], llr, 0, q->nof_bits); + + return 0; +} + +int pdcch_decode_current_mode(pdcch_t *q, float *llr, dci_t *dci, int subframe) { + int dci_cnt; + int k, i; + + if (q->current_search_mode == SEARCH_UE) { + k = subframe; + } else { + k = 0; + } + + dci_cnt = 0; + for (i = 0; i < q->search_mode[q->current_search_mode].nof_candidates + && dci_cnt < dci->nof_dcis; i++) { + if (pdcch_decode_candidate(q, q->pdcch_llr, + &q->search_mode[q->current_search_mode].candidates[k][i], + &dci->msg[dci_cnt])) { + dci_cnt++; + } + } + return dci_cnt; +} + +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, int nsubframe) { + pdcch_set_search_ue(q); + return pdcch_decode_current_mode(q, llr, dci, nsubframe); +} + + +/* Decodes PDCCH channels + * + * dci->nof_dcis is the size of the dci->msg buffer (ie max number of messages) + * + * Returns number of messages stored in dci + */ +int pdcch_decode(pdcch_t *q, cf_t *slot1_symbols, cf_t *ce[MAX_PORTS_CTRL], + dci_t *dci, int nsubframe, float ebno) { + + if (pdcch_extract_llr(q, slot1_symbols, ce, q->pdcch_llr, nsubframe, + ebno)) { + return -1; + } + + if (q->current_search_mode != SEARCH_NONE) { + return pdcch_decode_current_mode(q, q->pdcch_llr, dci, nsubframe); + } + + return 0; +} + +void crc_set_mask_rnti(char *crc, unsigned short rnti) { + int i; + char mask[16]; + char *r = mask; + + INFO("Mask CRC with RNTI 0x%x\n", rnti); + + bit_pack(rnti, &r, 16); + for (i = 0; i < 16; i++) { + crc[i] = (crc[i] + mask[i]) % 2; + } +} + +/** 36.212 5.3.3.2 to 5.3.3.4 + * TODO: UE transmit antenna selection CRC mask + */ +void dci_encode(char *data, char *e, int nof_bits, int E, unsigned short rnti) { + convcoder_t encoder; + char tmp[3 * (DCI_MAX_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(0, data, nof_bits, 16, LTE_CRC16, 1); + 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, e, 3 * (nof_bits + 16), E); +} + +/** Converts the MIB message to symbols mapped to SLOT #1 ready for transmission + */ +int pdcch_encode(pdcch_t *q, dci_t *dci, cf_t *slot1_symbols[MAX_PORTS_CTRL], + int nsubframe) { + int i; + /* 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; + } + + /* 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(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); + + /* 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); + } 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++) { + pdcch_put(q->pdcch_symbols[i], slot1_symbols[i], q->nof_symbols); + } + return 0; +} + diff --git a/lte/lib/phch/src/regs.c b/lte/lib/phch/src/regs.c index 9d38f4549..06b9a0c79 100644 --- a/lte/lib/phch/src/regs.c +++ b/lte/lib/phch/src/regs.c @@ -58,6 +58,9 @@ void regs_pdcch_free(regs_t *h) { } } +int regs_pdcch_nregs(regs_t *h) { + return 9; +} @@ -90,6 +93,9 @@ int regs_phich_init(regs_t *h) { case R_2: ng = 2; break; + default: + ng = 0; + break; } h->ngroups_phich = (int) ceilf(ng * ((float) h->nof_prb/8)); h->phich = malloc(sizeof(regs_ch_t) * h->ngroups_phich); diff --git a/lte/lib/phch/src/sequences.c b/lte/lib/phch/src/sequences.c index 566d2c589..21a851300 100644 --- a/lte/lib/phch/src/sequences.c +++ b/lte/lib/phch/src/sequences.c @@ -54,3 +54,11 @@ int sequence_phich(sequence_t *seq, int nslot, int cell_id) { bzero(seq, sizeof(sequence_t)); return sequence_LTEPRS(seq, 12, (nslot/2+1) * (2*cell_id + 1) * 512 + cell_id); } + +/** + * 36.211 6.8.2 + */ +int sequence_pdcch(sequence_t *seq, int nslot, int cell_id, int len) { + bzero(seq, sizeof(sequence_t)); + return sequence_LTEPRS(seq, len, (nslot/2) * 512 + cell_id); +} diff --git a/lte/lib/phch/test/CMakeLists.txt b/lte/lib/phch/test/CMakeLists.txt index e7f3a8fd5..204441ba9 100644 --- a/lte/lib/phch/test/CMakeLists.txt +++ b/lte/lib/phch/test/CMakeLists.txt @@ -68,6 +68,12 @@ ADD_TEST(phich_test_102 phich_test -p 2 -n 10 -g 2) ADD_TEST(phich_test_104 phich_test -p 4 -n 10 -e -l -g 1/2) +######################################################################## +# PDCCH TEST +######################################################################## + +ADD_EXECUTABLE(pdcch_test pdcch_test.c) +TARGET_LINK_LIBRARIES(pdcch_test lte) ######################################################################## # FILE TEST @@ -79,6 +85,10 @@ TARGET_LINK_LIBRARIES(pbch_file_test lte) ADD_EXECUTABLE(pcfich_file_test pcfich_file_test.c) TARGET_LINK_LIBRARIES(pcfich_file_test lte) +ADD_EXECUTABLE(phich_file_test phich_file_test.c) +TARGET_LINK_LIBRARIES(phich_file_test lte) + ADD_TEST(pbch_file_test pbch_file_test -i ${CMAKE_CURRENT_SOURCE_DIR}/signal.1.92M.dat) ADD_TEST(pcfich_file_test pcfich_file_test -c 150 -n 50 -p 2 -i ${CMAKE_CURRENT_SOURCE_DIR}/signal.10M.dat) +ADD_TEST(phich_file_test phich_file_test -c 150 -n 50 -p 2 -i ${CMAKE_CURRENT_SOURCE_DIR}/signal.10M.dat) \ No newline at end of file diff --git a/lte/lib/phch/test/pbch_file_test.c b/lte/lib/phch/test/pbch_file_test.c index bc03a0b34..15cf7ace0 100644 --- a/lte/lib/phch/test/pbch_file_test.c +++ b/lte/lib/phch/test/pbch_file_test.c @@ -141,7 +141,7 @@ int base_init() { return -1; } - if (pbch_init(&pbch, cell_id, cp)) { + if (pbch_init(&pbch, nof_prb, cell_id, cp)) { fprintf(stderr, "Error initiating PBCH\n"); return -1; } @@ -209,7 +209,7 @@ int main(int argc, char **argv) { INFO("Decoding PBCH\n", 0); - n = pbch_decode(&pbch, fft_buffer, ce, nof_prb, 1, &mib); + n = pbch_decode(&pbch, fft_buffer, ce, 1, &mib); base_free(); fftwf_cleanup(); diff --git a/lte/lib/phch/test/pbch_test.c b/lte/lib/phch/test/pbch_test.c index dc3db5122..7a4b9d3c0 100644 --- a/lte/lib/phch/test/pbch_test.c +++ b/lte/lib/phch/test/pbch_test.c @@ -99,7 +99,7 @@ int main(int argc, char **argv) { } } - if (pbch_init(&pbch, cell_id, CPNORM)) { + if (pbch_init(&pbch, nof_prb, cell_id, CPNORM)) { fprintf(stderr, "Error creating PBCH object\n"); exit(-1); } @@ -110,7 +110,7 @@ int main(int argc, char **argv) { mib_tx.phich_resources = R_1_6; mib_tx.sfn = 124; - pbch_encode(&pbch, &mib_tx, slot1_symbols, nof_prb, nof_ports); + pbch_encode(&pbch, &mib_tx, slot1_symbols, nof_ports); /* combine outputs */ for (i=1;i +#include +#include +#include +#include + +#include "lte.h" + +int cell_id = 1; +int nof_prb = 6; +int nof_ports = 1; + +void usage(char *prog) { + printf("Usage: %s [cpv]\n", prog); + printf("\t-c cell id [Default %d]\n", cell_id); + printf("\t-p nof_ports [Default %d]\n", nof_ports); + printf("\t-n nof_prb [Default %d]\n", nof_prb); + printf("\t-v [set verbose to debug, default none]\n"); +} + +void parse_args(int argc, char **argv) { + int opt; + while ((opt = getopt(argc, argv, "cpnv")) != -1) { + switch(opt) { + case 'p': + nof_ports = atoi(argv[optind]); + break; + case 'n': + nof_prb = atoi(argv[optind]); + break; + case 'c': + cell_id = atoi(argv[optind]); + break; + case 'v': + verbose++; + break; + default: + usage(argv[0]); + exit(-1); + } + } +} + +int main(int argc, char **argv) { + pdcch_t pdcch; + dci_t dci_tx, dci_rx; + dci_format1_t dci_msg; + regs_t regs; + int i, j; + cf_t *ce[MAX_PORTS_CTRL]; + int nof_re; + cf_t *slot1_symbols[MAX_PORTS_CTRL]; + int nof_dcis; + int ret = -1; + + parse_args(argc,argv); + + nof_re = CPNORM_NSYMB * nof_prb * RE_X_RB; + + /* init memory */ + for (i=0;i +#include +#include +#include +#include + +#include "lte.h" + +char *input_file_name = NULL; +char *matlab_file_name = NULL; +int cell_id = 150; +lte_cp_t cp = CPNORM; +int nof_prb = 50; +int nof_ports = 2; +int flen; +int nof_ctrl_symbols = 1; +phich_resources_t phich_res = R_1; +phich_length_t phich_length = PHICH_NORM; +int numsubframe = 0; + +FILE *fmatlab = NULL; + +filesource_t fsrc; +cf_t *input_buffer, *fft_buffer, *ce[MAX_PORTS_CTRL]; +phich_t phich; +regs_t regs; +lte_fft_t fft; +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-p nof_ports [Default %d]\n", nof_ports); + printf("\t-n nof_prb [Default %d]\n", nof_prb); + printf("\t-f nof control symbols [Default %d]\n", nof_ctrl_symbols); + printf("\t-g phich ng factor: 1/6, 1/2, 1, 2 [Default 1]\n"); + printf("\t-e phich extended length [Default normal]\n"); + printf("\t-l extended cyclic 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, "iovcenpfgl")) != -1) { + switch(opt) { + case 'i': + input_file_name = argv[optind]; + break; + case 'o': + matlab_file_name = argv[optind]; + break; + case 'c': + cell_id = atoi(argv[optind]); + break; + case 'f': + nof_ctrl_symbols = atoi(argv[optind]); + break; + case 'g': + if (!strcmp(argv[optind], "1/6")) { + phich_res = R_1_6; + } else if (!strcmp(argv[optind], "1/2")) { + phich_res = R_1_2; + } else if (!strcmp(argv[optind], "1")) { + phich_res = R_1; + } else if (!strcmp(argv[optind], "2")) { + phich_res = R_2; + } else { + fprintf(stderr, "Invalid phich ng factor %s. Setting to default.\n", argv[optind]); + } + break; + case 'e': + phich_length = PHICH_EXT; + break; + case 'n': + nof_prb = atoi(argv[optind]); + break; + case 'p': + nof_ports = atoi(argv[optind]); + break; + case 'v': + verbose++; + break; + case 'l': + cp = CPEXT; + break; + default: + usage(argv[0]); + exit(-1); + } + } + if (!input_file_name) { + usage(argv[0]); + exit(-1); + } +} + +int base_init() { + int i; + + if (filesource_init(&fsrc, input_file_name, COMPLEX_FLOAT_BIN)) { + fprintf(stderr, "Error opening file %s\n", input_file_name); + exit(-1); + } + + if (matlab_file_name) { + fmatlab = fopen(matlab_file_name, "w"); + if (!fmatlab) { + perror("fopen"); + return -1; + } + } else { + fmatlab = NULL; + } + + flen = SLOT_LEN(lte_symbol_sz(nof_prb), cp); + + input_buffer = malloc(flen * sizeof(cf_t)); + if (!input_buffer) { + perror("malloc"); + exit(-1); + } + + fft_buffer = malloc(CP_NSYMB(cp) * nof_prb * RE_X_RB * sizeof(cf_t)); + if (!fft_buffer) { + perror("malloc"); + return -1; + } + + for (i=0;i