mirror of https://github.com/pvnis/srsRAN_4G.git
commit
b1fc0986b1
@ -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 */
|
@ -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)
|
@ -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
|
@ -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
|
@ -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;
|
||||||
|
}
|
@ -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;
|
||||||
|
}
|
||||||
|
|
@ -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(®s, cell_id, nof_prb, nof_ports, R_1, PHICH_NORM, CPNORM)) {
|
||||||
|
fprintf(stderr, "Error initiating regs\n");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pdcch_init(&pdcch, ®s, 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(®s);
|
||||||
|
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);
|
||||||
|
}
|
@ -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(®s, cell_id, nof_prb, nof_ports, phich_res, phich_length, cp)) {
|
||||||
|
fprintf(stderr, "Error initiating regs\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (phich_init(&phich, ®s, 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(®s);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue