Merge pull request #4 from libLTE/master

Merge from ismagom
This commit is contained in:
suttonpd 2014-05-14 10:52:18 +01:00
commit b1fc0986b1
33 changed files with 1670 additions and 97 deletions

View file

@ -25,9 +25,9 @@ The library currently uses Ettus Universal Hardware Driver (UHD). Thus, any hard
Download & Install Instructions
=================================
* Requirements: Currently, the library requires libfftw, although we plan make this dependency optional in the future. Also, QT4 is needed for graphics visualization. Compilation is possible without QT4, although graphics will be disabled.
* Requirements: Currently, the library requires libfftw, although we plan make this dependency optional in the future. Also, QT4 and Qwt6 are needed for graphics visualization. Compilation is possible without QT4, although graphics will be disabled.
To install QT4 and libfftw use your distribution packet management system, for instance in ubuntu you can run: `sudo apt-get install libfftw3-dev libqt4-dev` to install all requirements.
To install QT4, Qwt6 and libfftw use your distribution packet management system, for instance in ubuntu you can run: `sudo apt-get install libfftw3-dev libqwt-dev libqt4-dev` to install all requirements.
Finally, to download and build libLTE, just run:

View file

@ -0,0 +1,25 @@
#ifdef CHECK_FUNCTION_EXISTS
char CHECK_FUNCTION_EXISTS();
#ifdef __CLASSIC_C__
int main(){
int ac;
char*av[];
#else
int main(int ac, char*av[]){
#endif
float ac2 = sqrtf(rand());
CHECK_FUNCTION_EXISTS();
if(ac2 * ac > 1000)
{
return *av[0];
}
return 0;
}
#else /* CHECK_FUNCTION_EXISTS */
# error "CHECK_FUNCTION_EXISTS has to specify the function"
#endif /* CHECK_FUNCTION_EXISTS */

View file

@ -0,0 +1,57 @@
# - Check if a C function can be linked
# CHECK_FUNCTION_EXISTS(<function> <variable>)
#
# Check that the <function> is provided by libraries on the system and
# store the result in a <variable>. This does not verify that any
# system header file declares the function, only that it can be found
# at link time (considure using CheckSymbolExists).
#
# The following variables may be set before calling this macro to
# modify the way the check is run:
#
# CMAKE_REQUIRED_FLAGS = string of compile command line flags
# CMAKE_REQUIRED_DEFINITIONS = list of macros to define (-DFOO=bar)
# CMAKE_REQUIRED_INCLUDES = list of include directories
# CMAKE_REQUIRED_LIBRARIES = list of libraries to link
MACRO(CHECK_FUNCTION_EXISTS_MATH FUNCTION VARIABLE)
IF("${VARIABLE}" MATCHES "^${VARIABLE}$")
SET(MACRO_CHECK_FUNCTION_DEFINITIONS
"-DCHECK_FUNCTION_EXISTS=${FUNCTION} ${CMAKE_REQUIRED_FLAGS}")
MESSAGE(STATUS "Looking for ${FUNCTION}")
IF(CMAKE_REQUIRED_LIBRARIES)
SET(CHECK_FUNCTION_EXISTS_ADD_LIBRARIES
"-DLINK_LIBRARIES:STRING=${CMAKE_REQUIRED_LIBRARIES}")
ELSE(CMAKE_REQUIRED_LIBRARIES)
SET(CHECK_FUNCTION_EXISTS_ADD_LIBRARIES)
ENDIF(CMAKE_REQUIRED_LIBRARIES)
IF(CMAKE_REQUIRED_INCLUDES)
SET(CHECK_FUNCTION_EXISTS_ADD_INCLUDES
"-DINCLUDE_DIRECTORIES:STRING=${CMAKE_REQUIRED_INCLUDES}")
ELSE(CMAKE_REQUIRED_INCLUDES)
SET(CHECK_FUNCTION_EXISTS_ADD_INCLUDES)
ENDIF(CMAKE_REQUIRED_INCLUDES)
TRY_COMPILE(${VARIABLE}
${CMAKE_BINARY_DIR}
${CMAKE_SOURCE_DIR}/cmake/modules/CheckFunctionExists.c
COMPILE_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS}
CMAKE_FLAGS -DCOMPILE_DEFINITIONS:STRING=${MACRO_CHECK_FUNCTION_DEFINITIONS}
"${CHECK_FUNCTION_EXISTS_ADD_LIBRARIES}"
"${CHECK_FUNCTION_EXISTS_ADD_INCLUDES}"
OUTPUT_VARIABLE OUTPUT)
IF(${VARIABLE})
SET(${VARIABLE} 1 CACHE INTERNAL "Have function ${FUNCTION}")
MESSAGE(STATUS "Looking for ${FUNCTION} - found")
FILE(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
"Determining if the function ${FUNCTION} exists passed with the following output:\n"
"${OUTPUT}\n\n")
ELSE(${VARIABLE})
MESSAGE(STATUS "Looking for ${FUNCTION} - not found")
SET(${VARIABLE} "" CACHE INTERNAL "Have function ${FUNCTION}")
FILE(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
"Determining if the function ${FUNCTION} exists failed with the following output:\n"
"${OUTPUT}\n\n")
ENDIF(${VARIABLE})
ENDIF("${VARIABLE}" MATCHES "^${VARIABLE}$")
ENDMACRO(CHECK_FUNCTION_EXISTS_MATH)

View file

@ -24,6 +24,36 @@ FIND_LIBRARY(
/usr/lib64
)
# Some functions are not defined in old volk versions
SET(CMAKE_REQUIRED_LIBRARIES volk m)
CHECK_FUNCTION_EXISTS_MATH(volk_32f_index_max_16u HAVE_VOLK_MAX_FUNCTION)
CHECK_FUNCTION_EXISTS_MATH(volk_32f_accumulator_s32f HAVE_VOLK_ACC_FUNCTION)
CHECK_FUNCTION_EXISTS_MATH(volk_32fc_s32fc_multiply_32fc HAVE_VOLK_MULT_FUNCTION)
CHECK_FUNCTION_EXISTS_MATH(volk_32fc_conjugate_32fc HAVE_VOLK_CONJ_FUNCTION)
CHECK_FUNCTION_EXISTS_MATH(volk_32fc_x2_multiply_32fc HAVE_VOLK_MULT2_FUNCTION)
CHECK_FUNCTION_EXISTS_MATH(volk_32fc_magnitude_32f HAVE_VOLK_MAG_FUNCTION)
SET(VOLK_DEFINITIONS "HAVE_VOLK")
IF(${HAVE_VOLK_MAX_FUNCTION})
SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_MAX_FUNCTION")
ENDIF()
IF(${HAVE_VOLK_ACC_FUNCTION})
SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_ACC_FUNCTION")
ENDIF()
IF(${HAVE_VOLK_MULT_FUNCTION})
SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_MULT_FUNCTION")
ENDIF()
IF(${HAVE_VOLK_CONJ_FUNCTION})
SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_CONJ_FUNCTION")
ENDIF()
IF(${HAVE_VOLK_MULT2_FUNCTION})
SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_MULT2_FUNCTION")
ENDIF()
IF(${HAVE_VOLK_MAG_FUNCTION})
SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_MAG_FUNCTION")
ENDIF()
INCLUDE(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(VOLK DEFAULT_MSG VOLK_LIBRARIES VOLK_INCLUDE_DIRS)
MARK_AS_ADVANCED(VOLK_LIBRARIES VOLK_INCLUDE_DIRS)
MARK_AS_ADVANCED(VOLK_LIBRARIES VOLK_INCLUDE_DIRS VOLK_DEFINITIONS)

View file

@ -152,7 +152,7 @@ void base_init() {
fprintf(stderr, "Error creating iFFT object\n");
exit(-1);
}
if (pbch_init(&pbch, cell_id, CPNORM)) {
if (pbch_init(&pbch, 6, cell_id, CPNORM)) {
fprintf(stderr, "Error creating PBCH object\n");
exit(-1);
}
@ -249,7 +249,7 @@ int main(int argc, char **argv) {
sss_put_slot(ns?sss_signal5:sss_signal0, slot_buffer, nof_prb, CPNORM);
break;
case 1: // tx pbch
pbch_encode(&pbch, &mib, slot1_symbols, nof_prb, 1);
pbch_encode(&pbch, &mib, slot1_symbols, 1);
break;
default: // transmit zeros
break;

View file

@ -274,7 +274,7 @@ int mib_decoder_init(int cell_id) {
return -1;
}
if (pbch_init(&pbch, cell_id, CPNORM)) {
if (pbch_init(&pbch, 6, cell_id, CPNORM)) {
fprintf(stderr, "Error initiating PBCH\n");
return -1;
}
@ -292,7 +292,7 @@ int mib_decoder_run(cf_t *input, pbch_mib_t *mib) {
}
DEBUG("Decoding PBCH\n", 0);
n = pbch_decode(&pbch, fft_buffer, ce, 6, 1, mib);
n = pbch_decode(&pbch, fft_buffer, ce, 1, mib);
#ifndef DISABLE_GRAPHICS

View file

@ -325,7 +325,7 @@ int mib_decoder_init(int cell_id) {
return -1;
}
if (pbch_init(&pbch, cell_id, CPNORM)) {
if (pbch_init(&pbch, 6, cell_id, CPNORM)) {
fprintf(stderr, "Error initiating PBCH\n");
return -1;
}
@ -343,7 +343,7 @@ int mib_decoder_run(cf_t *input, pbch_mib_t *mib) {
}
DEBUG("Decoding PBCH\n", 0);
return pbch_decode(&pbch, fft_buffer, ce, 6, 1, mib);
return pbch_decode(&pbch, fft_buffer, ce, 1, mib);
}
int main(int argc, char **argv) {

View file

@ -72,6 +72,8 @@
#include "lte/mimo/layermap.h"
#include "lte/phch/regs.h"
#include "lte/phch/dci.h"
#include "lte/phch/pdcch.h"
#include "lte/phch/pbch.h"
#include "lte/phch/pcfich.h"
#include "lte/phch/phich.h"

View file

@ -32,6 +32,8 @@
#define NSUBFRAMES_X_FRAME 10
#define NSLOTS_X_FRAME (2*NSUBFRAMES_X_FRAME)
#define LTE_NIL_SYMBOL 2
#define MAX_PORTS 4
#define MAX_PORTS_CTRL 4
#define MAX_LAYERS 8
@ -39,6 +41,9 @@
typedef enum {CPNORM, CPEXT} lte_cp_t;
#define SIRNTI 0xFFFF
#define PRNTI 0xFFFE
#define MAX_NSYMB 7
#define CPNORM_NSYMB 7

View file

@ -44,5 +44,6 @@ int sequence_LTEPRS(sequence_t *q, int len, int seed);
int sequence_pbch(sequence_t *seq, lte_cp_t cp, int cell_id);
int sequence_pcfich(sequence_t *seq, int nslot, int cell_id);
int sequence_phich(sequence_t *seq, int nslot, int cell_id);
int sequence_pdcch(sequence_t *seq, int nslot, int cell_id, int len);
#endif

View file

@ -38,11 +38,10 @@ typedef struct {
int R;
int K;
int poly[3];
int framelength;
bool tail_biting;
}convcoder_t;
int convcoder_encode(convcoder_t *q, char *input, char *output);
int convcoder_encode(convcoder_t *q, char *input, char *output, int frame_length);
/* High-level API */

View file

@ -30,6 +30,11 @@
#ifndef CRC_
#define CRC_
#define LTE_CRC24A 0x1864CFB
#define LTE_CRC24B 0X1800063
#define LTE_CRC16 0x11021
#define LTE_CRC8 0x19B
unsigned int crc(unsigned int crc, char *bufptr, int len,
int long_crc,unsigned int poly, int paste_word);

View file

@ -42,16 +42,16 @@ typedef struct {
unsigned int framebits;
bool tail_biting;
int poly[3];
int (*decode) (void*, unsigned char*, char*);
int (*decode) (void*, unsigned char*, char*, int);
void (*free) (void*);
unsigned char *tmp;
unsigned char *symbols_uc;
}viterbi_t;
int viterbi_init(viterbi_t *q, viterbi_type_t type, int poly[3], int framebits, bool tail_bitting);
int viterbi_init(viterbi_t *q, viterbi_type_t type, int poly[3], int max_frame_length, bool tail_bitting);
void viterbi_free(viterbi_t *q);
int viterbi_decode_f(viterbi_t *q, float *symbols, char *data);
int viterbi_decode_uc(viterbi_t *q, unsigned char *symbols, char *data);
int viterbi_decode_f(viterbi_t *q, float *symbols, char *data, int frame_length);
int viterbi_decode_uc(viterbi_t *q, unsigned char *symbols, char *data, int frame_length);
/* High-level API */

113
lte/include/lte/phch/dci.h Normal file
View file

@ -0,0 +1,113 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2014 The libLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the libLTE library.
*
* libLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* libLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* A copy of the GNU Lesser General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#ifndef DCI_
#define DCI_
#include "lte/common/base.h"
typedef _Complex float cf_t;
/**
* DCI message generation according to the formats, as specified in
* 36.212 Section 5.3.3.1
*
* Call the function dci_init(&q) to generate a collection of DCI messages
* to be transmitted in a subframe. Each subsequent call to
* dci_add_formatXX(&q, ...) generates the DCI message and appends the data
* to the collection "q".
*
*/
#define DCI_MAX_BITS 45
typedef enum {
FORMAT0,
FORMAT1,
FORMAT1A,
/* ... */
}dci_format_t;
typedef enum {
DCI_COMMON=0, DCI_UE=1
}dci_spec_t;
/** TODO: this is Release 8 */
typedef struct {
/* 36.213 Table 8.4-2: hop_half is 0 for < 10 Mhz and 10 for > 10 Mh.
* hop_quart is 00 for > 10 Mhz and hop_quart_neg is 01 for > 10 Mhz.
*/
enum {hop_disabled, hop_half, hop_quart, hop_quart_neg, hop_type_2} freq_hop_fl;
int n_rb_ul; // number of resource blocks
int riv; // Resource Indication Value (36.213 8.1)
int mcs_and_rv; // MCS and RV value
enum {ndi_true=1, ndi_false=0} ndi; // New Data Indicator
int tpc; // Transmit Power Control
int dm_rs; // DM RS
enum {cqi_true=0, cqi_false=1} cqi_request;
}dci_format0_t;
typedef struct {
}dci_format1_t;
typedef struct {
unsigned char nof_bits;
unsigned char L; // Aggregation level
unsigned char ncce; // Position of first CCE of the dci
unsigned short rnti;
}dci_candidate_t;
typedef struct {
char data[DCI_MAX_BITS];
dci_candidate_t location;
}dci_msg_t;
typedef struct {
dci_msg_t *msg;
int nof_dcis;
}dci_t;
int dci_init(dci_t *q, int nof_dci);
void dci_free(dci_t *q);
void dci_candidate_fprint(FILE *f, dci_candidate_t *q);
int dci_format0_add(dci_t *q, dci_format0_t *msg, int L, int nCCE, unsigned short rnti);
int dci_format0_sizeof(int nof_prb);
int dci_format1_add(dci_t *q, dci_format1_t *msg, int L, int nCCE, unsigned short rnti);
int dci_format1_sizeof(int nof_prb, int P);
int dci_format1A_add(dci_t *q, dci_format1_t *msg);
int dci_format1A_sizeof(int nof_prb, bool random_access_initiated);
int dci_format1C_add(dci_t *q, dci_format1_t *msg);
int dci_format1C_sizeof();
#endif

View file

@ -57,6 +57,7 @@ typedef struct {
typedef struct {
int cell_id;
lte_cp_t cp;
int nof_prb;
int nof_symbols;
/* buffers */
@ -82,11 +83,10 @@ typedef struct {
}pbch_t;
int pbch_init(pbch_t *q, int cell_id, lte_cp_t cp);
int pbch_init(pbch_t *q, int nof_prb, int cell_id, lte_cp_t cp);
void pbch_free(pbch_t *q);
int pbch_decode(pbch_t *q, cf_t *slot1_symbols, cf_t *ce[MAX_PORTS_CTRL], int nof_prb, float ebno, pbch_mib_t *mib);
void pbch_encode(pbch_t *q, pbch_mib_t *mib, cf_t *slot1_symbols[MAX_PORTS_CTRL],
int nof_prb, int nof_ports);
int pbch_decode(pbch_t *q, cf_t *slot1_symbols, cf_t *ce[MAX_PORTS_CTRL], float ebno, pbch_mib_t *mib);
void pbch_encode(pbch_t *q, pbch_mib_t *mib, cf_t *slot1_symbols[MAX_PORTS_CTRL], int nof_ports);
void pbch_decode_reset(pbch_t *q);
void pbch_mib_fprint(FILE *stream, pbch_mib_t *mib);

View file

@ -0,0 +1,126 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2014 The libLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the libLTE library.
*
* libLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* libLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* A copy of the GNU Lesser General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#ifndef PDCCH_
#define PDCCH_
#include "lte/common/base.h"
#include "lte/mimo/precoding.h"
#include "lte/mimo/layermap.h"
#include "lte/modem/mod.h"
#include "lte/modem/demod_soft.h"
#include "lte/scrambling/scrambling.h"
#include "lte/ratematching/rm_conv.h"
#include "lte/fec/convcoder.h"
#include "lte/fec/viterbi.h"
#include "lte/fec/crc.h"
#include "lte/phch/dci.h"
#include "lte/phch/regs.h"
typedef _Complex float cf_t;
#define PDCCH_NOF_SEARCH_MODES 3
typedef enum {
SEARCH_NONE=3, SEARCH_SI=0, SEARCH_RA=1, SEARCH_UE=2
}pdcch_search_mode_t;
/*
* A search mode is indicated by higher layers to look for SI/C/RA-RNTI
* DCI messages as defined in Section 7.1 of 36.213
*/
typedef struct {
int nof_candidates;
dci_candidate_t *candidates[NSUBFRAMES_X_FRAME];
}pdcch_search_t;
/* PDCCH object */
typedef struct {
int cell_id;
lte_cp_t cp;
int nof_prb;
int nof_bits;
int nof_symbols;
int nof_ports;
int nof_regs;
int nof_cce;
pdcch_search_t search_mode[PDCCH_NOF_SEARCH_MODES];
pdcch_search_mode_t current_search_mode;
regs_t *regs;
/* buffers */
cf_t *ce[MAX_PORTS_CTRL];
cf_t *pdcch_symbols[MAX_PORTS_CTRL];
cf_t *pdcch_x[MAX_PORTS_CTRL];
cf_t *pdcch_d;
char *pdcch_e;
float *pdcch_llr;
/* tx & rx objects */
modem_table_t mod;
demod_soft_t demod;
sequence_t seq_pdcch[NSUBFRAMES_X_FRAME];
viterbi_t decoder;
}pdcch_t;
int pdcch_init(pdcch_t *q, regs_t *regs, int nof_prb, int nof_ports, int cell_id, lte_cp_t cp);
void pdcch_free(pdcch_t *q);
/* Encoding functions */
int pdcch_encode(pdcch_t *q, dci_t *dci, cf_t *slot1_symbols[MAX_PORTS_CTRL], int nsubframe);
/* Decoding functions */
/* There are two ways to decode the DCI messages:
* a) call pdcch_set_search_si/ue/ra and then call pdcch_decode()
* b) call pdcch_extract_llr() and then call pdcch_decode_si/ue/ra
*/
int pdcch_decode(pdcch_t *q, cf_t *slot1_symbols, cf_t *ce[MAX_PORTS_CTRL],
dci_t *dci, int nsubframe, float ebno);
int pdcch_extract_llr(pdcch_t *q, cf_t *slot1_symbols, cf_t *ce[MAX_PORTS_CTRL], float *llr,
int nsubframe, float ebno);
void pdcch_init_search_si(pdcch_t *q);
void pdcch_set_search_si(pdcch_t *q);
int pdcch_decode_si(pdcch_t *q, float *llr, dci_t *dci);
void pdcch_init_search_ue(pdcch_t *q, unsigned short c_rnti);
void pdcch_set_search_ue(pdcch_t *q);
int pdcch_decode_ue(pdcch_t *q, float *llr, dci_t *dci, int nsubframe);
void pdcch_init_search_ra(pdcch_t *q, unsigned short ra_rnti);
void pdcch_set_search_ra(pdcch_t *q);
int pdcch_decode_ra(pdcch_t *q, float *llr, dci_t *dci);
#endif

View file

@ -89,5 +89,6 @@ int regs_phich_get(regs_t *h, cf_t *slot_symbols, cf_t phich_symbols[REGS_PHICH_
int regs_phich_ngroups(regs_t *h);
int regs_phich_reset(regs_t *h, cf_t *slot_symbols);
int regs_pdcch_nregs(regs_t *h);
#endif

View file

@ -23,6 +23,7 @@
########################################################################
# Find Dependencies
########################################################################
include(CheckFunctionExistsMath)
FIND_PACKAGE(FFTW3F REQUIRED) # TODO: distribute kissfft instead
INCLUDE_DIRECTORIES(${FFTW3F_INCLUDE_DIRS})
@ -57,9 +58,9 @@ LIBLTE_SET_PIC(lte)
IF(VOLK_FOUND)
INCLUDE_DIRECTORIES(${VOLK_INCLUDE_DIRS})
SET_TARGET_PROPERTIES(lte PROPERTIES COMPILE_DEFINITIONS "HAVE_VOLK")
SET_TARGET_PROPERTIES(lte PROPERTIES COMPILE_DEFINITIONS "${VOLK_DEFINITIONS}")
TARGET_LINK_LIBRARIES(lte ${VOLK_LIBRARIES})
MESSAGE(STATUS " Compiling with VOLK SIMD library.")
MESSAGE(STATUS " Compiling with VOLK SIMD library.")
ELSE(VOLK_FOUND)
MESSAGE(STATUS " VOLK SIMD library NOT found. Using generic implementation.")
ENDIF(VOLK_FOUND)

View file

@ -33,27 +33,25 @@
#include "lte/fec/convcoder.h"
#include "parity.h"
int convcoder_encode(convcoder_t *q, char *input, char *output) {
int convcoder_encode(convcoder_t *q, char *input, char *output, int frame_length) {
unsigned int sr;
int i,j;
int len = q->tail_biting ? q->framelength : (q->framelength + q->K - 1);
int len = q->tail_biting ? frame_length : (frame_length + q->K - 1);
if (q->tail_biting) {
sr = 0;
for (i=q->framelength - q->K + 1; i<q->framelength; i++) {
for (i=frame_length - q->K + 1; i<frame_length; i++) {
sr = (sr << 1) | (input[i] & 1);
}
} else {
sr = 0;
}
//printf("Start state %d\n", sr);
for (i = 0; i < len; i++) {
int bit = (i < q->framelength) ? (input[i] & 1) : 0;
int bit = (i < frame_length) ? (input[i] & 1) : 0;
sr = (sr << 1) | bit;
for (j=0;j<q->R;j++) {
output[q->R * i + j] = parity(sr & q->poly[j]);
}
//printf("%3d - sr=%u\n", i, sr%64);
}
return q->R*len;
@ -69,12 +67,11 @@ int convcoder_work(convcoder_hl* hl) {
hl->obj.K = hl->ctrl_in.constraint_length;
hl->obj.R = hl->ctrl_in.rate;
hl->obj.framelength = hl->in_len;
hl->obj.poly[0] = hl->ctrl_in.generator_0;
hl->obj.poly[1] = hl->ctrl_in.generator_1;
hl->obj.poly[2] = hl->ctrl_in.generator_2;
hl->obj.tail_biting = hl->ctrl_in.tail_bitting?true:false;
hl->out_len = convcoder_encode(&hl->obj, hl->input, hl->output);
hl->out_len = convcoder_encode(&hl->obj, hl->input, hl->output, hl->in_len);
return 0;
}

View file

@ -38,49 +38,62 @@
#define DEB 0
int decode37(void *o, unsigned char *symbols, char *data) {
int decode37(void *o, unsigned char *symbols, char *data, int frame_length) {
viterbi_t *q = o;
int i;
int best_state;
if (frame_length > q->framebits) {
fprintf(stderr, "Initialized decoder for max frame length %d bits\n",
q->framebits);
return -1;
}
/* Initialize Viterbi decoder */
init_viterbi37_port(q->ptr, q->tail_biting?-1:0);
init_viterbi37_port(q->ptr, q->tail_biting ? -1 : 0);
/* Decode block */
if (q->tail_biting) {
memcpy(q->tmp, symbols, 3 * q->framebits * sizeof(char));
for (i=0;i<3*(q->K-1);i++) {
q->tmp[i+3*q->framebits] = q->tmp[i];
memcpy(q->tmp, symbols, 3 * frame_length * sizeof(char));
for (i = 0; i < 3 * (q->K - 1); i++) {
q->tmp[i + 3 * frame_length] = q->tmp[i];
}
} else {
q->tmp = symbols;
}
update_viterbi37_blk_port(q->ptr, q->tmp, q->framebits + q->K - 1, q->tail_biting?&best_state:NULL);
update_viterbi37_blk_port(q->ptr, q->tmp, frame_length + q->K - 1,
q->tail_biting ? &best_state : NULL);
/* Do Viterbi chainback */
chainback_viterbi37_port(q->ptr, data, q->framebits, q->tail_biting?best_state:0);
chainback_viterbi37_port(q->ptr, data, frame_length,
q->tail_biting ? best_state : 0);
return q->framebits;
}
int decode39(void *o, unsigned char *symbols, char *data) {
int decode39(void *o, unsigned char *symbols, char *data, int frame_length) {
viterbi_t *q = o;
if (frame_length > q->framebits) {
fprintf(stderr, "Initialized decoder for max frame length %d bits\n",
q->framebits);
return -1;
}
/* Initialize Viterbi decoder */
init_viterbi39_port(q->ptr, 0);
/* Decode block */
update_viterbi39_blk_port(q->ptr, symbols,q->framebits + q->K - 1);
update_viterbi39_blk_port(q->ptr, symbols, frame_length + q->K - 1);
/* Do Viterbi chainback */
chainback_viterbi39_port(q->ptr, data, q->framebits, 0);
chainback_viterbi39_port(q->ptr, data, frame_length, 0);
return q->framebits;
}
void free37(void *o) {
viterbi_t *q = o;
if (q->symbols_uc) {
@ -107,13 +120,13 @@ int init37(viterbi_t *q, int poly[3], int framebits, bool tail_biting) {
q->tail_biting = tail_biting;
q->decode = decode37;
q->free = free37;
q->symbols_uc = malloc(3 * (q->framebits + q->K -1) * sizeof(char));
q->symbols_uc = malloc(3 * (q->framebits + q->K - 1) * sizeof(char));
if (!q->symbols_uc) {
perror("malloc");
return -1;
}
if (q->tail_biting) {
q->tmp = malloc(3 * (q->framebits + q->K -1) * sizeof(char));
q->tmp = malloc(3 * (q->framebits + q->K - 1) * sizeof(char));
if (!q->tmp) {
perror("malloc");
free37(q);
@ -140,10 +153,11 @@ int init39(viterbi_t *q, int poly[3], int framebits, bool tail_biting) {
q->decode = decode39;
q->free = free39;
if (q->tail_biting) {
fprintf(stderr, "Error: Tailbitting not supported in 1/3 K=9 decoder\n");
fprintf(stderr,
"Error: Tailbitting not supported in 1/3 K=9 decoder\n");
return -1;
}
q->symbols_uc = malloc(3 * (q->framebits + q->K -1) * sizeof(char));
q->symbols_uc = malloc(3 * (q->framebits + q->K - 1) * sizeof(char));
if (!q->symbols_uc) {
perror("malloc");
return -1;
@ -157,12 +171,13 @@ int init39(viterbi_t *q, int poly[3], int framebits, bool tail_biting) {
}
}
int viterbi_init(viterbi_t *q, viterbi_type_t type, int poly[3], int framebits, bool tail_bitting) {
switch(type) {
int viterbi_init(viterbi_t *q, viterbi_type_t type, int poly[3],
int max_frame_length, bool tail_bitting) {
switch (type) {
case viterbi_37:
return init37(q, poly, framebits, tail_bitting);
return init37(q, poly, max_frame_length, tail_bitting);
case viterbi_39:
return init39(q, poly, framebits, tail_bitting);
return init39(q, poly, max_frame_length, tail_bitting);
default:
fprintf(stderr, "Decoder not implemented\n");
return -1;
@ -174,22 +189,27 @@ void viterbi_free(viterbi_t *q) {
}
/* symbols are real-valued */
int viterbi_decode_f(viterbi_t *q, float *symbols, char *data) {
int viterbi_decode_f(viterbi_t *q, float *symbols, char *data, int frame_length) {
int len;
if (frame_length > q->framebits) {
fprintf(stderr, "Initialized decoder for max frame length %d bits\n",
q->framebits);
return -1;
}
if (q->tail_biting) {
len = 3 * q->framebits;
len = 3 * frame_length;
} else {
len = 3 * (q->framebits + q->K - 1);
len = 3 * (frame_length + q->K - 1);
}
vec_quant_fuc(symbols, q->symbols_uc, 32, 127.5, 255, len);
return q->decode(q, q->symbols_uc, data);
return q->decode(q, q->symbols_uc, data, frame_length);
}
int viterbi_decode_uc(viterbi_t *q, unsigned char *symbols, char *data) {
return q->decode(q, symbols, data);
int viterbi_decode_uc(viterbi_t *q, unsigned char *symbols, char *data,
int frame_length) {
return q->decode(q, symbols, data, frame_length);
}
int viterbi_initialize(viterbi_hl* h) {
int poly[3];
viterbi_type_t type;
@ -222,15 +242,16 @@ int viterbi_initialize(viterbi_hl* h) {
poly[1] = h->init.generator_1;
poly[2] = h->init.generator_2;
return viterbi_init(&h->obj, type, poly, h->init.frame_length,
h->init.tail_bitting?true:false);
h->init.tail_bitting ? true : false);
}
int viterbi_work(viterbi_hl* hl) {
if (hl->in_len != hl->init.frame_length) {
fprintf(stderr, "Expected input length %d but got %d\n", hl->init.frame_length, hl->in_len);
fprintf(stderr, "Expected input length %d but got %d\n",
hl->init.frame_length, hl->in_len);
return -1;
}
return viterbi_decode_f(&hl->obj, hl->input, hl->output);
return viterbi_decode_f(&hl->obj, hl->input, hl->output, hl->init.frame_length);
}
int viterbi_stop(viterbi_hl* h) {

View file

@ -27,6 +27,8 @@
#include <stdbool.h>
#include "lte/fec/crc.h"
typedef struct {
int n;
int l;
@ -37,10 +39,10 @@ typedef struct {
static expected_word_t expected_words[] = {
{5000, 24, 0x1864CFB, 1, 0x4D0836}, // LTE CRC24A (36.212 Sec 5.1.1)
{5000, 24, 0X1800063, 1, 0x9B68F8}, // LTE CRC24B
{5000, 16, 0x11021, 1, 0xBFFA}, // LTE CRC16
{5000, 8, 0x19B, 1, 0xF8}, // LTE CRC8
{5000, 24, LTE_CRC24A, 1, 0x4D0836}, // LTE CRC24A (36.212 Sec 5.1.1)
{5000, 24, LTE_CRC24B, 1, 0x9B68F8}, // LTE CRC24B
{5000, 16, LTE_CRC16, 1, 0xBFFA}, // LTE CRC16
{5000, 8, LTE_CRC8, 1, 0xF8}, // LTE CRC8
{-1, -1, 0, 0, 0}
};

View file

@ -187,7 +187,6 @@ int main(int argc, char **argv) {
max_coded_length = 0;
for (i=0;i<ncods;i++) {
cod[i].R = 3;
cod[i].framelength = frame_length;
coded_length[i] = cod[i].R * (frame_length + ((cod[i].tail_biting) ? 0 : cod[i].K - 1));
if (coded_length[i] > max_coded_length) {
max_coded_length = coded_length[i];
@ -273,7 +272,7 @@ int main(int argc, char **argv) {
/* coded BER */
for (n=0;n<ncods;n++) {
convcoder_encode(&cod[n], data_tx, symbols);
convcoder_encode(&cod[n], data_tx, symbols, frame_length);
for (j = 0; j < coded_length[n]; j++) {
llr[j] = symbols[j] ? sqrt(2) : -sqrt(2);
@ -283,7 +282,7 @@ int main(int argc, char **argv) {
vec_quant_fuc(llr, llr_c, Gain, 127.5, 255, coded_length[n]);
/* decoder 1 */
viterbi_decode_uc(&dec[n], llr_c, data_rx[1+n]);
viterbi_decode_uc(&dec[n], llr_c, data_rx[1+n], frame_length);
}
/* check errors */

122
lte/lib/phch/src/dci.c Normal file
View file

@ -0,0 +1,122 @@
/**
*
* \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 <stdint.h>
#include <stdio.h>
#include <string.h>
#include <strings.h>
#include <stdlib.h>
#include <stdbool.h>
#include <assert.h>
#include <math.h>
#include "lte/phch/dci.h"
#include "lte/common/base.h"
#include "lte/utils/bit.h"
#include "lte/utils/vector.h"
#include "lte/utils/debug.h"
int dci_init(dci_t *q, int nof_dcis) {
q->msg = calloc(sizeof(dci_msg_t), nof_dcis);
if (!q->msg) {
perror("malloc");
return -1;
}
q->nof_dcis = nof_dcis;
return 0;
}
void dci_free(dci_t *q) {
if (q->msg) {
free(q->msg);
}
}
void dci_candidate_fprint(FILE *f, dci_candidate_t *q) {
fprintf(f, "L: %d, nCCE: %d, RNTI: 0x%x, nBits: %d\n",
q->L, q->ncce, q->rnti, q->nof_bits);
}
int dci_format1_add(dci_t *q, dci_format1_t *msg, int L, int nCCE, unsigned short rnti) {
int i, j;
i=0;
while(i<q->nof_dcis && q->msg[i].location.nof_bits)
i++;
if (i == q->nof_dcis) {
fprintf(stderr, "No more space in DCI container\n");
return -1;
}
q->msg[i].location.L = L;
q->msg[i].location.ncce = nCCE;
q->msg[i].location.nof_bits = dci_format1_sizeof(6, 1);
q->msg[i].location.rnti = rnti;
for (j=0;j<q->msg[i].location.nof_bits;j++) {
q->msg[i].data[j] = rand()%2;
}
return 0;
}
int dci_format0_add(dci_t *q, dci_format0_t *msg, int L, int nCCE, unsigned short rnti) {
int i, j;
i=0;
while(i<q->nof_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;j<q->msg[i].location.nof_bits;j++) {
q->msg[i].data[j] = rand()%2;
}
return 0;
}
int dci_format0_sizeof(int nof_prb) {
return 1+1+(int) ceilf(log2f(nof_prb*(nof_prb+1)/2))+2+3+1;
}
int dci_format1_sizeof(int nof_prb, int P) {
return (nof_prb>10)?1:0+(int) ceilf(log2f(nof_prb/P))+5+3+1+2+2;
}
int dci_format1A_sizeof(int nof_prb, bool random_access_initiated) {
if (random_access_initiated) {
return 1+(int) ceilf(log2f(nof_prb*(nof_prb+1)/2))+6+4;
} else {
return 1+(int) ceilf(log2f(nof_prb*(nof_prb+1)/2))+5+3+1+2+2;
}
}
int dci_format1C_sizeof() {
return 10;
}

View file

@ -109,7 +109,7 @@ int pbch_get(cf_t *slot1_data, cf_t *pbch, int nof_prb, lte_cp_t cp, int cell_id
}
/** Initializes the PBCH transmitter and receiver */
int pbch_init(pbch_t *q, int cell_id, lte_cp_t cp) {
int pbch_init(pbch_t *q, int nof_prb, int cell_id, lte_cp_t cp) {
int ret = -1;
if (cell_id < 0) {
return -1;
@ -117,6 +117,7 @@ int pbch_init(pbch_t *q, int cell_id, lte_cp_t cp) {
bzero(q, sizeof(pbch_t));
q->cell_id = cell_id;
q->cp = cp;
q->nof_prb = nof_prb;
if (modem_table_std(&q->mod, LTE_QPSK, true)) {
goto clean;
@ -134,7 +135,6 @@ int pbch_init(pbch_t *q, int cell_id, lte_cp_t cp) {
}
q->encoder.K = 7;
q->encoder.R = 3;
q->encoder.framelength = 40;
q->encoder.tail_biting = true;
memcpy(q->encoder.poly, poly, 3 * sizeof(int));
@ -360,7 +360,7 @@ int pbch_crc_check(char *bits, int nof_ports) {
char data[40];
memcpy(data, bits, 40 * sizeof(char));
crc_set_mask(data, nof_ports);
return crc(0, data, 40, 16, 0x11021, 0);
return crc(0, data, 40, 16, LTE_CRC16, 0);
}
int pbch_decode_frame(pbch_t *q, pbch_mib_t *mib, int src, int dst, int n, int nof_bits, int nof_ports) {
@ -389,7 +389,7 @@ int pbch_decode_frame(pbch_t *q, pbch_mib_t *mib, int src, int dst, int n, int n
}
/* decode */
viterbi_decode_f(&q->decoder, q->pbch_rm_f, q->data);
viterbi_decode_f(&q->decoder, q->pbch_rm_f, q->data, 40);
int c=0;
for (j=0;j<40;j++) {
@ -420,7 +420,7 @@ int pbch_decode_frame(pbch_t *q, pbch_mib_t *mib, int src, int dst, int n, int n
*
* Returns 1 if successfully decoded MIB, 0 if not and -1 on error
*/
int pbch_decode(pbch_t *q, cf_t *slot1_symbols, cf_t *ce[MAX_PORTS_CTRL], int nof_prb, float ebno, pbch_mib_t *mib) {
int pbch_decode(pbch_t *q, cf_t *slot1_symbols, cf_t *ce[MAX_PORTS_CTRL], float ebno, pbch_mib_t *mib) {
int src, dst, res, nb;
int nant_[3] = {1, 2, 4};
int na, nant;
@ -437,7 +437,7 @@ int pbch_decode(pbch_t *q, cf_t *slot1_symbols, cf_t *ce[MAX_PORTS_CTRL], int no
memset(&x[MAX_PORTS_CTRL], 0, sizeof(cf_t*) * (MAX_LAYERS - MAX_PORTS_CTRL));
/* extract symbols */
if (q->nof_symbols != pbch_get(slot1_symbols, q->pbch_symbols[0], nof_prb,
if (q->nof_symbols != pbch_get(slot1_symbols, q->pbch_symbols[0], q->nof_prb,
q->cp, q->cell_id)) {
fprintf(stderr, "There was an error getting the PBCH symbols\n");
return -1;
@ -445,7 +445,7 @@ int pbch_decode(pbch_t *q, cf_t *slot1_symbols, cf_t *ce[MAX_PORTS_CTRL], int no
/* extract channel estimates */
for (i=0;i<MAX_PORTS_CTRL;i++) {
if (q->nof_symbols != pbch_get(ce[i], q->ce[i], nof_prb,
if (q->nof_symbols != pbch_get(ce[i], q->ce[i], q->nof_prb,
q->cp, q->cell_id)) {
fprintf(stderr, "There was an error getting the PBCH symbols\n");
return -1;
@ -503,8 +503,7 @@ int pbch_decode(pbch_t *q, cf_t *slot1_symbols, cf_t *ce[MAX_PORTS_CTRL], int no
/** Converts the MIB message to symbols mapped to SLOT #1 ready for transmission
*/
void pbch_encode(pbch_t *q, pbch_mib_t *mib, cf_t *slot1_symbols[MAX_PORTS_CTRL],
int nof_prb, int nof_ports) {
void pbch_encode(pbch_t *q, pbch_mib_t *mib, cf_t *slot1_symbols[MAX_PORTS_CTRL], int nof_ports) {
int i;
int nof_bits = 2 * q->nof_symbols;
@ -527,7 +526,7 @@ void pbch_encode(pbch_t *q, pbch_mib_t *mib, cf_t *slot1_symbols[MAX_PORTS_CTRL]
crc(0, q->data, 24, 16, 0x11021, 1);
crc_set_mask(q->data, nof_ports);
convcoder_encode(&q->encoder, q->data, q->data_enc);
convcoder_encode(&q->encoder, q->data, q->data_enc, 40);
rm_conv_tx(q->data_enc, q->pbch_rm_b, 120, 4 * nof_bits);
@ -549,7 +548,7 @@ void pbch_encode(pbch_t *q, pbch_mib_t *mib, cf_t *slot1_symbols[MAX_PORTS_CTRL]
/* mapping to resource elements */
for (i=0;i<nof_ports;i++) {
pbch_put(q->pbch_symbols[i], slot1_symbols[i], nof_prb, q->cp, q->cell_id);
pbch_put(q->pbch_symbols[i], slot1_symbols[i], q->nof_prb, q->cp, q->cell_id);
}
q->frame_idx++;
if (q->frame_idx == 4) {

585
lte/lib/phch/src/pdcch.c Normal file
View file

@ -0,0 +1,585 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2014 The libLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the libLTE library.
*
* libLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* libLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* A copy of the GNU Lesser General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <strings.h>
#include <stdlib.h>
#include <stdbool.h>
#include <assert.h>
#include <math.h>
#include "lte/phch/dci.h"
#include "lte/phch/regs.h"
#include "lte/phch/pdcch.h"
#include "lte/common/base.h"
#include "lte/utils/bit.h"
#include "lte/utils/vector.h"
#include "lte/utils/debug.h"
#define PDCCH_NOF_FORMATS 4
#define PDCCH_FORMAT_NOF_CCE(i) (1<<i)
#define PDCCH_FORMAT_NOF_REGS(i) ((1<<i)*9)
#define PDCCH_FORMAT_NOF_BITS(i) ((1<<i)*72)
int pdcch_put(cf_t *pdcch, cf_t *slot1_data, int nsymbols) {
memcpy(slot1_data, pdcch, sizeof(cf_t) * nsymbols);
return nsymbols;
}
int pdcch_get(cf_t *slot1_data, cf_t *pdcch, int nsymbols) {
memcpy(pdcch, slot1_data, sizeof(cf_t) * nsymbols);
return nsymbols;
}
#define MIN(a,b) ((a>b)?b:a)
/**
* 36.213 9.1
*/
int gen_common_search(dci_candidate_t *c, int nof_cce, int nof_bits, unsigned short rnti) {
int i, L, k;
k = 0;
for (L = 2; L > 0; L--) {
for (i = 0; i < MIN(nof_cce,16) / (4 * L); i++) {
c[k].L = 4 * L;
c[k].nof_bits = nof_bits;
c[k].rnti = rnti;
c[k].ncce = (4 * L) * (i % (nof_cce / (4 * L)));
k++;
INFO(
"Common SS Candidate %d: RNTI: 0x%x, nCCE: %d, Nbits: %d, L: %d\n",
k, c[k].rnti, c[k].ncce, c[k].nof_bits, c[k].L);
}
}
return k;
}
/**
* 36.213 9.1
*/
int gen_ue_search(dci_candidate_t *c, int nof_cce, int nof_bits, unsigned short rnti, int subframe) {
int i, l, L, k, m;
unsigned int Yk;
const int S[4] = { 6, 12, 8, 16 };
k = 0;
for (l = 3; l >= 0; l--) {
L = (1 << l);
for (i = 0; i < MIN(nof_cce/L,16/S[l]); i++) {
c[k].L = l;
c[k].nof_bits = nof_bits;
c[k].rnti = rnti;
Yk = rnti;
for (m = 0; m < subframe; m++) {
Yk = (39827 * Yk) % 65537;
}
c[k].ncce = L * ((Yk + i) % (nof_cce / L));
INFO("UE-specific SS Candidate %d: SF: %d, RNTI: 0x%x, nCCE: %d, Nbits: %d, L: %d\n",
k, subframe, c[k].rnti, c[k].ncce, c[k].nof_bits, c[k].L);
k++;
}
}
return k;
}
void pdcch_init_common(pdcch_t *q, pdcch_search_t *s, unsigned short rnti) {
int k;
s->nof_candidates = 2*(MIN(q->nof_cce,16) / 4 + MIN(q->nof_cce,16) / 8);
if (s->nof_candidates) {
s->candidates[0] = malloc(sizeof(dci_candidate_t) * s->nof_candidates);
dci_candidate_t *c = s->candidates[0];
if (c) {
// Format 1A and 1C L=4 and L=8, 4 and 2 candidates, only if nof_cce > 16
k = 0;
k += gen_common_search(&c[k], q->nof_cce,
dci_format1A_sizeof(q->nof_prb, true), SIRNTI);
k += gen_common_search(&c[k], q->nof_cce,
dci_format1C_sizeof(q->nof_prb), SIRNTI);
}
}
}
/** 36.213 v9.3 Table 7.1-1: System Information DCI messages
* Expect DCI formats 1C and 1A in the common search space
*/
void pdcch_init_search_si(pdcch_t *q) {
pdcch_init_common(q, &q->search_mode[SEARCH_SI], SIRNTI);
q->current_search_mode = SEARCH_SI;
}
/** 36.213 v9.3 Table 7.1-5
* user-specific search space. Currently supported transmission Mode 1:
* DCI Format 1A and 1 + PUSCH scheduling format 0
*/
void pdcch_init_search_ue(pdcch_t *q, unsigned short c_rnti) {
int l, n, k;
pdcch_search_t *s = &q->search_mode[SEARCH_UE];
s->nof_candidates = 0;
for (l=0;l<3;l++) {
s->nof_candidates += 3*(MIN(q->nof_cce,16) / (1<<l));
}
INFO("Initiating %d candidate(s) in the UE-specific search space for C-RNTI: 0x%x\n", s->nof_candidates, c_rnti);
if (s->nof_candidates) {
for (n=0;n<NSUBFRAMES_X_FRAME;n++) {
s->candidates[n] = malloc(sizeof(dci_candidate_t) * s->nof_candidates);
dci_candidate_t *c = s->candidates[n];
if (c) {
// Expect Formats 1, 1A, 0
k = 0;
k += gen_ue_search(&c[k], q->nof_cce,
dci_format0_sizeof(q->nof_prb), c_rnti, n);
k += gen_ue_search(&c[k], q->nof_cce,
dci_format1_sizeof(q->nof_prb, 1), c_rnti, n);
k += gen_ue_search(&c[k], q->nof_cce,
dci_format1A_sizeof(q->nof_prb, true), c_rnti, n);
}
}
}
q->current_search_mode = SEARCH_UE;
}
/** 36.213 v9.3 Table 7.1-3
* Expect DCI formats 1C and 1A in the common search space
*/
void pdcch_init_search_ra(pdcch_t *q, unsigned short ra_rnti) {
pdcch_init_common(q, &q->search_mode[SEARCH_RA], ra_rnti);
q->current_search_mode = SEARCH_RA;
}
void pdcch_set_search_si(pdcch_t *q) {
q->current_search_mode = SEARCH_SI;
}
void pdcch_set_search_ue(pdcch_t *q) {
q->current_search_mode = SEARCH_UE;
}
void pdcch_set_search_ra(pdcch_t *q) {
q->current_search_mode = SEARCH_RA;
}
/** Initializes the PDCCH transmitter and receiver */
int pdcch_init(pdcch_t *q, regs_t *regs, int nof_prb, int nof_ports,
int cell_id, lte_cp_t cp) {
int ret = -1;
int i;
if (cell_id < 0) {
return -1;
}
if (nof_ports > MAX_PORTS_CTRL) {
fprintf(stderr, "Invalid number of ports %d\n", nof_ports);
return -1;
}
bzero(q, sizeof(pdcch_t));
q->cell_id = cell_id;
q->cp = cp;
q->regs = regs;
q->nof_ports = nof_ports;
q->current_search_mode = SEARCH_NONE;
q->nof_regs = regs_pdcch_nregs(q->regs);
q->nof_cce = q->nof_regs / 9;
q->nof_symbols = 4 * q->nof_regs;
q->nof_bits = 2 * q->nof_symbols;
INFO("Init PDCCH: %d REGs, %d bits, %d symbols, %d ports\n", q->nof_regs,
q->nof_bits, q->nof_symbols, q->nof_ports);
if (modem_table_std(&q->mod, LTE_QPSK, true)) {
goto clean;
}
demod_soft_init(&q->demod);
demod_soft_table_set(&q->demod, &q->mod);
demod_soft_alg_set(&q->demod, APPROX);
for (i = 0; i < NSUBFRAMES_X_FRAME; i++) {
if (sequence_pdcch(&q->seq_pdcch[i], 2 * i, q->cell_id, q->nof_bits)) {
goto clean;
}
}
int poly[3] = { 0x6D, 0x4F, 0x57 };
if (viterbi_init(&q->decoder, viterbi_37, poly, DCI_MAX_BITS + 16, true)) {
goto clean;
}
q->pdcch_e = malloc(sizeof(char) * q->nof_bits);
if (!q->pdcch_e) {
goto clean;
}
q->pdcch_llr = malloc(sizeof(float) * q->nof_bits);
if (!q->pdcch_llr) {
goto clean;
}
q->pdcch_d = malloc(sizeof(cf_t) * q->nof_symbols);
if (!q->pdcch_d) {
goto clean;
}
for (i = 0; i < MAX_PORTS_CTRL; i++) {
q->ce[i] = malloc(sizeof(cf_t) * q->nof_symbols);
if (!q->ce[i]) {
goto clean;
}
q->pdcch_x[i] = malloc(sizeof(cf_t) * q->nof_symbols);
if (!q->pdcch_x[i]) {
goto clean;
}
q->pdcch_symbols[i] = malloc(sizeof(cf_t) * q->nof_symbols);
if (!q->pdcch_symbols[i]) {
goto clean;
}
}
ret = 0;
clean: if (ret == -1) {
pdcch_free(q);
}
return ret;
}
void pdcch_free(pdcch_t *q) {
int i, j;
for (i=0;i<PDCCH_NOF_SEARCH_MODES;i++) {
for (j = 0; j < NSUBFRAMES_X_FRAME; j++) {
if (q->search_mode[i].candidates[j]) {
free(q->search_mode[i].candidates[j]);
}
}
}
if (q->pdcch_e) {
free(q->pdcch_e);
}
if (q->pdcch_llr) {
free(q->pdcch_llr);
}
if (q->pdcch_d) {
free(q->pdcch_d);
}
for (i = 0; i < MAX_PORTS_CTRL; i++) {
if (q->ce[i]) {
free(q->ce[i]);
}
if (q->pdcch_x[i]) {
free(q->pdcch_x[i]);
}
if (q->pdcch_symbols[i]) {
free(q->pdcch_symbols[i]);
}
}
for (i = 0; i < NSUBFRAMES_X_FRAME; i++) {
sequence_free(&q->seq_pdcch[i]);
}
modem_table_free(&q->mod);
viterbi_free(&q->decoder);
}
/** 36.212 5.3.3.2 to 5.3.3.4
*
* Returns XOR between parity and remainder bits
*
* TODO: UE transmit antenna selection CRC mask
*/
unsigned short dci_decode(viterbi_t *decoder, float *e, char *data, int E,
int nof_bits) {
float tmp[3 * (DCI_MAX_BITS + 16)];
unsigned short p_bits;
char *x;
assert(nof_bits < DCI_MAX_BITS);
/* unrate matching */
rm_conv_rx(e, tmp, E, 3 * (nof_bits + 16));
DEBUG("Viterbi input: ", 0);
if (VERBOSE_ISDEBUG()) {
vec_fprint_f(stdout, tmp, 3 * (nof_bits + 16));
}
/* viterbi decoder */
viterbi_decode_f(decoder, tmp, data, nof_bits + 16);
x = &data[nof_bits];
p_bits = (unsigned short) bit_unpack(&x, 16);
return (p_bits
^ ((unsigned short) crc(0, data, nof_bits, 16, LTE_CRC16, 0)
& 0xffff));
}
int pdcch_decode_candidate(pdcch_t *q, float *llr, dci_candidate_t *c,
dci_msg_t *msg) {
unsigned short crc_res;
crc_res = dci_decode(&q->decoder, &llr[72 * c->ncce], msg->data,
PDCCH_FORMAT_NOF_BITS(c->L), c->nof_bits);
if (c->rnti == crc_res) {
memcpy(&msg->location, c, sizeof(dci_candidate_t));
INFO(
"FOUND CAND: Nbits: %d, E: %d, nCCE: %d, L: %d, RNTI: 0x%x\n",
c->nof_bits, PDCCH_FORMAT_NOF_BITS(c->L), c->ncce, c->L,
c->rnti);
return 1;
}
return 0;
}
int pdcch_extract_llr(pdcch_t *q, cf_t *slot1_symbols, cf_t *ce[MAX_PORTS_CTRL],
float *llr, int nsubframe, float ebno) {
/* Set pointers for layermapping & precoding */
int i;
cf_t *x[MAX_LAYERS];
if (nsubframe < 0 || nsubframe > NSUBFRAMES_X_FRAME) {
fprintf(stderr, "Invalid subframe %d\n", nsubframe);
return -1;
}
if (ebno == 0.0) {
fprintf(stderr, "EbNo is Zero\n");
return -1;
}
/* number of layers equals number of ports */
for (i = 0; i < q->nof_ports; i++) {
x[i] = q->pdcch_x[i];
}
memset(&x[q->nof_ports], 0, sizeof(cf_t*) * (MAX_LAYERS - q->nof_ports));
/* extract symbols */
if (q->nof_symbols
!= pdcch_get(slot1_symbols, q->pdcch_symbols[0], q->nof_symbols)) {
fprintf(stderr, "There was an error getting the PDCCH symbols\n");
return -1;
}
/* extract channel estimates */
for (i = 0; i < q->nof_ports; i++) {
if (q->nof_symbols != pdcch_get(ce[i], q->ce[i], q->nof_symbols)) {
fprintf(stderr, "There was an error getting the PDCCH symbols\n");
return -1;
}
}
DEBUG("pdcch_symbols: ", 0);
if (VERBOSE_ISDEBUG()) {
vec_fprint_c(stdout, q->pdcch_symbols[0], q->nof_symbols);
}
/* in control channels, only diversity is supported */
if (q->nof_ports == 1) {
/* no need for layer demapping */
predecoding_single_zf(q->pdcch_symbols[0], q->ce[0], q->pdcch_d,
q->nof_symbols);
} else {
predecoding_diversity_zf(q->pdcch_symbols, q->ce, x, q->nof_ports,
q->nof_symbols);
layerdemap_diversity(x, q->pdcch_d, q->nof_ports,
q->nof_symbols / q->nof_ports);
}
/* demodulate symbols */
demod_soft_sigma_set(&q->demod, ebno);
demod_soft_demodulate(&q->demod, q->pdcch_d, q->pdcch_llr, q->nof_symbols);
DEBUG("llr: ", 0);
if (VERBOSE_ISDEBUG()) {
vec_fprint_f(stdout, q->pdcch_llr, q->nof_symbols);
}
/* descramble */
scrambling_f_offset(&q->seq_pdcch[nsubframe], llr, 0, q->nof_bits);
return 0;
}
int pdcch_decode_current_mode(pdcch_t *q, float *llr, dci_t *dci, int subframe) {
int dci_cnt;
int k, i;
if (q->current_search_mode == SEARCH_UE) {
k = subframe;
} else {
k = 0;
}
dci_cnt = 0;
for (i = 0; i < q->search_mode[q->current_search_mode].nof_candidates
&& dci_cnt < dci->nof_dcis; i++) {
if (pdcch_decode_candidate(q, q->pdcch_llr,
&q->search_mode[q->current_search_mode].candidates[k][i],
&dci->msg[dci_cnt])) {
dci_cnt++;
}
}
return dci_cnt;
}
int pdcch_decode_si(pdcch_t *q, float *llr, dci_t *dci) {
pdcch_set_search_si(q);
return pdcch_decode_current_mode(q, llr, dci, 0);
}
int pdcch_decode_ra(pdcch_t *q, float *llr, dci_t *dci) {
pdcch_set_search_ra(q);
return pdcch_decode_current_mode(q, llr, dci, 0);
}
int pdcch_decode_ue(pdcch_t *q, float *llr, dci_t *dci, int nsubframe) {
pdcch_set_search_ue(q);
return pdcch_decode_current_mode(q, llr, dci, nsubframe);
}
/* Decodes PDCCH channels
*
* dci->nof_dcis is the size of the dci->msg buffer (ie max number of messages)
*
* Returns number of messages stored in dci
*/
int pdcch_decode(pdcch_t *q, cf_t *slot1_symbols, cf_t *ce[MAX_PORTS_CTRL],
dci_t *dci, int nsubframe, float ebno) {
if (pdcch_extract_llr(q, slot1_symbols, ce, q->pdcch_llr, nsubframe,
ebno)) {
return -1;
}
if (q->current_search_mode != SEARCH_NONE) {
return pdcch_decode_current_mode(q, q->pdcch_llr, dci, nsubframe);
}
return 0;
}
void crc_set_mask_rnti(char *crc, unsigned short rnti) {
int i;
char mask[16];
char *r = mask;
INFO("Mask CRC with RNTI 0x%x\n", rnti);
bit_pack(rnti, &r, 16);
for (i = 0; i < 16; i++) {
crc[i] = (crc[i] + mask[i]) % 2;
}
}
/** 36.212 5.3.3.2 to 5.3.3.4
* TODO: UE transmit antenna selection CRC mask
*/
void dci_encode(char *data, char *e, int nof_bits, int E, unsigned short rnti) {
convcoder_t encoder;
char tmp[3 * (DCI_MAX_BITS + 16)];
assert(nof_bits < DCI_MAX_BITS);
int poly[3] = { 0x6D, 0x4F, 0x57 };
encoder.K = 7;
encoder.R = 3;
encoder.tail_biting = true;
memcpy(encoder.poly, poly, 3 * sizeof(int));
crc(0, data, nof_bits, 16, LTE_CRC16, 1);
crc_set_mask_rnti(&data[nof_bits], rnti);
convcoder_encode(&encoder, data, tmp, nof_bits + 16);
DEBUG("CConv output: ", 0);
if (VERBOSE_ISDEBUG()) {
vec_fprint_b(stdout, tmp, 3 * (nof_bits + 16));
}
rm_conv_tx(tmp, e, 3 * (nof_bits + 16), E);
}
/** Converts the MIB message to symbols mapped to SLOT #1 ready for transmission
*/
int pdcch_encode(pdcch_t *q, dci_t *dci, cf_t *slot1_symbols[MAX_PORTS_CTRL],
int nsubframe) {
int i;
/* Set pointers for layermapping & precoding */
cf_t *x[MAX_LAYERS];
if (nsubframe < 0 || nsubframe > NSUBFRAMES_X_FRAME) {
fprintf(stderr, "Invalid subframe %d\n", nsubframe);
return -1;
}
/* number of layers equals number of ports */
for (i = 0; i < q->nof_ports; i++) {
x[i] = q->pdcch_x[i];
}
memset(&x[q->nof_ports], 0, sizeof(cf_t*) * (MAX_LAYERS - q->nof_ports));
/* should add <NIL> elements? Or maybe random bits to facilitate power estimation */
bzero(q->pdcch_e, q->nof_bits);
/* Encode DCIs */
for (i = 0; i < dci->nof_dcis; i++) {
/* do some sanity checks */
if (dci->msg[i].location.ncce + PDCCH_FORMAT_NOF_CCE(dci->msg[i].location.L) > q->nof_cce
|| dci->msg[i].location.L > 3
|| dci->msg[i].location.nof_bits > DCI_MAX_BITS) {
fprintf(stderr, "Illegal DCI message %d\n", i);
return -1;
}
INFO("Encoding DCI %d: Nbits: %d, E: %d, nCCE: %d, L: %d, RNTI: 0x%x\n",
i, dci->msg[i].location.nof_bits, PDCCH_FORMAT_NOF_BITS(dci->msg[i].location.L),
dci->msg[i].location.ncce, dci->msg[i].location.L, dci->msg[i].location.rnti);
dci_encode(dci->msg[i].data, &q->pdcch_e[72 * dci->msg[i].location.ncce],
dci->msg[i].location.nof_bits, PDCCH_FORMAT_NOF_BITS(dci->msg[i].location.L),
dci->msg[i].location.rnti);
}
scrambling_b_offset(&q->seq_pdcch[nsubframe], q->pdcch_e, 0, q->nof_bits);
mod_modulate(&q->mod, q->pdcch_e, q->pdcch_d, q->nof_bits);
/* layer mapping & precoding */
if (q->nof_ports > 1) {
layermap_diversity(q->pdcch_d, x, q->nof_ports, q->nof_symbols);
precoding_diversity(x, q->pdcch_symbols, q->nof_ports,
q->nof_symbols / q->nof_ports);
} else {
memcpy(q->pdcch_symbols[0], q->pdcch_d, q->nof_symbols * sizeof(cf_t));
}
/* mapping to resource elements */
for (i = 0; i < q->nof_ports; i++) {
pdcch_put(q->pdcch_symbols[i], slot1_symbols[i], q->nof_symbols);
}
return 0;
}

View file

@ -58,6 +58,9 @@ void regs_pdcch_free(regs_t *h) {
}
}
int regs_pdcch_nregs(regs_t *h) {
return 9;
}
@ -90,6 +93,9 @@ int regs_phich_init(regs_t *h) {
case R_2:
ng = 2;
break;
default:
ng = 0;
break;
}
h->ngroups_phich = (int) ceilf(ng * ((float) h->nof_prb/8));
h->phich = malloc(sizeof(regs_ch_t) * h->ngroups_phich);

View file

@ -54,3 +54,11 @@ int sequence_phich(sequence_t *seq, int nslot, int cell_id) {
bzero(seq, sizeof(sequence_t));
return sequence_LTEPRS(seq, 12, (nslot/2+1) * (2*cell_id + 1) * 512 + cell_id);
}
/**
* 36.211 6.8.2
*/
int sequence_pdcch(sequence_t *seq, int nslot, int cell_id, int len) {
bzero(seq, sizeof(sequence_t));
return sequence_LTEPRS(seq, len, (nslot/2) * 512 + cell_id);
}

View file

@ -68,6 +68,12 @@ ADD_TEST(phich_test_102 phich_test -p 2 -n 10 -g 2)
ADD_TEST(phich_test_104 phich_test -p 4 -n 10 -e -l -g 1/2)
########################################################################
# PDCCH TEST
########################################################################
ADD_EXECUTABLE(pdcch_test pdcch_test.c)
TARGET_LINK_LIBRARIES(pdcch_test lte)
########################################################################
# FILE TEST
@ -79,6 +85,10 @@ TARGET_LINK_LIBRARIES(pbch_file_test lte)
ADD_EXECUTABLE(pcfich_file_test pcfich_file_test.c)
TARGET_LINK_LIBRARIES(pcfich_file_test lte)
ADD_EXECUTABLE(phich_file_test phich_file_test.c)
TARGET_LINK_LIBRARIES(phich_file_test lte)
ADD_TEST(pbch_file_test pbch_file_test -i ${CMAKE_CURRENT_SOURCE_DIR}/signal.1.92M.dat)
ADD_TEST(pcfich_file_test pcfich_file_test -c 150 -n 50 -p 2 -i ${CMAKE_CURRENT_SOURCE_DIR}/signal.10M.dat)
ADD_TEST(phich_file_test phich_file_test -c 150 -n 50 -p 2 -i ${CMAKE_CURRENT_SOURCE_DIR}/signal.10M.dat)

View file

@ -141,7 +141,7 @@ int base_init() {
return -1;
}
if (pbch_init(&pbch, cell_id, cp)) {
if (pbch_init(&pbch, nof_prb, cell_id, cp)) {
fprintf(stderr, "Error initiating PBCH\n");
return -1;
}
@ -209,7 +209,7 @@ int main(int argc, char **argv) {
INFO("Decoding PBCH\n", 0);
n = pbch_decode(&pbch, fft_buffer, ce, nof_prb, 1, &mib);
n = pbch_decode(&pbch, fft_buffer, ce, 1, &mib);
base_free();
fftwf_cleanup();

View file

@ -99,7 +99,7 @@ int main(int argc, char **argv) {
}
}
if (pbch_init(&pbch, cell_id, CPNORM)) {
if (pbch_init(&pbch, nof_prb, cell_id, CPNORM)) {
fprintf(stderr, "Error creating PBCH object\n");
exit(-1);
}
@ -110,7 +110,7 @@ int main(int argc, char **argv) {
mib_tx.phich_resources = R_1_6;
mib_tx.sfn = 124;
pbch_encode(&pbch, &mib_tx, slot1_symbols, nof_prb, nof_ports);
pbch_encode(&pbch, &mib_tx, slot1_symbols, nof_ports);
/* combine outputs */
for (i=1;i<nof_ports;i++) {
@ -120,7 +120,7 @@ int main(int argc, char **argv) {
}
pbch_decode_reset(&pbch);
if (1 != pbch_decode(&pbch, slot1_symbols[0], ce, nof_prb, 1, &mib_rx)) {
if (1 != pbch_decode(&pbch, slot1_symbols[0], ce, 1, &mib_rx)) {
printf("Error decoding\n");
exit(-1);
}

View file

@ -0,0 +1,172 @@
/**
*
* \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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <unistd.h>
#include "lte.h"
int cell_id = 1;
int nof_prb = 6;
int nof_ports = 1;
void usage(char *prog) {
printf("Usage: %s [cpv]\n", prog);
printf("\t-c cell id [Default %d]\n", cell_id);
printf("\t-p nof_ports [Default %d]\n", nof_ports);
printf("\t-n nof_prb [Default %d]\n", nof_prb);
printf("\t-v [set verbose to debug, default none]\n");
}
void parse_args(int argc, char **argv) {
int opt;
while ((opt = getopt(argc, argv, "cpnv")) != -1) {
switch(opt) {
case 'p':
nof_ports = atoi(argv[optind]);
break;
case 'n':
nof_prb = atoi(argv[optind]);
break;
case 'c':
cell_id = atoi(argv[optind]);
break;
case 'v':
verbose++;
break;
default:
usage(argv[0]);
exit(-1);
}
}
}
int main(int argc, char **argv) {
pdcch_t pdcch;
dci_t dci_tx, dci_rx;
dci_format1_t dci_msg;
regs_t regs;
int i, j;
cf_t *ce[MAX_PORTS_CTRL];
int nof_re;
cf_t *slot1_symbols[MAX_PORTS_CTRL];
int nof_dcis;
int ret = -1;
parse_args(argc,argv);
nof_re = CPNORM_NSYMB * nof_prb * RE_X_RB;
/* init memory */
for (i=0;i<MAX_PORTS_CTRL;i++) {
ce[i] = malloc(sizeof(cf_t) * nof_re);
if (!ce[i]) {
perror("malloc");
exit(-1);
}
for (j=0;j<nof_re;j++) {
ce[i][j] = 1;
}
slot1_symbols[i] = malloc(sizeof(cf_t) * nof_re);
if (!slot1_symbols[i]) {
perror("malloc");
exit(-1);
}
}
if (regs_init(&regs, cell_id, nof_prb, nof_ports, R_1, PHICH_NORM, CPNORM)) {
fprintf(stderr, "Error initiating regs\n");
exit(-1);
}
if (pdcch_init(&pdcch, &regs, nof_prb, nof_ports, cell_id, CPNORM)) {
fprintf(stderr, "Error creating PBCH object\n");
exit(-1);
}
dci_init(&dci_tx, 1);
dci_format1_add(&dci_tx, &dci_msg, 1, 0, 1234);
pdcch_encode(&pdcch, &dci_tx, slot1_symbols, 0);
/* combine outputs */
for (i=1;i<nof_ports;i++) {
for (j=0;j<nof_re;j++) {
slot1_symbols[0][j] += slot1_symbols[i][j];
}
}
pdcch_init_search_ue(&pdcch, 1234);
dci_init(&dci_rx, 1);
nof_dcis = pdcch_decode(&pdcch, slot1_symbols[0], ce, &dci_rx, 0, 1);
if (nof_dcis < 0) {
printf("Error decoding\n");
} else if (nof_dcis == dci_tx.nof_dcis) {
for (i=0;i<nof_dcis;i++) {
if (dci_tx.msg[i].location.L != dci_rx.msg[i].location.L
|| dci_tx.msg[i].location.ncce != dci_rx.msg[i].location.ncce
|| dci_tx.msg[i].location.nof_bits != dci_rx.msg[i].location.nof_bits
|| dci_tx.msg[i].location.rnti != dci_rx.msg[i].location.rnti) {
printf("Error in DCI %d: Received location does not match\n", i);
dci_candidate_fprint(stdout, &dci_tx.msg[i].location);
dci_candidate_fprint(stdout, &dci_rx.msg[i].location);
goto quit;
}
if (memcmp(dci_tx.msg[i].data, dci_rx.msg[i].data, dci_tx.msg[i].location.nof_bits)) {
printf("Error in DCI %d: Received data does not match\n", i);
goto quit;
}
/* check more things ... */
}
} else {
printf("Transmitted %d DCIs but got %d\n", dci_tx.nof_dcis, nof_dcis);
goto quit;
}
ret = 0;
quit:
pdcch_free(&pdcch);
regs_free(&regs);
dci_free(&dci_tx);
dci_free(&dci_rx);
for (i=0;i<MAX_PORTS_CTRL;i++) {
free(ce[i]);
free(slot1_symbols[i]);
}
if (ret) {
printf("Error\n");
} else {
printf("Ok\n");
}
exit(ret);
}

View file

@ -0,0 +1,286 @@
/**
*
* \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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <unistd.h>
#include "lte.h"
char *input_file_name = NULL;
char *matlab_file_name = NULL;
int cell_id = 150;
lte_cp_t cp = CPNORM;
int nof_prb = 50;
int nof_ports = 2;
int flen;
int nof_ctrl_symbols = 1;
phich_resources_t phich_res = R_1;
phich_length_t phich_length = PHICH_NORM;
int numsubframe = 0;
FILE *fmatlab = NULL;
filesource_t fsrc;
cf_t *input_buffer, *fft_buffer, *ce[MAX_PORTS_CTRL];
phich_t phich;
regs_t regs;
lte_fft_t fft;
chest_t chest;
void usage(char *prog) {
printf("Usage: %s [vcoe] -i input_file\n", prog);
printf("\t-o output matlab file name [Default Disabled]\n");
printf("\t-c cell_id [Default %d]\n", cell_id);
printf("\t-p nof_ports [Default %d]\n", nof_ports);
printf("\t-n nof_prb [Default %d]\n", nof_prb);
printf("\t-f nof control symbols [Default %d]\n", nof_ctrl_symbols);
printf("\t-g phich ng factor: 1/6, 1/2, 1, 2 [Default 1]\n");
printf("\t-e phich extended length [Default normal]\n");
printf("\t-l extended cyclic prefix [Default normal]\n");
printf("\t-v [set verbose to debug, default none]\n");
}
void parse_args(int argc, char **argv) {
int opt;
while ((opt = getopt(argc, argv, "iovcenpfgl")) != -1) {
switch(opt) {
case 'i':
input_file_name = argv[optind];
break;
case 'o':
matlab_file_name = argv[optind];
break;
case 'c':
cell_id = atoi(argv[optind]);
break;
case 'f':
nof_ctrl_symbols = atoi(argv[optind]);
break;
case 'g':
if (!strcmp(argv[optind], "1/6")) {
phich_res = R_1_6;
} else if (!strcmp(argv[optind], "1/2")) {
phich_res = R_1_2;
} else if (!strcmp(argv[optind], "1")) {
phich_res = R_1;
} else if (!strcmp(argv[optind], "2")) {
phich_res = R_2;
} else {
fprintf(stderr, "Invalid phich ng factor %s. Setting to default.\n", argv[optind]);
}
break;
case 'e':
phich_length = PHICH_EXT;
break;
case 'n':
nof_prb = atoi(argv[optind]);
break;
case 'p':
nof_ports = atoi(argv[optind]);
break;
case 'v':
verbose++;
break;
case 'l':
cp = CPEXT;
break;
default:
usage(argv[0]);
exit(-1);
}
}
if (!input_file_name) {
usage(argv[0]);
exit(-1);
}
}
int base_init() {
int i;
if (filesource_init(&fsrc, input_file_name, COMPLEX_FLOAT_BIN)) {
fprintf(stderr, "Error opening file %s\n", input_file_name);
exit(-1);
}
if (matlab_file_name) {
fmatlab = fopen(matlab_file_name, "w");
if (!fmatlab) {
perror("fopen");
return -1;
}
} else {
fmatlab = NULL;
}
flen = SLOT_LEN(lte_symbol_sz(nof_prb), cp);
input_buffer = malloc(flen * sizeof(cf_t));
if (!input_buffer) {
perror("malloc");
exit(-1);
}
fft_buffer = malloc(CP_NSYMB(cp) * nof_prb * RE_X_RB * sizeof(cf_t));
if (!fft_buffer) {
perror("malloc");
return -1;
}
for (i=0;i<MAX_PORTS_CTRL;i++) {
ce[i] = malloc(CP_NSYMB(cp) * nof_prb * RE_X_RB * sizeof(cf_t));
if (!ce[i]) {
perror("malloc");
return -1;
}
}
if (chest_init(&chest, LINEAR, cp, nof_prb, nof_ports)) {
fprintf(stderr, "Error initializing equalizer\n");
return -1;
}
if (chest_ref_LTEDL(&chest, cell_id)) {
fprintf(stderr, "Error initializing reference signal\n");
return -1;
}
if (lte_fft_init(&fft, cp, nof_prb)) {
fprintf(stderr, "Error initializing FFT\n");
return -1;
}
if (regs_init(&regs, cell_id, nof_prb, nof_ports, phich_res, phich_length, cp)) {
fprintf(stderr, "Error initiating regs\n");
return -1;
}
if (phich_init(&phich, &regs, cell_id, nof_prb, nof_ports, cp)) {
fprintf(stderr, "Error creating PBCH object\n");
return -1;
}
DEBUG("Memory init OK\n",0);
return 0;
}
void base_free() {
int i;
filesource_free(&fsrc);
if (fmatlab) {
fclose(fmatlab);
}
free(input_buffer);
free(fft_buffer);
filesource_free(&fsrc);
for (i=0;i<MAX_PORTS_CTRL;i++) {
free(ce[i]);
}
chest_free(&chest);
lte_fft_free(&fft);
phich_free(&phich);
regs_free(&regs);
}
int main(int argc, char **argv) {
int distance;
int i, n;
int ngroup, nseq, max_nseq;
char ack_rx;
if (argc < 3) {
usage(argv[0]);
exit(-1);
}
parse_args(argc,argv);
max_nseq = CP_ISNORM(cp)?PHICH_NORM_NSEQUENCES:PHICH_EXT_NSEQUENCES;
if (base_init()) {
fprintf(stderr, "Error initializing memory\n");
exit(-1);
}
n = filesource_read(&fsrc, input_buffer, flen);
lte_fft_run(&fft, input_buffer, fft_buffer);
if (fmatlab) {
fprintf(fmatlab, "infft=");
vec_fprint_c(fmatlab, input_buffer, flen);
fprintf(fmatlab, ";\n");
fprintf(fmatlab, "outfft=");
vec_fprint_c(fmatlab, fft_buffer, CP_NSYMB(cp) * nof_prb * RE_X_RB);
fprintf(fmatlab, ";\n");
}
/* Get channel estimates for each port */
for (i=0;i<nof_ports;i++) {
chest_ce_slot_port(&chest, fft_buffer, ce[i], 0, i);
if (fmatlab) {
chest_fprint(&chest, fmatlab, 0, i);
}
}
INFO("Decoding PHICH\n", 0);
/* Receive all PHICH groups and sequence numbers */
for (ngroup=0;ngroup<phich_ngroups(&phich);ngroup++) {
for (nseq=0;nseq<max_nseq;nseq++) {
if (phich_decode(&phich, fft_buffer, ce, ngroup, nseq, numsubframe, &ack_rx, &distance)<0) {
printf("Error decoding ACK\n");
exit(-1);
}
INFO("%d/%d, ack_rx: %d, ns: %d, distance: %d\n",
ngroup, nseq, ack_rx, numsubframe, distance);
}
}
base_free();
fftwf_cleanup();
if (n < 0) {
fprintf(stderr, "Error decoding phich\n");
exit(-1);
} else if (n == 0) {
printf("Could not decode phich\n");
exit(-1);
} else {
exit(0);
}
}

View file

@ -45,17 +45,17 @@ int vec_acc_ii(int *x, int len) {
}
float vec_acc_ff(float *x, int len) {
#ifndef HAVE_VOLK
#ifdef HAVE_VOLK_ACC_FUNCTION
float result;
volk_32f_accumulator_s32f_u(&result,x,(unsigned int) len);
return result;
#else
int i;
float z=0;
for (i=0;i<len;i++) {
z+=x[i];
}
return z;
#else
float result;
volk_32f_accumulator_s32f_u(&result,x,(unsigned int) len);
return result;
#endif
}
@ -83,7 +83,7 @@ void vec_sum_bbb(char *z, char *x, char *y, int len) {
}
void vec_sc_prod_cfc(cf_t *x, float h, cf_t *z, int len) {
#ifndef HAVE_VOLK
#ifndef HAVE_VOLK_MULT_FUNCTION
int i;
for (i=0;i<len;i++) {
z[i] = x[i]*h;
@ -97,7 +97,7 @@ void vec_sc_prod_cfc(cf_t *x, float h, cf_t *z, int len) {
}
void vec_sc_prod_ccc(cf_t *x, cf_t h, cf_t *z, int len) {
#ifndef HAVE_VOLK
#ifndef HAVE_VOLK_MULT_FUNCTION
int i;
for (i=0;i<len;i++) {
z[i] = x[i]*h;
@ -162,7 +162,7 @@ void vec_fprint_i(FILE *stream, int *x, int len) {
}
void vec_conj_cc(cf_t *x, cf_t *y, int len) {
#ifndef HAVE_VOLK
#ifndef HAVE_VOLK_CONJ_FUNCTION
int i;
for (i=0;i<len;i++) {
y[i] = conjf(x[i]);
@ -173,7 +173,7 @@ void vec_conj_cc(cf_t *x, cf_t *y, int len) {
}
void vec_prod_ccc(cf_t *x,cf_t *y, cf_t *z, int len) {
#ifndef HAVE_VOLK
#ifndef HAVE_VOLK_MULT2_FUNCTION
int i;
for (i=0;i<len;i++) {
z[i] = x[i]*y[i];
@ -201,7 +201,7 @@ float vec_avg_power_cf(cf_t *x, int len) {
}
void vec_prod_ccc_unalign(cf_t *x,cf_t *y, cf_t *z, int len) {
#ifndef HAVE_VOLK
#ifndef HAVE_VOLK_MULT_FUNCTION
int i;
for (i=0;i<len;i++) {
z[i] = x[i]*y[i];
@ -212,7 +212,7 @@ void vec_prod_ccc_unalign(cf_t *x,cf_t *y, cf_t *z, int len) {
}
void vec_abs_cf(cf_t *x, float *abs, int len) {
#ifndef HAVE_VOLK
#ifndef HAVE_VOLK_MAG_FUNCTION
int i;
for (i=0;i<len;i++) {
abs[i] = cabsf(x[i]);
@ -225,7 +225,12 @@ void vec_abs_cf(cf_t *x, float *abs, int len) {
}
int vec_max_fi(float *x, int len) {
#ifndef HAVE_VOLK
#ifdef HAVE_VOLK_MAX_FUNCTION
unsigned int target=0;
volk_32f_index_max_16u_u(&target,x,(unsigned int) len);
return (int) target;
#else
int i;
float m=-FLT_MAX;
int p=0;
@ -236,10 +241,6 @@ int vec_max_fi(float *x, int len) {
}
}
return p;
#else
unsigned int target=0;
volk_32f_index_max_16u_u(&target,x,(unsigned int) len);
return (int) target;
#endif
}