diff --git a/cmake/modules/CheckFunctionExistsMath.cmake b/cmake/modules/CheckFunctionExistsMath.cmake index 0fbccb836..a05b431de 100644 --- a/cmake/modules/CheckFunctionExistsMath.cmake +++ b/cmake/modules/CheckFunctionExistsMath.cmake @@ -14,6 +14,16 @@ # CMAKE_REQUIRED_INCLUDES = list of include directories # CMAKE_REQUIRED_LIBRARIES = list of libraries to link +#============================================================================= +# Copyright 2002-2011 Kitware, Inc. +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file Copyright.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= MACRO(CHECK_FUNCTION_EXISTS_MATH FUNCTION VARIABLE) IF("${VARIABLE}" MATCHES "^${VARIABLE}$") diff --git a/cuhd/lib/CMakeLists.txt b/cuhd/lib/CMakeLists.txt index 82ad6382c..fb74eae89 100644 --- a/cuhd/lib/CMakeLists.txt +++ b/cuhd/lib/CMakeLists.txt @@ -25,19 +25,17 @@ IF(UHD_FOUND) ADD_LIBRARY(cuhd cuhd_imp.cpp cuhd_utils.c) INCLUDE_DIRECTORIES(${UHD_INCLUDE_DIRS}) + LINK_DIRECTORIES(${UHD_LIBRARY_DIRS}) TARGET_LINK_LIBRARIES(cuhd ${UHD_LIBRARIES}) - + LIBLTE_SET_PIC(cuhd) APPEND_INTERNAL_LIST(OPTIONAL_LIBS cuhd) INSTALL(TARGETS cuhd DESTINATION ${LIBRARY_DIR}) - + MESSAGE(STATUS " cuhd UHD C wrapper will be installed.") - + ELSE(UHD_FOUND) - MESSAGE(STATUS " UHD driver not found. CUHD library is not generated") + MESSAGE(STATUS " UHD driver not found. CUHD library is not generated") ENDIF(UHD_FOUND) - - - \ No newline at end of file diff --git a/cuhd/lib/cuhd_imp.cpp b/cuhd/lib/cuhd_imp.cpp index 88e1ce27f..732a2be34 100644 --- a/cuhd/lib/cuhd_imp.cpp +++ b/cuhd/lib/cuhd_imp.cpp @@ -46,7 +46,18 @@ typedef _Complex float complex_t; bool isLocked(void *h) { cuhd_handler* handler = static_cast(h); - return handler->usrp->get_rx_sensor("lo_locked", 0).to_bool(); + 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; + } } bool cuhd_rx_wait_lo_locked(void *h) @@ -89,12 +100,14 @@ int cuhd_start_rx_stream_nsamples(void *h, int nsamples) { 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); + + // Try to set LTE clock + handler->usrp->set_master_clock_rate(30720000); + handler->usrp->set_clock_source("internal"); std::string otw, cpu; @@ -190,4 +203,3 @@ int cuhd_send(void *h, void *data, int nsamples, int blocking) { return handler->tx_stream->send(data, nsamples, md, 0.0); } } - diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 21d3cdba8..117c6d47c 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -38,6 +38,7 @@ target_link_libraries(ll_example lte) add_executable(synch_file synch_file.c) target_link_libraries(synch_file lte) +LINK_DIRECTORIES(${UHD_LIBRARY_DIRS}) ################################################################# # Check if UHD C-API and Graphics library are available @@ -59,8 +60,8 @@ target_link_libraries(pbch_enodeb lte) 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") -ELSE(${CUHD_FIND} EQUAL -1) - target_link_libraries(pbch_ue cuhd) +ELSE(${CUHD_FIND} EQUAL -1) + target_link_libraries(pbch_ue cuhd) target_link_libraries(pbch_enodeb cuhd) ENDIF(${CUHD_FIND} EQUAL -1) @@ -79,13 +80,13 @@ ENDIF(${GRAPHICS_FIND} EQUAL -1) ################################################################# IF(${CUHD_FIND} GREATER -1) - + add_executable(scan_rssi scan_rssi.c) target_link_libraries(scan_rssi lte cuhd ) - + add_executable(scan_pss scan_pss.c) target_link_libraries(scan_pss lte cuhd ) - + add_executable(scan_mib scan_mib.c) target_link_libraries(scan_mib lte cuhd ) @@ -93,5 +94,4 @@ IF(${CUHD_FIND} GREATER -1) ELSE(${CUHD_FIND} GREATER -1) MESSAGE(STATUS " UHD examples NOT INSTALLED: CUHD library not compiled.") -ENDIF(${CUHD_FIND} GREATER -1) - +ENDIF(${CUHD_FIND} GREATER -1) diff --git a/examples/pbch_enodeb.c b/examples/pbch_enodeb.c index 21a10b514..4cf26bb68 100644 --- a/examples/pbch_enodeb.c +++ b/examples/pbch_enodeb.c @@ -39,7 +39,7 @@ #endif char *output_file_name = NULL; -int nof_slots=-1; +int nof_frames=-1; int cell_id = 1; int nof_prb = 6; char *uhd_args = ""; @@ -66,7 +66,7 @@ void usage(char *prog) { 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_slots); + 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"); @@ -92,7 +92,7 @@ void parse_args(int argc, char **argv) { output_file_name = argv[optind]; break; case 'n': - nof_slots = atoi(argv[optind]); + nof_frames = atoi(argv[optind]); break; case 'p': nof_prb = atoi(argv[optind]); @@ -238,7 +238,7 @@ int main(int argc, char **argv) { nf = 0; - while(nf +#include "lte/phch/ra.h" typedef _Complex float cf_t; @@ -37,77 +38,63 @@ 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 + +#define DCI_MAX_BITS 57 typedef enum { - FORMAT0, - FORMAT1, - FORMAT1A, - /* ... */ -}dci_format_t; + Format0, Format1, Format1A, Format1C +} dci_format_t; + +// Each type is for a different interface to packing/unpacking functions +typedef struct { + enum { + PUSCH_SCHED, PDSCH_SCHED, MCCH_CHANGE, TPC_COMMAND, RA_PROC_PDCCH + } type; + dci_format_t format; +}dci_msg_type_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; + DCI_COMMON = 0, DCI_UE = 1 +} dci_spec_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; +} dci_candidate_t; typedef struct { char data[DCI_MAX_BITS]; dci_candidate_t location; -}dci_msg_t; +} dci_msg_t; typedef struct { dci_msg_t *msg; int nof_dcis; -}dci_t; + int max_dcis; +} dci_t; - -int dci_init(dci_t *q, int nof_dci); +int dci_init(dci_t *q, int max_dci); void dci_free(dci_t *q); +char* dci_format_string(dci_format_t format); + +int dci_msg_candidate_set(dci_msg_t *msg, int L, int nCCE, unsigned short rnti); 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_msg_get_type(dci_msg_t *msg, dci_msg_type_t *type, int nof_prb, unsigned short crnti); +void dci_msg_type_fprint(FILE *f, dci_msg_type_t type); -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); +// For dci_msg_type_t = PUSCH_SCHED +int dci_msg_pack_pusch(ra_pusch_t *data, dci_msg_t *msg, int nof_prb); +int dci_msg_unpack_pusch(dci_msg_t *msg, ra_pusch_t *data, int nof_prb); -int dci_format1A_add(dci_t *q, dci_format1_t *msg); -int dci_format1A_sizeof(int nof_prb, bool random_access_initiated); +// For dci_msg_type_t = PDSCH_SCHED +int dci_msg_pack_pdsch(ra_pdsch_t *data, dci_msg_t *msg, dci_format_t format, int nof_prb, bool crc_is_crnti); +int dci_msg_unpack_pdsch(dci_msg_t *msg, ra_pdsch_t *data, int nof_prb, bool crc_is_crnti); -int dci_format1C_add(dci_t *q, dci_format1_t *msg); -int dci_format1C_sizeof(); +int dci_format_sizeof(dci_format_t format, int nof_prb); #endif diff --git a/lte/include/lte/phch/pbch.h b/lte/include/lte/phch/pbch.h index 9cb3ae113..877dd6439 100644 --- a/lte/include/lte/phch/pbch.h +++ b/lte/include/lte/phch/pbch.h @@ -35,7 +35,7 @@ #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/rm_conv.h" #include "lte/fec/convcoder.h" #include "lte/fec/viterbi.h" #include "lte/fec/crc.h" @@ -79,6 +79,7 @@ typedef struct { demod_soft_t demod; sequence_t seq_pbch; viterbi_t decoder; + crc_t crc; convcoder_t encoder; }pbch_t; diff --git a/lte/include/lte/phch/pdcch.h b/lte/include/lte/phch/pdcch.h index 75c8e768c..b7767d0b5 100644 --- a/lte/include/lte/phch/pdcch.h +++ b/lte/include/lte/phch/pdcch.h @@ -35,7 +35,7 @@ #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/rm_conv.h" #include "lte/fec/convcoder.h" #include "lte/fec/viterbi.h" #include "lte/fec/crc.h" @@ -88,7 +88,7 @@ typedef struct { demod_soft_t demod; sequence_t seq_pdcch[NSUBFRAMES_X_FRAME]; viterbi_t decoder; - + crc_t crc; }pdcch_t; int pdcch_init(pdcch_t *q, regs_t *regs, int nof_prb, int nof_ports, int cell_id, lte_cp_t cp); diff --git a/lte/include/lte/phch/ra.h b/lte/include/lte/phch/ra.h new file mode 100644 index 000000000..0519dc51d --- /dev/null +++ b/lte/include/lte/phch/ra.h @@ -0,0 +1,156 @@ +/** + * + * \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 RB_ALLOC_H_ +#define RB_ALLOC_H_ + +#include +#include + +/** Structures and utility functions for DL/UL resource + * allocation. + */ + +typedef enum { + MOD_NULL = 0, BPSK = 1, QPSK = 2, QAM16 = 4, QAM64 = 16 +} ra_mod_t; + +typedef struct { + 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; + int tbs; // If tbs<=0, the tbs_idx value is taken by the packing functions to generate the DCI + // message. Otherwise the tbs_idx corresponding to the lower nearest TBS is taken. +}ra_mcs_t; + + +typedef enum { + alloc_type0 = 0, alloc_type1 = 1, alloc_type2 = 2 +}ra_type_t; + +typedef struct { + uint32_t rbg_bitmask; +}ra_type0_t; + +typedef struct { + uint32_t vrb_bitmask; + uint8_t rbg_subset; + bool shift; +}ra_type1_t; + +typedef struct { + uint32_t riv; // if L_crb==0, DCI message packer will take this value directly + uint16_t L_crb; + uint16_t RB_start; + enum {nprb1a_2 = 0, nprb1a_3 = 1} n_prb1a; + enum {t2_ng1 = 0, t2_ng2 = 1} n_gap; + enum {t2_loc = 0, t2_dist = 1} mode; +}ra_type2_t; + +typedef struct { + unsigned short rnti; + ra_type_t alloc_type; + union { + ra_type0_t type0_alloc; + ra_type1_t type1_alloc; + ra_type2_t type2_alloc; + }; + ra_mcs_t mcs; + uint8_t harq_process; + uint8_t rv_idx; + bool ndi; +} ra_pdsch_t; + +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 = -1, + hop_quart = 0, + hop_quart_neg = 1, + hop_half = 2, + hop_type_2 = 3 + } freq_hop_fl; + + ra_type2_t type2_alloc; + ra_mcs_t mcs; + uint8_t rv_idx; // If set to non-zero, a retransmission is requested with the same modulation + // than before (Format0 message, see also 8.6.1 in 36.2313). + bool ndi; + bool cqi_request; + +} ra_pusch_t; + +typedef struct { + uint8_t prb_idx[110]; + int nof_prb; +}ra_prb_slot_t; + +typedef struct { + ra_prb_slot_t slot1; + ra_prb_slot_t slot2; + bool is_dist; +}ra_prb_t; + + +void ra_prb_fprint(FILE *f, ra_prb_slot_t *prb); +int ra_prb_get_dl(ra_prb_t *prb, ra_pdsch_t *ra, int nof_prb); +int ra_prb_get_ul(ra_prb_slot_t *prb, ra_pusch_t *ra, int nof_prb); +int ra_nprb_dl(ra_pdsch_t *ra, int nof_prb); +int ra_nprb_ul(ra_pusch_t *ra, int nof_prb); + +uint8_t ra_mcs_to_table_idx(ra_mcs_t *mcs); +int ra_mcs_from_idx_dl(uint8_t idx, ra_mcs_t *mcs); +int ra_mcs_from_idx_ul(uint8_t idx, ra_mcs_t *mcs); +int ra_tbs_from_idx_format1c(uint8_t tbs_idx); +int ra_tbs_to_table_idx_format1c(int tbs); +int ra_tbs_from_idx(uint8_t tbs_idx, int n_prb); +int ra_tbs_to_table_idx(int tbs, int n_prb); + +uint8_t ra_mcs_to_table_idx(ra_mcs_t *mcs); +int ra_mcs_from_idx_dl(uint8_t idx, ra_mcs_t *mcs); +int ra_mcs_from_idx_ul(uint8_t idx, ra_mcs_t *mcs); + +char *ra_mod_string(ra_mod_t mod); + +int ra_type0_P(int nof_prb); + +uint32_t ra_type2_to_riv(uint16_t L_crb, uint16_t RB_start, int nof_prb); +void ra_type2_from_riv(uint32_t riv, uint16_t *L_crb, uint16_t *RB_start, int nof_prb, int nof_vrb); +int ra_type2_n_vrb_dl(int nof_prb, bool ngap_is_1); +int ra_type2_n_rb_step(int nof_prb); +int ra_type2_ngap(int nof_prb, bool ngap_is_1); +int ra_type1_N_rb(int nof_prb); + +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); +void ra_pdsch_fprint(FILE *f, ra_pdsch_t *ra, int nof_prb); +void ra_pusch_fprint(FILE *f, ra_pusch_t *ra, int nof_prb); + +#endif /* RB_ALLOC_H_ */ diff --git a/lte/include/lte/phch/regs.h b/lte/include/lte/phch/regs.h index a439e2e61..657776650 100644 --- a/lte/include/lte/phch/regs.h +++ b/lte/include/lte/phch/regs.h @@ -59,36 +59,42 @@ typedef struct { int cell_id; int nof_prb; int max_ctrl_symbols; + int cfi; int ngroups_phich; - int refs_in_symbol1; + int nof_ports; lte_cp_t cp; phich_resources_t phich_res; phich_length_t phich_len; - int nof_cce; regs_ch_t pcfich; regs_ch_t *phich; // there are several phich - regs_ch_t *pdcch; // there are several pdcch + regs_ch_t pdcch[3]; /* PDCCH indexing, permutation and interleaving is computed for + the three possible CFI value */ int nof_regs; regs_reg_t *regs; }regs_t; -int regs_init(regs_t *h, int cell_id, int nof_prb, int refs_in_symbol1, +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); void regs_free(regs_t *h); +int regs_set_cfi(regs_t *h, int nof_ctrl_symbols); int regs_put_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, int nof_prb); int regs_get_reg(regs_reg_t *reg, cf_t *slot_symbols, cf_t *reg_data, int nof_prb); int regs_reset_reg(regs_reg_t *reg, cf_t *slot_symbols, int nof_prb); +int regs_pcfich_nregs(regs_t *h); int regs_pcfich_put(regs_t *h, cf_t pcfich_symbols[REGS_PCFICH_NSYM], cf_t *slot_symbols); -int regs_pcfich_get(regs_t *h, cf_t *slot_symbols, cf_t ch_data[REGS_PCFICH_NSYM]); +int regs_pcfich_get(regs_t *h, cf_t *slot_symbols, cf_t pcfich_symbols[REGS_PCFICH_NSYM]); +int regs_phich_nregs(regs_t *h); int regs_phich_add(regs_t *h, cf_t phich_symbols[REGS_PHICH_NSYM], int ngroup, cf_t *slot_symbols); int regs_phich_get(regs_t *h, cf_t *slot_symbols, cf_t phich_symbols[REGS_PHICH_NSYM], int ngroup); 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); +int regs_pdcch_put(regs_t *h, cf_t *pdcch_symbols, cf_t *slot_symbols); +int regs_pdcch_get(regs_t *h, cf_t *slot_symbols, cf_t *pdcch_symbols); #endif diff --git a/lte/include/lte/utils/bit.h b/lte/include/lte/utils/bit.h index 00e2523f1..18ef23e9e 100644 --- a/lte/include/lte/utils/bit.h +++ b/lte/include/lte/utils/bit.h @@ -36,6 +36,7 @@ uint32_t bit_unpack(char **bits, int nof_bits); void bit_pack(uint32_t value, char **bits, int nof_bits); void bit_fprint(FILE *stream, char *bits, int nof_bits); unsigned int bit_diff(char *x, char *y, int nbits); +int bit_count(unsigned int n); #endif diff --git a/lte/include/lte/utils/debug.h b/lte/include/lte/utils/debug.h index f6f08d777..993bab615 100644 --- a/lte/include/lte/utils/debug.h +++ b/lte/include/lte/utils/debug.h @@ -41,8 +41,8 @@ void get_time_interval(struct timeval * tdata); extern int verbose; -#define VERBOSE_ISINFO() (verbose==VERBOSE_INFO) -#define VERBOSE_ISDEBUG() (verbose==VERBOSE_DEBUG) +#define VERBOSE_ISINFO() (verbose>=VERBOSE_INFO) +#define VERBOSE_ISDEBUG() (verbose>=VERBOSE_DEBUG) #define PRINT_DEBUG verbose=VERBOSE_DEBUG #define PRINT_INFO verbose=VERBOSE_INFO diff --git a/lte/lib/common/src/lte.c b/lte/lib/common/src/lte.c index e475cf161..657f6fdb6 100644 --- a/lte/lib/common/src/lte.c +++ b/lte/lib/common/src/lte.c @@ -34,6 +34,43 @@ #include "lte/common/base.h" +const int tc_cb_sizes[NOF_TC_CB_SIZES] = { 40, 48, 56, 64, 72, 80, 88, 96, 104, 112, 120, + 128, 136, 144, 152, 160, 168, 176, 184, 192, 200, 208, 216, 224, 232, + 240, 248, 256, 264, 272, 280, 288, 296, 304, 312, 320, 328, 336, 344, + 352, 360, 368, 376, 384, 392, 400, 408, 416, 424, 432, 440, 448, 456, + 464, 472, 480, 488, 496, 504, 512, 528, 544, 560, 576, 592, 608, 624, + 640, 656, 672, 688, 704, 720, 736, 752, 768, 784, 800, 816, 832, 848, + 864, 880, 896, 912, 928, 944, 960, 976, 992, 1008, 1024, 1056, 1088, + 1120, 1152, 1184, 1216, 1248, 1280, 1312, 1344, 1376, 1408, 1440, 1472, + 1504, 1536, 1568, 1600, 1632, 1664, 1696, 1728, 1760, 1792, 1824, 1856, + 1888, 1920, 1952, 1984, 2016, 2048, 2112, 2176, 2240, 2304, 2368, 2432, + 2496, 2560, 2624, 2688, 2752, 2816, 2880, 2944, 3008, 3072, 3136, 3200, + 3264, 3328, 3392, 3456, 3520, 3584, 3648, 3712, 3776, 3840, 3904, 3968, + 4032, 4096, 4160, 4224, 4288, 4352, 4416, 4480, 4544, 4608, 4672, 4736, + 4800, 4864, 4928, 4992, 5056, 5120, 5184, 5248, 5312, 5376, 5440, 5504, + 5568, 5632, 5696, 5760, 5824, 5888, 5952, 6016, 6080, 6144 }; + +int lte_cb_size(int index) { + if (index >= 0 && index < NOF_TC_CB_SIZES) { + return tc_cb_sizes[index]; + } else { + return -1; + } +} + +int lte_find_cb_index(int 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; + } else { + return j; + } +} + const int lte_symbol_sz(int nof_prb) { if (nof_prb<=0) { return -1; @@ -135,7 +172,7 @@ struct lte_band lte_bands[NOF_LTE_BANDS] = { }; #define EOF_BAND 9919 -int lte_str2mimotype(char *mimo_type_str, mimo_type_t *type) { +int lte_str2mimotype(char *mimo_type_str, lte_mimo_type_t *type) { if (!strcmp(mimo_type_str, "single")) { *type = SINGLE_ANTENNA; } else if (!strcmp(mimo_type_str, "diversity")) { @@ -148,7 +185,7 @@ int lte_str2mimotype(char *mimo_type_str, mimo_type_t *type) { return 0; } -char *lte_mimotype2str(mimo_type_t type) { +char *lte_mimotype2str(lte_mimo_type_t type) { switch(type) { case SINGLE_ANTENNA: return "single"; diff --git a/lte/lib/common/test/fft_test.c b/lte/lib/common/test/fft_test.c index e82206eb8..2e4feff2a 100644 --- a/lte/lib/common/test/fft_test.c +++ b/lte/lib/common/test/fft_test.c @@ -122,7 +122,7 @@ int main(int argc, char **argv) { } printf("MSE=%f\n", mse); - if (mse >= 0.05) { + if (mse >= 0.07) { printf("MSE too large\n"); exit(-1); } diff --git a/lte/lib/fec/src/crc.c b/lte/lib/fec/src/crc.c index 6360d3537..e2de27c4f 100644 --- a/lte/lib/fec/src/crc.c +++ b/lte/lib/fec/src/crc.c @@ -25,66 +25,141 @@ * */ - #include #include +#include -unsigned int cword; +#include "lte/utils/pack.h" +#include "lte/fec/crc.h" -unsigned int icrc1(unsigned int crc, unsigned short onech,int long_crc, - int left_shift,unsigned int poly) -{ - int i; - unsigned int tmp=(unsigned int) (crc ^ (onech << (long_crc >> 1) )); +void gen_crc_table(crc_t *h) { - for (i=0;iorder - 8); + unsigned long bit, crc; - return tmp; + for (i = 0; i < 256; i++) { + crc = ((unsigned long) i) << ord; + for (j = 0; j < 8; j++) { + bit = crc & h->crchighbit; + crc <<= 1; + if (bit) + crc ^= h->polynom; + } + h->table[i] = crc & h->crcmask; + } } -unsigned int crc(unsigned int crc, char *bufptr, int len, - int long_crc,unsigned int poly, int paste_word) { +unsigned long crctable(crc_t *h) { - int i,k; - unsigned int data; - int stop; - unsigned int ret; + // Polynom order 8, 16, 24 or 32 only. + int ord = h->order - 8; + unsigned long crc = h->crcinit; + unsigned char byte = h->byte; - cword=crc; - - k=0; - stop=0; - while(!stop) { - data=0; - for (i=0;i>long_crc), - data,long_crc,i,poly)<>long_crc; - } - - ret=cword; - if (paste_word) { - cword<<=32-long_crc; - for (i=0;i>31); - cword<<=1; - } - } - return (ret); + crc = (crc << 8) ^ h->table[((crc >> (ord)) & 0xff) ^ byte]; + h->crcinit = crc; + return (crc & h->crcmask); } +unsigned long reversecrcbit(unsigned int crc, int nbits, crc_t *h) { + + unsigned long m, rmask = 0x1; + + for (m = 0; m < nbits; m++) { + if ((rmask & crc) == 0x01) + crc = (crc ^ h->polynom) >> 1; + else + crc = crc >> 1; + } + return (crc & h->crcmask); +} + +int crc_set_init(crc_t *crc_par, unsigned long crc_init_value) { + + crc_par->crcinit = crc_init_value; + if (crc_par->crcinit != (crc_par->crcinit & crc_par->crcmask)) { + printf("ERROR, invalid crcinit in crc_set_init().\n"); + return -1; + } + return 0; +} + +int crc_init(crc_t *h, unsigned int crc_poly, int crc_order) { + + // Set crc working default parameters + h->polynom = crc_poly; + h->order = crc_order; + h->crcinit = 0x00000000; + + // Compute bit masks for whole CRC and CRC high bit + h->crcmask = ((((unsigned long) 1 << (h->order - 1)) - 1) << 1) + | 1; + h->crchighbit = (unsigned long) 1 << (h->order - 1); + + // check parameters + if (h->order % 8 != 0) { + fprintf(stderr, "ERROR, invalid order=%d, it must be 8, 16, 24 or 32.\n", + h->order); + return -1; + } + + if (crc_set_init(h, h->crcinit)) { + fprintf(stderr, "Error setting CRC init word\n"); + return -1; + } + + // generate lookup table + gen_crc_table(h); + + return 0; +} + +unsigned int crc_checksum(crc_t *h, char *data, int len) { + int i, k, len8, res8, a = 0; + unsigned int crc = 0; + char *pter; + + crc_set_init(h, 0); + + // Pack bits into bytes + len8 = (len >> 3); + res8 = (len - (len8 << 3)); + if (res8 > 0) { + a = 1; + } + + // Calculate CRC + for (i = 0; i < len8 + a; i++) { + pter = (char *) (data + 8 * i); + if (i == len8) { + h->byte = 0x00; + for (k = 0; k < res8; k++) { + h->byte |= ((unsigned char) *(pter + k)) << (7 - k); + } + } else { + h->byte = (unsigned char) (unpack_bits(&pter, 8) & 0xFF); + } + crc = crctable(h); + } + + // Reverse CRC res8 positions + if (a == 1) { + crc = reversecrcbit(crc, 8 - res8, h); + } + + //Return CRC value + return crc; + +} + +/** Appends crc_order checksum bits to the buffer data. + * The buffer data must be len + crc_order bytes + */ +void crc_attach(crc_t *h, char *data, int len) { + unsigned int checksum = crc_checksum(h, data, len); + + // Add CRC + char *ptr = &data[len]; + pack_bits(checksum, &ptr, h->order); +} diff --git a/lte/lib/fec/src/parity.h b/lte/lib/fec/src/parity.h index 56689124b..dfda24f57 100644 --- a/lte/lib/fec/src/parity.h +++ b/lte/lib/fec/src/parity.h @@ -11,7 +11,7 @@ /* Determine parity of argument: 1 = odd, 0 = even */ #ifdef __i386__ static inline int parityb(unsigned char x){ - __asm__ __volatile__ ("test %1,%1;setpo %0" : "=g"(x) : "r" (x)); + __asm__ __volatile__ ("test %1,%1;setpo %0" : "=qhm" (x) : "qh" (x)); return x; } #else diff --git a/lte/lib/ratematching/src/rm_conv.c b/lte/lib/fec/src/rm_conv.c similarity index 83% rename from lte/lib/ratematching/src/rm_conv.c rename to lte/lib/fec/src/rm_conv.c index 3694f4e02..d8270d243 100644 --- a/lte/lib/ratematching/src/rm_conv.c +++ b/lte/lib/fec/src/rm_conv.c @@ -28,20 +28,20 @@ #include #include -#include "lte/ratematching/rm_conv.h" +#include "lte/fec/rm_conv.h" #define NCOLS 32 #define NROWS_MAX NCOLS #define RATE 3 -unsigned char RM_PERM_CC[NCOLS] = +unsigned char RM_PERM_TC[NCOLS] = { 1, 17, 9, 25, 5, 21, 13, 29, 3, 19, 11, 27, 7, 23, 15, 31, 0, 16, 8, 24, 4, 20, 12, 28, 2, 18, 10, 26, 6, 22, 14, 30 }; -unsigned char RM_PERM_CC_INV[NCOLS] = { 16, 0, 24, 8, 20, 4, 28, 12, 18, 2, 26, +unsigned char RM_PERM_TC_INV[NCOLS] = { 16, 0, 24, 8, 20, 4, 28, 12, 18, 2, 26, 10, 22, 6, 30, 14, 17, 1, 25, 9, 21, 5, 29, 13, 19, 3, 27, 11, 23, 7, 31, 15 }; -int rm_conv_tx(char *input, char *output, int in_len, int out_len) { +int rm_conv_tx(char *input, int in_len, char *output, int out_len) { char tmp[RATE * NCOLS * NROWS_MAX]; int nrows, ndummy, K_p; @@ -59,19 +59,21 @@ int rm_conv_tx(char *input, char *output, int in_len, int out_len) { if (ndummy < 0) { ndummy = 0; } + /* Sub-block interleaver 5.1.4.2.1 */ k=0; for (s = 0; s < 3; s++) { for (j = 0; j < NCOLS; j++) { for (i = 0; i < nrows; i++) { - if (i*NCOLS + RM_PERM_CC[j] < ndummy) { + if (i*NCOLS + RM_PERM_TC[j] < ndummy) { tmp[k] = TX_NULL; } else { - tmp[k] = input[(i*NCOLS + RM_PERM_CC[j]-ndummy)*3+s]; + tmp[k] = input[(i*NCOLS + RM_PERM_TC[j]-ndummy)*3+s]; } k++; } } } + /* Bit collection, selection and transmission 5.1.4.2.2 */ k = 0; j = 0; while (k < out_len) { @@ -91,7 +93,7 @@ int rm_conv_tx(char *input, char *output, int in_len, 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, float *output, int in_len, int out_len) { +int rm_conv_rx(float *input, int in_len, float *output, int out_len) { int nrows, ndummy, K_p; int i, j, k; @@ -123,7 +125,7 @@ int rm_conv_rx(float *input, float *output, int in_len, int out_len) { d_i = (j % K_p) / nrows; d_j = (j % K_p) % nrows; - if (d_j * NCOLS + RM_PERM_CC[d_i] >= ndummy) { + if (d_j * NCOLS + RM_PERM_TC[d_i] >= ndummy) { if (tmp[j] == RX_NULL) { tmp[j] = input[k]; } else if (input[k] != RX_NULL) { @@ -142,8 +144,13 @@ int rm_conv_rx(float *input, float *output, int in_len, int out_len) { d_i = (i + ndummy) / NCOLS; d_j = (i + ndummy) % NCOLS; for (j = 0; j < RATE; j++) { - output[i * RATE + j] = tmp[K_p * j + RM_PERM_CC_INV[d_j] * nrows - + d_i]; + float o = tmp[K_p * j + RM_PERM_TC_INV[d_j] * nrows + + d_i]; + if (o != RX_NULL) { + output[i * RATE + j] = o; + } else { + output[i * RATE + j] = 0; + } } } return 0; diff --git a/lte/lib/fec/src/rm_turbo.c b/lte/lib/fec/src/rm_turbo.c new file mode 100644 index 000000000..d057eb9df --- /dev/null +++ b/lte/lib/fec/src/rm_turbo.c @@ -0,0 +1,262 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * A copy of the GNU Lesser General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#include +#include +#include +#include +#include + +#include "lte/fec/rm_turbo.h" + +#define NCOLS 32 +#define NROWS_MAX NCOLS +#define RATE 3 + +unsigned char RM_PERM_TC[NCOLS] = + { 0, 16, 8, 24, 4, 20, 12, 28, 2, 18, 10, 26, 6, 22, 14, 30, 1, 17, 9, + 25, 5, 21, 13, 29, 3, 19, 11, 27, 7, 23, 15, 31 }; + +int rm_turbo_init(rm_turbo_t *q, int buffer_len) { + q->buffer_len = buffer_len; + q->buffer = malloc(buffer_len * sizeof(float)); + if (!q->buffer) { + perror("malloc"); + return -1; + } + q->d2_perm = malloc(buffer_len * sizeof(int) / 3 + 1); + if (!q->d2_perm) { + 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 + * + * 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) { + + char *tmp = (char*) q->buffer; + int nrows, ndummy, K_p; + + int i, j, k, s, kidx, N_cb, k0; + + nrows = (int) (in_len / RATE - 1) / NCOLS + 1; + K_p = nrows * NCOLS; + if (3 * K_p > q->buffer_len) { + fprintf(stderr, + "Input too large. Max input length including dummy bits is %d\n", + q->buffer_len); + return -1; + } + + ndummy = K_p - in_len / RATE; + if (ndummy < 0) { + 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 (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]; + } + } + + /* Bit selection and transmission 5.1.4.1.2 */ + N_cb = 3 * K_p; // TODO: Soft buffer size limitation + + k0 = nrows * (2 * (int) ceilf((float) N_cb / (float) (8 * nrows)) + * rv_idx + 2); + k = 0; + j = 0; + + while (k < out_len) { + if (tmp[(k0 + j) % N_cb] != TX_NULL) { + output[k] = tmp[(k0 + j) % N_cb]; + k++; + } + j++; + } + return 0; +} + +/* 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 nrows, ndummy, K_p, k0, N_cb, jp, kidx; + int i, j, k; + int d_i, d_j; + bool isdummy; + + float *tmp = (float*) q->buffer; + + nrows = (int) (out_len / RATE - 1) / NCOLS + 1; + K_p = nrows * NCOLS; + if (3 * K_p > q->buffer_len) { + fprintf(stderr, + "Input too large. Max input length including dummy bits is %d\n", + q->buffer_len); + return -1; + } + + ndummy = K_p - out_len / RATE; + if (ndummy < 0) { + ndummy = 0; + } + + for (i = 0; i < RATE * K_p; i++) { + tmp[i] = RX_NULL; + } + + /* Undo bit collection. Account for dummy bits */ + N_cb = 3 * K_p; // TODO: Soft buffer size limitation + k0 = nrows * (2 * (int) ceilf((float) N_cb / (float) (8 * nrows)) + * rv_idx + 2); + k = 0; + j = 0; + while (k < in_len) { + jp = (k0 + j) % N_cb; + + if (jp == 32 || jp == 95 || jp == 0) { + i=0; + } + + if (jp < K_p || !(jp%2)) { + if (jp >= K_p) { + d_i = ((jp-K_p) / 2) / nrows; + d_j = ((jp-K_p) / 2) % nrows; + } else { + d_i = jp / nrows; + d_j = jp % nrows; + } + if (d_j * NCOLS + RM_PERM_TC[d_i] >= ndummy) { + isdummy = false; + } else { + isdummy = true; + } + } else { + int jpp = (jp-K_p-1)/2; + kidx = (RM_PERM_TC[jpp / nrows] + NCOLS * (jpp % nrows) + 1) % K_p; + q->d2_perm[kidx] = jpp; // save the permutation in a temporary buffer + if ((kidx - ndummy) < 0) { + isdummy = true; + } else { + isdummy = false; + } + } + + if (!isdummy) { + if (tmp[jp] == RX_NULL) { + tmp[jp] = input[k]; + } else if (input[k] != RX_NULL) { + tmp[jp] += input[k]; /* soft combine LLRs */ + } + k++; + } + j++; + } + + /* interleaving and bit selection */ + for (i = 0; i < out_len / RATE; i++) { + d_i = (i + ndummy) / NCOLS; + d_j = (i + ndummy) % NCOLS; + for (j = 0; j < RATE; j++) { + if (j != 2) { + kidx = K_p * j + (j+1)*(RM_PERM_TC[d_j] * nrows + d_i); + } else { + // use the saved permuatation function to avoid computing the inverse + kidx = 2*q->d2_perm[(i+ndummy)%K_p]+K_p+1; + } + float o = tmp[kidx]; + if (o != RX_NULL) { + output[i * RATE + j] = o; + } else { + output[i * RATE + j] = 0; + } + } + } + return 0; +} + + +/** High-level API */ + +int rm_turbo_initialize(rm_turbo_hl* h) { + return rm_turbo_init(&h->q, 7000); +} + +/** 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/lib/fec/src/tc_interl_lte.c b/lte/lib/fec/src/tc_interl_lte.c new file mode 100644 index 000000000..1db75cf92 --- /dev/null +++ b/lte/lib/fec/src/tc_interl_lte.c @@ -0,0 +1,117 @@ +/** + * + * \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 "lte/common/base.h" +#include "lte/fec/tc_interl.h" +#include "lte/fec/turbocoder.h" +#include "lte/utils/debug.h" + +/************************************************ + * + * LTE TURBO CODE INTERLEAVER + * + ************************************************/ + +const int f1_list[NOF_TC_CB_SIZES] = { 3, 7, 19, 7, 7, 11, 5, 11, 7, 41, 103, 15, 9, 17, + 9, 21, 101, 21, 57, 23, 13, 27, 11, 27, 85, 29, 33, 15, 17, 33, 103, 19, + 19, 37, 19, 21, 21, 115, 193, 21, 133, 81, 45, 23, 243, 151, 155, 25, + 51, 47, 91, 29, 29, 247, 29, 89, 91, 157, 55, 31, 17, 35, 227, 65, 19, + 37, 41, 39, 185, 43, 21, 155, 79, 139, 23, 217, 25, 17, 127, 25, 239, + 17, 137, 215, 29, 15, 147, 29, 59, 65, 55, 31, 17, 171, 67, 35, 19, 39, + 19, 199, 21, 211, 21, 43, 149, 45, 49, 71, 13, 17, 25, 183, 55, 127, 27, + 29, 29, 57, 45, 31, 59, 185, 113, 31, 17, 171, 209, 253, 367, 265, 181, + 39, 27, 127, 143, 43, 29, 45, 157, 47, 13, 111, 443, 51, 51, 451, 257, + 57, 313, 271, 179, 331, 363, 375, 127, 31, 33, 43, 33, 477, 35, 233, + 357, 337, 37, 71, 71, 37, 39, 127, 39, 39, 31, 113, 41, 251, 43, 21, 43, + 45, 45, 161, 89, 323, 47, 23, 47, 263 }; + +const int f2_list[NOF_TC_CB_SIZES] = { 10, 12, 42, 16, 18, 20, 22, 24, 26, 84, 90, 32, + 34, 108, 38, 120, 84, 44, 46, 48, 50, 52, 36, 56, 58, 60, 62, 32, 198, + 68, 210, 36, 74, 76, 78, 120, 82, 84, 86, 44, 90, 46, 94, 48, 98, 40, + 102, 52, 106, 72, 110, 168, 114, 58, 118, 180, 122, 62, 84, 64, 66, 68, + 420, 96, 74, 76, 234, 80, 82, 252, 86, 44, 120, 92, 94, 48, 98, 80, 102, + 52, 106, 48, 110, 112, 114, 58, 118, 60, 122, 124, 84, 64, 66, 204, 140, + 72, 74, 76, 78, 240, 82, 252, 86, 88, 60, 92, 846, 48, 28, 80, 102, 104, + 954, 96, 110, 112, 114, 116, 354, 120, 610, 124, 420, 64, 66, 136, 420, + 216, 444, 456, 468, 80, 164, 504, 172, 88, 300, 92, 188, 96, 28, 240, + 204, 104, 212, 192, 220, 336, 228, 232, 236, 120, 244, 248, 168, 64, + 130, 264, 134, 408, 138, 280, 142, 480, 146, 444, 120, 152, 462, 234, + 158, 80, 96, 902, 166, 336, 170, 86, 174, 176, 178, 120, 182, 184, 186, + 94, 190, 480 }; + +int tc_interl_LTE_init(tc_interl_t *h, int long_cb) { + int cb_table_idx, f1, f2; + unsigned long long i, j; + + cb_table_idx = lte_find_cb_index(long_cb); + if (cb_table_idx == -1) { + fprintf(stderr, "Can't find long_cb=%d in valid TC CB table\n", long_cb); + return -1; + } + + h->forward = h->reverse = NULL; + h->forward = malloc(sizeof(int) * (long_cb)); + if (!h->forward) { + return -1; + } + h->reverse = malloc(sizeof(int) * (long_cb)); + if (!h->reverse) { + perror("malloc"); + free(h->forward); + h->forward = h->reverse = NULL; + return -1; + } + + f1 = f1_list[cb_table_idx]; + f2 = f2_list[cb_table_idx]; + + DEBUG("table_idx: %d, f1: %d, f2: %d\n", cb_table_idx, f1, f2); + + h->forward[0] = 0; + 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; + } + return 0; + +} + + + + + + + + + + + diff --git a/lte/lib/fec/src/tc_interl_umts.c b/lte/lib/fec/src/tc_interl_umts.c new file mode 100644 index 000000000..a71d2f0e0 --- /dev/null +++ b/lte/lib/fec/src/tc_interl_umts.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 "lte/fec/tc_interl.h" +#include "lte/fec/turbocoder.h" + +#define TURBO_RATE 3 + +int mcd(int x, int y); + +/************************************************ + * + * UMTS TURBO CODE INTERLEAVER + * + ************************************************/ + +#define MAX_ROWS 20 +#define MAX_COLS 256 + +const unsigned short table_p[52] = { 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, + 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, + 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, + 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257 }; +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 }; + +void tc_interl_free(tc_interl_t *h) { + if (h->forward) { + free(h->forward); + } + if (h->reverse) { + free(h->reverse); + } + h->forward = h->reverse = NULL; +} + +int tc_interl_UMTS_init(tc_interl_t *h, int 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; + + h->forward = h->reverse = NULL; + h->forward = malloc(sizeof(int) * (long_cb)); + if (!h->forward) { + return -1; + } + h->reverse = malloc(sizeof(int) * (long_cb)); + if (!h->reverse) { + perror("malloc"); + free(h->forward); + h->forward = h->reverse = NULL; + return -1; + } + M_long = long_cb; + + /* Find R*/ + if ((40 <= M_long) && (M_long <= 159)) + M_Rows = 5; + else if (((160 <= M_long) && (M_long <= 200)) + || ((481 <= M_long) && (M_long <= 530))) + M_Rows = 10; + else + M_Rows = 20; + + /* Find p i v*/ + if ((481 <= M_long) && (M_long <= 530)) { + p = 53; + v = 2; + M_Cols = p; + } else { + i = 0; + do { + p = table_p[i]; + v = table_v[i]; + i++; + } while (M_long > (M_Rows * (p + 1))); + + } + + /* Find C*/ + if ((M_long) <= (M_Rows) * ((p) - 1)) + M_Cols = (p) - 1; + else if (((M_Rows) * (p - 1) < M_long) && (M_long <= (M_Rows) * (p))) + M_Cols = p; + else if ((M_Rows) * (p) < M_long) + M_Cols = (p) + 1; + + q[0] = 1; + prim = 6; + + for (i = 1; i < M_Rows; i++) { + do { + prim++; + res = mcd(prim, p - 1); + } while (res != 1); + q[i] = prim; + } + + s[0] = 1; + for (i = 1; i < p - 1; i++) { + s[i] = (v * s[i - 1]) % p; + } + + if (M_long <= 159 && M_long >= 40) { + T[0] = 4; + T[1] = 3; + T[2] = 2; + T[3] = 1; + T[4] = 0; + } else if ((M_long <= 200 && M_long >= 160) + || (M_long <= 530 && M_long >= 481)) { + T[0] = 9; + T[1] = 8; + T[2] = 7; + T[3] = 6; + T[4] = 5; + T[5] = 4; + T[6] = 3; + T[7] = 2; + T[8] = 1; + T[9] = 0; + } else if ((M_long <= 2480 && M_long >= 2281) + || (M_long <= 3210 && M_long >= 3161)) { + T[0] = 19; + T[1] = 9; + T[2] = 14; + T[3] = 4; + T[4] = 0; + T[5] = 2; + T[6] = 5; + T[7] = 7; + T[8] = 12; + T[9] = 18; + T[10] = 16; + T[11] = 13; + T[12] = 17; + T[13] = 15; + T[14] = 3; + T[15] = 1; + T[16] = 6; + T[17] = 11; + T[18] = 8; + T[19] = 10; + } else { + T[0] = 19; + T[1] = 9; + T[2] = 14; + T[3] = 4; + T[4] = 0; + T[5] = 2; + T[6] = 5; + T[7] = 7; + T[8] = 12; + T[9] = 18; + T[10] = 10; + T[11] = 8; + T[12] = 13; + T[13] = 17; + T[14] = 3; + T[15] = 1; + T[16] = 16; + T[17] = 6; + T[18] = 15; + T[19] = 11; + } + + for (i = 0; i < M_Rows; i++) { + r[T[i]] = q[i]; + } + + for (i = 0; i < M_Rows; i++) { + for (j = 0; j < p - 1; j++) { + U[i * M_Cols + j] = s[(j * r[i]) % (p - 1)]; + if (M_Cols == (p - 1)) + U[i * M_Cols + j] -= 1; + } + } + + if (M_Cols == p) { + for (i = 0; i < M_Rows; i++) + U[i * M_Cols + p - 1] = 0; + } else if (M_Cols == p + 1) { + for (i = 0; i < M_Rows; i++) { + U[i * M_Cols + p - 1] = 0; + U[i * M_Cols + p] = p; + } + if (M_long == M_Cols * M_Rows) { + aux = U[(M_Rows - 1) * M_Cols + p]; + U[(M_Rows - 1) * M_Cols + p] = U[(M_Rows - 1) * M_Cols + 0]; + U[(M_Rows - 1) * M_Cols + 0] = aux; + } + } + + per = h->forward; + desper = h->reverse; + + k = 0; + for (j = 0; j < M_Cols; j++) { + for (i = 0; i < M_Rows; i++) { + kp = T[i] * M_Cols + U[i * M_Cols + j]; + if (kp < M_long) { + desper[kp] = k; + per[k] = kp; + k++; + } + } + } + + return 0; + +} + +int mcd(int x, int y) { + int r = 1; + + while (r) { + r = x % y; + x = y; + y = r; + } + return x; +} diff --git a/lte/lib/fec/src/turbocoder.c b/lte/lib/fec/src/turbocoder.c new file mode 100644 index 000000000..4ff72df26 --- /dev/null +++ b/lte/lib/fec/src/turbocoder.c @@ -0,0 +1,134 @@ +/** + * + * \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 "lte/fec/tc_interl.h" +#include "lte/fec/turbocoder.h" + +#define NOF_REGS 3 + +int tcod_init(tcod_t *h, int long_cb) { + + if (tc_interl_LTE_init(&h->interl, long_cb)) { + return -1; + } + h->long_cb = long_cb; + return 0; +} + +void tcod_free(tcod_t *h) { + tc_interl_free(&h->interl); + h->long_cb = 0; +} + +void tcod_encode(tcod_t *h, char *input, char *output) { + + char reg1_0,reg1_1,reg1_2, reg2_0,reg2_1,reg2_2; + int i,k=0,j; + char bit; + char in,out; + int *per; + + per=h->interl.forward; + + reg1_0=0; + reg1_1=0; + reg1_2=0; + + reg2_0=0; + reg2_1=0; + reg2_2=0; + + k=0; + for (i=0;ilong_cb;i++) { + bit=input[i]; + + output[k]=bit; + k++; + + in=bit^(reg1_2^reg1_1); + out=reg1_2^(reg1_0^in); + + reg1_2=reg1_1; + reg1_1=reg1_0; + reg1_0=in; + + output[k]=out; + k++; + + bit=input[per[i]]; + + in=bit^(reg2_2^reg2_1); + out=reg2_2^(reg2_0^in); + + reg2_2=reg2_1; + reg2_1=reg2_0; + reg2_0=in; + + output[k]=out; + k++; + } + + k=3*h->long_cb; + + /* TAILING CODER #1 */ + for (j=0;j +#include +#include +#include + +#include "lte/fec/tc_interl.h" +#include "lte/fec/turbodecoder.h" + +/************************************************ + * + * MAP_GEN is the MAX-LOG-MAP generic implementation of the + * Decoder + * + ************************************************/ +void map_gen_beta(map_gen_t *s, llr_t *input, llr_t *parity) { + llr_t m_b[8], new[8], old[8]; + llr_t x, y, xy; + int k; + int end = s->long_cb + RATE; + llr_t *beta = s->beta; + int i; + + for (i=0;i<8;i++) { + old[i] = beta[8 * (end) + i]; + } + + for (k = end - 1; k >= 0; k--) { + x = input[k]; + y = parity[k]; + + xy = x + y; + + m_b[0] = old[4] + xy; + m_b[1] = old[4]; + m_b[2] = old[5] + y; + m_b[3] = old[5] + x; + m_b[4] = old[6] + x; + m_b[5] = old[6] + y; + m_b[6] = old[7]; + m_b[7] = old[7] + xy; + + new[0] = old[0]; + new[1] = old[0] + xy; + new[2] = old[1] + x; + new[3] = old[1] + y; + new[4] = old[2] + y; + new[5] = old[2] + x; + new[6] = old[3] + xy; + new[7] = old[3]; + + for (i=0;i<8;i++) { + if (m_b[i] > new[i]) + new[i] = m_b[i]; + beta[8 * k + i] = new[i]; + old[i] = new[i]; + } + } +} + +void map_gen_alpha(map_gen_t *s, llr_t *input, llr_t *parity, llr_t *output) { + llr_t m_b[8], new[8], old[8], max1[8], max0[8]; + llr_t m1, m0; + llr_t x, y, xy; + llr_t out; + int k; + int end = s->long_cb; + llr_t *beta = s->beta; + int i; + + old[0] = 0; + for (i=1;i<8;i++) { + old[i] = -INF; + } + + for (k = 1; k < end + 1; k++) { + x = input[k - 1]; + y = parity[k - 1]; + + xy = x + y; + + m_b[0] = old[0]; + m_b[1] = old[3] + y; + m_b[2] = old[4] + y; + m_b[3] = old[7]; + m_b[4] = old[1]; + m_b[5] = old[2] + y; + m_b[6] = old[5] + y; + m_b[7] = old[6]; + + new[0] = old[1] + xy; + new[1] = old[2] + x; + new[2] = old[5] + x; + new[3] = old[6] + xy; + new[4] = old[0] + xy; + new[5] = old[3] + x; + new[6] = old[4] + x; + new[7] = old[7] + xy; + + for (i=0;i<8;i++) { + max0[i] = m_b[i] + beta[8 * k + i]; + max1[i] = new[i] + beta[8 * k + i]; + } + + m1 = max1[0]; + m0 = max0[0]; + + for (i=1;i<8;i++) { + if (max1[i] > m1) + m1 = max1[i]; + if (max0[i] > m0) + m0 = max0[i]; + } + + for (i=0;i<8;i++) { + if (m_b[i] > new[i]) + new[i] = m_b[i]; + old[i] = new[i]; + } + + out = m1 - m0; + output[k - 1] = out; + } +} + +int map_gen_init(map_gen_t *h, int long_cb) { + bzero(h, sizeof(map_gen_t)); + h->beta = malloc(sizeof(llr_t) * (long_cb + TOTALTAIL + 1)* NUMSTATES); + if (!h->beta) { + perror("malloc"); + return -1; + } + h->long_cb = long_cb; + return 0; +} + +void map_gen_free(map_gen_t *h) { + if (h->beta) { + free(h->beta); + } + bzero(h, sizeof(map_gen_t)); +} + +void map_gen_dec(map_gen_t *h, llr_t *input, llr_t *parity, llr_t *output) { + int k; + + h->beta[(h->long_cb + TAIL) * NUMSTATES] = 0; + for (k = 1; k < NUMSTATES; k++) + h->beta[(h->long_cb + TAIL) * NUMSTATES + k] = -INF; + + map_gen_beta(h, input, parity); + map_gen_alpha(h, input, parity, output); +} + + + + + + + + + +/************************************************ + * + * TURBO DECODER INTERFACE + * + ************************************************/ +int tdec_init(tdec_t *h, int long_cb) { + int ret = -1; + bzero(h, sizeof(tdec_t)); + int len = long_cb + TOTALTAIL; + + h->llr1 = malloc(sizeof(llr_t) * len); + if (!h->llr1) { + perror("malloc"); + goto clean_and_exit; + } + h->llr2 = malloc(sizeof(llr_t) * len); + if (!h->llr2) { + perror("malloc"); + goto clean_and_exit; + } + h->w = malloc(sizeof(llr_t) * len); + if (!h->w) { + perror("malloc"); + goto clean_and_exit; + } + h->syst = malloc(sizeof(llr_t) * len); + if (!h->syst) { + perror("malloc"); + goto clean_and_exit; + } + h->parity = malloc(sizeof(llr_t) * len); + if (!h->parity) { + perror("malloc"); + goto clean_and_exit; + } + + if (map_gen_init(&h->dec, long_cb)) { + goto clean_and_exit; + } + + h->long_cb = long_cb; + + if (tc_interl_LTE_init(&h->interleaver, h->long_cb) < 0) { + goto clean_and_exit; + } + + ret = 0; +clean_and_exit: + if (ret == -1) { + tdec_free(h); + } + return ret; +} + +void tdec_free(tdec_t *h) { + if (h->llr1) { + free(h->llr1); + } + if (h->llr2) { + free(h->llr2); + } + if (h->w) { + free(h->w); + } + if (h->syst) { + free(h->syst); + } + if (h->parity) { + free(h->parity); + } + + map_gen_free(&h->dec); + + tc_interl_free(&h->interleaver); + + bzero(h, sizeof(tdec_t)); +} + +void tdec_iteration(tdec_t *h, llr_t *input) { + int i; + + // Prepare systematic and parity bits for MAP DEC #1 + for (i = 0; i < h->long_cb; i++) { + h->syst[i] = input[RATE * i] + h->w[i]; + h->parity[i] = input[RATE * i + 1]; + } + for (i=h->long_cb;ilong_cb+RATE;i++) { + h->syst[i] = input[RATE * h->long_cb + NINPUTS * (i - h->long_cb)]; + h->parity[i] = input[RATE * h->long_cb + NINPUTS * (i - h->long_cb) + 1]; + } + + // Run MAP DEC #1 + map_gen_dec(&h->dec, h->syst, h->parity, h->llr1); + + // Prepare systematic and parity bits for MAP DEC #1 + for (i = 0; i < h->long_cb; i++) { + h->syst[i] = h->llr1[h->interleaver.forward[i]] - h->w[h->interleaver.forward[i]]; + h->parity[i] = input[RATE * i + 2]; + } + for (i=h->long_cb;ilong_cb+RATE;i++) { + h->syst[i] = input[RATE * h->long_cb + NINPUTS * RATE + NINPUTS * (i - h->long_cb)]; + h->parity[i] = input[RATE * h->long_cb + NINPUTS * RATE + NINPUTS * (i - h->long_cb) + 1]; + } + + // Run MAP DEC #1 + map_gen_dec(&h->dec, h->syst, h->parity, h->llr2); + + // Update a-priori LLR from the last iteration + for (i = 0; i < h->long_cb; i++) { + h->w[i] += h->llr2[h->interleaver.reverse[i]] - h->llr1[i]; + } + +} + +void tdec_reset(tdec_t *h) { + memset(h->w, 0, sizeof(llr_t) * h->long_cb); +} + +void tdec_decision(tdec_t *h, char *output) { + int i; + for (i = 0; i < h->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 iter = 0; + + tdec_reset(h); + + do { + tdec_iteration(h, input); + iter++; + } while (iter < nof_iterations); + + tdec_decision(h, output); +} + diff --git a/lte/lib/fec/test/CMakeLists.txt b/lte/lib/fec/test/CMakeLists.txt index 72768b3b2..1d0cc28bb 100644 --- a/lte/lib/fec/test/CMakeLists.txt +++ b/lte/lib/fec/test/CMakeLists.txt @@ -19,6 +19,32 @@ # and at http://www.gnu.org/licenses/. # + +######################################################################## +# RATEMATCHING TEST +######################################################################## + +ADD_EXECUTABLE(rm_conv_test rm_conv_test.c) +TARGET_LINK_LIBRARIES(rm_conv_test lte) + +ADD_EXECUTABLE(rm_turbo_test rm_turbo_test.c) +TARGET_LINK_LIBRARIES(rm_turbo_test lte) + +ADD_TEST(rm_conv_test_1 rm_conv_test -t 480 -r 1920) +ADD_TEST(rm_conv_test_2 rm_conv_test -t 1920 -r 480) + + +######################################################################## +# Turbo Coder TEST +######################################################################## +ADD_EXECUTABLE(turbocoder_test turbocoder_test.c) +TARGET_LINK_LIBRARIES(turbocoder_test lte) + +ADD_TEST(turbocoder_test_504_1 turbocoder_test -n 100 -s 1 -l 504 -e 1.0 -t) +ADD_TEST(turbocoder_test_504_2 turbocoder_test -n 100 -s 1 -l 504 -e 2.0 -t) +ADD_TEST(turbocoder_test_6114_1_5 turbocoder_test -n 100 -s 1 -l 6144 -e 1.5 -t) +ADD_TEST(turbocoder_test_known turbocoder_test -n 1 -s 1 -k -e 0.5) + ######################################################################## # Viterbi TEST ######################################################################## @@ -43,9 +69,9 @@ ADD_TEST(viterbi_1000_4 viterbi_test -n 100 -s 1 -l 1000 -k 7 -t -e 4.5) ADD_EXECUTABLE(crc_test crc_test.c) TARGET_LINK_LIBRARIES(crc_test lte) -ADD_TEST(crc_24A crc_test -n 5000 -l 24 -p 0x1864CFB -s 1) -ADD_TEST(crc_24B crc_test -n 5000 -l 24 -p 0x1800063 -s 1) -ADD_TEST(crc_16 crc_test -n 5000 -l 16 -p 0x11021 -s 1) -ADD_TEST(crc_8 crc_test -n 5000 -l 8 -p 0x19B -s 1) +ADD_TEST(crc_24A crc_test -n 5001 -l 24 -p 0x1864CFB -s 1) +ADD_TEST(crc_24B crc_test -n 5001 -l 24 -p 0x1800063 -s 1) +ADD_TEST(crc_16 crc_test -n 5001 -l 16 -p 0x11021 -s 1) +ADD_TEST(crc_8 crc_test -n 5001 -l 8 -p 0x19B -s 1) diff --git a/lte/lib/fec/test/crc_test.c b/lte/lib/fec/test/crc_test.c index da2f1dfb3..e21c89c4d 100644 --- a/lte/lib/fec/test/crc_test.c +++ b/lte/lib/fec/test/crc_test.c @@ -25,7 +25,6 @@ * */ - #include #include #include @@ -35,13 +34,11 @@ #include #include "lte.h" - #include "crc_test.h" -int num_bits = 1000, crc_length = 16; -unsigned int crc_poly = 0x11021; -unsigned int seed = 0; - +int num_bits = 5001, crc_length = 24; +unsigned int crc_poly = 0x1864CFB; +unsigned int seed = 1; void usage(char *prog) { printf("Usage: %s [nlps]\n", prog); @@ -78,10 +75,11 @@ int main(int argc, char **argv) { int i; char *data; unsigned int crc_word, expected_word; + crc_t crc_p; parse_args(argc, argv); - data = malloc(sizeof(char) * (num_bits+crc_length)); + data = malloc(sizeof(char) * (num_bits + crc_length * 2)); if (!data) { perror("malloc"); exit(-1); @@ -93,25 +91,23 @@ int main(int argc, char **argv) { srand(seed); // Generate data - for (i=0;i +#include +#include +#include +#include +#include +#include +#include + +#include "lte.h" + +int nof_tx_bits=-1, nof_rx_bits=-1; +int rv_idx = 0; + +void usage(char *prog) { + printf("Usage: %s -t nof_tx_bits -r nof_rx_bits [-i rv_idx]\n", prog); +} + +void parse_args(int argc, char **argv) { + int opt; + while ((opt = getopt(argc, argv, "tri")) != -1) { + switch (opt) { + case 't': + nof_tx_bits = atoi(argv[optind]); + break; + case 'r': + nof_rx_bits = atoi(argv[optind]); + break; + case 'i': + rv_idx = atoi(argv[optind]); + break; + default: + usage(argv[0]); + exit(-1); + } + } + if (nof_tx_bits == -1) { + usage(argv[0]); + exit(-1); + } + if (nof_rx_bits == -1) { + usage(argv[0]); + exit(-1); + } +} + +int main(int argc, char **argv) { + int i; + char *bits, *rm_bits; + float *rm_symbols, *unrm_symbols; + int nof_errors; + rm_turbo_t rm_turbo; + + parse_args(argc, argv); + + bits = malloc(sizeof(char) * nof_tx_bits); + if (!bits) { + perror("malloc"); + exit(-1); + } + rm_bits = malloc(sizeof(char) * nof_rx_bits); + if (!rm_bits) { + perror("malloc"); + exit(-1); + } + rm_symbols = malloc(sizeof(float) * nof_rx_bits); + if (!rm_symbols) { + perror("malloc"); + exit(-1); + } + unrm_symbols = malloc(sizeof(float) * nof_tx_bits); + if (!unrm_symbols) { + perror("malloc"); + exit(-1); + } + + for (i=0;i 0) != bits[i]) { + nof_errors++; + printf("%.2f != %d\n", unrm_symbols[i], bits[i]); + } + } + + rm_turbo_free(&rm_turbo); + + free(bits); + free(rm_bits); + free(rm_symbols); + free(unrm_symbols); + + if (nof_tx_bits >= nof_rx_bits) { + if (nof_errors) { + printf("nof_errors=%d\n", nof_errors); + exit(-1); + } + } + + printf("Ok\n"); + exit(0); +} diff --git a/lte/lib/fec/test/turbocoder_test.c b/lte/lib/fec/test/turbocoder_test.c new file mode 100644 index 000000000..ad28ee470 --- /dev/null +++ b/lte/lib/fec/test/turbocoder_test.c @@ -0,0 +1,324 @@ +/** + * + * \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 "lte.h" + +#include "turbocoder_test.h" + +typedef _Complex float cf_t; + +int frame_length = 1000, nof_frames=100; +float ebno_db = 100.0; +unsigned int seed = 0; +int K = -1; + +#define MAX_ITERATIONS 4 +int nof_iterations = MAX_ITERATIONS; +int test_known_data = 0; +int test_errors = 0; + +#define SNR_POINTS 8 +#define SNR_MIN 0.0 +#define SNR_MAX 4.0 + +void usage(char *prog) { + printf("Usage: %s [nlesv]\n", prog); + printf("\t-k Test with known data (ignores frame_length) [Default disabled]\n"); + printf("\t-i nof_iterations [Default %d]\n", nof_iterations); + printf("\t-n nof_frames [Default %d]\n", nof_frames); + printf("\t-l frame_length [Default %d]\n", frame_length); + printf("\t-e ebno in dB [Default scan]\n"); + printf("\t-t test: check errors on exit [Default disabled]\n"); + printf("\t-s seed [Default 0=time]\n"); +} + +void parse_args(int argc, char **argv) { + int opt; + while ((opt = getopt(argc, argv, "inlstvekt")) != -1) { + switch (opt) { + case 'n': + nof_frames = atoi(argv[optind]); + break; + case 'k': + test_known_data = 1; + break; + case 't': + test_errors = 1; + break; + case 'i': + nof_iterations = atoi(argv[optind]); + break; + case 'l': + frame_length = atoi(argv[optind]); + break; + case 'e': + ebno_db = atof(argv[optind]); + break; + case 's': + seed = (unsigned int) strtoul(argv[optind], NULL, 0); + break; + case 'v': + verbose++; + break; + default: + usage(argv[0]); + exit(-1); + } + } +} + +void output_matlab(float ber[MAX_ITERATIONS][SNR_POINTS], int snr_points) { + int i, j; + FILE *f = fopen("turbocoder_snr.m", "w"); + if (!f) { + perror("fopen"); + exit(-1); + } + fprintf(f, "ber=["); + for (j=0;j known_data_errors[j]) { + fprintf(stderr, "Expected %d errors but got %d\n", + known_data_errors[j], errors[j]); + exit(-1); + }else { + printf("Iter %d ok\n", j+1); + } + } + } else { + for (j=0;j get_expected_errors(frame_cnt, seed, j+1, frame_length, ebno_db)) { + fprintf(stderr, "Expected %d errors but got %d\n", + get_expected_errors(frame_cnt, seed, j+1, frame_length, ebno_db), + errors[j]); + exit(-1); + } else { + printf("Iter %d ok\n", j+1); + } + } + } + } + } + } + + free(data_tx); + free(symbols); + free(llr); + free(llr_c); + free(data_rx); + + tdec_free(&tdec); + tcod_free(&tcod); + + printf("\n"); + output_matlab(ber, snr_points); + printf("Done\n"); + exit(0); +} diff --git a/lte/lib/fec/test/turbocoder_test.h b/lte/lib/fec/test/turbocoder_test.h new file mode 100644 index 000000000..768f5406b --- /dev/null +++ b/lte/lib/fec/test/turbocoder_test.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/. + * + */ + +#include + +typedef struct { + int n; + unsigned int s; + int iterations; + int len; + float ebno; + int errors; +} expected_errors_t; + +static expected_errors_t expected_errors[] = { + { 100, 1, 1, 504, 1.0, 3989 }, + { 100, 1, 2, 504, 1.0, 1922 }, + { 100, 1, 3, 504, 1.0, 1096 }, + { 100, 1, 4, 504, 1.0, 957 }, + + { 100, 1, 1, 504, 2.0, 803 }, + { 100, 1, 2, 504, 2.0, 47 }, + { 100, 1, 3, 504, 2.0, 7 }, + { 100, 1, 4, 504, 2.0, 0 }, + + { 100, 1, 1, 6144, 1.5, 24719 }, + { 100, 1, 2, 6144, 1.5, 897 }, + { 100, 1, 3, 6144, 1.5, 2 }, + { 100, 1, 4, 6144, 1.5, 0 }, + { -1, 0, -1, -1, -1.0, -1} +}; + + +int get_expected_errors(int n, unsigned int s, int iterations, int len, float ebno) { + int i; + i = 0; + while (expected_errors[i].n != -1) { + if (expected_errors[i].n == n + && expected_errors[i].s == s + && expected_errors[i].len == len + && expected_errors[i].iterations == iterations + && expected_errors[i].ebno == ebno) { + break; + } else { + i++; + } + } + return expected_errors[i].errors; +} + +#define KNOWN_DATA_NFRAMES 1 +#define KNOWN_DATA_SEED 1 +#define KNOWN_DATA_EBNO 0.5 +const int known_data_errors[4] = {47, 18, 0, 0}; + +#define KNOWN_DATA_LEN 504 +const char known_data[KNOWN_DATA_LEN] = { 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, + 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, + 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, + 1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, + 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, + 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, + 1, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, + 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, + 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, + 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, + 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, + 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, + 1, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, + 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, + 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, + 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, + 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, + 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, + 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, + 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, + 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1 }; + +const char known_data_encoded[3 * KNOWN_DATA_LEN + 12] = { 0, 0, 0, 0, 0, 1, 1, + 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, + 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, + 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, + 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, + 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, + 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, + 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, + 1, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, + 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, + 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, + 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, + 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, + 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, + 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, + 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, + 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, + 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0, + 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, + 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, + 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, + 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, + 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, + 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, + 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, + 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, + 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, + 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, + 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, + 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, + 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, + 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, + 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, + 1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, + 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, + 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, + 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, + 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, + 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, + 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, + 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, + 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, + 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, + 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, + 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, + 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, + 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, + 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, + 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, + 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, + 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, + 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, + 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, + 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, + 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0, + 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, + 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, + 1, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, + 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, + 1, 0, 1, 1, 1 }; diff --git a/lte/lib/fec/test/viterbi_test.c b/lte/lib/fec/test/viterbi_test.c index e7ee9e92c..76dd14754 100644 --- a/lte/lib/fec/test/viterbi_test.c +++ b/lte/lib/fec/test/viterbi_test.c @@ -39,7 +39,7 @@ typedef _Complex float cf_t; -int frame_length = 1000, nof_slots = 128; +int frame_length = 1000, nof_frames = 128; float ebno_db = 100.0; unsigned int seed = 0; bool tail_biting = false; @@ -54,7 +54,7 @@ int K = -1; void usage(char *prog) { printf("Usage: %s [nlestk]\n", prog); - printf("\t-n nof_frames [Default %d]\n", nof_slots); + printf("\t-n nof_frames [Default %d]\n", nof_frames); printf("\t-l frame_length [Default %d]\n", frame_length); printf("\t-e ebno in dB [Default scan]\n"); printf("\t-s seed [Default 0=time]\n"); @@ -67,7 +67,7 @@ void parse_args(int argc, char **argv) { while ((opt = getopt(argc, argv, "nlstek")) != -1) { switch (opt) { case 'n': - nof_slots = atoi(argv[optind]); + nof_frames = atoi(argv[optind]); break; case 'l': frame_length = atoi(argv[optind]); @@ -254,7 +254,7 @@ int main(int argc, char **argv) { for (j = 0; j < NTYPES; j++) { errors[j] = 0; } - while (frame_cnt < nof_slots) { + while (frame_cnt < nof_frames) { /* generate data_tx */ for (j = 0; j < frame_length; j++) { @@ -291,7 +291,7 @@ int main(int argc, char **argv) { } frame_cnt++; printf("Eb/No: %3.2f %10d/%d ", - SNR_MIN + i * ebno_inc,frame_cnt,nof_slots); + SNR_MIN + i * ebno_inc,frame_cnt,nof_frames); for (n=0;n<1+ncods;n++) { printf("BER: %.2e ",(float) errors[n] / (frame_cnt * frame_length)); } @@ -324,7 +324,7 @@ int main(int argc, char **argv) { } if (snr_points == 1) { - int expected_errors = get_expected_errors(nof_slots, + int expected_errors = get_expected_errors(nof_frames, seed, frame_length, K, tail_biting, ebno_db); if (expected_errors == -1) { fprintf(stderr, "Test parameters not defined in test_results.h\n"); diff --git a/lte/lib/mimo/src/layermap.c b/lte/lib/mimo/src/layermap.c index cd685dcd0..b178b953d 100644 --- a/lte/lib/mimo/src/layermap.c +++ b/lte/lib/mimo/src/layermap.c @@ -78,7 +78,7 @@ int layermap_multiplex(cf_t *d[MAX_CODEWORDS], cf_t *x[MAX_LAYERS], int nof_cw, * Returns the number of symbols per layer (M_symb^layer in the specs) */ int layermap_type(cf_t *d[MAX_CODEWORDS], cf_t *x[MAX_LAYERS], int nof_cw, int nof_layers, - int nof_symbols[MAX_CODEWORDS], mimo_type_t type) { + int nof_symbols[MAX_CODEWORDS], lte_mimo_type_t type) { if (nof_cw > MAX_CODEWORDS) { fprintf(stderr, "Maximum number of codewords is %d (nof_cw=%d)\n", MAX_CODEWORDS, nof_cw); @@ -167,7 +167,7 @@ int layerdemap_multiplex(cf_t *x[MAX_LAYERS], cf_t *d[MAX_CODEWORDS], int nof_la * nof_symbols. Returns -1 on error */ int layerdemap_type(cf_t *x[MAX_LAYERS], cf_t *d[MAX_CODEWORDS], int nof_layers, int nof_cw, - int nof_layer_symbols, int nof_symbols[MAX_CODEWORDS], mimo_type_t type) { + int nof_layer_symbols, int nof_symbols[MAX_CODEWORDS], lte_mimo_type_t type) { if (nof_cw > MAX_CODEWORDS) { fprintf(stderr, "Maximum number of codewords is %d (nof_cw=%d)\n", MAX_CODEWORDS, nof_cw); diff --git a/lte/lib/mimo/src/precoding.c b/lte/lib/mimo/src/precoding.c index dd136a01a..8cc033233 100644 --- a/lte/lib/mimo/src/precoding.c +++ b/lte/lib/mimo/src/precoding.c @@ -85,7 +85,7 @@ int precoding_diversity(cf_t *x[MAX_LAYERS], cf_t *y[MAX_PORTS], int nof_ports, /* 36.211 v10.3.0 Section 6.3.4 */ int precoding_type(cf_t *x[MAX_LAYERS], cf_t *y[MAX_PORTS], int nof_layers, int nof_ports, int nof_symbols, - mimo_type_t type) { + lte_mimo_type_t type) { if (nof_ports > MAX_PORTS) { fprintf(stderr, "Maximum number of ports is %d (nof_ports=%d)\n", MAX_PORTS, nof_ports); @@ -177,7 +177,7 @@ int predecoding_diversity_zf(cf_t *y[MAX_PORTS], cf_t *ce[MAX_PORTS], /* 36.211 v10.3.0 Section 6.3.4 */ int predecoding_type(cf_t *y[MAX_PORTS], cf_t *ce[MAX_PORTS], - cf_t *x[MAX_LAYERS], int nof_ports, int nof_layers, int nof_symbols, mimo_type_t type) { + cf_t *x[MAX_LAYERS], int nof_ports, int nof_layers, int nof_symbols, lte_mimo_type_t type) { if (nof_ports > MAX_PORTS) { fprintf(stderr, "Maximum number of ports is %d (nof_ports=%d)\n", MAX_PORTS, nof_ports); diff --git a/lte/lib/mimo/test/layermap_test.c b/lte/lib/mimo/test/layermap_test.c index 3e60737f0..0c701cc4b 100644 --- a/lte/lib/mimo/test/layermap_test.c +++ b/lte/lib/mimo/test/layermap_test.c @@ -75,7 +75,7 @@ void parse_args(int argc, char **argv) { int main(int argc, char **argv) { int i, j, num_errors, symbols_layer; cf_t *d[MAX_CODEWORDS], *x[MAX_LAYERS], *dp[MAX_CODEWORDS]; - mimo_type_t type; + lte_mimo_type_t type; int nof_symb_cw[MAX_CODEWORDS]; int n[2]; diff --git a/lte/lib/mimo/test/precoding_test.c b/lte/lib/mimo/test/precoding_test.c index 741bbd216..e913cc512 100644 --- a/lte/lib/mimo/test/precoding_test.c +++ b/lte/lib/mimo/test/precoding_test.c @@ -78,7 +78,7 @@ int main(int argc, char **argv) { int i, j; float mse; cf_t *x[MAX_LAYERS], *r[MAX_PORTS], *y[MAX_PORTS], *h[MAX_PORTS], *xr[MAX_LAYERS]; - mimo_type_t type; + lte_mimo_type_t type; parse_args(argc, argv); diff --git a/lte/lib/modem/src/demod_soft.c b/lte/lib/modem/src/demod_soft.c index 3180ff114..3b42467e3 100644 --- a/lte/lib/modem/src/demod_soft.c +++ b/lte/lib/modem/src/demod_soft.c @@ -47,7 +47,7 @@ void demod_soft_alg_set(demod_soft_t *q, enum alg alg_type) { } void demod_soft_sigma_set(demod_soft_t *q, float sigma) { - q->sigma = sigma; + q->sigma = 2*sigma; } int demod_soft_demodulate(demod_soft_t *q, const cf_t* symbols, float* llr, int nsymbols) { diff --git a/lte/lib/phch/src/dci.c b/lte/lib/phch/src/dci.c index 30d9feb93..c66abf6e1 100644 --- a/lte/lib/phch/src/dci.c +++ b/lte/lib/phch/src/dci.c @@ -41,14 +41,14 @@ #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); +int dci_init(dci_t *q, int max_dcis) { + q->msg = calloc(sizeof(dci_msg_t), max_dcis); if (!q->msg) { perror("malloc"); return -1; } - q->nof_dcis = nof_dcis; + q->nof_dcis = 0; + q->max_dcis = max_dcis; return 0; } @@ -63,60 +63,755 @@ void dci_candidate_fprint(FILE *f, dci_candidate_t *q) { 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"); +int dci_msg_candidate_set(dci_msg_t *msg, int L, int nCCE, unsigned short rnti) { + if (L >= 0 && L <=3) { + msg->location.L = (unsigned char) L; + } else { + fprintf(stderr, "Invalid L %d\n", L); 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; + if (nCCE >= 0 && nCCE <= 87) { + msg->location.ncce = (unsigned char) nCCE; + } else { + fprintf(stderr, "Invalid nCCE %d\n", nCCE); + return -1; } + msg->location.rnti = rnti; 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 riv_nbits(int nof_prb) { + return (int) ceilf(log2f((float) nof_prb*((float) nof_prb+1)/2)); } +const int ambiguous_sizes[10] = {12, 14, 16, 20, 24, 26, 32, 40, 44, 56}; + +bool is_ambiguous_size(int size) { + int i; + for (i=0;i<10;i++) { + if (size == ambiguous_sizes[i]) { + return true; + } + } + return false; +} + + + +/********************************** + * PAYLOAD sizeof functions + * ********************************/ +int dci_format0_sizeof_(int nof_prb) { + return 1+1+riv_nbits(nof_prb)+5+1+2+3+1; +} + + +int dci_format1A_sizeof(int nof_prb) { + int n; + n = 1+1+riv_nbits(nof_prb)+5+3+1+2+2; + while(n < dci_format0_sizeof_(nof_prb)) { + n++; + } + if (is_ambiguous_size(n)) { + n++; + } + return n; +} + + int dci_format0_sizeof(int nof_prb) { - return 1+1+(int) ceilf(log2f(nof_prb*(nof_prb+1)/2))+2+3+1; + int n = dci_format0_sizeof_(nof_prb); + while (n < dci_format1A_sizeof(nof_prb)) { + n++; + } + return n; } -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_format1_sizeof(int nof_prb) { + + int n = (int) ceilf((float) nof_prb/ra_type0_P(nof_prb))+5+3+1+2+2; + if (nof_prb > 10) { + n++; + } + while(n == dci_format0_sizeof(nof_prb) + || n == dci_format1A_sizeof(nof_prb) + || is_ambiguous_size(n)) { + n++; + } + return n; } -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(int nof_prb) { + int n_vrb_dl_gap1 = ra_type2_n_vrb_dl(nof_prb, true); + int n_step = ra_type2_n_rb_step(nof_prb); + int n = + riv_nbits((int) n_vrb_dl_gap1/n_step) + 5; + if (nof_prb >= 50) { + n++; + } + return n; +} + +int dci_format_sizeof(dci_format_t format, int nof_prb) { + switch(format) { + case Format0: + return dci_format0_sizeof(nof_prb); + case Format1: + return dci_format1_sizeof(nof_prb); + case Format1A: + return dci_format1A_sizeof(nof_prb); + case Format1C: + return dci_format1C_sizeof(nof_prb); + default: + return -1; } } -int dci_format1C_sizeof() { - return 10; + + +/********************************** + * DCI Resource Allocation functions + * ********************************/ + + +/* Packs DCI format 0 data to a sequence of bits and store them in msg according + * to 36.212 5.3.3.1.1 + * + * 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) { + + /* pack bits */ + char *y = msg->data; + int n_ul_hop; + + *y++ = 0; // format differentiation + if (data->freq_hop_fl == hop_disabled) { // frequency hopping + *y++ = 0; + n_ul_hop = 0; + } else { + *y++ = 1; + if (nof_prb < 50) { + n_ul_hop = 1; // Table 8.4-1 of 36.213 + *y++ = data->freq_hop_fl & 1; + } else { + n_ul_hop = 2; // Table 8.4-1 of 36.213 + *y++ = (data->freq_hop_fl & 2) >> 1; + *y++ = data->freq_hop_fl & 1; + } + } + + /* pack RIV according to 8.1 of 36.213 */ + uint32_t riv; + if (data->type2_alloc.L_crb) { + riv = ra_type2_to_riv(data->type2_alloc.L_crb, data->type2_alloc.RB_start, nof_prb); + } else { + riv = data->type2_alloc.riv; + } + 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(mcs, &y, 5); + + *y++ = data->ndi; + + // TCP commands not implemented + *y++ = 0; + *y++ = 0; + + // DM RS not implemented + *y++ = 0; + *y++ = 0; + *y++ = 0; + + // CQI request + *y++ = data->cqi_request; + + // Padding with zeros + int n = dci_format0_sizeof(nof_prb); + while (y-msg->data < n) { + *y++ = 0; + } + msg->location.nof_bits = (y - msg->data); + return 0; } +/* 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) { + + /* pack bits */ + char *y = msg->data; + int n_ul_hop; + + /* 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; + } + if (*y++ != 0) { + fprintf(stderr, "Invalid format differentiation field value. This is Format1A\n"); + return -1; + } + if (*y++ == 0) { + data->freq_hop_fl = hop_disabled; + n_ul_hop = 0; + } else { + if (nof_prb < 50) { + n_ul_hop = 1; // Table 8.4-1 of 36.213 + data->freq_hop_fl = *y++; + } else { + n_ul_hop = 2; // Table 8.4-1 of 36.213 + data->freq_hop_fl = y[0]<<1 | y[1]; + y += 2; + } + } + /* unpack RIV according to 8.1 of 36.213 */ + uint32_t riv = bit_unpack(&y, riv_nbits(nof_prb) - n_ul_hop); + ra_type2_from_riv(riv, &data->type2_alloc.L_crb, &data->type2_alloc.RB_start, nof_prb, nof_prb); + bit_pack(riv, &y, riv_nbits(nof_prb) - n_ul_hop); + data->type2_alloc.riv = riv; + + /* unpack MCS according to 8.6 of 36.213 */ + uint32_t mcs = bit_unpack(&y, 5); + + data->ndi = *y++?true:false; + + // TCP and DM RS commands not implemented + y+= 5; + + // CQI request + 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; + } + + return 0; +} + +/* Packs DCI format 1 data to a sequence of bits and store them in msg according + * to 36.212 5.3.3.1.2 + * + * TODO: TPC commands + */ + +int dci_format1_pack(ra_pdsch_t *data, dci_msg_t *msg, int nof_prb) { + + /* pack bits */ + char *y = msg->data; + + if (nof_prb > 10) { + *y++ = data->alloc_type; + } + + /* Resource allocation: type0 or type 1 */ + int P = ra_type0_P(nof_prb); + int alloc_size = (int) ceilf((float) nof_prb/P); + switch(data->alloc_type) { + case alloc_type0: + bit_pack(data->type0_alloc.rbg_bitmask, &y, alloc_size); + break; + case alloc_type1: + bit_pack(data->type1_alloc.rbg_subset, &y, (int) ceilf(log2f(P))); + *y++ = data->type1_alloc.shift?1:0; + bit_pack(data->type1_alloc.vrb_bitmask, &y, alloc_size - (int) ceilf(log2f(P)) - 1); + break; + default: + fprintf(stderr, "Format 1 accepts type0 or type1 resource allocation only\n"); + return -1; + + } + /* 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); + } + bit_pack(mcs, &y, 5); + + /* harq process number */ + bit_pack(data->harq_process, &y, 3); + + *y++ = data->ndi; + + // rv version + bit_pack(data->rv_idx, &y, 2); + + // TPC not implemented + *y++ = 0; + *y++ = 0; + + // Padding with zeros + int n = dci_format1_sizeof(nof_prb); + while (y-msg->data < n) { + *y++ = 0; + } + msg->location.nof_bits = (y - msg->data); + + return 0; +} + +int dci_format1_unpack(dci_msg_t *msg, ra_pdsch_t *data, int nof_prb) { + + /* pack bits */ + char *y = msg->data; + + /* 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; + } + + if (nof_prb > 10) { + data->alloc_type = *y++; + } else { + data->alloc_type = alloc_type0; + } + + /* Resource allocation: type0 or type 1 */ + int P = ra_type0_P(nof_prb); + int alloc_size = (int) ceilf((float) nof_prb/P); + switch(data->alloc_type) { + case alloc_type0: + data->type0_alloc.rbg_bitmask = bit_unpack(&y, alloc_size); + break; + case alloc_type1: + data->type1_alloc.rbg_subset = bit_unpack(&y, (int) ceilf(log2f(P))); + data->type1_alloc.shift = *y++?true:false; + data->type1_alloc.vrb_bitmask = bit_unpack(&y, alloc_size - (int) ceilf(log2f(P)) - 1); + break; + default: + fprintf(stderr, "Format 1 accepts type0 or type1 resource allocation only\n"); + return -1; + + } + /* pack 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); + data->mcs.tbs = ra_tbs_from_idx(data->mcs.tbs_idx, ra_nprb_dl(data, nof_prb)); + + /* harq process number */ + data->harq_process = bit_unpack(&y, 3); + + data->ndi = *y++?true:false; + + // rv version + data->rv_idx = bit_unpack(&y, 2); + + // TPC not implemented + + + return 0; +} + + +/* Packs DCI format 1A for compact scheduling of PDSCH words according to 36.212 5.3.3.1.3 + * + * TODO: RA procedure initiated by PDCCH, TPC commands + */ +int dci_format1As_pack(ra_pdsch_t *data, dci_msg_t *msg, int nof_prb, bool crc_is_crnti) { + + /* pack bits */ + char *y = msg->data; + + *y++ = 1; // format differentiation + + if (data->alloc_type != alloc_type2) { + fprintf(stderr, "Format 1A accepts type2 resource allocation only\n"); + return -1; + } + + *y++ = data->type2_alloc.mode; // localized or distributed VRB assignment + + if (data->type2_alloc.mode == t2_loc) { + if (data->type2_alloc.L_crb > nof_prb) { + fprintf(stderr, "L_CRB=%d can not exceed system BW for localized type2\n", data->type2_alloc.L_crb); + return -1; + } + } else { + int n_vrb_dl; + if (crc_is_crnti && nof_prb > 50) { + n_vrb_dl = 16; + } else { + n_vrb_dl = ra_type2_n_vrb_dl(nof_prb, data->type2_alloc.n_gap==t2_ng1); + } + if (data->type2_alloc.L_crb > n_vrb_dl) { + fprintf(stderr, "L_CRB=%d can not exceed N_vrb_dl=%d for distributed type2\n", data->type2_alloc.L_crb, n_vrb_dl); + return -1; + } + } + /* pack RIV according to 7.1.6.3 of 36.213 */ + uint32_t riv; + if (data->type2_alloc.L_crb) { + riv = ra_type2_to_riv(data->type2_alloc.L_crb, data->type2_alloc.RB_start, nof_prb); + } else { + riv = data->type2_alloc.riv; + } + int 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); + + // 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 + int n_prb; + if (!crc_is_crnti) { + n_prb = ra_nprb_dl(data, nof_prb); + } else { + n_prb = data->type2_alloc.n_prb1a==nprb1a_2?2:3; + } + data->mcs.tbs_idx = ra_tbs_to_table_idx(data->mcs.tbs, n_prb); + } + mcs = data->mcs.tbs_idx; + } + bit_pack(mcs, &y, 5); + + 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; + } else { + y++; // bit reserved + } + + // rv version + bit_pack(data->rv_idx, &y, 2); + + if (crc_is_crnti) { + // TPC not implemented + *y++ = 0; + *y++ = 0; + } else { + y++; // MSB of TPC is reserved + *y++ = data->type2_alloc.n_prb1a; // LSB indicates N_prb_1a for TBS + } + + // Padding with zeros + int n = dci_format1A_sizeof(nof_prb); + while (y-msg->data < n) { + *y++ = 0; + } + msg->location.nof_bits = (y - msg->data); + + return 0; +} + +/* Unpacks DCI format 1A for compact scheduling of PDSCH words according to 36.212 5.3.3.1.3 + * + */ +int dci_format1As_unpack(dci_msg_t *msg, ra_pdsch_t *data, int nof_prb, bool crc_is_crnti) { + + /* pack bits */ + char *y = msg->data; + + /* 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; + } + if (*y++ != 1) { + fprintf(stderr, "Invalid format differentiation field value. This is Format0\n"); + return -1; + } + + data->alloc_type = alloc_type2; + data->type2_alloc.mode = *y++; + + // by default, set N_gap to 1 + data->type2_alloc.n_gap = t2_ng1; + + /* unpack RIV according to 7.1.6.3 of 36.213 */ + int 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; + 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); + ra_type2_from_riv(riv, &data->type2_alloc.L_crb, &data->type2_alloc.RB_start, nof_prb, nof_vrb); + data->type2_alloc.riv = riv; + + // unpack MCS + data->mcs.mcs_idx = bit_unpack(&y, 5); + + data->harq_process = bit_unpack(&y, 3); + + if (!crc_is_crnti && nof_prb >= 50 && data->type2_alloc.mode == t2_dist) { + data->type2_alloc.n_gap = *y++; + } else { + y++; // bit reserved + } + + // rv version + bit_pack(data->rv_idx, &y, 2); + + if (crc_is_crnti) { + // TPC not implemented + y++; + y++; + } else { + y++; // MSB of TPC is reserved + *y++ = data->type2_alloc.n_prb1a; // LSB indicates N_prb_1a for TBS + } + data->mcs.tbs_idx = data->mcs.mcs_idx; + int n_prb; + if (crc_is_crnti) { + n_prb = ra_nprb_dl(data, nof_prb); + } else { + n_prb = data->type2_alloc.n_prb1a==nprb1a_2?2:3; + } + data->mcs.tbs = ra_tbs_from_idx(data->mcs.tbs_idx, n_prb); + data->mcs.mod = QPSK; + + return 0; +} + +/* Format 1C for compact scheduling of PDSCH words + * + */ +int dci_format1Cs_pack(ra_pdsch_t *data, dci_msg_t *msg, int nof_prb) { + + /* pack bits */ + char *y = msg->data; + + if (data->alloc_type != alloc_type2 || data->type2_alloc.mode != t2_dist) { + fprintf(stderr, "Format 1C accepts distributed type2 resource allocation only\n"); + return -1; + } + + 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); + + if (data->type2_alloc.L_crb > ((int) n_vrb_dl/n_step)*n_step) { + fprintf(stderr, "L_CRB=%d can not exceed N_vrb_dl=%d for distributed type2\n", data->type2_alloc.L_crb, + ((int) n_vrb_dl/n_step)*n_step); + return -1; + } + if (data->type2_alloc.L_crb % n_step) { + fprintf(stderr, "L_crb must be multiple of n_step\n"); + return -1; + } + if (data->type2_alloc.RB_start % n_step) { + fprintf(stderr, "RB_start must be multiple of n_step\n"); + return -1; + } + int L_p = data->type2_alloc.L_crb/n_step; + int RB_p = data->type2_alloc.RB_start/n_step; + int n_vrb_p = (int) n_vrb_dl / n_step; + + uint32_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)); + + // 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(mcs, &y, 5); + + msg->location.nof_bits = (y - msg->data); + + return 0; +} + +int dci_format1Cs_unpack(dci_msg_t *msg, ra_pdsch_t *data, int nof_prb) { + uint16_t L_p, RB_p; + + /* pack bits */ + char *y = msg->data; + + if (msg->location.nof_bits != dci_format_sizeof(Format1C, nof_prb)) { + fprintf(stderr, "Invalid message length for format 1C\n"); + return -1; + } + data->alloc_type = alloc_type2; + data->type2_alloc.mode = t2_dist; + 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); + + uint32_t riv = bit_unpack(&y, riv_nbits((int) n_vrb_dl/n_step)); + int n_vrb_p = (int) n_vrb_dl / n_step; + + ra_type2_from_riv(riv, &L_p, &RB_p, n_vrb_p, n_vrb_p); + data->type2_alloc.L_crb = L_p * n_step; + 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; + + msg->location.nof_bits = (y - msg->data); + + return 0; +} + +int dci_msg_pack_pdsch(ra_pdsch_t *data, dci_msg_t *msg, dci_format_t format, int nof_prb, bool crc_is_crnti) { + switch(format) { + case Format1: + return dci_format1_pack(data, msg, nof_prb); + case Format1A: + return dci_format1As_pack(data, msg, nof_prb, crc_is_crnti); + case Format1C: + return dci_format1Cs_pack(data, msg, nof_prb); + default: + fprintf(stderr, "Invalid DCI format %s for PDSCH resource allocation\n", dci_format_string(format)); + return -1; + } +} + +int dci_msg_unpack_pdsch(dci_msg_t *msg, ra_pdsch_t *data, int nof_prb, bool crc_is_crnti) { + if (msg->location.nof_bits == dci_format_sizeof(Format1, nof_prb)) { + return dci_format1_unpack(msg, data, nof_prb); + } else if (msg->location.nof_bits == dci_format_sizeof(Format1A, nof_prb)) { + return dci_format1As_unpack(msg, data, nof_prb, crc_is_crnti); + } else if (msg->location.nof_bits == dci_format_sizeof(Format1C, nof_prb)) { + return dci_format1Cs_unpack(msg, data, nof_prb); + } else { + return -1; + } +} + +int dci_msg_pack_pusch(ra_pusch_t *data, dci_msg_t *msg, int 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) { + return dci_format0_unpack(msg, data, nof_prb); +} + +char* dci_format_string(dci_format_t format) { + switch(format) { + case Format0: + return "Format0"; + case Format1: + return "Format1"; + case Format1A: + return "Format1A"; + case Format1C: + return "Format1C"; + default: + return "N/A"; // fatal error + } +} + +void dci_msg_type_fprint(FILE *f, dci_msg_type_t type) { + switch(type.type) { + case PUSCH_SCHED: + fprintf(f,"%s PUSCH Scheduling\n", dci_format_string(type.format)); + break; + case PDSCH_SCHED: + fprintf(f,"%s PDSCH Scheduling\n", dci_format_string(type.format)); + break; + case RA_PROC_PDCCH: + fprintf(f,"%s Random access initiated by PDCCH\n", dci_format_string(type.format)); + break; + case MCCH_CHANGE: + fprintf(f,"%s MCCH change notification\n", dci_format_string(type.format)); + break; + case TPC_COMMAND: + fprintf(f,"%s TPC command\n", dci_format_string(type.format)); + break; + } +} + +int dci_msg_get_type(dci_msg_t *msg, dci_msg_type_t *type, int nof_prb, unsigned short crnti) { + if (msg->location.nof_bits == dci_format_sizeof(Format0, nof_prb) + && !msg->data[0]) { + type->type = PUSCH_SCHED; + type->format = Format0; + return 0; + } 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; + } else if (msg->location.nof_bits == dci_format_sizeof(Format1A, nof_prb)) { + if (msg->location.rnti == crnti) { + type->type = RA_PROC_PDCCH; + type->format = Format1A; + } else { + type->type = PDSCH_SCHED; // only these 2 types supported + type->format = Format1A; + } + return 0; + } else if (msg->location.nof_bits == dci_format_sizeof(Format1C, nof_prb)) { + if (msg->location.rnti == MRNTI) { + type->type = MCCH_CHANGE; + type->format = Format1C; + } else { + type->type = PDSCH_SCHED; // only these 2 types supported + type->format = Format1C; + } + return 0; + } + return -1; +} + diff --git a/lte/lib/phch/src/pbch.c b/lte/lib/phch/src/pbch.c index a20684380..146bc9710 100644 --- a/lte/lib/phch/src/pbch.c +++ b/lte/lib/phch/src/pbch.c @@ -133,6 +133,9 @@ int pbch_init(pbch_t *q, int nof_prb, int cell_id, lte_cp_t cp) { 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; @@ -356,11 +359,11 @@ void crc_set_mask(char *data, int nof_ports) { * * Returns 0 if the data is correct, -1 otherwise */ -int pbch_crc_check(char *bits, int nof_ports) { +int pbch_crc_check(pbch_t *q, 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, LTE_CRC16, 0); + 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) { @@ -379,7 +382,7 @@ int pbch_decode_frame(pbch_t *q, pbch_mib_t *mib, int src, int dst, int n, int n } /* unrate matching */ - rm_conv_rx(q->temp, q->pbch_rm_f, 4 * nof_bits, 120); + rm_conv_rx(q->temp, 4 * nof_bits, q->pbch_rm_f, 120); /* FIXME: If channel estimates are zero, received LLR are NaN. Check and return error */ for (j=0;j<120;j++) { @@ -399,7 +402,7 @@ int pbch_decode_frame(pbch_t *q, pbch_mib_t *mib, int src, int dst, int n, int n c=1; } - if (!pbch_crc_check(q->data, nof_ports)) { + if (!pbch_crc_check(q, q->data, nof_ports)) { /* unpack MIB */ pbch_mib_unpack(q->data, mib); @@ -523,12 +526,12 @@ void pbch_encode(pbch_t *q, pbch_mib_t *mib, cf_t *slot1_symbols[MAX_PORTS_CTRL] pbch_mib_pack(mib, q->data); /* encode & modulate */ - crc(0, q->data, 24, 16, 0x11021, 1); + crc_attach(&q->crc, q->data, 24); crc_set_mask(q->data, nof_ports); convcoder_encode(&q->encoder, q->data, q->data_enc, 40); - rm_conv_tx(q->data_enc, q->pbch_rm_b, 120, 4 * nof_bits); + rm_conv_tx(q->data_enc, 120, q->pbch_rm_b, 4 * nof_bits); } diff --git a/lte/lib/phch/src/pdcch.c b/lte/lib/phch/src/pdcch.c index 1dc8463ca..33bf768ac 100644 --- a/lte/lib/phch/src/pdcch.c +++ b/lte/lib/phch/src/pdcch.c @@ -47,15 +47,11 @@ #define PDCCH_FORMAT_NOF_REGS(i) ((1<b)?b:a) @@ -63,18 +59,18 @@ int pdcch_get(cf_t *slot1_data, cf_t *pdcch, int nsymbols) { * 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; + int i, l, 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; + 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 = (4 * L) * (i % (nof_cce / (4 * L))); - k++; - INFO( - "Common SS Candidate %d: RNTI: 0x%x, nCCE: %d, Nbits: %d, L: %d\n", + 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; @@ -88,6 +84,11 @@ int gen_ue_search(dci_candidate_t *c, int nof_cce, int nof_bits, unsigned short 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_ISINFO()) printf("[INFO]: "); + } for (l = 3; l >= 0; l--) { L = (1 << l); for (i = 0; i < MIN(nof_cce/L,16/S[l]); i++) { @@ -99,27 +100,35 @@ int gen_ue_search(dci_candidate_t *c, int nof_cce, int nof_bits, unsigned short 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); + if (!subframe) { + if (VERBOSE_ISINFO()) { + printf("(%d, %d), ", c[k].ncce, c[k].L); + } + } k++; } } + if (!subframe) { + if (VERBOSE_ISINFO()) printf("\n"); + } 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); + 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; - 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); + for(i=0;inof_cce, + dci_format_sizeof(common_formats[i], q->nof_prb), SIRNTI); + s->nof_candidates++; + } } } } @@ -137,11 +146,11 @@ 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; + int l, n, k, i; pdcch_search_t *s = &q->search_mode[SEARCH_UE]; s->nof_candidates = 0; for (l=0;l<3;l++) { - s->nof_candidates += 3*(MIN(q->nof_cce,16) / (1<nof_candidates += NOF_UE_FORMATS*(MIN(q->nof_cce,16) / (1<nof_candidates, c_rnti); if (s->nof_candidates) { @@ -152,12 +161,10 @@ void pdcch_init_search_ue(pdcch_t *q, unsigned short c_rnti) { 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); + for(i=0;inof_cce, + dci_format_sizeof(ue_formats[i], q->nof_prb), c_rnti, n); + } } } } @@ -200,19 +207,23 @@ int pdcch_init(pdcch_t *q, regs_t *regs, int nof_prb, int nof_ports, q->cp = cp; q->regs = regs; q->nof_ports = nof_ports; + q->nof_prb = nof_prb; q->current_search_mode = SEARCH_NONE; - q->nof_regs = regs_pdcch_nregs(q->regs); + q->nof_regs = (regs_pdcch_nregs(q->regs)/9)*9; q->nof_cce = q->nof_regs / 9; q->nof_symbols = 4 * q->nof_regs; q->nof_bits = 2 * q->nof_symbols; - INFO("Init PDCCH: %d REGs, %d bits, %d symbols, %d ports\n", q->nof_regs, - q->nof_bits, q->nof_symbols, q->nof_ports); + INFO("Init PDCCH: %d CCEs (%d REGs), %d bits, %d symbols, %d ports\n", q->nof_cce, + q->nof_regs, q->nof_bits, q->nof_symbols, q->nof_ports); if (modem_table_std(&q->mod, LTE_QPSK, true)) { goto clean; } + if (crc_init(&q->crc, LTE_CRC16, 16)) { + goto clean; + } demod_soft_init(&q->demod); demod_soft_table_set(&q->demod, &q->mod); @@ -310,17 +321,24 @@ void pdcch_free(pdcch_t *q) { * * TODO: UE transmit antenna selection CRC mask */ -unsigned short dci_decode(viterbi_t *decoder, float *e, char *data, int E, +unsigned short dci_decode(pdcch_t *q, float *e, char *data, int E, int nof_bits) { float tmp[3 * (DCI_MAX_BITS + 16)]; - unsigned short p_bits; + unsigned short p_bits, crc_res; char *x; assert(nof_bits < DCI_MAX_BITS); +/* char a[] = {1,1,0,0,1,0,0,0,0,0,0,1,1,0,0,1,0,0,0,0,0,0,1,1,1,1,0,0,0,0,1,1,0,1,0,1,1,0,1,1,1,1,1,0,1,0,1,1,0,1,0,0,0,1,0,0,1,1,1,1,0,1,0,1,1,0,0,0,0,0,1,1,0,0,0,0,1,0,0,1,0,0,0,0,1,1,1,1,1,0,1,1,1,0,1,1,1,1,0,0,1,1,0,0,1,0,1,1,1,0,0,1,1,0,1,0,1,1,0,0,1,0,0,1,1,0,0,1,0,0,0,0,0,0,1,1,0,0,1,0,0,0,0,0,0,1,1,1,1,0,0,0,0,1,1,0,1,0,1,1,0,1,1,1,1,1,0,1,0,1,1,0,1,0,0,0,1,0,0,1,1,1,1,0,1,0,1,1,0,0,0,0,0,1,1,0,0,0,0,1,0,0,1,0,0,0,0,1,1,1,1,1,0,1,1,1,0,1,1,1,1,0,0,1,1,0,0,1,0,1,1,1,0,0,1,1,0,1,0,1,1,0,0,1,0,0,1,1,0,0,1,0,0,0,0,0,0,1,1,0,0,1,0,0,0,0,0,0,1,1,1,1,0,0,0,0,1,1,0,1,0,1,1,0,1,1,1,1,1,0,1,0,1,1,0,1,0,0,0,1,0,0,1,1,1,1,0,1,0,1,1,0,0,0,0,0,1,1,0,0,0,0,1,0,0,1,0,0,0,0,1,1,1,1,1,0,1,1,1,0,1,1,1,1,0,0,1,1,0,0,1,0,1,1,1,0,0,1,1,0,1,0,1,1,0,0,1,0,0,1,1,0,0,1,0,0,0,0,0,0,1,1,0,0,1,0,0,0,0,0,0,1,1,1,1,0,0,0,0,1,1,0,1,0,1,1,0,1,1,1,1,1,0,1,0,1,1,0,1,0,0,0,1,0,0,1,1,1,1,0,1,0,1,1,0,0,0,0,0,1,1,0,0,0,0,1,0,0,1,0,0,0,0,1,1,1,1,1,0,1,1,1,0,1,1,1,1,0,0,1,1,0,0,1,0,1,1,1,0,0,1,1,0,1,0,1,1,0,0,1,0,0,1,1,0,0,1,0,0,0,0,0,0,1,1,0,0,1,0,0,0,0,0,0,1,1,1,1,0,0,0,0,1,1,0,1,0,1,1,0,1,1,1,1,1,0,1,0,1,1,0,1,0,0,0,1,0,0,1,1,1,1,0,1,0,1,1,0,0,0,0,0,1,1,0,0,0,0,1,0,0,1,0,0,0,0}; + + float *b = malloc(sizeof(E)); + for (int i=0;idecoder, tmp, data, nof_bits + 16); + + if (VERBOSE_ISDEBUG()) { + bit_fprint(stdout, data, nof_bits+16); + } 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)); + 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); } 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, + DEBUG("Trying Candidate: Nbits: %d, E: %d, nCCE: %d, L: %d, RNTI: 0x%x\n", + c->nof_bits, PDCCH_FORMAT_NOF_BITS(c->L), c->ncce, c->L, + c->rnti); + crc_res = dci_decode(q, &llr[72 * c->ncce], msg->data, PDCCH_FORMAT_NOF_BITS(c->L), c->nof_bits); if (c->rnti == crc_res) { memcpy(&msg->location, c, sizeof(dci_candidate_t)); INFO( - "FOUND CAND: Nbits: %d, E: %d, nCCE: %d, L: %d, RNTI: 0x%x\n", + "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; @@ -379,25 +403,21 @@ int pdcch_extract_llr(pdcch_t *q, cf_t *slot1_symbols, cf_t *ce[MAX_PORTS_CTRL], memset(&x[q->nof_ports], 0, sizeof(cf_t*) * (MAX_LAYERS - q->nof_ports)); /* extract symbols */ - 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"); + int n = regs_pdcch_get(q->regs, slot1_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; } /* 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"); + 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 -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 */ @@ -410,13 +430,18 @@ int pdcch_extract_llr(pdcch_t *q, cf_t *slot1_symbols, cf_t *ce[MAX_PORTS_CTRL], q->nof_symbols / q->nof_ports); } + DEBUG("pdcch d symbols: ", 0); + if (VERBOSE_ISDEBUG()) { + vec_fprint_c(stdout, q->pdcch_d, q->nof_symbols); + } + /* 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); + vec_fprint_f(stdout, q->pdcch_llr, q->nof_bits); } /* descramble */ @@ -426,7 +451,6 @@ int pdcch_extract_llr(pdcch_t *q, cf_t *slot1_symbols, cf_t *ce[MAX_PORTS_CTRL], } 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) { @@ -435,16 +459,15 @@ int pdcch_decode_current_mode(pdcch_t *q, float *llr, dci_t *dci, int subframe) k = 0; } - dci_cnt = 0; for (i = 0; i < q->search_mode[q->current_search_mode].nof_candidates - && dci_cnt < dci->nof_dcis; i++) { + && dci->nof_dcis < dci->max_dcis; i++) { if (pdcch_decode_candidate(q, q->pdcch_llr, &q->search_mode[q->current_search_mode].candidates[k][i], - &dci->msg[dci_cnt])) { - dci_cnt++; + &dci->msg[dci->nof_dcis])) { + dci->nof_dcis++; } } - return dci_cnt; + return dci->nof_dcis; } int pdcch_decode_si(pdcch_t *q, float *llr, dci_t *dci) { @@ -498,7 +521,7 @@ 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(char *data, char *e, int nof_bits, int E, unsigned short rnti) { +void dci_encode(pdcch_t *q, char *data, char *e, int nof_bits, int E, unsigned short rnti) { convcoder_t encoder; char tmp[3 * (DCI_MAX_BITS + 16)]; @@ -510,7 +533,7 @@ void dci_encode(char *data, char *e, int nof_bits, int E, unsigned short rnti) { encoder.tail_biting = true; memcpy(encoder.poly, poly, 3 * sizeof(int)); - crc(0, data, nof_bits, 16, LTE_CRC16, 1); + crc_attach(&q->crc, data, nof_bits); crc_set_mask_rnti(&data[nof_bits], rnti); convcoder_encode(&encoder, data, tmp, nof_bits + 16); @@ -520,7 +543,7 @@ void dci_encode(char *data, char *e, int nof_bits, int E, unsigned short rnti) { vec_fprint_b(stdout, tmp, 3 * (nof_bits + 16)); } - rm_conv_tx(tmp, e, 3 * (nof_bits + 16), E); + rm_conv_tx(tmp, 3 * (nof_bits + 16), e, E); } /** Converts the MIB message to symbols mapped to SLOT #1 ready for transmission @@ -558,7 +581,7 @@ int pdcch_encode(pdcch_t *q, dci_t *dci, cf_t *slot1_symbols[MAX_PORTS_CTRL], 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_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); } @@ -578,7 +601,7 @@ int pdcch_encode(pdcch_t *q, dci_t *dci, cf_t *slot1_symbols[MAX_PORTS_CTRL], /* mapping to resource elements */ for (i = 0; i < q->nof_ports; i++) { - pdcch_put(q->pdcch_symbols[i], slot1_symbols[i], q->nof_symbols); + regs_pdcch_put(q->regs, q->pdcch_symbols[i], slot1_symbols[i]); } return 0; } diff --git a/lte/lib/phch/src/ra.c b/lte/lib/phch/src/ra.c new file mode 100644 index 000000000..936d2169a --- /dev/null +++ b/lte/lib/phch/src/ra.c @@ -0,0 +1,518 @@ +/** + * + * \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 "lte/common/base.h" +#include "lte/utils/bit.h" +#include "lte/utils/vector.h" +#include "lte/utils/debug.h" +#include "lte/phch/ra.h" +#include "lte/utils/bit.h" + +#include "tbs_tables.h" + +#define min(a,b) (anof_prb - 1)/ 25 + 1; + for (j=0;jnof_prb-j*25);i++) { + fprintf(f, "%3d, ", prb->prb_idx[j*25+i]); + } + fprintf(f, "\n"); + } +} + +/** 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 i; + if (ra->type2_alloc.mode != t2_loc) { + fprintf(stderr, "Uplink only accepts type2 localized scheduling\n"); + return -1; + } + for (i=0;itype2_alloc.L_crb;i++) { + prb->prb_idx[i] = i+ra->type2_alloc.RB_start; + prb->nof_prb++; + } + return 0; +} + +/** Compute PRB allocation for Downlink as defined in 7.1.6 of 36.213 */ +int ra_prb_get_dl(ra_prb_t *prb_dist, ra_pdsch_t *ra, int nof_prb) { + int i, j; + uint32_t bitmask; + int P = ra_type0_P(nof_prb); + ra_prb_slot_t *prb; + + bzero(prb_dist, sizeof(ra_prb_t)); + switch(ra->alloc_type) { + case alloc_type0: + prb = &prb_dist->slot1; + prb_dist->is_dist = false; + bitmask = ra->type0_alloc.rbg_bitmask; + int nb = (int) ceilf((float)nof_prb/P); + for (i=0;iprb_idx[prb->nof_prb] = i*P+j; + prb->nof_prb++; + } + } + } + break; + case alloc_type1: + prb = &prb_dist->slot1; + prb_dist->is_dist = false; + int n_rb_type1 = ra_type1_N_rb(nof_prb); + int n_rb_rbg_subset; + if (ra->type1_alloc.rbg_subset < (nof_prb/P) % P) { + n_rb_rbg_subset = ((nof_prb-1)/(P*P)) * P + P; + } else if (ra->type1_alloc.rbg_subset == ((nof_prb/P) % P)) { + n_rb_rbg_subset = ((nof_prb-1)/(P*P)) * P + ((nof_prb-1)%P)+1; + } else { + n_rb_rbg_subset = ((nof_prb-1)/(P*P)) * P; + } + int shift = ra->type1_alloc.shift?(n_rb_rbg_subset-n_rb_type1):0; + bitmask = ra->type1_alloc.vrb_bitmask; + for (i=0;iprb_idx[prb->nof_prb] = ((i+shift)/P)*P*P+ + ra->type1_alloc.rbg_subset*P+(i+shift)%P; + prb->nof_prb++; + } + } + break; + case alloc_type2: + if (ra->type2_alloc.mode == t2_loc) { + prb = &prb_dist->slot1; + prb_dist->is_dist = false; + for (i=0;itype2_alloc.L_crb;i++) { + prb->prb_idx[i] = i+ra->type2_alloc.RB_start; + prb->nof_prb++; + } + } else { + /* Mapping of Virtual to Physical RB for distributed type is defined in + * 6.2.3.2 of 36.211 + */ + prb_dist->is_dist = true; + int N_gap, N_tilde_vrb, n_tilde_vrb, n_tilde_prb, n_tilde2_prb, N_null, N_row, n_vrb; + int n_tilde_prb_odd, n_tilde_prb_even; + if (ra->type2_alloc.n_gap == t2_ng1) { + N_tilde_vrb = nof_prb; + N_gap = ra_type2_ngap(nof_prb, true); + } else { + N_tilde_vrb = 2*nof_prb; + N_gap = ra_type2_ngap(nof_prb, false); + } + N_row = (int) ceilf((float) N_tilde_vrb/(4*P))*P; + N_null = 4*N_row-N_tilde_vrb; + for (i=0;itype2_alloc.L_crb;i++) { + n_vrb = i+ra->type2_alloc.RB_start; + n_tilde_vrb = n_vrb%N_tilde_vrb; + n_tilde_prb = 2*N_row*(n_tilde_vrb % 2)+n_tilde_vrb/2+N_tilde_vrb*(n_vrb/N_tilde_vrb); + n_tilde2_prb = N_row*(n_tilde_vrb % 4)+n_tilde_vrb/4+N_tilde_vrb*(n_vrb/N_tilde_vrb); + + if (N_null != 0 && n_tilde_vrb >= (N_tilde_vrb - N_null) && (n_tilde_vrb%2) == 1) { + n_tilde_prb_odd = n_tilde_prb-N_row; + } else if (N_null != 0 && n_tilde_vrb >= (N_tilde_vrb - N_null) && (n_tilde_vrb%2) == 0) { + n_tilde_prb_odd = n_tilde_prb-N_row+N_null/2; + } else if (N_null != 0 && n_tilde_vrb < (N_tilde_vrb - N_null) && (n_tilde_vrb%4) >= 2) { + n_tilde_prb_odd = n_tilde2_prb-N_null/2; + } else { + n_tilde_prb_odd = n_tilde2_prb; + } + n_tilde_prb_even = (n_tilde_prb_odd+N_tilde_vrb/2)%N_tilde_vrb+N_tilde_vrb*(n_vrb/N_tilde_vrb); + + if (n_tilde_prb_odd < N_tilde_vrb/2) { + prb_dist->slot1.prb_idx[i] = n_tilde_prb_odd; + } else { + prb_dist->slot1.prb_idx[i] = n_tilde_prb_odd+N_gap-N_tilde_vrb/2; + } + prb_dist->slot1.nof_prb++; + if (n_tilde_prb_even < N_tilde_vrb/2) { + prb_dist->slot2.prb_idx[i] = n_tilde_prb_even; + } else { + prb_dist->slot2.prb_idx[i] = n_tilde_prb_even+N_gap-N_tilde_vrb/2; + } + prb_dist->slot2.nof_prb++; + } + } + break; + default: + return -1; + } + return 0; +} + +/* Returns the number of allocated PRB for Uplink */ +int ra_nprb_ul(ra_pusch_t *ra, int 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; + 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)) { + fprintf(stderr, "Number of RGB (%d) can not exceed %d\n", nof_prb, + (int) ceilf((float)nof_prb/P)); + return -1; + } + nprb = nof_rbg * P; + + // last RBG may have smaller size. Add if set + int P_last = (nof_prb%P); + if (!P_last) P_last = P; + nprb += P_last*(ra->type0_alloc.rbg_bitmask&1); + break; + case alloc_type1: + nprb = bit_count(ra->type1_alloc.vrb_bitmask); + 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; + } + break; + case alloc_type2: + nprb = ra->type2_alloc.L_crb; + break; + default: + return -1; + } + 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) { + if (nof_prb <= 10) { + return 1; + } else if (nof_prb <= 26) { + return 2; + } else if (nof_prb <= 63) { + return 3; + } else { + return 4; + } +} + +/* 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; +} + +/* Convert Type2 scheduling L_crb and RB_start to RIV value */ +uint32_t ra_type2_to_riv(uint16_t L_crb, uint16_t RB_start, int nof_prb) { + uint32_t riv; + if (L_crb <= (int) nof_prb/2) { + riv = nof_prb*(L_crb-1) + RB_start; + } else { + riv = nof_prb*(nof_prb-L_crb+1) + nof_prb - 1 - RB_start; + } + return riv; +} + +/* Convert Type2 scheduling RIV value to L_crb and RB_start values */ +void ra_type2_from_riv(uint32_t riv, uint16_t *L_crb, uint16_t *RB_start, int nof_prb, int nof_vrb) { + *L_crb = (int) (riv/nof_prb) + 1; + *RB_start = riv%nof_prb; + if (*L_crb > nof_vrb - *RB_start) { + *L_crb = nof_prb - (int) (riv/nof_prb) + 1; + *RB_start = nof_prb - riv%nof_prb - 1; + } +} + + +/* Table 6.2.3.2-1 in 36.211 */ +int ra_type2_ngap(int nof_prb, bool ngap_is_1) { + if (nof_prb <= 10) { + return nof_prb/2; + } else if (nof_prb == 11) { + return 4; + } else if (nof_prb <= 19) { + return 8; + } else if (nof_prb <= 26) { + return 12; + } else if (nof_prb <= 44) { + return 18; + } else if (nof_prb <= 49) { + return 27; + } else if (nof_prb <= 63) { + return ngap_is_1?27:9; + } else if (nof_prb <= 79) { + return ngap_is_1?32:16; + } else { + return ngap_is_1?48:16; + } +} + + +/* Table 7.1.6.3-1 in 36.213 */ +int ra_type2_n_rb_step(int nof_prb) { + if (nof_prb < 50) { + return 2; + } else { + return 4; + } +} + + +/* as defined in 6.2.3.2 of 36.211 */ +int ra_type2_n_vrb_dl(int nof_prb, bool ngap_is_1) { + int ngap = ra_type2_ngap(nof_prb, ngap_is_1); + if (ngap_is_1) { + return 2*(ngap<(nof_prb-ngap)?ngap:nof_prb-ngap); + } else { + return ((int) 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) { + 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 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(uint8_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; + } else { + mcs->mod = MOD_NULL; + mcs->tbs_idx = 0; + return -1; + } + return 0; +} + + +/* Converts MCS index to ra_mcs_t structure for Uplink as defined in Table 8.6.1-1 on 36.213 */ +int ra_mcs_from_idx_ul(uint8_t idx, ra_mcs_t *mcs) { + if (idx < 11) { + 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; + } else { + mcs->mod = MOD_NULL; + mcs->tbs_idx = 0; + return -1; + } + return 0; +} + +/* 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) { + if (tbs_idx < 32) { + return tbs_format1c_table[tbs_idx]; + } else { + return -1; + } +} + +/* 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 idx; + if (tbs < tbs_format1c_table[0]) { + return -1; + } + for (idx=1;idx<32;idx++) { + if (tbs_format1c_table[idx-1] <= tbs && + tbs_format1c_table[idx] >= tbs) { + return idx; + } + } + return -1; +} + +/* 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) { + return tbs_table[tbs_idx][n_prb-1]; + } else { + return -1; + } +} + +/* 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 idx; + if (n_prb > 0 && n_prb <= 110) { + return -1; + } + if (tbs < tbs_table[0][n_prb]) { + return -1; + } + for (idx=1;idx<28;idx++) { + if (tbs_table[idx-1][n_prb] <= tbs && + tbs_table[idx][n_prb] >= tbs) { + return idx; + } + } + return -1; +} + +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, int nof_prb) { + fprintf(f, "Frequency Hopping:\t"); + if (ra->freq_hop_fl == hop_disabled) { + fprintf(f, "No"); + } else { + fprintf(f, "Yes"); + + } +} + +char *ra_type_string(ra_type_t alloc_type) { + switch(alloc_type) { + case alloc_type0: + return "Type 0"; + case alloc_type1: + return "Type 1"; + case alloc_type2: + return "Type 2"; + default: + return "N/A"; + } +} + +void ra_pdsch_set_mcs_index(ra_pdsch_t *ra, uint8_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) { + ra->mcs.mod = mod; + ra->mcs.tbs_idx = tbs_idx; +} + + +void ra_pdsch_fprint(FILE *f, ra_pdsch_t *ra, int nof_prb) { + fprintf(f, " - Resource Allocation Type:\t\t%s\n",ra_type_string(ra->alloc_type)); + switch(ra->alloc_type) { + case alloc_type0: + fprintf(f, " + Resource Block Group Size:\t\t%d\n",ra_type0_P(nof_prb)); + fprintf(f, " + RBG Bitmap:\t\t\t0x%x\n",ra->type0_alloc.rbg_bitmask); + break; + case alloc_type1: + fprintf(f, " + Resource Block Group Size:\t\t%d\n",ra_type0_P(nof_prb)); + fprintf(f, " + RBG Bitmap:\t\t\t0x%x\n",ra->type1_alloc.vrb_bitmask); + fprintf(f, " + RBG Subset:\t\t\t%d\n",ra->type1_alloc.rbg_subset); + fprintf(f, " + RBG Shift:\t\t\t\t%s\n",ra->type1_alloc.shift?"Yes":"No"); + break; + case alloc_type2: + fprintf(f, " + Type:\t\t\t\t%s\n", + ra->type2_alloc.mode==t2_loc?"Localized":"Distributed"); + fprintf(f, " + Resource Indicator Value:\t\t%d\n",ra->type2_alloc.riv); + if (ra->type2_alloc.mode == t2_loc) { + fprintf(f, " + VRB Assignment:\t\t\t%d VRB starting with VRB %d\n", + ra->type2_alloc.L_crb, ra->type2_alloc.RB_start); + } else { + fprintf(f, " + VRB Assignment:\t\t\t%d VRB starting with VRB %d\n", + ra->type2_alloc.L_crb, ra->type2_alloc.RB_start); + fprintf(f, " + VRB gap selection:\t\t\tGap %d\n", + ra->type2_alloc.n_gap == t2_ng1?1:2); + fprintf(f, " + VRB gap:\t\t\t\t%d\n", + ra_type2_ngap(nof_prb, ra->type2_alloc.n_gap == t2_ng1)); + } + break; + } + + ra_prb_t alloc; + ra_prb_get_dl(&alloc, ra, nof_prb); + if (alloc.is_dist) { + fprintf(f, " - PRB Bitmap Assignment 1st slot:\n"); + ra_prb_fprint(f, &alloc.slot1); + fprintf(f, " - PRB Bitmap Assignment 2nd slot:\n"); + ra_prb_fprint(f, &alloc.slot2); + } else { + fprintf(f, " - PRB Bitmap Assignment:\n"); + ra_prb_fprint(f, &alloc.slot1); + } + + 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, " - Transport block size:\t\t%d\n", ra->mcs.tbs); + fprintf(f, " - HARQ process:\t\t\t%d\n", ra->harq_process); + fprintf(f, " - New data indicator:\t\t\t%s\n", ra->ndi?"Yes":"No"); + fprintf(f, " - Redundancy version:\t\t\t%d\n", ra->rv_idx); + fprintf(f, " - TPC command for PUCCH:\t\t--\n"); +} + diff --git a/lte/lib/phch/src/regs.c b/lte/lib/phch/src/regs.c index 06b9a0c79..6583dbdc3 100644 --- a/lte/lib/phch/src/regs.c +++ b/lte/lib/phch/src/regs.c @@ -37,29 +37,144 @@ regs_reg_t *regs_find_reg(regs_t *h, int k, int l); - - /*************************************************************** * * PDCCH REG ALLOCATION * ***************************************************************/ +void regs_pdcch_free(regs_t *h) { + int i; + for (i=0;i<3;i++) { + if (h->pdcch[i].regs) { + free(h->pdcch[i].regs); + } + } +} + +#define PDCCH_NCOLS 32 +const unsigned char PDCCH_PERM[PDCCH_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 }; + /** Initialize REGs for PDCCH * 36.211 10.3 section 6.8.5 */ int regs_pdcch_init(regs_t *h) { - return 0; -} + int i, m, cfi, nof_ctrl_symbols; + int ret = -1; + int nrows, ndummy, j, k, kp; + regs_reg_t **tmp = NULL; -void regs_pdcch_free(regs_t *h) { - if (h->pdcch) { - free(h->pdcch); + bzero(&h->pdcch, sizeof(regs_ch_t)); + + for (cfi=0;cfi<3;cfi++) { + if (h->nof_prb < 10) { + nof_ctrl_symbols = cfi+2; + } else { + nof_ctrl_symbols = cfi+1; + } + + tmp = malloc(sizeof(regs_reg_t*) * h->nof_regs); + if (!tmp) { + perror("malloc"); + goto clean_and_exit; + } + + /* Number and count REGs for this CFI */ + m=0; + for (i=0;inof_regs;i++) { + if (h->regs[i].l < nof_ctrl_symbols && !h->regs[i].assigned) { + tmp[m] = &h->regs[i]; + m++; + } + } + + h->pdcch[cfi].nof_regs = m; + + h->pdcch[cfi].regs = malloc(sizeof(regs_reg_t*) * h->pdcch[cfi].nof_regs); + if (!h->pdcch[cfi].regs) { + perror("malloc"); + goto clean_and_exit; + } + + /* Interleave REGs */ + nrows = (h->pdcch[cfi].nof_regs-1)/PDCCH_NCOLS+1; + ndummy = PDCCH_NCOLS*nrows - h->pdcch[cfi].nof_regs; + if (ndummy < 0) { + ndummy = 0; + } + + k=0; + for (j = 0; j < PDCCH_NCOLS; j++) { + 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; + } + h->pdcch[cfi].regs[m] = tmp[kp]; + k++; + } + } + } + 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; +clean_and_exit: + if (tmp) { + free(tmp); + } + if (ret == -1) { + regs_pdcch_free(h); + } + return ret; } int regs_pdcch_nregs(regs_t *h) { - return 9; + if (h->cfi == -1) { + fprintf(stderr, "Must call regs_set_cfi() first\n"); + return -1; + } else { + return h->pdcch[h->cfi].nof_regs; + } +} + +/** 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 == -1) { + fprintf(stderr, "Must call regs_set_cfi() first\n"); + return -1; + } + 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); + } + 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) { + fprintf(stderr, "Must call regs_set_cfi() first\n"); + return -1; + } + 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); + } + return h->pdcch[h->cfi].nof_regs*4; } @@ -195,6 +310,16 @@ void regs_phich_free(regs_t *h) { } } +int regs_phich_nregs(regs_t *h) { + int i, n; + n=0; + for (i=0;ingroups_phich;i++) { + n += h->phich[i].nof_regs; + } + return n; +} + + int regs_phich_ngroups(regs_t *h) { return h->ngroups_phich; } @@ -274,10 +399,6 @@ int regs_phich_get(regs_t *h, cf_t *slot_symbols, cf_t phich_symbols[REGS_PHICH_ - - - - /*************************************************************** * * PCFICH REG ALLOCATION @@ -330,6 +451,10 @@ void regs_pcfich_free(regs_t *h) { } } +int regs_pcfich_nregs(regs_t *h) { + return h->pcfich.nof_regs; +} + /** * Maps the PCFICH symbols to the resource grid pointed by slot_symbols * @@ -392,13 +517,13 @@ 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 refs_in_symbol1, lte_cp_t cp) { +int regs_num_x_symbol(int symbol, int nof_port, lte_cp_t cp) { switch (symbol) { case 0: return 2; case 1: - switch (refs_in_symbol1) { + switch (nof_port) { case 1: case 2: return 3; @@ -430,10 +555,10 @@ int regs_reg_init(regs_reg_t *reg, int symbol, int nreg, int k0, int maxreg, int reg->l = symbol; reg->assigned = false; - reg->k0 = k0 + nreg * 6; switch (maxreg) { case 2: + reg->k0 = k0 + nreg * 6; /* there are two references in the middle */ j = z = 0; for (i = 0; i < vo; i++) { @@ -456,6 +581,7 @@ int regs_reg_init(regs_reg_t *reg, int symbol, int nreg, int k0, int maxreg, int break; case 3: + reg->k0 = k0 + nreg * 4; /* there is no reference */ for (i = 0; i < 4; i++) { reg->k[i] = k0 + nreg * 4 + i; @@ -479,15 +605,33 @@ void regs_free(regs_t *h) { bzero(h, sizeof(regs_t)); } +/** Sets the CFI value for this subframe (CFI must be in the range 1..3). + */ +int regs_set_cfi(regs_t *h, int cfi) { + if (cfi > 0 && cfi <= 3) { + if (h->phich_len == PHICH_EXT && + ((h->nof_prb < 10 && cfi < 2) || (h->nof_prb >= 10 && cfi < 3))) { + fprintf(stderr, "PHICH length is extended. The number of control symbols should be at least 3.\n"); + return -1; + } else { + h->cfi = cfi - 1; + return 0; + } + } else { + fprintf(stderr, "Invalid CFI %d\n", cfi); + return -1; + } +} + /** * Initializes REGs structure. * 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 refs_in_symbol1, +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, n, p, k; + int i, j[4], jmax, n[4], prb, k; int vo = cell_id % 3; int max_ctrl_symbols = nof_prb<10?4:3; @@ -496,18 +640,19 @@ int regs_init(regs_t *h, int cell_id, int nof_prb, int refs_in_symbol1, 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->refs_in_symbol1 = refs_in_symbol1; + h->nof_ports = nof_ports; h->nof_regs = 0; for (i = 0; i < max_ctrl_symbols; i++) { - n = regs_num_x_symbol(i, refs_in_symbol1, cp); - if (n == -1) { + n[i] = regs_num_x_symbol(i, nof_ports, cp); + if (n[i] == -1) { return -1; } - h->nof_regs += nof_prb * n; + 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"); @@ -517,26 +662,36 @@ int regs_init(regs_t *h, int cell_id, int nof_prb, int refs_in_symbol1, goto clean_and_exit; } - k = 0; - for (i = 0; i < max_ctrl_symbols; i++) { - n = regs_num_x_symbol(i, refs_in_symbol1, cp); - for (p = 0; p < nof_prb; p++) { - for (j = 0; j < n; j++) { - if (regs_reg_init(&h->regs[k], i, j, p * RE_X_RB, n, vo)) { - fprintf(stderr, "Error initializing REGs\n"); - goto clean_and_exit; - } - DEBUG("Available REG #%3d: %d:%d:%d (k0=%d)\n", k, i, p, j, - h->regs[k].k0); - k++; + /* 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++; + } + 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; } + if (regs_phich_init(h)) { fprintf(stderr, "Error initializing PHICH REGs\n"); goto clean_and_exit; @@ -548,7 +703,8 @@ int regs_init(regs_t *h, int cell_id, int nof_prb, int refs_in_symbol1, ret = 0; - clean_and_exit: if (ret == -1) { +clean_and_exit: + if (ret == -1) { regs_free(h); } return ret; @@ -562,13 +718,8 @@ int regs_init(regs_t *h, int cell_id, int nof_prb, int refs_in_symbol1, 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++) { - if (reg->assigned) { - 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]; - } else { - fprintf(stderr, "Error REG not assigned\n"); - return -1; - } + 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; } @@ -580,15 +731,10 @@ int regs_put_reg(regs_reg_t *reg, cf_t *reg_data, cf_t *slot_symbols, int nof_pr int regs_add_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++) { - if (reg->assigned) { - 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)]); - } else { - fprintf(stderr, "Error REG not assigned\n"); - return -1; - } + 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; } @@ -600,13 +746,8 @@ 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++) { - if (reg->assigned) { - 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; - } else { - fprintf(stderr, "Error REG not assigned\n"); - return -1; - } + 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; } @@ -617,14 +758,9 @@ int regs_reset_reg(regs_reg_t *reg, cf_t *slot_symbols, int nof_prb) { int regs_get_reg(regs_reg_t *reg, cf_t *slot_symbols, cf_t *reg_data, int nof_prb) { int i; for (i = 0; i < REGS_RE_X_REG; i++) { - if (reg->assigned) { - 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]); - } else { - fprintf(stderr, "Error REG not assigned\n"); - return -1; - } + 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/lib/phch/src/tbs_tables.h b/lte/lib/phch/src/tbs_tables.h new file mode 100644 index 000000000..3a6cad731 --- /dev/null +++ b/lte/lib/phch/src/tbs_tables.h @@ -0,0 +1,278 @@ + +const int tbs_format1c_table[32] = { + 40, 56, 72, 120, 136, 144, 176, 208, 224, 256, 280, 296, 328, 336, 392, 488, + 552, 600, 632, 696, 776, 840, 904, 1000, 1064, 1128, 1224, 1288, 1384, 1480, 1608, 1736 +}; + + +/* Transport Block Size from 3GPP TS 36.213 v10.3.0 table 7.1.7.2.1-1 */ +const int tbs_table[27][110] = {{ 16, 32, 56, 88, 120, 152, 176, 208, 224, 256, 288, + 328, 344, 376, 392, 424, 456, 488, 504, 536, 568, 600, + 616, 648, 680, 712, 744, 776, 776, 808, 840, 872, 904, + 936, 968, 1000, 1032, 1032, 1064, 1096, 1128, 1160, 1192, 1224, + 1256, 1256, 1288, 1320, 1352, 1384, 1416, 1416, 1480, 1480, 1544, + 1544, 1608, 1608, 1608, 1672, 1672, 1736, 1736, 1800, 1800, 1800, + 1864, 1864, 1928, 1928, 1992, 1992, 2024, 2088, 2088, 2088, 2152, + 2152, 2216, 2216, 2280, 2280, 2280, 2344, 2344, 2408, 2408, 2472, + 2472, 2536, 2536, 2536, 2600, 2600, 2664, 2664, 2728, 2728, 2728, + 2792, 2792, 2856, 2856, 2856, 2984, 2984, 2984, 2984, 2984, 3112}, + { 24, 56, 88, 144, 176, 208, 224, 256, 328, 344, 376, + 424, 456, 488, 520, 568, 600, 632, 680, 712, 744, 776, + 808, 872, 904, 936, 968, 1000, 1032, 1064, 1128, 1160, 1192, + 1224, 1256, 1288, 1352, 1384, 1416, 1416, 1480, 1544, 1544, 1608, + 1608, 1672, 1736, 1736, 1800, 1800, 1864, 1864, 1928, 1992, 1992, + 2024, 2088, 2088, 2152, 2152, 2216, 2280, 2280, 2344, 2344, 2408, + 2472, 2472, 2536, 2536, 2600, 2600, 2664, 2728, 2728, 2792, 2792, + 2856, 2856, 2856, 2984, 2984, 2984, 3112, 3112, 3112, 3240, 3240, + 3240, 3240, 3368, 3368, 3368, 3496, 3496, 3496, 3496, 3624, 3624, + 3624, 3752, 3752, 3752, 3752, 3880, 3880, 3880, 4008, 4008, 4008}, + { 32, 72, 144, 176, 208, 256, 296, 328, 376, 424, 472, + 520, 568, 616, 648, 696, 744, 776, 840, 872, 936, 968, + 1000, 1064, 1096, 1160, 1192, 1256, 1288, 1320, 1384, 1416, 1480, + 1544, 1544, 1608, 1672, 1672, 1736, 1800, 1800, 1864, 1928, 1992, + 2024, 2088, 2088, 2152, 2216, 2216, 2280, 2344, 2344, 2408, 2472, + 2536, 2536, 2600, 2664, 2664, 2728, 2792, 2856, 2856, 2856, 2984, + 2984, 3112, 3112, 3112, 3240, 3240, 3240, 3368, 3368, 3368, 3496, + 3496, 3496, 3624, 3624, 3624, 3752, 3752, 3880, 3880, 3880, 4008, + 4008, 4008, 4136, 4136, 4136, 4264, 4264, 4264, 4392, 4392, 4392, + 4584, 4584, 4584, 4584, 4584, 4776, 4776, 4776, 4776, 4968, 4968}, + { 40, 104, 176, 208, 256, 328, 392, 440, 504, 568, 616, + 680, 744, 808, 872, 904, 968, 1032, 1096, 1160, 1224, 1256, + 1320, 1384, 1416, 1480, 1544, 1608, 1672, 1736, 1800, 1864, 1928, + 1992, 2024, 2088, 2152, 2216, 2280, 2344, 2408, 2472, 2536, 2536, + 2600, 2664, 2728, 2792, 2856, 2856, 2984, 2984, 3112, 3112, 3240, + 3240, 3368, 3368, 3496, 3496, 3624, 3624, 3624, 3752, 3752, 3880, + 3880, 4008, 4008, 4136, 4136, 4264, 4264, 4392, 4392, 4392, 4584, + 4584, 4584, 4776, 4776, 4776, 4776, 4968, 4968, 4968, 5160, 5160, + 5160, 5352, 5352, 5352, 5352, 5544, 5544, 5544, 5736, 5736, 5736, + 5736, 5992, 5992, 5992, 5992, 6200, 6200, 6200, 6200, 6456, 6456}, + { 56, 120, 208, 256, 328, 408, 488, 552, 632, 696, 776, + 840, 904, 1000, 1064, 1128, 1192, 1288, 1352, 1416, 1480, 1544, + 1608, 1736, 1800, 1864, 1928, 1992, 2088, 2152, 2216, 2280, 2344, + 2408, 2472, 2600, 2664, 2728, 2792, 2856, 2984, 2984, 3112, 3112, + 3240, 3240, 3368, 3496, 3496, 3624, 3624, 3752, 3752, 3880, 4008, + 4008, 4136, 4136, 4264, 4264, 4392, 4392, 4584, 4584, 4584, 4776, + 4776, 4968, 4968, 4968, 5160, 5160, 5160, 5352, 5352, 5544, 5544, + 5544, 5736, 5736, 5736, 5992, 5992, 5992, 5992, 6200, 6200, 6200, + 6456, 6456, 6456, 6456, 6712, 6712, 6712, 6968, 6968, 6968, 6968, + 7224, 7224, 7224, 7480, 7480, 7480, 7480, 7736, 7736, 7736, 7992}, + { 72, 144, 224, 328, 424, 504, 600, 680, 776, 872, 968, + 1032, 1128, 1224, 1320, 1384, 1480, 1544, 1672, 1736, 1864, 1928, + 2024, 2088, 2216, 2280, 2344, 2472, 2536, 2664, 2728, 2792, 2856, + 2984, 3112, 3112, 3240, 3368, 3496, 3496, 3624, 3752, 3752, 3880, + 4008, 4008, 4136, 4264, 4392, 4392, 4584, 4584, 4776, 4776, 4776, + 4968, 4968, 5160, 5160, 5352, 5352, 5544, 5544, 5736, 5736, 5736, + 5992, 5992, 5992, 6200, 6200, 6200, 6456, 6456, 6712, 6712, 6712, + 6968, 6968, 6968, 7224, 7224, 7224, 7480, 7480, 7480, 7736, 7736, + 7736, 7992, 7992, 7992, 8248, 8248, 8248, 8504, 8504, 8760, 8760, + 8760, 8760, 9144, 9144, 9144, 9144, 9528, 9528, 9528, 9528, 9528}, + { 328, 176, 256, 392, 504, 600, 712, 808, 936, 1032, 1128, + 1224, 1352, 1480, 1544, 1672, 1736, 1864, 1992, 2088, 2216, 2280, + 2408, 2472, 2600, 2728, 2792, 2984, 2984, 3112, 3240, 3368, 3496, + 3496, 3624, 3752, 3880, 4008, 4136, 4136, 4264, 4392, 4584, 4584, + 4776, 4776, 4968, 4968, 5160, 5160, 5352, 5352, 5544, 5736, 5736, + 5992, 5992, 5992, 6200, 6200, 6456, 6456, 6456, 6712, 6712, 6968, + 6968, 6968, 7224, 7224, 7480, 7480, 7736, 7736, 7736, 7992, 7992, + 8248, 8248, 8248, 8504, 8504, 8760, 8760, 8760, 9144, 9144, 9144, + 9144, 9528, 9528, 9528, 9528, 9912, 9912, 9912,10296,10296,10296, + 10296,10680,10680,10680,10680,11064,11064,11064,11448,11448,11448}, + { 104, 224, 328, 472, 584, 712, 840, 968, 1096, 1224, 1320, + 1480, 1608, 1672, 1800, 1928, 2088, 2216, 2344, 2472, 2536, 2664, + 2792, 2984, 3112, 3240, 3368, 3368, 3496, 3624, 3752, 3880, 4008, + 4136, 4264, 4392, 4584, 4584, 4776, 4968, 4968, 5160, 5352, 5352, + 5544, 5736, 5736, 5992, 5992, 6200, 6200, 6456, 6456, 6712, 6712, + 6712, 6968, 6968, 7224, 7224, 7480, 7480, 7736, 7736, 7992, 7992, + 8248, 8248, 8504, 8504, 8760, 8760, 8760, 9144, 9144, 9144, 9528, + 9528, 9528, 9912, 9912, 9912,10296,10296,10296,10680,10680,10680, + 11064,11064,11064,11448,11448,11448,11448,11832,11832,11832,12216, + 12216,12216,12576,12576,12576,12960,12960,12960,12960,13536,13536}, + { 120, 256, 392, 536, 680, 808, 968, 1096, 1256, 1384, 1544, + 1672, 1800, 1928, 2088, 2216, 2344, 2536, 2664, 2792, 2984, 3112, + 3240, 3368, 3496, 3624, 3752, 3880, 4008, 4264, 4392, 4584, 4584, + 4776, 4968, 4968, 5160, 5352, 5544, 5544, 5736, 5992, 5992, 6200, + 6200, 6456, 6456, 6712, 6968, 6968, 7224, 7224, 7480, 7480, 7736, + 7736, 7992, 7992, 8248, 8504, 8504, 8760, 8760, 9144, 9144, 9144, + 9528, 9528, 9528, 9912, 9912, 9912,10296,10296,10680,10680,10680, + 11064,11064,11064,11448,11448,11448,11832,11832,12216,12216,12216, + 12576,12576,12576,12960,12960,12960,13536,13536,13536,13536,14112, + 14112,14112,14112,14688,14688,14688,14688,15264,15264,15264,15264}, + { 136, 296, 456, 616, 776, 936, 1096, 1256, 1416, 1544, 1736, + 1864, 2024, 2216, 2344, 2536, 2664, 2856, 2984, 3112, 3368, 3496, + 3624, 3752, 4008, 4136, 4264, 4392, 4584, 4776, 4968, 5160, 5160, + 5352, 5544, 5736, 5736, 5992, 6200, 6200, 6456, 6712, 6712, 6968, + 6968, 7224, 7480, 7480, 7736, 7992, 7992, 8248, 8248, 8504, 8760, + 8760, 9144, 9144, 9144, 9528, 9528, 9912, 9912,10296,10296,10296, + 10680,10680,11064,11064,11064,11448,11448,11832,11832,11832,12216, + 12216,12576,12576,12960,12960,12960,13536,13536,13536,13536,14112, + 14112,14112,14112,14688,14688,14688,15264,15264,15264,15264,15840, + 15840,15840,16416,16416,16416,16416,16992,16992,16992,16992,17568}, + { 144, 328, 504, 680, 872, 1032, 1224, 1384, 1544, 1736, 1928, + 2088, 2280, 2472, 2664, 2792, 2984, 3112, 3368, 3496, 3752, 3880, + 4008, 4264, 4392, 4584, 4776, 4968, 5160, 5352, 5544, 5736, 5736, + 5992, 6200, 6200, 6456, 6712, 6712, 6968, 7224, 7480, 7480, 7736, + 7992, 7992, 8248, 8504, 8504, 8760, 9144, 9144, 9144, 9528, 9528, + 9912, 9912,10296,10296,10680,10680,11064,11064,11448,11448,11448, + 11832,11832,12216,12216,12576,12576,12960,12960,12960,13536,13536, + 13536,14112,14112,14112,14688,14688,14688,14688,15264,15264,15264, + 15840,15840,15840,16416,16416,16416,16992,16992,16992,16992,17568, + 17568,17568,18336,18336,18336,18336,18336,19080,19080,19080,19080}, + { 176, 376, 584, 776, 1000, 1192, 1384, 1608, 1800, 2024, 2216, + 2408, 2600, 2792, 2984, 3240, 3496, 3624, 3880, 4008, 4264, 4392, + 4584, 4776, 4968, 5352, 5544, 5736, 5992, 5992, 6200, 6456, 6712, + 6968, 6968, 7224, 7480, 7736, 7736, 7992, 8248, 8504, 8760, 8760, + 9144, 9144, 9528, 9528, 9912, 9912,10296,10680,10680,11064,11064, + 11448,11448,11832,11832,12216,12216,12576,12576,12960,12960,13536, + 13536,13536,14112,14112,14112,14688,14688,14688,15264,15264,15840, + 15840,15840,16416,16416,16416,16992,16992,16992,17568,17568,17568, + 18336,18336,18336,18336,19080,19080,19080,19080,19848,19848,19848, + 19848,20616,20616,20616,21384,21384,21384,21384,22152,22152,22152}, + { 208, 440, 680, 904, 1128, 1352, 1608, 1800, 2024, 2280, 2472, + 2728, 2984, 3240, 3368, 3624, 3880, 4136, 4392, 4584, 4776, 4968, + 5352, 5544, 5736, 5992, 6200, 6456, 6712, 6712, 6968, 7224, 7480, + 7736, 7992, 8248, 8504, 8760, 8760, 9144, 9528, 9528, 9912, 9912, + 10296,10680,10680,11064,11064,11448,11832,11832,12216,12216,12576, + 12576,12960,12960,13536,13536,14112,14112,14112,14688,14688,15264, + 15264,15264,15840,15840,16416,16416,16416,16992,16992,17568,17568, + 17568,18336,18336,18336,19080,19080,19080,19080,19848,19848,19848, + 20616,20616,20616,21384,21384,21384,21384,22152,22152,22152,22920, + 22920,22920,23688,23688,23688,23688,24496,24496,24496,24496,25456}, + { 224, 488, 744, 1000, 1256, 1544, 1800, 2024, 2280, 2536, 2856, + 3112, 3368, 3624, 3880, 4136, 4392, 4584, 4968, 5160, 5352, 5736, + 5992, 6200, 6456, 6712, 6968, 7224, 7480, 7736, 7992, 8248, 8504, + 8760, 9144, 9144, 9528, 9912, 9912,10296,10680,10680,11064,11448, + 11448,11832,12216,12216,12576,12960,12960,13536,13536,14112,14112, + 14688,14688,14688,15264,15264,15840,15840,16416,16416,16992,16992, + 16992,17568,17568,18336,18336,18336,19080,19080,19080,19848,19848, + 19848,20616,20616,20616,21384,21384,21384,22152,22152,22152,22920, + 22920,22920,23688,23688,23688,24496,24496,24496,25456,25456,25456, + 25456,26416,26416,26416,26416,27376,27376,27376,27376,28336,28336}, + { 256, 552, 840, 1128, 1416, 1736, 1992, 2280, 2600, 2856, 3112, + 3496, 3752, 4008, 4264, 4584, 4968, 5160, 5544, 5736, 5992, 6200, + 6456, 6968, 7224, 7480, 7736, 7992, 8248, 8504, 8760, 9144, 9528, + 9912, 9912,10296,10680,11064,11064,11448,11832,12216,12216,12576, + 12960,12960,13536,13536,14112,14112,14688,14688,15264,15264,15840, + 15840,16416,16416,16992,16992,17568,17568,18336,18336,18336,19080, + 19080,19848,19848,19848,20616,20616,20616,21384,21384,22152,22152, + 22152,22920,22920,22920,23688,23688,24496,24496,24496,25456,25456, + 25456,25456,26416,26416,26416,27376,27376,27376,28336,28336,28336, + 28336,29296,29296,29296,29296,30576,30576,30576,30576,31704,31704}, + { 280, 600, 904, 1224, 1544, 1800, 2152, 2472, 2728, 3112, 3368, + 3624, 4008, 4264, 4584, 4968, 5160, 5544, 5736, 6200, 6456, 6712, + 6968, 7224, 7736, 7992, 8248, 8504, 8760, 9144, 9528, 9912,10296, + 10296,10680,11064,11448,11832,11832,12216,12576,12960,12960,13536, + 13536,14112,14688,14688,15264,15264,15840,15840,16416,16416,16992, + 16992,17568,17568,18336,18336,18336,19080,19080,19848,19848,20616, + 20616,20616,21384,21384,22152,22152,22152,22920,22920,23688,23688, + 23688,24496,24496,24496,25456,25456,25456,26416,26416,26416,27376, + 27376,27376,28336,28336,28336,29296,29296,29296,29296,30576,30576, + 30576,30576,31704,31704,31704,31704,32856,32856,32856,34008,34008}, + { 328, 632, 968, 1288, 1608, 1928, 2280, 2600, 2984, 3240, 3624, + 3880, 4264, 4584, 4968, 5160, 5544, 5992, 6200, 6456, 6712, 7224, + 7480, 7736, 7992, 8504, 8760, 9144, 9528, 9912, 9912,10296,10680, + 11064,11448,11832,12216,12216,12576,12960,13536,13536,14112,14112, + 14688,14688,15264,15840,15840,16416,16416,16992,16992,17568,17568, + 18336,18336,19080,19080,19848,19848,19848,20616,20616,21384,21384, + 22152,22152,22152,22920,22920,23688,23688,24496,24496,24496,25456, + 25456,25456,26416,26416,26416,27376,27376,27376,28336,28336,28336, + 29296,29296,29296,30576,30576,30576,30576,31704,31704,31704,31704, + 32856,32856,32856,34008,34008,34008,34008,35160,35160,35160,35160}, + { 336, 696, 1064, 1416, 1800, 2152, 2536, 2856, 3240, 3624, 4008, + 4392, 4776, 5160, 5352, 5736, 6200, 6456, 6712, 7224, 7480, 7992, + 8248, 8760, 9144, 9528, 9912,10296,10296,10680,11064,11448,11832, + 12216,12576,12960,13536,13536,14112,14688,14688,15264,15264,15840, + 16416,16416,16992,17568,17568,18336,18336,19080,19080,19848,19848, + 20616,20616,20616,21384,21384,22152,22152,22920,22920,23688,23688, + 24496,24496,24496,25456,25456,26416,26416,26416,27376,27376,27376, + 28336,28336,29296,29296,29296,30576,30576,30576,30576,31704,31704, + 31704,32856,32856,32856,34008,34008,34008,35160,35160,35160,35160, + 36696,36696,36696,36696,37888,37888,37888,39232,39232,39232,39232}, + { 376, 776, 1160, 1544, 1992, 2344, 2792, 3112, 3624, 4008, 4392, + 4776, 5160, 5544, 5992, 6200, 6712, 7224, 7480, 7992, 8248, 8760, + 9144, 9528, 9912,10296,10680,11064,11448,11832,12216,12576,12960, + 13536,14112,14112,14688,15264,15264,15840,16416,16416,16992,17568, + 17568,18336,18336,19080,19080,19848,19848,20616,21384,21384,22152, + 22152,22920,22920,23688,23688,24496,24496,24496,25456,25456,26416, + 26416,27376,27376,27376,28336,28336,29296,29296,29296,30576,30576, + 30576,31704,31704,31704,32856,32856,32856,34008,34008,34008,35160, + 35160,35160,36696,36696,36696,37888,37888,37888,37888,39232,39232, + 39232,40576,40576,40576,40576,42368,42368,42368,42368,43816,43816}, + { 408, 840, 1288, 1736, 2152, 2600, 2984, 3496, 3880, 4264, 4776, + 5160, 5544, 5992, 6456, 6968, 7224, 7736, 8248, 8504, 9144, 9528, + 9912,10296,10680,11064,11448,12216,12576,12960,13536,13536,14112, + 14688,15264,15264,15840,16416,16992,16992,17568,18336,18336,19080, + 19080,19848,20616,20616,21384,21384,22152,22152,22920,22920,23688, + 24496,24496,25456,25456,25456,26416,26416,27376,27376,28336,28336, + 29296,29296,29296,30576,30576,30576,31704,31704,32856,32856,32856, + 34008,34008,34008,35160,35160,35160,36696,36696,36696,37888,37888, + 37888,39232,39232,39232,40576,40576,40576,40576,42368,42368,42368, + 43816,43816,43816,43816,45352,45352,45352,46888,46888,46888,46888}, + { 440, 904, 1384, 1864, 2344, 2792, 3240, 3752, 4136, 4584, 5160, + 5544, 5992, 6456, 6968, 7480, 7992, 8248, 8760, 9144, 9912,10296, + 10680,11064,11448,12216,12576,12960,13536,14112,14688,14688,15264, + 15840,16416,16992,16992,17568,18336,18336,19080,19848,19848,20616, + 20616,21384,22152,22152,22920,22920,23688,24496,24496,25456,25456, + 26416,26416,27376,27376,28336,28336,29296,29296,29296,30576,30576, + 31704,31704,31704,32856,32856,34008,34008,34008,35160,35160,35160, + 36696,36696,36696,37888,37888,39232,39232,39232,40576,40576,40576, + 42368,42368,42368,42368,43816,43816,43816,45352,45352,45352,46888, + 46888,46888,46888,48936,48936,48936,48936,48936,51024,51024,51024}, + { 488, 1000, 1480, 1992, 2472, 2984, 3496, 4008, 4584, 4968, 5544, + 5992, 6456, 6968, 7480, 7992, 8504, 9144, 9528, 9912,10680,11064, + 11448,12216,12576,12960,13536,14112,14688,15264,15840,15840,16416, + 16992,17568,18336,18336,19080,19848,19848,20616,21384,21384,22152, + 22920,22920,23688,24496,24496,25456,25456,26416,26416,27376,27376, + 28336,28336,29296,29296,30576,30576,31704,31704,31704,32856,32856, + 34008,34008,35160,35160,35160,36696,36696,36696,37888,37888,39232, + 39232,39232,40576,40576,40576,42368,42368,42368,43816,43816,43816, + 45352,45352,45352,46888,46888,46888,46888,48936,48936,48936,48936, + 51024,51024,51024,51024,52752,52752,52752,52752,55056,55056,55056}, + { 520, 1064, 1608, 2152, 2664, 3240, 3752, 4264, 4776, 5352, 5992, + 6456, 6968, 7480, 7992, 8504, 9144, 9528,10296,10680,11448,11832, + 12576,12960,13536,14112,14688,15264,15840,16416,16992,16992,17568, + 18336,19080,19080,19848,20616,21384,21384,22152,22920,22920,23688, + 24496,24496,25456,25456,26416,27376,27376,28336,28336,29296,29296, + 30576,30576,31704,31704,32856,32856,34008,34008,34008,35160,35160, + 36696,36696,36696,37888,37888,39232,39232,40576,40576,40576,42368, + 42368,42368,43816,43816,43816,45352,45352,45352,46888,46888,46888, + 48936,48936,48936,48936,51024,51024,51024,51024,52752,52752,52752, + 55056,55056,55056,55056,57336,57336,57336,57336,59256,59256,59256}, + { 552, 1128, 1736, 2280, 2856, 3496, 4008, 4584, 5160, 5736, 6200, + 6968, 7480, 7992, 8504, 9144, 9912,10296,11064,11448,12216,12576, + 12960,13536,14112,14688,15264,15840,16416,16992,17568,18336,19080, + 19848,19848,20616,21384,22152,22152,22920,23688,24496,24496,25456, + 25456,26416,27376,27376,28336,28336,29296,29296,30576,30576,31704, + 31704,32856,32856,34008,34008,35160,35160,36696,36696,37888,37888, + 37888,39232,39232,40576,40576,40576,42368,42368,43816,43816,43816, + 45352,45352,45352,46888,46888,46888,48936,48936,48936,51024,51024, + 51024,51024,52752,52752,52752,55056,55056,55056,55056,57336,57336, + 57336,57336,59256,59256,59256,59256,61664,61664,61664,61664,63776}, + { 584, 1192, 1800, 2408, 2984, 3624, 4264, 4968, 5544, 5992, 6712, + 7224, 7992, 8504, 9144, 9912,10296,11064,11448,12216,12960,13536, + 14112,14688,15264,15840,16416,16992,17568,18336,19080,19848,19848, + 20616,21384,22152,22920,22920,23688,24496,25456,25456,26416,26416, + 27376,28336,28336,29296,29296,30576,31704,31704,32856,32856,34008, + 34008,35160,35160,36696,36696,36696,37888,37888,39232,39232,40576, + 40576,42368,42368,42368,43816,43816,45352,45352,45352,46888,46888, + 46888,48936,48936,48936,51024,51024,51024,52752,52752,52752,52752, + 55056,55056,55056,57336,57336,57336,57336,59256,59256,59256,61664, + 61664,61664,61664,63776,63776,63776,63776,66592,66592,66592,66592}, + { 616, 1256, 1864, 2536, 3112, 3752, 4392, 5160, 5736, 6200, 6968, + 7480, 8248, 8760, 9528,10296,10680,11448,12216,12576,13536,14112, + 14688,15264,15840,16416,16992,17568,18336,19080,19848,20616,20616, + 21384,22152,22920,23688,24496,24496,25456,26416,26416,27376,28336, + 28336,29296,29296,30576,31704,31704,32856,32856,34008,34008,35160, + 35160,36696,36696,37888,37888,39232,39232,40576,40576,40576,42368, + 42368,43816,43816,43816,45352,45352,46888,46888,46888,48936,48936, + 48936,51024,51024,51024,52752,52752,52752,55056,55056,55056,55056, + 57336,57336,57336,59256,59256,59256,61664,61664,61664,61664,63776, + 63776,63776,63776,66592,66592,66592,66592,68808,68808,68808,71112}, + { 712, 1480, 2216, 2984, 3752, 4392, 5160, 5992, 6712, 7480, 8248, + 8760, 9528,10296,11064,11832,12576,13536,14112,14688,15264,16416, + 16992,17568,18336,19080,19848,20616,21384,22152,22920,23688,24496, + 25456,25456,26416,27376,28336,29296,29296,30576,30576,31704,32856, + 32856,34008,35160,35160,36696,36696,37888,37888,39232,40576,40576, + 40576,42368,42368,43816,43816,45352,45352,46888,46888,48936,48936, + 48936,51024,51024,52752,52752,52752,55056,55056,55056,55056,57336, + 57336,57336,59256,59256,59256,61664,61664,61664,63776,63776,63776, + 66592,66592,66592,68808,68808,68808,71112,71112,71112,73712,73712, + 75376,75376,75376,75376,75376,75376,75376,75376,75376,75376,75376}}; diff --git a/lte/lib/phch/test/CMakeLists.txt b/lte/lib/phch/test/CMakeLists.txt index 204441ba9..f7a6c00d1 100644 --- a/lte/lib/phch/test/CMakeLists.txt +++ b/lte/lib/phch/test/CMakeLists.txt @@ -75,6 +75,11 @@ ADD_TEST(phich_test_104 phich_test -p 4 -n 10 -e -l -g 1/2) ADD_EXECUTABLE(pdcch_test pdcch_test.c) TARGET_LINK_LIBRARIES(pdcch_test lte) +ADD_TEST(pdcch_test pdcch_test) + +ADD_EXECUTABLE(dci_unpacking dci_unpacking.c) +TARGET_LINK_LIBRARIES(dci_unpacking lte) + ######################################################################## # FILE TEST ######################################################################## @@ -88,7 +93,11 @@ TARGET_LINK_LIBRARIES(pcfich_file_test lte) ADD_EXECUTABLE(phich_file_test phich_file_test.c) TARGET_LINK_LIBRARIES(phich_file_test lte) +ADD_EXECUTABLE(pdcch_file_test pdcch_file_test.c) +TARGET_LINK_LIBRARIES(pdcch_file_test lte) + ADD_TEST(pbch_file_test pbch_file_test -i ${CMAKE_CURRENT_SOURCE_DIR}/signal.1.92M.dat) ADD_TEST(pcfich_file_test pcfich_file_test -c 150 -n 50 -p 2 -i ${CMAKE_CURRENT_SOURCE_DIR}/signal.10M.dat) ADD_TEST(phich_file_test phich_file_test -c 150 -n 50 -p 2 -i ${CMAKE_CURRENT_SOURCE_DIR}/signal.10M.dat) +ADD_TEST(pdcch_file_test pdcch_file_test -c 1 -f 3 -n 6 -p 1 -i ${CMAKE_CURRENT_SOURCE_DIR}/signal.1.92M.amar.dat) \ No newline at end of file diff --git a/lte/lib/phch/test/dci_unpacking.c b/lte/lib/phch/test/dci_unpacking.c new file mode 100644 index 000000000..97b3266ee --- /dev/null +++ b/lte/lib/phch/test/dci_unpacking.c @@ -0,0 +1,105 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * A copy of the GNU Lesser General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#include +#include +#include +#include +#include + +#include "lte.h" + +void usage(char *prog) { + printf("Usage: %s nof_prb length_bits Word0 Word1 ...\n", prog); +} + +int main(int argc, char **argv) { + dci_msg_t msg; + ra_pdsch_t ra_dl; + ra_pdsch_t ra_ul; + int len, rlen; + int nof_prb; + int nwords; + int i; + char *y; + + if (argc < 3) { + usage(argv[0]); + exit(-1); + } + + nof_prb = atoi(argv[1]); + len = atoi(argv[2]); + + nwords = (len-1)/32+1; + + if (argc < 3 + nwords) { + usage(argv[0]); + exit(-1); + } + + y = msg.data; + rlen = 0; + unsigned int x; + for (i=0;i +#include +#include +#include +#include + +#include "lte.h" + +char *input_file_name = NULL; +char *matlab_file_name = NULL; +int cell_id = 0; +int cfi = 2; +lte_cp_t cp = CPNORM; +int nof_prb = 6; +int nof_ports = 1; +int flen; +unsigned short rnti = SIRNTI; +int max_frames = 10; +FILE *fmatlab = NULL; + +filesource_t fsrc; +pdcch_t pdcch; +cf_t *input_buffer, *fft_buffer, *ce[MAX_PORTS_CTRL]; +regs_t regs; +lte_fft_t fft; +chest_t chest; +dci_t dci_rx; + +void usage(char *prog) { + printf("Usage: %s [vcfoe] -i input_file\n", prog); + printf("\t-o output matlab file name [Default Disabled]\n"); + printf("\t-c cell_id [Default %d]\n", cell_id); + printf("\t-f cfi [Default %d]\n", cfi); + printf("\t-r rnti [Default SI-RNTI]\n"); + printf("\t-p nof_ports [Default %d]\n", nof_ports); + printf("\t-n nof_prb [Default %d]\n", nof_prb); + printf("\t-m max_frames [Default %d]\n", max_frames); + printf("\t-e Set extended prefix [Default Normal]\n"); + printf("\t-v [set verbose to debug, default none]\n"); +} + +void parse_args(int argc, char **argv) { + int opt; + while ((opt = getopt(argc, argv, "irovfcenmp")) != -1) { + switch(opt) { + case 'i': + input_file_name = argv[optind]; + break; + case 'c': + cell_id = atoi(argv[optind]); + break; + case 'r': + rnti = strtoul(argv[optind], NULL, 0); + break; + case 'm': + max_frames = strtoul(argv[optind], NULL, 0); + break; + case 'f': + cfi = atoi(argv[optind]); + break; + case 'n': + nof_prb = atoi(argv[optind]); + break; + case 'p': + nof_ports = atoi(argv[optind]); + break; + case 'o': + matlab_file_name = argv[optind]; + break; + case 'v': + verbose++; + break; + case 'e': + cp = CPEXT; + break; + default: + usage(argv[0]); + exit(-1); + } + } + if (!input_file_name) { + usage(argv[0]); + exit(-1); + } +} + +int base_init() { + int i; + + if (filesource_init(&fsrc, input_file_name, COMPLEX_FLOAT_BIN)) { + fprintf(stderr, "Error opening file %s\n", input_file_name); + exit(-1); + } + + if (matlab_file_name) { + fmatlab = fopen(matlab_file_name, "w"); + if (!fmatlab) { + perror("fopen"); + return -1; + } + } else { + fmatlab = NULL; + } + + flen = 2 * (SLOT_LEN(lte_symbol_sz(nof_prb), cp)); + + input_buffer = malloc(flen * sizeof(cf_t)); + if (!input_buffer) { + perror("malloc"); + exit(-1); + } + + fft_buffer = malloc(CP_NSYMB(cp) * nof_prb * RE_X_RB * sizeof(cf_t)); + if (!fft_buffer) { + perror("malloc"); + return -1; + } + + for (i=0;i