Merge pull request #22 from ismagom/master

Pull from ismagom fork. Fixed B210 USRP Clock issue added PDCCH
master
Ismael Gómez-Miguelez 11 years ago
commit 8ee7385aeb

@ -14,6 +14,16 @@
# CMAKE_REQUIRED_INCLUDES = list of include directories
# CMAKE_REQUIRED_LIBRARIES = list of libraries to link
#=============================================================================
# Copyright 2002-2011 Kitware, Inc.
#
# Distributed under the OSI-approved BSD License (the "License");
# see accompanying file Copyright.txt for details.
#
# This software is distributed WITHOUT ANY WARRANTY; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the License for more information.
#=============================================================================
MACRO(CHECK_FUNCTION_EXISTS_MATH FUNCTION VARIABLE)
IF("${VARIABLE}" MATCHES "^${VARIABLE}$")

@ -25,6 +25,7 @@ IF(UHD_FOUND)
ADD_LIBRARY(cuhd cuhd_imp.cpp cuhd_utils.c)
INCLUDE_DIRECTORIES(${UHD_INCLUDE_DIRS})
LINK_DIRECTORIES(${UHD_LIBRARY_DIRS})
TARGET_LINK_LIBRARIES(cuhd ${UHD_LIBRARIES})
LIBLTE_SET_PIC(cuhd)
@ -38,6 +39,3 @@ ELSE(UHD_FOUND)
MESSAGE(STATUS " UHD driver not found. CUHD library is not generated")
ENDIF(UHD_FOUND)

@ -46,8 +46,19 @@ typedef _Complex float complex_t;
bool isLocked(void *h)
{
cuhd_handler* handler = static_cast<cuhd_handler*>(h);
std::vector<std::string> mb_sensors = handler->usrp->get_mboard_sensor_names();
std::vector<std::string> rx_sensors = handler->usrp->get_rx_sensor_names(0);
if(std::find(rx_sensors.begin(), rx_sensors.end(), "lo_locked") != rx_sensors.end()) {
return handler->usrp->get_rx_sensor("lo_locked", 0).to_bool();
}
else if(std::find(mb_sensors.begin(), mb_sensors.end(), "ref_locked") != mb_sensors.end()) {
return handler->usrp->get_mboard_sensor("ref_locked", 0).to_bool();
}
else {
usleep(500);
return true;
}
}
bool cuhd_rx_wait_lo_locked(void *h)
{
@ -89,12 +100,14 @@ int cuhd_start_rx_stream_nsamples(void *h, int nsamples) {
return 0;
}
int cuhd_open(char *args, void **h) {
cuhd_handler* handler = new cuhd_handler();
std::string _args=std::string(args);
handler->usrp = uhd::usrp::multi_usrp::make(_args);
// Try to set LTE clock
handler->usrp->set_master_clock_rate(30720000);
handler->usrp->set_clock_source("internal");
std::string otw, cpu;
@ -190,4 +203,3 @@ int cuhd_send(void *h, void *data, int nsamples, int blocking) {
return handler->tx_stream->send(data, nsamples, md, 0.0);
}
}

@ -38,6 +38,7 @@ target_link_libraries(ll_example lte)
add_executable(synch_file synch_file.c)
target_link_libraries(synch_file lte)
LINK_DIRECTORIES(${UHD_LIBRARY_DIRS})
#################################################################
# Check if UHD C-API and Graphics library are available
@ -94,4 +95,3 @@ IF(${CUHD_FIND} GREATER -1)
ELSE(${CUHD_FIND} GREATER -1)
MESSAGE(STATUS " UHD examples NOT INSTALLED: CUHD library not compiled.")
ENDIF(${CUHD_FIND} GREATER -1)

@ -39,7 +39,7 @@
#endif
char *output_file_name = NULL;
int nof_slots=-1;
int nof_frames=-1;
int cell_id = 1;
int nof_prb = 6;
char *uhd_args = "";
@ -66,7 +66,7 @@ void usage(char *prog) {
printf("\t UHD is disabled. CUHD library not available\n");
#endif
printf("\t-o output_file [Default USRP]\n");
printf("\t-n number of frames [Default %d]\n", nof_slots);
printf("\t-n number of frames [Default %d]\n", nof_frames);
printf("\t-c cell id [Default %d]\n", cell_id);
printf("\t-p nof_prb [Default %d]\n", nof_prb);
printf("\t-v [set verbose to debug, default none]\n");
@ -92,7 +92,7 @@ void parse_args(int argc, char **argv) {
output_file_name = argv[optind];
break;
case 'n':
nof_slots = atoi(argv[optind]);
nof_frames = atoi(argv[optind]);
break;
case 'p':
nof_prb = atoi(argv[optind]);
@ -238,7 +238,7 @@ int main(int argc, char **argv) {
nf = 0;
while(nf<nof_slots || nof_slots == -1) {
while(nf<nof_frames || nof_frames == -1) {
for (ns=0;ns<NSLOTS_X_FRAME;ns++) {
bzero(slot_buffer, sizeof(cf_t) * slot_n_re);

@ -57,8 +57,8 @@
#define NOF_PORTS 2
float find_threshold = 30.0, track_threshold = 10.0;
int max_track_lost = 20, nof_slots = -1;
float find_threshold = 20.0, track_threshold = 10.0;
int max_track_lost = 20, nof_frames = -1;
int track_len=300;
char *input_file_name = NULL;
int disable_plots = 0;
@ -89,7 +89,7 @@ void usage(char *prog) {
#else
printf("\t UHD is disabled. CUHD library not available\n");
#endif
printf("\t-n nof_frames [Default %d]\n", nof_slots);
printf("\t-n nof_frames [Default %d]\n", nof_frames);
printf("\t-p PSS threshold [Default %f]\n", find_threshold);
#ifndef DISABLE_GRAPHICS
printf("\t-d disable plots [Default enabled]\n");
@ -119,7 +119,7 @@ void parse_args(int argc, char **argv) {
find_threshold = atof(argv[optind]);
break;
case 'n':
nof_slots = atoi(argv[optind]);
nof_frames = atoi(argv[optind]);
break;
case 'd':
disable_plots = 1;
@ -375,7 +375,7 @@ int main(int argc, char **argv) {
sync_set_threshold(&sfind, find_threshold);
sync_force_N_id_2(&sfind, -1);
while(!go_exit && (frame_cnt < nof_slots || nof_slots==-1)) {
while(!go_exit && (frame_cnt < nof_frames || nof_frames==-1)) {
INFO(" ----- RECEIVING %d SAMPLES ---- \n", FLEN);
if (input_file_name) {
n = filesource_read(&fsrc, input_buffer, FLEN);

@ -35,7 +35,7 @@
#include "lte.h"
#include "cuhd.h"
int nof_slots=1000;
int nof_frames=1000;
int band;
cf_t *input_buffer, *fft_buffer;
@ -52,7 +52,7 @@ void usage(char *prog) {
printf("Usage: %s [nvse] -b band\n", prog);
printf("\t-s earfcn_start [Default All]\n");
printf("\t-e earfcn_end [Default All]\n");
printf("\t-n number of frames [Default %d]\n", nof_slots);
printf("\t-n number of frames [Default %d]\n", nof_frames);
printf("\t-v [set verbose to debug, default none]\n");
}
@ -70,7 +70,7 @@ void parse_args(int argc, char **argv) {
earfcn_end = atoi(argv[optind]);
break;
case 'n':
nof_slots = atoi(argv[optind]);
nof_frames = atoi(argv[optind]);
break;
case 'v':
verbose++;
@ -132,7 +132,7 @@ int main(int argc, char **argv) {
frame_cnt = 0;
nsamples=0;
rssi[i]=0;
while(frame_cnt < nof_slots) {
while(frame_cnt < nof_frames) {
nsamples += cuhd_recv(uhd, input_buffer, 1920, 1);
rssi[i] += vec_avg_power_cf(input_buffer, 1920);
frame_cnt++;

@ -35,7 +35,7 @@
char *input_file_name;
char *output_file_name="abs_corr.txt";
int nof_slots=100, frame_length=9600, symbol_sz=128;
int nof_frames=100, frame_length=9600, symbol_sz=128;
float corr_peak_threshold=25.0;
int out_N_id_2 = 0, force_N_id_2=-1;
@ -46,7 +46,7 @@ void usage(char *prog) {
printf("Usage: %s [olntsNfcv] -i input_file\n", prog);
printf("\t-o output_file [Default %s]\n", output_file_name);
printf("\t-l frame_length [Default %d]\n", frame_length);
printf("\t-n number of frames [Default %d]\n", nof_slots);
printf("\t-n number of frames [Default %d]\n", nof_frames);
printf("\t-t correlation threshold [Default %g]\n", corr_peak_threshold);
printf("\t-s symbol_sz [Default %d]\n", symbol_sz);
printf("\t-N out_N_id_2 [Default %d]\n", out_N_id_2);
@ -66,7 +66,7 @@ void parse_args(int argc, char **argv) {
output_file_name = argv[optind];
break;
case 'n':
nof_slots = atoi(argv[optind]);
nof_frames = atoi(argv[optind]);
break;
case 'l':
frame_length = atoi(argv[optind]);
@ -143,12 +143,12 @@ int main(int argc, char **argv) {
perror("malloc");
exit(-1);
}
cfo = malloc(nof_slots*sizeof(float));
cfo = malloc(nof_frames*sizeof(float));
if (!cfo) {
perror("malloc");
exit(-1);
}
exec_time = malloc(nof_slots*sizeof(int));
exec_time = malloc(nof_frames*sizeof(int));
if (!exec_time) {
perror("malloc");
exit(-1);
@ -192,7 +192,7 @@ int main(int argc, char **argv) {
/* read all file or nof_frames */
frame_cnt = 0;
while (frame_length == filesource_read(&fsrc, input, frame_length)
&& frame_cnt < nof_slots) {
&& frame_cnt < nof_frames) {
gettimeofday(&tdata[1], NULL);
if (force_cfo != CFO_AUTO) {

@ -58,6 +58,11 @@
#include "lte/fec/viterbi.h"
#include "lte/fec/convcoder.h"
#include "lte/fec/crc.h"
#include "lte/fec/tc_interl.h"
#include "lte/fec/turbocoder.h"
#include "lte/fec/turbodecoder.h"
#include "lte/fec/rm_conv.h"
#include "lte/fec/rm_turbo.h"
#include "lte/filter/filter2d.h"
@ -82,8 +87,6 @@
#include "lte/phch/pcfich.h"
#include "lte/phch/phich.h"
#include "lte/ratematching/rm_conv.h"
#include "lte/scrambling/scrambling.h"
#include "lte/resampling/interp.h"

@ -39,10 +39,16 @@
#define MAX_LAYERS 8
#define MAX_CODEWORDS 2
#define LTE_CRC24A 0x1864CFB
#define LTE_CRC24B 0X1800063
#define LTE_CRC16 0x11021
#define LTE_CRC8 0x19B
typedef enum {CPNORM, CPEXT} lte_cp_t;
#define SIRNTI 0xFFFF
#define PRNTI 0xFFFE
#define MRNTI 0xFFFD
#define MAX_NSYMB 7
@ -90,10 +96,12 @@ int lte_voffset(int symbol_id, int cell_id, int nof_ports);
#define NOF_LTE_BANDS 29
#define NOF_TC_CB_SIZES 188
typedef enum {
SINGLE_ANTENNA,TX_DIVERSITY, SPATIAL_MULTIPLEX
} mimo_type_t;
} lte_mimo_type_t;
typedef enum { PHICH_NORM, PHICH_EXT} phich_length_t;
typedef enum { R_1_6, R_1_2, R_1, R_2} phich_resources_t;
@ -108,13 +116,16 @@ enum band_geographical_area {
ALL, NAR, APAC, EMEA, JAPAN, CALA, NA
};
int lte_cb_size(int index);
int lte_find_cb_index(int long_cb);
float lte_band_fd(int earfcn);
int lte_band_get_fd_band(int band, lte_earfcn_t *earfcn, int earfcn_start, int earfcn_end, int max_elems);
int lte_band_get_fd_band_all(int band, lte_earfcn_t *earfcn, int max_nelems);
int lte_band_get_fd_region(enum band_geographical_area region, lte_earfcn_t *earfcn, int max_elems);
int lte_str2mimotype(char *mimo_type_str, mimo_type_t *type);
char *lte_mimotype2str(mimo_type_t type);
int lte_str2mimotype(char *mimo_type_str, lte_mimo_type_t *type);
char *lte_mimotype2str(lte_mimo_type_t type);
#endif

@ -26,17 +26,23 @@
*/
#ifndef CRC_
#define CRC_
#define LTE_CRC24A 0x1864CFB
#define LTE_CRC24B 0X1800063
#define LTE_CRC16 0x11021
#define LTE_CRC8 0x19B
typedef struct {
unsigned long table[256];
unsigned char byte;
int polynom;
int order;
unsigned long crcinit;
unsigned long crcmask;
unsigned long crchighbit;
unsigned int crc_out;
} crc_t;
unsigned int crc(unsigned int crc, char *bufptr, int len,
int long_crc,unsigned int poly, int paste_word);
int crc_init(crc_t *h, unsigned int crc_poly, int crc_order);
int crc_set_init(crc_t *h, unsigned long crc_init_value);
void crc_attach(crc_t *h, char *data, int len);
unsigned int crc_checksum(crc_t *h, char *data, int len);
#endif

@ -33,8 +33,8 @@
#define TX_NULL 80
int rm_conv_tx(char *input, char *output, int in_len, int out_len);
int rm_conv_rx(float *input, float *output, int in_len, int out_len);
int rm_conv_tx(char *input, int in_len, char *output, int out_len);
int rm_conv_rx(float *input, int in_len, float *output, int out_len);
/* High-level API */

@ -0,0 +1,73 @@
/**
*
* \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 RM_TURBO_
#define RM_TURBO_
#ifndef RX_NULL
#define RX_NULL 10000
#endif
#ifndef TX_NULL
#define TX_NULL 80
#endif
typedef struct {
int buffer_len;
char *buffer;
int *d2_perm;
} rm_turbo_t;
int rm_turbo_init(rm_turbo_t *q, int max_codeblock_len);
void rm_turbo_free(rm_turbo_t *q);
int rm_turbo_tx(rm_turbo_t *q, char *input, int in_len, char *output, int out_len, int rv_idx);
int rm_turbo_rx(rm_turbo_t *q, float *input, int in_len, float *output, int out_len, int rv_idx);
/* High-level API */
typedef struct {
rm_turbo_t q;
struct rm_turbo_init {
int direction;
} init;
void *input; // input type may be char or float depending on hard
int in_len;
struct rm_turbo_ctrl_in {
int E;
int S;
int rv_idx;
} ctrl_in;
void *output;
int out_len;
}rm_turbo_hl;
int rm_turbo_initialize(rm_turbo_hl* h);
int rm_turbo_work(rm_turbo_hl* hl);
int rm_turbo_stop(rm_turbo_hl* hl);
#endif

@ -0,0 +1,41 @@
/**
*
* \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 _PERMUTE_H
#define _PERMUTE_H
typedef struct {
int *forward;
int *reverse;
}tc_interl_t;
int tc_interl_LTE_init(tc_interl_t *h, int long_cb);
int tc_interl_UMTS_init(tc_interl_t *h, int long_cb);
void tc_interl_free(tc_interl_t *h);
#endif

@ -0,0 +1,45 @@
/**
*
* \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/.
*
*/
#define NUMREGS 3
#define RATE 3
#define TOTALTAIL 12
typedef struct {
int long_cb;
tc_interl_t interl;
}tcod_t;
int tcod_init(tcod_t *h, int long_cb);
void tcod_free(tcod_t *h);
void tcod_encode(tcod_t *h, char *input, char *output);

@ -0,0 +1,44 @@
#define RATE 3
#define TOTALTAIL 12
#define LOG18 -2.07944
#define NUMSTATES 8
#define NINPUTS 2
#define TAIL 3
#define TOTALTAIL 12
#define INF 9e4
#define ZERO 9e-4
#define MAX_LONG_CB 6114
#define MAX_LONG_CODED (RATE*MAX_LONG_CB+TOTALTAIL)
typedef float llr_t;
typedef struct {
int long_cb;
llr_t *beta;
}map_gen_t;
typedef struct {
int long_cb;
map_gen_t dec;
llr_t *llr1;
llr_t *llr2;
llr_t *w;
llr_t *syst;
llr_t *parity;
tc_interl_t interleaver;
}tdec_t;
int tdec_init(tdec_t *h, int long_cb);
void tdec_free(tdec_t *h);
void tdec_reset(tdec_t *h);
void tdec_iteration(tdec_t *h, llr_t *input);
void tdec_decision(tdec_t *h, char *output);
void tdec_run_all(tdec_t *h, llr_t *input, char *output, int nof_iterations);

@ -38,7 +38,7 @@ int layermap_diversity(cf_t *d, cf_t *x[MAX_LAYERS], int nof_layers, int nof_sym
int layermap_multiplex(cf_t *d[MAX_CODEWORDS], cf_t *x[MAX_LAYERS], int nof_cw, int nof_layers,
int nof_symbols[MAX_CODEWORDS]);
int layermap_type(cf_t *d[MAX_CODEWORDS], cf_t *x[MAX_LAYERS], int nof_cw, int nof_layers,
int nof_symbols[MAX_CODEWORDS], mimo_type_t type);
int nof_symbols[MAX_CODEWORDS], lte_mimo_type_t type);
/* Generates the vector of data symbols "d" based on the vector of layer-mapped symbols "x"
@ -48,6 +48,6 @@ int layerdemap_diversity(cf_t *x[MAX_LAYERS], cf_t *d, int nof_layers, int nof_l
int layerdemap_multiplex(cf_t *x[MAX_LAYERS], cf_t *d[MAX_CODEWORDS], int nof_layers, int nof_cw,
int nof_layer_symbols, int nof_symbols[MAX_CODEWORDS]);
int layerdemap_type(cf_t *x[MAX_LAYERS], cf_t *d[MAX_CODEWORDS], int nof_layers, int nof_cw,
int nof_layer_symbols, int nof_symbols[MAX_CODEWORDS], mimo_type_t type);
int nof_layer_symbols, int nof_symbols[MAX_CODEWORDS], lte_mimo_type_t type);
#endif

@ -41,7 +41,7 @@ typedef _Complex float cf_t;
int precoding_single(cf_t *x, cf_t *y, int nof_symbols);
int precoding_diversity(cf_t *x[MAX_LAYERS], cf_t *y[MAX_PORTS], int nof_ports, int nof_symbols);
int precoding_type(cf_t *x[MAX_LAYERS], cf_t *y[MAX_PORTS], int nof_layers, int nof_ports,
int nof_symbols, mimo_type_t type);
int nof_symbols, lte_mimo_type_t type);
/* Estimates the vector "x" based on the received signal "y" and the channel estimates "ce"
@ -51,6 +51,6 @@ int predecoding_diversity_zf(cf_t *y[MAX_PORTS], cf_t *ce[MAX_PORTS],
cf_t *x[MAX_LAYERS], int nof_ports, int nof_symbols);
int predecoding_type(cf_t *y[MAX_PORTS], cf_t *ce[MAX_PORTS],
cf_t *x[MAX_LAYERS], int nof_ports, int nof_layers, int nof_symbols,
mimo_type_t type);
lte_mimo_type_t type);
#endif /* PRECODING_H_ */

@ -49,7 +49,7 @@ typedef struct {
// Modulation standards
enum modem_std {
LTE_BPSK, LTE_QPSK, LTE_QAM16, LTE_QAM64
LTE_BPSK = 1, LTE_QPSK = 2, LTE_QAM16 = 4, LTE_QAM64 = 6
};
void modem_table_init(modem_table_t* q);

@ -25,11 +25,12 @@
*
*/
#ifndef DCI_
#define DCI_
#include "lte/common/base.h"
#include <stdint.h>
#include "lte/phch/ra.h"
typedef _Complex float cf_t;
@ -37,45 +38,27 @@ typedef _Complex float cf_t;
* DCI message generation according to the formats, as specified in
* 36.212 Section 5.3.3.1
*
* Call the function dci_init(&q) to generate a collection of DCI messages
* to be transmitted in a subframe. Each subsequent call to
* dci_add_formatXX(&q, ...) generates the DCI message and appends the data
* to the collection "q".
*
*/
#define DCI_MAX_BITS 45
#define DCI_MAX_BITS 57
typedef enum {
FORMAT0,
FORMAT1,
FORMAT1A,
/* ... */
Format0, Format1, Format1A, Format1C
} dci_format_t;
// Each type is for a different interface to packing/unpacking functions
typedef struct {
enum {
PUSCH_SCHED, PDSCH_SCHED, MCCH_CHANGE, TPC_COMMAND, RA_PROC_PDCCH
} type;
dci_format_t format;
}dci_msg_type_t;
typedef enum {
DCI_COMMON = 0, DCI_UE = 1
} dci_spec_t;
/** TODO: this is Release 8 */
typedef struct {
/* 36.213 Table 8.4-2: hop_half is 0 for < 10 Mhz and 10 for > 10 Mh.
* hop_quart is 00 for > 10 Mhz and hop_quart_neg is 01 for > 10 Mhz.
*/
enum {hop_disabled, hop_half, hop_quart, hop_quart_neg, hop_type_2} freq_hop_fl;
int n_rb_ul; // number of resource blocks
int riv; // Resource Indication Value (36.213 8.1)
int mcs_and_rv; // MCS and RV value
enum {ndi_true=1, ndi_false=0} ndi; // New Data Indicator
int tpc; // Transmit Power Control
int dm_rs; // DM RS
enum {cqi_true=0, cqi_false=1} cqi_request;
}dci_format0_t;
typedef struct {
}dci_format1_t;
typedef struct {
unsigned char nof_bits;
unsigned char L; // Aggregation level
@ -91,23 +74,27 @@ typedef struct {
typedef struct {
dci_msg_t *msg;
int nof_dcis;
int max_dcis;
} dci_t;
int dci_init(dci_t *q, int nof_dci);
int dci_init(dci_t *q, int max_dci);
void dci_free(dci_t *q);
char* dci_format_string(dci_format_t format);
int dci_msg_candidate_set(dci_msg_t *msg, int L, int nCCE, unsigned short rnti);
void dci_candidate_fprint(FILE *f, dci_candidate_t *q);
int dci_format0_add(dci_t *q, dci_format0_t *msg, int L, int nCCE, unsigned short rnti);
int dci_format0_sizeof(int nof_prb);
int dci_msg_get_type(dci_msg_t *msg, dci_msg_type_t *type, int nof_prb, unsigned short crnti);
void dci_msg_type_fprint(FILE *f, dci_msg_type_t type);
int dci_format1_add(dci_t *q, dci_format1_t *msg, int L, int nCCE, unsigned short rnti);
int dci_format1_sizeof(int nof_prb, int P);
// For dci_msg_type_t = PUSCH_SCHED
int dci_msg_pack_pusch(ra_pusch_t *data, dci_msg_t *msg, int nof_prb);
int dci_msg_unpack_pusch(dci_msg_t *msg, ra_pusch_t *data, int nof_prb);
int dci_format1A_add(dci_t *q, dci_format1_t *msg);
int dci_format1A_sizeof(int nof_prb, bool random_access_initiated);
// For dci_msg_type_t = PDSCH_SCHED
int dci_msg_pack_pdsch(ra_pdsch_t *data, dci_msg_t *msg, dci_format_t format, int nof_prb, bool crc_is_crnti);
int dci_msg_unpack_pdsch(dci_msg_t *msg, ra_pdsch_t *data, int nof_prb, bool crc_is_crnti);
int dci_format1C_add(dci_t *q, dci_format1_t *msg);
int dci_format1C_sizeof();
int dci_format_sizeof(dci_format_t format, int nof_prb);
#endif

@ -35,7 +35,7 @@
#include "lte/modem/mod.h"
#include "lte/modem/demod_soft.h"
#include "lte/scrambling/scrambling.h"
#include "lte/ratematching/rm_conv.h"
#include "lte/fec/rm_conv.h"
#include "lte/fec/convcoder.h"
#include "lte/fec/viterbi.h"
#include "lte/fec/crc.h"
@ -79,6 +79,7 @@ typedef struct {
demod_soft_t demod;
sequence_t seq_pbch;
viterbi_t decoder;
crc_t crc;
convcoder_t encoder;
}pbch_t;

@ -35,7 +35,7 @@
#include "lte/modem/mod.h"
#include "lte/modem/demod_soft.h"
#include "lte/scrambling/scrambling.h"
#include "lte/ratematching/rm_conv.h"
#include "lte/fec/rm_conv.h"
#include "lte/fec/convcoder.h"
#include "lte/fec/viterbi.h"
#include "lte/fec/crc.h"
@ -88,7 +88,7 @@ typedef struct {
demod_soft_t demod;
sequence_t seq_pdcch[NSUBFRAMES_X_FRAME];
viterbi_t decoder;
crc_t crc;
}pdcch_t;
int pdcch_init(pdcch_t *q, regs_t *regs, int nof_prb, int nof_ports, int cell_id, lte_cp_t cp);

@ -0,0 +1,156 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2014 The libLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the libLTE library.
*
* libLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* libLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* A copy of the GNU Lesser General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#ifndef RB_ALLOC_H_
#define RB_ALLOC_H_
#include <stdint.h>
#include <stdbool.h>
/** Structures and utility functions for DL/UL resource
* allocation.
*/
typedef enum {
MOD_NULL = 0, BPSK = 1, QPSK = 2, QAM16 = 4, QAM64 = 16
} ra_mod_t;
typedef struct {
ra_mod_t mod; // By default, mod = MOD_NULL and the mcs_idx value is taken by the packing functions
// otherwise mod + tbs values are used to generate the mcs_idx automatically.
uint8_t tbs_idx;
uint8_t mcs_idx;
int tbs; // If tbs<=0, the tbs_idx value is taken by the packing functions to generate the DCI
// message. Otherwise the tbs_idx corresponding to the lower nearest TBS is taken.
}ra_mcs_t;
typedef enum {
alloc_type0 = 0, alloc_type1 = 1, alloc_type2 = 2
}ra_type_t;
typedef struct {
uint32_t rbg_bitmask;
}ra_type0_t;
typedef struct {
uint32_t vrb_bitmask;
uint8_t rbg_subset;
bool shift;
}ra_type1_t;
typedef struct {
uint32_t riv; // if L_crb==0, DCI message packer will take this value directly
uint16_t L_crb;
uint16_t RB_start;
enum {nprb1a_2 = 0, nprb1a_3 = 1} n_prb1a;
enum {t2_ng1 = 0, t2_ng2 = 1} n_gap;
enum {t2_loc = 0, t2_dist = 1} mode;
}ra_type2_t;
typedef struct {
unsigned short rnti;
ra_type_t alloc_type;
union {
ra_type0_t type0_alloc;
ra_type1_t type1_alloc;
ra_type2_t type2_alloc;
};
ra_mcs_t mcs;
uint8_t harq_process;
uint8_t rv_idx;
bool ndi;
} ra_pdsch_t;
typedef struct {
/* 36.213 Table 8.4-2: hop_half is 0 for < 10 Mhz and 10 for > 10 Mh.
* hop_quart is 00 for > 10 Mhz and hop_quart_neg is 01 for > 10 Mhz.
*/
enum {
hop_disabled = -1,
hop_quart = 0,
hop_quart_neg = 1,
hop_half = 2,
hop_type_2 = 3
} freq_hop_fl;
ra_type2_t type2_alloc;
ra_mcs_t mcs;
uint8_t rv_idx; // If set to non-zero, a retransmission is requested with the same modulation
// than before (Format0 message, see also 8.6.1 in 36.2313).
bool ndi;
bool cqi_request;
} ra_pusch_t;
typedef struct {
uint8_t prb_idx[110];
int nof_prb;
}ra_prb_slot_t;
typedef struct {
ra_prb_slot_t slot1;
ra_prb_slot_t slot2;
bool is_dist;
}ra_prb_t;
void ra_prb_fprint(FILE *f, ra_prb_slot_t *prb);
int ra_prb_get_dl(ra_prb_t *prb, ra_pdsch_t *ra, int nof_prb);
int ra_prb_get_ul(ra_prb_slot_t *prb, ra_pusch_t *ra, int nof_prb);
int ra_nprb_dl(ra_pdsch_t *ra, int nof_prb);
int ra_nprb_ul(ra_pusch_t *ra, int nof_prb);
uint8_t ra_mcs_to_table_idx(ra_mcs_t *mcs);
int ra_mcs_from_idx_dl(uint8_t idx, ra_mcs_t *mcs);
int ra_mcs_from_idx_ul(uint8_t idx, ra_mcs_t *mcs);
int ra_tbs_from_idx_format1c(uint8_t tbs_idx);
int ra_tbs_to_table_idx_format1c(int tbs);
int ra_tbs_from_idx(uint8_t tbs_idx, int n_prb);
int ra_tbs_to_table_idx(int tbs, int n_prb);
uint8_t ra_mcs_to_table_idx(ra_mcs_t *mcs);
int ra_mcs_from_idx_dl(uint8_t idx, ra_mcs_t *mcs);
int ra_mcs_from_idx_ul(uint8_t idx, ra_mcs_t *mcs);
char *ra_mod_string(ra_mod_t mod);
int ra_type0_P(int nof_prb);
uint32_t ra_type2_to_riv(uint16_t L_crb, uint16_t RB_start, int nof_prb);
void ra_type2_from_riv(uint32_t riv, uint16_t *L_crb, uint16_t *RB_start, int nof_prb, int nof_vrb);
int ra_type2_n_vrb_dl(int nof_prb, bool ngap_is_1);
int ra_type2_n_rb_step(int nof_prb);
int ra_type2_ngap(int nof_prb, bool ngap_is_1);
int ra_type1_N_rb(int nof_prb);
void ra_pdsch_set_mcs_index(ra_pdsch_t *ra, uint8_t mcs_idx);
void ra_pdsch_set_mcs(ra_pdsch_t *ra, ra_mod_t mod, uint8_t tbs_idx);
void ra_pdsch_fprint(FILE *f, ra_pdsch_t *ra, int nof_prb);
void ra_pusch_fprint(FILE *f, ra_pusch_t *ra, int nof_prb);
#endif /* RB_ALLOC_H_ */

@ -59,36 +59,42 @@ typedef struct {
int cell_id;
int nof_prb;
int max_ctrl_symbols;
int cfi;
int ngroups_phich;
int refs_in_symbol1;
int nof_ports;
lte_cp_t cp;
phich_resources_t phich_res;
phich_length_t phich_len;
int nof_cce;
regs_ch_t pcfich;
regs_ch_t *phich; // there are several phich
regs_ch_t *pdcch; // there are several pdcch
regs_ch_t pdcch[3]; /* PDCCH indexing, permutation and interleaving is computed for
the three possible CFI value */
int nof_regs;
regs_reg_t *regs;
}regs_t;
int regs_init(regs_t *h, int cell_id, int nof_prb, int refs_in_symbol1,
int regs_init(regs_t *h, int cell_id, int nof_prb, int nof_ports,
phich_resources_t phich_res, phich_length_t phich_len, lte_cp_t cp);
void regs_free(regs_t *h);
int regs_set_cfi(regs_t *h, int nof_ctrl_symbols);
int regs_put_reg(regs_reg_t *reg, cf_t *reg_data, cf_t *slot_symbols, int nof_prb);
int regs_add_reg(regs_reg_t *reg, cf_t *reg_data, cf_t *slot_symbols, int nof_prb);
int regs_get_reg(regs_reg_t *reg, cf_t *slot_symbols, cf_t *reg_data, int nof_prb);
int regs_reset_reg(regs_reg_t *reg, cf_t *slot_symbols, int nof_prb);
int regs_pcfich_nregs(regs_t *h);
int regs_pcfich_put(regs_t *h, cf_t pcfich_symbols[REGS_PCFICH_NSYM], cf_t *slot_symbols);
int regs_pcfich_get(regs_t *h, cf_t *slot_symbols, cf_t ch_data[REGS_PCFICH_NSYM]);
int regs_pcfich_get(regs_t *h, cf_t *slot_symbols, cf_t pcfich_symbols[REGS_PCFICH_NSYM]);
int regs_phich_nregs(regs_t *h);
int regs_phich_add(regs_t *h, cf_t phich_symbols[REGS_PHICH_NSYM], int ngroup, cf_t *slot_symbols);
int regs_phich_get(regs_t *h, cf_t *slot_symbols, cf_t phich_symbols[REGS_PHICH_NSYM], int ngroup);
int regs_phich_ngroups(regs_t *h);
int regs_phich_reset(regs_t *h, cf_t *slot_symbols);
int regs_pdcch_nregs(regs_t *h);
int regs_pdcch_put(regs_t *h, cf_t *pdcch_symbols, cf_t *slot_symbols);
int regs_pdcch_get(regs_t *h, cf_t *slot_symbols, cf_t *pdcch_symbols);
#endif

@ -36,6 +36,7 @@ uint32_t bit_unpack(char **bits, int nof_bits);
void bit_pack(uint32_t value, char **bits, int nof_bits);
void bit_fprint(FILE *stream, char *bits, int nof_bits);
unsigned int bit_diff(char *x, char *y, int nbits);
int bit_count(unsigned int n);
#endif

@ -41,8 +41,8 @@ void get_time_interval(struct timeval * tdata);
extern int verbose;
#define VERBOSE_ISINFO() (verbose==VERBOSE_INFO)
#define VERBOSE_ISDEBUG() (verbose==VERBOSE_DEBUG)
#define VERBOSE_ISINFO() (verbose>=VERBOSE_INFO)
#define VERBOSE_ISDEBUG() (verbose>=VERBOSE_DEBUG)
#define PRINT_DEBUG verbose=VERBOSE_DEBUG
#define PRINT_INFO verbose=VERBOSE_INFO

@ -34,6 +34,43 @@
#include "lte/common/base.h"
const int tc_cb_sizes[NOF_TC_CB_SIZES] = { 40, 48, 56, 64, 72, 80, 88, 96, 104, 112, 120,
128, 136, 144, 152, 160, 168, 176, 184, 192, 200, 208, 216, 224, 232,
240, 248, 256, 264, 272, 280, 288, 296, 304, 312, 320, 328, 336, 344,
352, 360, 368, 376, 384, 392, 400, 408, 416, 424, 432, 440, 448, 456,
464, 472, 480, 488, 496, 504, 512, 528, 544, 560, 576, 592, 608, 624,
640, 656, 672, 688, 704, 720, 736, 752, 768, 784, 800, 816, 832, 848,
864, 880, 896, 912, 928, 944, 960, 976, 992, 1008, 1024, 1056, 1088,
1120, 1152, 1184, 1216, 1248, 1280, 1312, 1344, 1376, 1408, 1440, 1472,
1504, 1536, 1568, 1600, 1632, 1664, 1696, 1728, 1760, 1792, 1824, 1856,
1888, 1920, 1952, 1984, 2016, 2048, 2112, 2176, 2240, 2304, 2368, 2432,
2496, 2560, 2624, 2688, 2752, 2816, 2880, 2944, 3008, 3072, 3136, 3200,
3264, 3328, 3392, 3456, 3520, 3584, 3648, 3712, 3776, 3840, 3904, 3968,
4032, 4096, 4160, 4224, 4288, 4352, 4416, 4480, 4544, 4608, 4672, 4736,
4800, 4864, 4928, 4992, 5056, 5120, 5184, 5248, 5312, 5376, 5440, 5504,
5568, 5632, 5696, 5760, 5824, 5888, 5952, 6016, 6080, 6144 };
int lte_cb_size(int index) {
if (index >= 0 && index < NOF_TC_CB_SIZES) {
return tc_cb_sizes[index];
} else {
return -1;
}
}
int lte_find_cb_index(int long_cb) {
int j = 0;
while (j < NOF_TC_CB_SIZES && tc_cb_sizes[j] < long_cb) {
j++;
}
if (j == NOF_TC_CB_SIZES) {
return -1;
} else {
return j;
}
}
const int lte_symbol_sz(int nof_prb) {
if (nof_prb<=0) {
return -1;
@ -135,7 +172,7 @@ struct lte_band lte_bands[NOF_LTE_BANDS] = {
};
#define EOF_BAND 9919
int lte_str2mimotype(char *mimo_type_str, mimo_type_t *type) {
int lte_str2mimotype(char *mimo_type_str, lte_mimo_type_t *type) {
if (!strcmp(mimo_type_str, "single")) {
*type = SINGLE_ANTENNA;
} else if (!strcmp(mimo_type_str, "diversity")) {
@ -148,7 +185,7 @@ int lte_str2mimotype(char *mimo_type_str, mimo_type_t *type) {
return 0;
}
char *lte_mimotype2str(mimo_type_t type) {
char *lte_mimotype2str(lte_mimo_type_t type) {
switch(type) {
case SINGLE_ANTENNA:
return "single";

@ -122,7 +122,7 @@ int main(int argc, char **argv) {
}
printf("MSE=%f\n", mse);
if (mse >= 0.05) {
if (mse >= 0.07) {
printf("MSE too large\n");
exit(-1);
}

@ -25,66 +25,141 @@
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "lte/utils/pack.h"
#include "lte/fec/crc.h"
void gen_crc_table(crc_t *h) {
int i, j, ord = (h->order - 8);
unsigned long bit, crc;
for (i = 0; i < 256; i++) {
crc = ((unsigned long) i) << ord;
for (j = 0; j < 8; j++) {
bit = crc & h->crchighbit;
crc <<= 1;
if (bit)
crc ^= h->polynom;
}
h->table[i] = crc & h->crcmask;
}
}
unsigned int cword;
unsigned long crctable(crc_t *h) {
unsigned int icrc1(unsigned int crc, unsigned short onech,int long_crc,
int left_shift,unsigned int poly)
{
int i;
unsigned int tmp=(unsigned int) (crc ^ (onech << (long_crc >> 1) ));
// Polynom order 8, 16, 24 or 32 only.
int ord = h->order - 8;
unsigned long crc = h->crcinit;
unsigned char byte = h->byte;
for (i=0;i<left_shift;i++) {
if (tmp & (0x1<<(long_crc-1)))
tmp=(tmp<<1)^poly;
crc = (crc << 8) ^ h->table[((crc >> (ord)) & 0xff) ^ byte];
h->crcinit = crc;
return (crc & h->crcmask);
}
unsigned long reversecrcbit(unsigned int crc, int nbits, crc_t *h) {
unsigned long m, rmask = 0x1;
for (m = 0; m < nbits; m++) {
if ((rmask & crc) == 0x01)
crc = (crc ^ h->polynom) >> 1;
else
tmp <<= 1;
crc = crc >> 1;
}
return (crc & h->crcmask);
}
int crc_set_init(crc_t *crc_par, unsigned long crc_init_value) {
return tmp;
crc_par->crcinit = crc_init_value;
if (crc_par->crcinit != (crc_par->crcinit & crc_par->crcmask)) {
printf("ERROR, invalid crcinit in crc_set_init().\n");
return -1;
}
return 0;
}
unsigned int crc(unsigned int crc, char *bufptr, int len,
int long_crc,unsigned int poly, int paste_word) {
int crc_init(crc_t *h, unsigned int crc_poly, int crc_order) {
int i,k;
unsigned int data;
int stop;
unsigned int ret;
// Set crc working default parameters
h->polynom = crc_poly;
h->order = crc_order;
h->crcinit = 0x00000000;
cword=crc;
// Compute bit masks for whole CRC and CRC high bit
h->crcmask = ((((unsigned long) 1 << (h->order - 1)) - 1) << 1)
| 1;
h->crchighbit = (unsigned long) 1 << (h->order - 1);
k=0;
stop=0;
while(!stop) {
data=0;
for (i=0;i<long_crc/2;i++) {
if (bufptr[k] && k<len)
data|=(0x1<<(long_crc/2-1-i));
k++;
if (k==len) {
stop=1;
i++;
break;
// check parameters
if (h->order % 8 != 0) {
fprintf(stderr, "ERROR, invalid order=%d, it must be 8, 16, 24 or 32.\n",
h->order);
return -1;
}
if (crc_set_init(h, h->crcinit)) {
fprintf(stderr, "Error setting CRC init word\n");
return -1;
}
cword=(unsigned int) (icrc1((unsigned int) (cword<<long_crc>>long_crc),
data,long_crc,i,poly)<<long_crc)>>long_crc;
// generate lookup table
gen_crc_table(h);
return 0;
}
ret=cword;
if (paste_word) {
cword<<=32-long_crc;
for (i=0;i<long_crc;i++) {
bufptr[i+len]=((cword&(0x1<<31))>>31);
cword<<=1;
unsigned int crc_checksum(crc_t *h, char *data, int len) {
int i, k, len8, res8, a = 0;
unsigned int crc = 0;
char *pter;
crc_set_init(h, 0);
// Pack bits into bytes
len8 = (len >> 3);
res8 = (len - (len8 << 3));
if (res8 > 0) {
a = 1;
}
// Calculate CRC
for (i = 0; i < len8 + a; i++) {
pter = (char *) (data + 8 * i);
if (i == len8) {
h->byte = 0x00;
for (k = 0; k < res8; k++) {
h->byte |= ((unsigned char) *(pter + k)) << (7 - k);
}
} else {
h->byte = (unsigned char) (unpack_bits(&pter, 8) & 0xFF);
}
crc = crctable(h);
}
return (ret);
// Reverse CRC res8 positions
if (a == 1) {
crc = reversecrcbit(crc, 8 - res8, h);
}
//Return CRC value
return crc;
}
/** Appends crc_order checksum bits to the buffer data.
* The buffer data must be len + crc_order bytes
*/
void crc_attach(crc_t *h, char *data, int len) {
unsigned int checksum = crc_checksum(h, data, len);
// Add CRC
char *ptr = &data[len];
pack_bits(checksum, &ptr, h->order);
}

@ -11,7 +11,7 @@
/* Determine parity of argument: 1 = odd, 0 = even */
#ifdef __i386__
static inline int parityb(unsigned char x){
__asm__ __volatile__ ("test %1,%1;setpo %0" : "=g"(x) : "r" (x));
__asm__ __volatile__ ("test %1,%1;setpo %0" : "=qhm" (x) : "qh" (x));
return x;
}
#else

@ -28,20 +28,20 @@
#include <string.h>
#include <stdio.h>
#include "lte/ratematching/rm_conv.h"
#include "lte/fec/rm_conv.h"
#define NCOLS 32
#define NROWS_MAX NCOLS
#define RATE 3
unsigned char RM_PERM_CC[NCOLS] =
unsigned char RM_PERM_TC[NCOLS] =
{ 1, 17, 9, 25, 5, 21, 13, 29, 3, 19, 11, 27, 7, 23, 15, 31, 0, 16, 8,
24, 4, 20, 12, 28, 2, 18, 10, 26, 6, 22, 14, 30 };
unsigned char RM_PERM_CC_INV[NCOLS] = { 16, 0, 24, 8, 20, 4, 28, 12, 18, 2, 26,
unsigned char RM_PERM_TC_INV[NCOLS] = { 16, 0, 24, 8, 20, 4, 28, 12, 18, 2, 26,
10, 22, 6, 30, 14, 17, 1, 25, 9, 21, 5, 29, 13, 19, 3, 27, 11, 23, 7,
31, 15 };
int rm_conv_tx(char *input, char *output, int in_len, int out_len) {
int rm_conv_tx(char *input, int in_len, char *output, int out_len) {
char tmp[RATE * NCOLS * NROWS_MAX];
int nrows, ndummy, K_p;
@ -59,19 +59,21 @@ int rm_conv_tx(char *input, char *output, int in_len, int out_len) {
if (ndummy < 0) {
ndummy = 0;
}
/* Sub-block interleaver 5.1.4.2.1 */
k=0;
for (s = 0; s < 3; s++) {
for (j = 0; j < NCOLS; j++) {
for (i = 0; i < nrows; i++) {
if (i*NCOLS + RM_PERM_CC[j] < ndummy) {
if (i*NCOLS + RM_PERM_TC[j] < ndummy) {
tmp[k] = TX_NULL;
} else {
tmp[k] = input[(i*NCOLS + RM_PERM_CC[j]-ndummy)*3+s];
tmp[k] = input[(i*NCOLS + RM_PERM_TC[j]-ndummy)*3+s];
}
k++;
}
}
}
/* Bit collection, selection and transmission 5.1.4.2.2 */
k = 0;
j = 0;
while (k < out_len) {
@ -91,7 +93,7 @@ int rm_conv_tx(char *input, char *output, int in_len, int out_len) {
/* Undoes Convolutional Code Rate Matching.
* 3GPP TS 36.212 v10.1.0 section 5.1.4.2
*/
int rm_conv_rx(float *input, float *output, int in_len, int out_len) {
int rm_conv_rx(float *input, int in_len, float *output, int out_len) {
int nrows, ndummy, K_p;
int i, j, k;
@ -123,7 +125,7 @@ int rm_conv_rx(float *input, float *output, int in_len, int out_len) {
d_i = (j % K_p) / nrows;
d_j = (j % K_p) % nrows;
if (d_j * NCOLS + RM_PERM_CC[d_i] >= ndummy) {
if (d_j * NCOLS + RM_PERM_TC[d_i] >= ndummy) {
if (tmp[j] == RX_NULL) {
tmp[j] = input[k];
} else if (input[k] != RX_NULL) {
@ -142,8 +144,13 @@ int rm_conv_rx(float *input, float *output, int in_len, int out_len) {
d_i = (i + ndummy) / NCOLS;
d_j = (i + ndummy) % NCOLS;
for (j = 0; j < RATE; j++) {
output[i * RATE + j] = tmp[K_p * j + RM_PERM_CC_INV[d_j] * nrows
float o = tmp[K_p * j + RM_PERM_TC_INV[d_j] * nrows
+ d_i];
if (o != RX_NULL) {
output[i * RATE + j] = o;
} else {
output[i * RATE + j] = 0;
}
}
}
return 0;

@ -0,0 +1,262 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2014 The libLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the libLTE library.
*
* libLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* libLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* A copy of the GNU Lesser General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#include <string.h>
#include <stdio.h>
#include <math.h>
#include <stdbool.h>
#include <stdlib.h>
#include "lte/fec/rm_turbo.h"
#define NCOLS 32
#define NROWS_MAX NCOLS
#define RATE 3
unsigned char RM_PERM_TC[NCOLS] =
{ 0, 16, 8, 24, 4, 20, 12, 28, 2, 18, 10, 26, 6, 22, 14, 30, 1, 17, 9,
25, 5, 21, 13, 29, 3, 19, 11, 27, 7, 23, 15, 31 };
int rm_turbo_init(rm_turbo_t *q, int buffer_len) {
q->buffer_len = buffer_len;
q->buffer = malloc(buffer_len * sizeof(float));
if (!q->buffer) {
perror("malloc");
return -1;
}
q->d2_perm = malloc(buffer_len * sizeof(int) / 3 + 1);
if (!q->d2_perm) {
perror("malloc");
return -1;
}
return 0;
}
void rm_turbo_free(rm_turbo_t *q) {
if (q->buffer) {
free(q->buffer);
}
}
/* Turbo Code Rate Matching.
* 3GPP TS 36.212 v10.1.0 section 5.1.4.1
*
* TODO: Soft buffer size limitation according to UE category
*/
int rm_turbo_tx(rm_turbo_t *q, char *input, int in_len, char *output, int out_len, int rv_idx) {
char *tmp = (char*) q->buffer;
int nrows, ndummy, K_p;
int i, j, k, s, kidx, N_cb, k0;
nrows = (int) (in_len / RATE - 1) / NCOLS + 1;
K_p = nrows * NCOLS;
if (3 * K_p > q->buffer_len) {
fprintf(stderr,
"Input too large. Max input length including dummy bits is %d\n",
q->buffer_len);
return -1;
}
ndummy = K_p - in_len / RATE;
if (ndummy < 0) {
ndummy = 0;
}
/* Sub-block interleaver (5.1.4.1.1) and bit collection */
k = 0;
for (s = 0; s < 2; s++) {
for (j = 0; j < NCOLS; j++) {
for (i = 0; i < nrows; i++) {
if (s == 0) {
kidx = k%K_p;
} else {
kidx = K_p + 2 * (k%K_p);
}
if (i * NCOLS + RM_PERM_TC[j] < ndummy) {
tmp[kidx] = TX_NULL;
} else {
tmp[kidx] = input[(i * NCOLS + RM_PERM_TC[j] - ndummy) * 3 + s];
}
k++;
}
}
}
// d_k^(2) goes through special permutation
for (k = 0; k < K_p; k++) {
kidx = (RM_PERM_TC[k / nrows] + NCOLS * (k % nrows) + 1) % K_p;
if ((kidx - ndummy) < 0) {
tmp[K_p + 2 * k + 1] = TX_NULL;
} else {
tmp[K_p + 2 * k + 1] = input[3 * (kidx - ndummy) + 2];
}
}
/* Bit selection and transmission 5.1.4.1.2 */
N_cb = 3 * K_p; // TODO: Soft buffer size limitation
k0 = nrows * (2 * (int) ceilf((float) N_cb / (float) (8 * nrows))
* rv_idx + 2);
k = 0;
j = 0;
while (k < out_len) {
if (tmp[(k0 + j) % N_cb] != TX_NULL) {
output[k] = tmp[(k0 + j) % N_cb];
k++;
}
j++;
}
return 0;
}
/* Undoes Turbo Code Rate Matching.
* 3GPP TS 36.212 v10.1.0 section 5.1.4.1
*/
int rm_turbo_rx(rm_turbo_t *q, float *input, int in_len, float *output, int out_len, int rv_idx) {
int nrows, ndummy, K_p, k0, N_cb, jp, kidx;
int i, j, k;
int d_i, d_j;
bool isdummy;
float *tmp = (float*) q->buffer;
nrows = (int) (out_len / RATE - 1) / NCOLS + 1;
K_p = nrows * NCOLS;
if (3 * K_p > q->buffer_len) {
fprintf(stderr,
"Input too large. Max input length including dummy bits is %d\n",
q->buffer_len);
return -1;
}
ndummy = K_p - out_len / RATE;
if (ndummy < 0) {
ndummy = 0;
}
for (i = 0; i < RATE * K_p; i++) {
tmp[i] = RX_NULL;
}
/* Undo bit collection. Account for dummy bits */
N_cb = 3 * K_p; // TODO: Soft buffer size limitation
k0 = nrows * (2 * (int) ceilf((float) N_cb / (float) (8 * nrows))
* rv_idx + 2);
k = 0;
j = 0;
while (k < in_len) {
jp = (k0 + j) % N_cb;
if (jp == 32 || jp == 95 || jp == 0) {
i=0;
}
if (jp < K_p || !(jp%2)) {
if (jp >= K_p) {
d_i = ((jp-K_p) / 2) / nrows;
d_j = ((jp-K_p) / 2) % nrows;
} else {
d_i = jp / nrows;
d_j = jp % nrows;
}
if (d_j * NCOLS + RM_PERM_TC[d_i] >= ndummy) {
isdummy = false;
} else {
isdummy = true;
}
} else {
int jpp = (jp-K_p-1)/2;
kidx = (RM_PERM_TC[jpp / nrows] + NCOLS * (jpp % nrows) + 1) % K_p;
q->d2_perm[kidx] = jpp; // save the permutation in a temporary buffer
if ((kidx - ndummy) < 0) {
isdummy = true;
} else {
isdummy = false;
}
}
if (!isdummy) {
if (tmp[jp] == RX_NULL) {
tmp[jp] = input[k];
} else if (input[k] != RX_NULL) {
tmp[jp] += input[k]; /* soft combine LLRs */
}
k++;
}
j++;
}
/* interleaving and bit selection */
for (i = 0; i < out_len / RATE; i++) {
d_i = (i + ndummy) / NCOLS;
d_j = (i + ndummy) % NCOLS;
for (j = 0; j < RATE; j++) {
if (j != 2) {
kidx = K_p * j + (j+1)*(RM_PERM_TC[d_j] * nrows + d_i);
} else {
// use the saved permuatation function to avoid computing the inverse
kidx = 2*q->d2_perm[(i+ndummy)%K_p]+K_p+1;
}
float o = tmp[kidx];
if (o != RX_NULL) {
output[i * RATE + j] = o;
} else {
output[i * RATE + j] = 0;
}
}
}
return 0;
}
/** High-level API */
int rm_turbo_initialize(rm_turbo_hl* h) {
return rm_turbo_init(&h->q, 7000);
}
/** This function can be called in a subframe (1ms) basis */
int rm_turbo_work(rm_turbo_hl* hl) {
if (hl->init.direction) {
rm_turbo_tx(&hl->q, hl->input, hl->in_len, hl->output, hl->ctrl_in.E, hl->ctrl_in.rv_idx);
hl->out_len = hl->ctrl_in.E;
} else {
rm_turbo_rx(&hl->q, hl->input, hl->in_len, hl->output, hl->ctrl_in.S, hl->ctrl_in.rv_idx);
hl->out_len = hl->ctrl_in.S;
}
return 0;
}
int rm_turbo_stop(rm_turbo_hl* hl) {
rm_turbo_free(&hl->q);
return 0;
}

@ -0,0 +1,117 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2014 The libLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the libLTE library.
*
* libLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* libLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* A copy of the GNU Lesser General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#include <stdio.h>
#include <stdlib.h>
#include "lte/common/base.h"
#include "lte/fec/tc_interl.h"
#include "lte/fec/turbocoder.h"
#include "lte/utils/debug.h"
/************************************************
*
* LTE TURBO CODE INTERLEAVER
*
************************************************/
const int f1_list[NOF_TC_CB_SIZES] = { 3, 7, 19, 7, 7, 11, 5, 11, 7, 41, 103, 15, 9, 17,
9, 21, 101, 21, 57, 23, 13, 27, 11, 27, 85, 29, 33, 15, 17, 33, 103, 19,
19, 37, 19, 21, 21, 115, 193, 21, 133, 81, 45, 23, 243, 151, 155, 25,
51, 47, 91, 29, 29, 247, 29, 89, 91, 157, 55, 31, 17, 35, 227, 65, 19,
37, 41, 39, 185, 43, 21, 155, 79, 139, 23, 217, 25, 17, 127, 25, 239,
17, 137, 215, 29, 15, 147, 29, 59, 65, 55, 31, 17, 171, 67, 35, 19, 39,
19, 199, 21, 211, 21, 43, 149, 45, 49, 71, 13, 17, 25, 183, 55, 127, 27,
29, 29, 57, 45, 31, 59, 185, 113, 31, 17, 171, 209, 253, 367, 265, 181,
39, 27, 127, 143, 43, 29, 45, 157, 47, 13, 111, 443, 51, 51, 451, 257,
57, 313, 271, 179, 331, 363, 375, 127, 31, 33, 43, 33, 477, 35, 233,
357, 337, 37, 71, 71, 37, 39, 127, 39, 39, 31, 113, 41, 251, 43, 21, 43,
45, 45, 161, 89, 323, 47, 23, 47, 263 };
const int f2_list[NOF_TC_CB_SIZES] = { 10, 12, 42, 16, 18, 20, 22, 24, 26, 84, 90, 32,
34, 108, 38, 120, 84, 44, 46, 48, 50, 52, 36, 56, 58, 60, 62, 32, 198,
68, 210, 36, 74, 76, 78, 120, 82, 84, 86, 44, 90, 46, 94, 48, 98, 40,
102, 52, 106, 72, 110, 168, 114, 58, 118, 180, 122, 62, 84, 64, 66, 68,
420, 96, 74, 76, 234, 80, 82, 252, 86, 44, 120, 92, 94, 48, 98, 80, 102,
52, 106, 48, 110, 112, 114, 58, 118, 60, 122, 124, 84, 64, 66, 204, 140,
72, 74, 76, 78, 240, 82, 252, 86, 88, 60, 92, 846, 48, 28, 80, 102, 104,
954, 96, 110, 112, 114, 116, 354, 120, 610, 124, 420, 64, 66, 136, 420,
216, 444, 456, 468, 80, 164, 504, 172, 88, 300, 92, 188, 96, 28, 240,
204, 104, 212, 192, 220, 336, 228, 232, 236, 120, 244, 248, 168, 64,
130, 264, 134, 408, 138, 280, 142, 480, 146, 444, 120, 152, 462, 234,
158, 80, 96, 902, 166, 336, 170, 86, 174, 176, 178, 120, 182, 184, 186,
94, 190, 480 };
int tc_interl_LTE_init(tc_interl_t *h, int long_cb) {
int cb_table_idx, f1, f2;
unsigned long long i, j;
cb_table_idx = lte_find_cb_index(long_cb);
if (cb_table_idx == -1) {
fprintf(stderr, "Can't find long_cb=%d in valid TC CB table\n", long_cb);
return -1;
}
h->forward = h->reverse = NULL;
h->forward = malloc(sizeof(int) * (long_cb));
if (!h->forward) {
return -1;
}
h->reverse = malloc(sizeof(int) * (long_cb));
if (!h->reverse) {
perror("malloc");
free(h->forward);
h->forward = h->reverse = NULL;
return -1;
}
f1 = f1_list[cb_table_idx];
f2 = f2_list[cb_table_idx];
DEBUG("table_idx: %d, f1: %d, f2: %d\n", cb_table_idx, f1, f2);
h->forward[0] = 0;
h->reverse[0] = 0;
for (i = 1; i < long_cb; i++) {
j = (f1*i + f2*i*i) % (long_cb);
h->forward[i] = j;
h->reverse[j] = i;
}
return 0;
}

@ -0,0 +1,257 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2014 The libLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the libLTE library.
*
* libLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* libLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* A copy of the GNU Lesser General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#include <stdio.h>
#include <stdlib.h>
#include "lte/fec/tc_interl.h"
#include "lte/fec/turbocoder.h"
#define TURBO_RATE 3
int mcd(int x, int y);
/************************************************
*
* UMTS TURBO CODE INTERLEAVER
*
************************************************/
#define MAX_ROWS 20
#define MAX_COLS 256
const unsigned short table_p[52] = { 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43,
47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113,
127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193,
197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257 };
const unsigned char table_v[52] = { 3, 2, 2, 3, 2, 5, 2, 3, 2, 6, 3, 5, 2, 2, 2,
2, 7, 5, 3, 2, 3, 5, 2, 5, 2, 6, 3, 3, 2, 3, 2, 2, 6, 5, 2, 5, 2, 2, 2,
19, 5, 2, 3, 2, 3, 2, 6, 3, 7, 7, 6, 3 };
void tc_interl_free(tc_interl_t *h) {
if (h->forward) {
free(h->forward);
}
if (h->reverse) {
free(h->reverse);
}
h->forward = h->reverse = NULL;
}
int tc_interl_UMTS_init(tc_interl_t *h, int long_cb) {
int i, j;
int res, prim, aux;
int kp, k;
int *per, *desper;
unsigned char v;
unsigned short p;
unsigned short s[MAX_COLS], q[MAX_ROWS], r[MAX_ROWS], T[MAX_ROWS];
unsigned short U[MAX_COLS * MAX_ROWS];
int M_Rows, M_Cols, M_long;
h->forward = h->reverse = NULL;
h->forward = malloc(sizeof(int) * (long_cb));
if (!h->forward) {
return -1;
}
h->reverse = malloc(sizeof(int) * (long_cb));
if (!h->reverse) {
perror("malloc");
free(h->forward);
h->forward = h->reverse = NULL;
return -1;
}
M_long = long_cb;
/* Find R*/
if ((40 <= M_long) && (M_long <= 159))
M_Rows = 5;
else if (((160 <= M_long) && (M_long <= 200))
|| ((481 <= M_long) && (M_long <= 530)))
M_Rows = 10;
else
M_Rows = 20;
/* Find p i v*/
if ((481 <= M_long) && (M_long <= 530)) {
p = 53;
v = 2;
M_Cols = p;
} else {
i = 0;
do {
p = table_p[i];
v = table_v[i];
i++;
} while (M_long > (M_Rows * (p + 1)));
}
/* Find C*/
if ((M_long) <= (M_Rows) * ((p) - 1))
M_Cols = (p) - 1;
else if (((M_Rows) * (p - 1) < M_long) && (M_long <= (M_Rows) * (p)))
M_Cols = p;
else if ((M_Rows) * (p) < M_long)
M_Cols = (p) + 1;
q[0] = 1;
prim = 6;
for (i = 1; i < M_Rows; i++) {
do {
prim++;
res = mcd(prim, p - 1);
} while (res != 1);
q[i] = prim;
}
s[0] = 1;
for (i = 1; i < p - 1; i++) {
s[i] = (v * s[i - 1]) % p;
}
if (M_long <= 159 && M_long >= 40) {
T[0] = 4;
T[1] = 3;
T[2] = 2;
T[3] = 1;
T[4] = 0;
} else if ((M_long <= 200 && M_long >= 160)
|| (M_long <= 530 && M_long >= 481)) {
T[0] = 9;
T[1] = 8;
T[2] = 7;
T[3] = 6;
T[4] = 5;
T[5] = 4;
T[6] = 3;
T[7] = 2;
T[8] = 1;
T[9] = 0;
} else if ((M_long <= 2480 && M_long >= 2281)
|| (M_long <= 3210 && M_long >= 3161)) {
T[0] = 19;
T[1] = 9;
T[2] = 14;
T[3] = 4;
T[4] = 0;
T[5] = 2;
T[6] = 5;
T[7] = 7;
T[8] = 12;
T[9] = 18;
T[10] = 16;
T[11] = 13;
T[12] = 17;
T[13] = 15;
T[14] = 3;
T[15] = 1;
T[16] = 6;
T[17] = 11;
T[18] = 8;
T[19] = 10;
} else {
T[0] = 19;
T[1] = 9;
T[2] = 14;
T[3] = 4;
T[4] = 0;
T[5] = 2;
T[6] = 5;
T[7] = 7;
T[8] = 12;
T[9] = 18;
T[10] = 10;
T[11] = 8;
T[12] = 13;
T[13] = 17;
T[14] = 3;
T[15] = 1;
T[16] = 16;
T[17] = 6;
T[18] = 15;
T[19] = 11;
}
for (i = 0; i < M_Rows; i++) {
r[T[i]] = q[i];
}
for (i = 0; i < M_Rows; i++) {
for (j = 0; j < p - 1; j++) {
U[i * M_Cols + j] = s[(j * r[i]) % (p - 1)];
if (M_Cols == (p - 1))
U[i * M_Cols + j] -= 1;
}
}
if (M_Cols == p) {
for (i = 0; i < M_Rows; i++)
U[i * M_Cols + p - 1] = 0;
} else if (M_Cols == p + 1) {
for (i = 0; i < M_Rows; i++) {
U[i * M_Cols + p - 1] = 0;
U[i * M_Cols + p] = p;
}
if (M_long == M_Cols * M_Rows) {
aux = U[(M_Rows - 1) * M_Cols + p];
U[(M_Rows - 1) * M_Cols + p] = U[(M_Rows - 1) * M_Cols + 0];
U[(M_Rows - 1) * M_Cols + 0] = aux;
}
}
per = h->forward;
desper = h->reverse;
k = 0;
for (j = 0; j < M_Cols; j++) {
for (i = 0; i < M_Rows; i++) {
kp = T[i] * M_Cols + U[i * M_Cols + j];
if (kp < M_long) {
desper[kp] = k;
per[k] = kp;
k++;
}
}
}
return 0;
}
int mcd(int x, int y) {
int r = 1;
while (r) {
r = x % y;
x = y;
y = r;
}
return x;
}

@ -0,0 +1,134 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2014 The libLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the libLTE library.
*
* libLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* libLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* A copy of the GNU Lesser General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#include "lte/fec/tc_interl.h"
#include "lte/fec/turbocoder.h"
#define NOF_REGS 3
int tcod_init(tcod_t *h, int long_cb) {
if (tc_interl_LTE_init(&h->interl, long_cb)) {
return -1;
}
h->long_cb = long_cb;
return 0;
}
void tcod_free(tcod_t *h) {
tc_interl_free(&h->interl);
h->long_cb = 0;
}
void tcod_encode(tcod_t *h, char *input, char *output) {
char reg1_0,reg1_1,reg1_2, reg2_0,reg2_1,reg2_2;
int i,k=0,j;
char bit;
char in,out;
int *per;
per=h->interl.forward;
reg1_0=0;
reg1_1=0;
reg1_2=0;
reg2_0=0;
reg2_1=0;
reg2_2=0;
k=0;
for (i=0;i<h->long_cb;i++) {
bit=input[i];
output[k]=bit;
k++;
in=bit^(reg1_2^reg1_1);
out=reg1_2^(reg1_0^in);
reg1_2=reg1_1;
reg1_1=reg1_0;
reg1_0=in;
output[k]=out;
k++;
bit=input[per[i]];
in=bit^(reg2_2^reg2_1);
out=reg2_2^(reg2_0^in);
reg2_2=reg2_1;
reg2_1=reg2_0;
reg2_0=in;
output[k]=out;
k++;
}
k=3*h->long_cb;
/* TAILING CODER #1 */
for (j=0;j<NOF_REGS;j++) {
bit=reg1_2^reg1_1;
output[k]=bit;
k++;
in=bit^(reg1_2^reg1_1);
out=reg1_2^(reg1_0^in);
reg1_2=reg1_1;
reg1_1=reg1_0;
reg1_0=in;
output[k]=out;
k++;
}
/* TAILING CODER #2 */
for (j=0;j<NOF_REGS;j++) {
bit=reg2_2^reg2_1;
output[k]=bit;
k++;
in=bit^(reg2_2^reg2_1);
out=reg2_2^(reg2_0^in);
reg2_2=reg2_1;
reg2_1=reg2_0;
reg2_0=in;
output[k]=out;
k++;
}
}

@ -0,0 +1,299 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include "lte/fec/tc_interl.h"
#include "lte/fec/turbodecoder.h"
/************************************************
*
* MAP_GEN is the MAX-LOG-MAP generic implementation of the
* Decoder
*
************************************************/
void map_gen_beta(map_gen_t *s, llr_t *input, llr_t *parity) {
llr_t m_b[8], new[8], old[8];
llr_t x, y, xy;
int k;
int end = s->long_cb + RATE;
llr_t *beta = s->beta;
int i;
for (i=0;i<8;i++) {
old[i] = beta[8 * (end) + i];
}
for (k = end - 1; k >= 0; k--) {
x = input[k];
y = parity[k];
xy = x + y;
m_b[0] = old[4] + xy;
m_b[1] = old[4];
m_b[2] = old[5] + y;
m_b[3] = old[5] + x;
m_b[4] = old[6] + x;
m_b[5] = old[6] + y;
m_b[6] = old[7];
m_b[7] = old[7] + xy;
new[0] = old[0];
new[1] = old[0] + xy;
new[2] = old[1] + x;
new[3] = old[1] + y;
new[4] = old[2] + y;
new[5] = old[2] + x;
new[6] = old[3] + xy;
new[7] = old[3];
for (i=0;i<8;i++) {
if (m_b[i] > new[i])
new[i] = m_b[i];
beta[8 * k + i] = new[i];
old[i] = new[i];
}
}
}
void map_gen_alpha(map_gen_t *s, llr_t *input, llr_t *parity, llr_t *output) {
llr_t m_b[8], new[8], old[8], max1[8], max0[8];
llr_t m1, m0;
llr_t x, y, xy;
llr_t out;
int k;
int end = s->long_cb;
llr_t *beta = s->beta;
int i;
old[0] = 0;
for (i=1;i<8;i++) {
old[i] = -INF;
}
for (k = 1; k < end + 1; k++) {
x = input[k - 1];
y = parity[k - 1];
xy = x + y;
m_b[0] = old[0];
m_b[1] = old[3] + y;
m_b[2] = old[4] + y;
m_b[3] = old[7];
m_b[4] = old[1];
m_b[5] = old[2] + y;
m_b[6] = old[5] + y;
m_b[7] = old[6];
new[0] = old[1] + xy;
new[1] = old[2] + x;
new[2] = old[5] + x;
new[3] = old[6] + xy;
new[4] = old[0] + xy;
new[5] = old[3] + x;
new[6] = old[4] + x;
new[7] = old[7] + xy;
for (i=0;i<8;i++) {
max0[i] = m_b[i] + beta[8 * k + i];
max1[i] = new[i] + beta[8 * k + i];
}
m1 = max1[0];
m0 = max0[0];
for (i=1;i<8;i++) {
if (max1[i] > m1)
m1 = max1[i];
if (max0[i] > m0)
m0 = max0[i];
}
for (i=0;i<8;i++) {
if (m_b[i] > new[i])
new[i] = m_b[i];
old[i] = new[i];
}
out = m1 - m0;
output[k - 1] = out;
}
}
int map_gen_init(map_gen_t *h, int long_cb) {
bzero(h, sizeof(map_gen_t));
h->beta = malloc(sizeof(llr_t) * (long_cb + TOTALTAIL + 1)* NUMSTATES);
if (!h->beta) {
perror("malloc");
return -1;
}
h->long_cb = long_cb;
return 0;
}
void map_gen_free(map_gen_t *h) {
if (h->beta) {
free(h->beta);
}
bzero(h, sizeof(map_gen_t));
}
void map_gen_dec(map_gen_t *h, llr_t *input, llr_t *parity, llr_t *output) {
int k;
h->beta[(h->long_cb + TAIL) * NUMSTATES] = 0;
for (k = 1; k < NUMSTATES; k++)
h->beta[(h->long_cb + TAIL) * NUMSTATES + k] = -INF;
map_gen_beta(h, input, parity);
map_gen_alpha(h, input, parity, output);
}
/************************************************
*
* TURBO DECODER INTERFACE
*
************************************************/
int tdec_init(tdec_t *h, int long_cb) {
int ret = -1;
bzero(h, sizeof(tdec_t));
int len = long_cb + TOTALTAIL;
h->llr1 = malloc(sizeof(llr_t) * len);
if (!h->llr1) {
perror("malloc");
goto clean_and_exit;
}
h->llr2 = malloc(sizeof(llr_t) * len);
if (!h->llr2) {
perror("malloc");
goto clean_and_exit;
}
h->w = malloc(sizeof(llr_t) * len);
if (!h->w) {
perror("malloc");
goto clean_and_exit;
}
h->syst = malloc(sizeof(llr_t) * len);
if (!h->syst) {
perror("malloc");
goto clean_and_exit;
}
h->parity = malloc(sizeof(llr_t) * len);
if (!h->parity) {
perror("malloc");
goto clean_and_exit;
}
if (map_gen_init(&h->dec, long_cb)) {
goto clean_and_exit;
}
h->long_cb = long_cb;
if (tc_interl_LTE_init(&h->interleaver, h->long_cb) < 0) {
goto clean_and_exit;
}
ret = 0;
clean_and_exit:
if (ret == -1) {
tdec_free(h);
}
return ret;
}
void tdec_free(tdec_t *h) {
if (h->llr1) {
free(h->llr1);
}
if (h->llr2) {
free(h->llr2);
}
if (h->w) {
free(h->w);
}
if (h->syst) {
free(h->syst);
}
if (h->parity) {
free(h->parity);
}
map_gen_free(&h->dec);
tc_interl_free(&h->interleaver);
bzero(h, sizeof(tdec_t));
}
void tdec_iteration(tdec_t *h, llr_t *input) {
int i;
// Prepare systematic and parity bits for MAP DEC #1
for (i = 0; i < h->long_cb; i++) {
h->syst[i] = input[RATE * i] + h->w[i];
h->parity[i] = input[RATE * i + 1];
}
for (i=h->long_cb;i<h->long_cb+RATE;i++) {
h->syst[i] = input[RATE * h->long_cb + NINPUTS * (i - h->long_cb)];
h->parity[i] = input[RATE * h->long_cb + NINPUTS * (i - h->long_cb) + 1];
}
// Run MAP DEC #1
map_gen_dec(&h->dec, h->syst, h->parity, h->llr1);
// Prepare systematic and parity bits for MAP DEC #1
for (i = 0; i < h->long_cb; i++) {
h->syst[i] = h->llr1[h->interleaver.forward[i]] - h->w[h->interleaver.forward[i]];
h->parity[i] = input[RATE * i + 2];
}
for (i=h->long_cb;i<h->long_cb+RATE;i++) {
h->syst[i] = input[RATE * h->long_cb + NINPUTS * RATE + NINPUTS * (i - h->long_cb)];
h->parity[i] = input[RATE * h->long_cb + NINPUTS * RATE + NINPUTS * (i - h->long_cb) + 1];
}
// Run MAP DEC #1
map_gen_dec(&h->dec, h->syst, h->parity, h->llr2);
// Update a-priori LLR from the last iteration
for (i = 0; i < h->long_cb; i++) {
h->w[i] += h->llr2[h->interleaver.reverse[i]] - h->llr1[i];
}
}
void tdec_reset(tdec_t *h) {
memset(h->w, 0, sizeof(llr_t) * h->long_cb);
}
void tdec_decision(tdec_t *h, char *output) {
int i;
for (i = 0; i < h->long_cb; i++) {
output[i] = (h->llr2[h->interleaver.reverse[i]] > 0) ? 1 : 0;
}
}
void tdec_run_all(tdec_t *h, llr_t *input, char *output, int nof_iterations) {
int iter = 0;
tdec_reset(h);
do {
tdec_iteration(h, input);
iter++;
} while (iter < nof_iterations);
tdec_decision(h, output);
}

@ -19,6 +19,32 @@
# and at http://www.gnu.org/licenses/.
#
########################################################################
# RATEMATCHING TEST
########################################################################
ADD_EXECUTABLE(rm_conv_test rm_conv_test.c)
TARGET_LINK_LIBRARIES(rm_conv_test lte)
ADD_EXECUTABLE(rm_turbo_test rm_turbo_test.c)
TARGET_LINK_LIBRARIES(rm_turbo_test lte)
ADD_TEST(rm_conv_test_1 rm_conv_test -t 480 -r 1920)
ADD_TEST(rm_conv_test_2 rm_conv_test -t 1920 -r 480)
########################################################################
# Turbo Coder TEST
########################################################################
ADD_EXECUTABLE(turbocoder_test turbocoder_test.c)
TARGET_LINK_LIBRARIES(turbocoder_test lte)
ADD_TEST(turbocoder_test_504_1 turbocoder_test -n 100 -s 1 -l 504 -e 1.0 -t)
ADD_TEST(turbocoder_test_504_2 turbocoder_test -n 100 -s 1 -l 504 -e 2.0 -t)
ADD_TEST(turbocoder_test_6114_1_5 turbocoder_test -n 100 -s 1 -l 6144 -e 1.5 -t)
ADD_TEST(turbocoder_test_known turbocoder_test -n 1 -s 1 -k -e 0.5)
########################################################################
# Viterbi TEST
########################################################################
@ -43,9 +69,9 @@ ADD_TEST(viterbi_1000_4 viterbi_test -n 100 -s 1 -l 1000 -k 7 -t -e 4.5)
ADD_EXECUTABLE(crc_test crc_test.c)
TARGET_LINK_LIBRARIES(crc_test lte)
ADD_TEST(crc_24A crc_test -n 5000 -l 24 -p 0x1864CFB -s 1)
ADD_TEST(crc_24B crc_test -n 5000 -l 24 -p 0x1800063 -s 1)
ADD_TEST(crc_16 crc_test -n 5000 -l 16 -p 0x11021 -s 1)
ADD_TEST(crc_8 crc_test -n 5000 -l 8 -p 0x19B -s 1)
ADD_TEST(crc_24A crc_test -n 5001 -l 24 -p 0x1864CFB -s 1)
ADD_TEST(crc_24B crc_test -n 5001 -l 24 -p 0x1800063 -s 1)
ADD_TEST(crc_16 crc_test -n 5001 -l 16 -p 0x11021 -s 1)
ADD_TEST(crc_8 crc_test -n 5001 -l 8 -p 0x19B -s 1)

@ -25,7 +25,6 @@
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@ -35,13 +34,11 @@
#include <time.h>
#include "lte.h"
#include "crc_test.h"
int num_bits = 1000, crc_length = 16;
unsigned int crc_poly = 0x11021;
unsigned int seed = 0;
int num_bits = 5001, crc_length = 24;
unsigned int crc_poly = 0x1864CFB;
unsigned int seed = 1;
void usage(char *prog) {
printf("Usage: %s [nlps]\n", prog);
@ -78,10 +75,11 @@ int main(int argc, char **argv) {
int i;
char *data;
unsigned int crc_word, expected_word;
crc_t crc_p;
parse_args(argc, argv);
data = malloc(sizeof(char) * (num_bits+crc_length));
data = malloc(sizeof(char) * (num_bits + crc_length * 2));
if (!data) {
perror("malloc");
exit(-1);
@ -97,21 +95,19 @@ int main(int argc, char **argv) {
data[i] = rand() % 2;
}
// generate CRC word
crc_word = crc(0, data, num_bits, crc_length, crc_poly, 1);
// check if result is zero
if (crc(0, data, num_bits + crc_length, crc_length, crc_poly, 0)) {
printf("CRC check is non-zero\n");
//Initialize CRC params and tables
if (crc_init(&crc_p, crc_poly, crc_length)) {
exit(-1);
}
free(data);
// generate CRC word
crc_word = crc_checksum(&crc_p, data, num_bits);
printf("CRC word: 0x%x\n", crc_word);
free(data);
// check if generated word is as expected
if (get_expected_word(num_bits, crc_length, crc_poly, seed, &expected_word)) {
if (get_expected_word(num_bits, crc_length, crc_poly, seed,
&expected_word)) {
fprintf(stderr, "Test parameters not defined in test_results.h\n");
exit(-1);
}

@ -39,10 +39,11 @@ typedef struct {
static expected_word_t expected_words[] = {
{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
{5001, 24, LTE_CRC24A, 1, 0x1C5C97}, // LTE CRC24A (36.212 Sec 5.1.1)
{5001, 24, LTE_CRC24B, 1, 0x36D1F0}, // LTE CRC24B
{5001, 16, LTE_CRC16, 1, 0x7FF4}, // LTE CRC16: 0x7FF4
{5001, 8, LTE_CRC8, 1, 0xF0}, // LTE CRC8 0xF8
{-1, -1, 0, 0, 0}
};

@ -100,7 +100,7 @@ int main(int argc, char **argv) {
bits[i] = rand()%2;
}
if (rm_conv_tx(bits, rm_bits, nof_tx_bits, nof_rx_bits)) {
if (rm_conv_tx(bits, nof_tx_bits, rm_bits, nof_rx_bits)) {
exit(-1);
}
@ -108,7 +108,7 @@ int main(int argc, char **argv) {
rm_symbols[i] = rm_bits[i]?1:-1;
}
if (rm_conv_rx(rm_symbols, unrm_symbols, nof_rx_bits, nof_tx_bits)) {
if (rm_conv_rx(rm_symbols, nof_rx_bits, unrm_symbols, nof_tx_bits)) {
exit(-1);
}

@ -0,0 +1,142 @@
/**
*
* \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 <math.h>
#include <time.h>
#include <stdbool.h>
#include "lte.h"
int nof_tx_bits=-1, nof_rx_bits=-1;
int rv_idx = 0;
void usage(char *prog) {
printf("Usage: %s -t nof_tx_bits -r nof_rx_bits [-i rv_idx]\n", prog);
}
void parse_args(int argc, char **argv) {
int opt;
while ((opt = getopt(argc, argv, "tri")) != -1) {
switch (opt) {
case 't':
nof_tx_bits = atoi(argv[optind]);
break;
case 'r':
nof_rx_bits = atoi(argv[optind]);
break;
case 'i':
rv_idx = atoi(argv[optind]);
break;
default:
usage(argv[0]);
exit(-1);
}
}
if (nof_tx_bits == -1) {
usage(argv[0]);
exit(-1);
}
if (nof_rx_bits == -1) {
usage(argv[0]);
exit(-1);
}
}
int main(int argc, char **argv) {
int i;
char *bits, *rm_bits;
float *rm_symbols, *unrm_symbols;
int nof_errors;
rm_turbo_t rm_turbo;
parse_args(argc, argv);
bits = malloc(sizeof(char) * nof_tx_bits);
if (!bits) {
perror("malloc");
exit(-1);
}
rm_bits = malloc(sizeof(char) * nof_rx_bits);
if (!rm_bits) {
perror("malloc");
exit(-1);
}
rm_symbols = malloc(sizeof(float) * nof_rx_bits);
if (!rm_symbols) {
perror("malloc");
exit(-1);
}
unrm_symbols = malloc(sizeof(float) * nof_tx_bits);
if (!unrm_symbols) {
perror("malloc");
exit(-1);
}
for (i=0;i<nof_tx_bits;i++) {
bits[i] = rand()%2;
}
rm_turbo_init(&rm_turbo, 1000);
rm_turbo_tx(&rm_turbo, bits, nof_tx_bits, rm_bits, nof_rx_bits, rv_idx);
for (i=0;i<nof_rx_bits;i++) {
rm_symbols[i] = (float) rm_bits[i]?1:-1;
}
rm_turbo_rx(&rm_turbo, rm_symbols, nof_rx_bits, unrm_symbols, nof_tx_bits, rv_idx);
nof_errors = 0;
for (i=0;i<nof_tx_bits;i++) {
if ((unrm_symbols[i] > 0) != bits[i]) {
nof_errors++;
printf("%.2f != %d\n", unrm_symbols[i], bits[i]);
}
}
rm_turbo_free(&rm_turbo);
free(bits);
free(rm_bits);
free(rm_symbols);
free(unrm_symbols);
if (nof_tx_bits >= nof_rx_bits) {
if (nof_errors) {
printf("nof_errors=%d\n", nof_errors);
exit(-1);
}
}
printf("Ok\n");
exit(0);
}

@ -0,0 +1,324 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2014 The libLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the libLTE library.
*
* libLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* libLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* A copy of the GNU Lesser General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <unistd.h>
#include <math.h>
#include <time.h>
#include <sys/time.h>
#include <time.h>
#include "lte.h"
#include "turbocoder_test.h"
typedef _Complex float cf_t;
int frame_length = 1000, nof_frames=100;
float ebno_db = 100.0;
unsigned int seed = 0;
int K = -1;
#define MAX_ITERATIONS 4
int nof_iterations = MAX_ITERATIONS;
int test_known_data = 0;
int test_errors = 0;
#define SNR_POINTS 8
#define SNR_MIN 0.0
#define SNR_MAX 4.0
void usage(char *prog) {
printf("Usage: %s [nlesv]\n", prog);
printf("\t-k Test with known data (ignores frame_length) [Default disabled]\n");
printf("\t-i nof_iterations [Default %d]\n", nof_iterations);
printf("\t-n nof_frames [Default %d]\n", nof_frames);
printf("\t-l frame_length [Default %d]\n", frame_length);
printf("\t-e ebno in dB [Default scan]\n");
printf("\t-t test: check errors on exit [Default disabled]\n");
printf("\t-s seed [Default 0=time]\n");
}
void parse_args(int argc, char **argv) {
int opt;
while ((opt = getopt(argc, argv, "inlstvekt")) != -1) {
switch (opt) {
case 'n':
nof_frames = atoi(argv[optind]);
break;
case 'k':
test_known_data = 1;
break;
case 't':
test_errors = 1;
break;
case 'i':
nof_iterations = atoi(argv[optind]);
break;
case 'l':
frame_length = atoi(argv[optind]);
break;
case 'e':
ebno_db = atof(argv[optind]);
break;
case 's':
seed = (unsigned int) strtoul(argv[optind], NULL, 0);
break;
case 'v':
verbose++;
break;
default:
usage(argv[0]);
exit(-1);
}
}
}
void output_matlab(float ber[MAX_ITERATIONS][SNR_POINTS], int snr_points) {
int i, j;
FILE *f = fopen("turbocoder_snr.m", "w");
if (!f) {
perror("fopen");
exit(-1);
}
fprintf(f, "ber=[");
for (j=0;j<MAX_ITERATIONS;j++) {
for (i = 0; i < snr_points; i++) {
fprintf(f, "%g ", ber[j][i]);
}
fprintf(f, ";\n");
}
fprintf(f, "];\n");
fprintf(f, "snr=linspace(%g,%g-%g/%d,%d);\n", SNR_MIN, SNR_MAX, SNR_MAX,
snr_points, snr_points);
fprintf(f, "semilogy(snr,ber,snr,0.5*erfc(sqrt(10.^(snr/10))));\n");
fprintf(f, "legend('1 iter','2 iter', '3 iter', '4 iter', 'theory-uncoded');");
fprintf(f, "grid on;\n");
fclose(f);
}
int main(int argc, char **argv) {
int frame_cnt;
float *llr;
unsigned char *llr_c;
char *data_tx, *data_rx, *symbols;
int i, j;
float var[SNR_POINTS];
int snr_points;
float ber[MAX_ITERATIONS][SNR_POINTS];
unsigned int errors[100];
int coded_length;
struct timeval tdata[3];
float mean_usec;
tdec_t tdec;
tcod_t tcod;
parse_args(argc, argv);
if (!seed) {
seed = time(NULL);
}
srand(seed);
if (test_known_data) {
frame_length = KNOWN_DATA_LEN;
} else {
frame_length = lte_cb_size(lte_find_cb_index(frame_length));
}
coded_length = 3*(frame_length)+TOTALTAIL;
printf(" Frame length: %d\n", frame_length);
if (ebno_db < 100.0) {
printf(" EbNo: %.2f\n", ebno_db);
}
data_tx = malloc(frame_length * sizeof(char));
if (!data_tx) {
perror("malloc");
exit(-1);
}
data_rx = malloc(frame_length * sizeof(char));
if (!data_rx) {
perror("malloc");
exit(-1);
}
symbols = malloc(coded_length * sizeof(char));
if (!symbols) {
perror("malloc");
exit(-1);
}
llr = malloc(coded_length * sizeof(float));
if (!llr) {
perror("malloc");
exit(-1);
}
llr_c = malloc(coded_length * sizeof(char));
if (!llr_c) {
perror("malloc");
exit(-1);
}
if (tcod_init(&tcod, frame_length)) {
fprintf(stderr, "Error initiating Turbo coder\n");
exit(-1);
}
if (tdec_init(&tdec, frame_length)) {
fprintf(stderr, "Error initiating Turbo decoder\n");
exit(-1);
}
float ebno_inc, esno_db;
ebno_inc = (SNR_MAX - SNR_MIN) / SNR_POINTS;
if (ebno_db == 100.0) {
snr_points = SNR_POINTS;
for (i = 0; i < snr_points; i++) {
ebno_db = SNR_MIN + i * ebno_inc;
esno_db = ebno_db + 10 * log10((double) 1 / 3);
var[i] = sqrt(1 / (pow(10, esno_db / 10)));
}
} else {
esno_db = ebno_db + 10 * log10((double) 1 / 3);
var[0] = sqrt(1 / (pow(10, esno_db / 10)));
snr_points = 1;
}
for (i = 0; i < snr_points; i++) {
mean_usec = 0;
frame_cnt = 0;
bzero(errors, sizeof(int) * MAX_ITERATIONS);
while (frame_cnt < nof_frames) {
/* generate data_tx */
for (j = 0; j < frame_length; j++) {
if (test_known_data) {
data_tx[j] = known_data[j];
} else {
data_tx[j] = rand() % 2;
}
}
/* coded BER */
if (test_known_data) {
for (j=0;j<coded_length;j++) {
symbols[j] = known_data_encoded[j];
}
} else {
tcod_encode(&tcod, data_tx, symbols);
}
for (j = 0; j < coded_length; j++) {
llr[j] = symbols[j] ? sqrt(2) : -sqrt(2);
}
ch_awgn_f(llr, llr, var[i], coded_length);
/* decoder */
tdec_reset(&tdec);
int t;
if (nof_iterations == -1) {
t = MAX_ITERATIONS;
} else {
t = nof_iterations;
}
for (j=0;j<t;j++) {
if (!j) gettimeofday(&tdata[1],NULL); // Only measure 1 iteration
tdec_iteration(&tdec, llr);
tdec_decision(&tdec, data_rx);
if (!j) gettimeofday(&tdata[2],NULL);
if (!j) get_time_interval(tdata);
if (!j) mean_usec = (float) mean_usec*0.9+(float) tdata[0].tv_usec*0.1;
/* check errors */
errors[j] += bit_diff(data_tx, data_rx, frame_length);
if (j < MAX_ITERATIONS) {
ber[j][i] = (float) errors[j] /(frame_cnt * frame_length);
}
}
frame_cnt++;
printf("Eb/No: %3.2f %10d/%d ",
SNR_MIN + i * ebno_inc,frame_cnt,nof_frames);
printf("BER: %.2e ",(float) errors[j-1] / (frame_cnt * frame_length));
printf("%3.1f Mbps (%6.2f usec)", (float) frame_length/mean_usec, mean_usec);
printf("\r");
}
printf("\n");
if (snr_points == 1) {
if (test_known_data && seed == KNOWN_DATA_SEED
&& ebno_db == KNOWN_DATA_EBNO
&& frame_cnt == KNOWN_DATA_NFRAMES) {
for (j=0;j<MAX_ITERATIONS;j++) {
if (errors[j] > known_data_errors[j]) {
fprintf(stderr, "Expected %d errors but got %d\n",
known_data_errors[j], errors[j]);
exit(-1);
}else {
printf("Iter %d ok\n", j+1);
}
}
} else {
for (j=0;j<MAX_ITERATIONS;j++) {
printf("BER: %g\t%u errors\n",
(float) errors[j] / (frame_cnt * frame_length), errors[j]);
if (test_errors) {
if (errors[j] > get_expected_errors(frame_cnt, seed, j+1, frame_length, ebno_db)) {
fprintf(stderr, "Expected %d errors but got %d\n",
get_expected_errors(frame_cnt, seed, j+1, frame_length, ebno_db),
errors[j]);
exit(-1);
} else {
printf("Iter %d ok\n", j+1);
}
}
}
}
}
}
free(data_tx);
free(symbols);
free(llr);
free(llr_c);
free(data_rx);
tdec_free(&tdec);
tcod_free(&tcod);
printf("\n");
output_matlab(ber, snr_points);
printf("Done\n");
exit(0);
}

@ -0,0 +1,168 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2014 The libLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the libLTE library.
*
* libLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* libLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* A copy of the GNU Lesser General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#include <stdbool.h>
typedef struct {
int n;
unsigned int s;
int iterations;
int len;
float ebno;
int errors;
} expected_errors_t;
static expected_errors_t expected_errors[] = {
{ 100, 1, 1, 504, 1.0, 3989 },
{ 100, 1, 2, 504, 1.0, 1922 },
{ 100, 1, 3, 504, 1.0, 1096 },
{ 100, 1, 4, 504, 1.0, 957 },
{ 100, 1, 1, 504, 2.0, 803 },
{ 100, 1, 2, 504, 2.0, 47 },
{ 100, 1, 3, 504, 2.0, 7 },
{ 100, 1, 4, 504, 2.0, 0 },
{ 100, 1, 1, 6144, 1.5, 24719 },
{ 100, 1, 2, 6144, 1.5, 897 },
{ 100, 1, 3, 6144, 1.5, 2 },
{ 100, 1, 4, 6144, 1.5, 0 },
{ -1, 0, -1, -1, -1.0, -1}
};
int get_expected_errors(int n, unsigned int s, int iterations, int len, float ebno) {
int i;
i = 0;
while (expected_errors[i].n != -1) {
if (expected_errors[i].n == n
&& expected_errors[i].s == s
&& expected_errors[i].len == len
&& expected_errors[i].iterations == iterations
&& expected_errors[i].ebno == ebno) {
break;
} else {
i++;
}
}
return expected_errors[i].errors;
}
#define KNOWN_DATA_NFRAMES 1
#define KNOWN_DATA_SEED 1
#define KNOWN_DATA_EBNO 0.5
const int known_data_errors[4] = {47, 18, 0, 0};
#define KNOWN_DATA_LEN 504
const char known_data[KNOWN_DATA_LEN] = { 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1,
0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1,
0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1,
1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0,
0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1,
1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0,
1, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0,
1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0,
1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1,
0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0,
0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0,
1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1,
1, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0,
0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0,
0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1,
1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1,
1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0,
0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0,
1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1,
1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1,
1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0,
0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1 };
const char known_data_encoded[3 * KNOWN_DATA_LEN + 12] = { 0, 0, 0, 0, 0, 1, 1,
1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1,
1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0,
0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0,
0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1,
1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1,
0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1,
1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1,
0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1,
1, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0,
1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1,
0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0,
1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1,
0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1,
0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0,
0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0,
0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0,
0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0,
0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1,
0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0,
1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0,
1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0,
1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1,
1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1,
1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0,
0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1,
1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1,
0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1,
1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1,
1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0,
0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0,
1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0,
0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1,
1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0,
0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1,
0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0,
0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1,
0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0,
0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0,
0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0,
0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1,
1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0,
0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1,
1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1,
1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1,
0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1,
0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0,
1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0,
1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1,
1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1,
1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1,
1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0,
0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0,
1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1,
1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1,
1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0,
0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0,
0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0,
1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0,
1, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0,
0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0,
1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1,
1, 0, 1, 1, 1 };

@ -39,7 +39,7 @@
typedef _Complex float cf_t;
int frame_length = 1000, nof_slots = 128;
int frame_length = 1000, nof_frames = 128;
float ebno_db = 100.0;
unsigned int seed = 0;
bool tail_biting = false;
@ -54,7 +54,7 @@ int K = -1;
void usage(char *prog) {
printf("Usage: %s [nlestk]\n", prog);
printf("\t-n nof_frames [Default %d]\n", nof_slots);
printf("\t-n nof_frames [Default %d]\n", nof_frames);
printf("\t-l frame_length [Default %d]\n", frame_length);
printf("\t-e ebno in dB [Default scan]\n");
printf("\t-s seed [Default 0=time]\n");
@ -67,7 +67,7 @@ void parse_args(int argc, char **argv) {
while ((opt = getopt(argc, argv, "nlstek")) != -1) {
switch (opt) {
case 'n':
nof_slots = atoi(argv[optind]);
nof_frames = atoi(argv[optind]);
break;
case 'l':
frame_length = atoi(argv[optind]);
@ -254,7 +254,7 @@ int main(int argc, char **argv) {
for (j = 0; j < NTYPES; j++) {
errors[j] = 0;
}
while (frame_cnt < nof_slots) {
while (frame_cnt < nof_frames) {
/* generate data_tx */
for (j = 0; j < frame_length; j++) {
@ -291,7 +291,7 @@ int main(int argc, char **argv) {
}
frame_cnt++;
printf("Eb/No: %3.2f %10d/%d ",
SNR_MIN + i * ebno_inc,frame_cnt,nof_slots);
SNR_MIN + i * ebno_inc,frame_cnt,nof_frames);
for (n=0;n<1+ncods;n++) {
printf("BER: %.2e ",(float) errors[n] / (frame_cnt * frame_length));
}
@ -324,7 +324,7 @@ int main(int argc, char **argv) {
}
if (snr_points == 1) {
int expected_errors = get_expected_errors(nof_slots,
int expected_errors = get_expected_errors(nof_frames,
seed, frame_length, K, tail_biting, ebno_db);
if (expected_errors == -1) {
fprintf(stderr, "Test parameters not defined in test_results.h\n");

@ -78,7 +78,7 @@ int layermap_multiplex(cf_t *d[MAX_CODEWORDS], cf_t *x[MAX_LAYERS], int nof_cw,
* Returns the number of symbols per layer (M_symb^layer in the specs)
*/
int layermap_type(cf_t *d[MAX_CODEWORDS], cf_t *x[MAX_LAYERS], int nof_cw, int nof_layers,
int nof_symbols[MAX_CODEWORDS], mimo_type_t type) {
int nof_symbols[MAX_CODEWORDS], lte_mimo_type_t type) {
if (nof_cw > MAX_CODEWORDS) {
fprintf(stderr, "Maximum number of codewords is %d (nof_cw=%d)\n", MAX_CODEWORDS, nof_cw);
@ -167,7 +167,7 @@ int layerdemap_multiplex(cf_t *x[MAX_LAYERS], cf_t *d[MAX_CODEWORDS], int nof_la
* nof_symbols. Returns -1 on error
*/
int layerdemap_type(cf_t *x[MAX_LAYERS], cf_t *d[MAX_CODEWORDS], int nof_layers, int nof_cw,
int nof_layer_symbols, int nof_symbols[MAX_CODEWORDS], mimo_type_t type) {
int nof_layer_symbols, int nof_symbols[MAX_CODEWORDS], lte_mimo_type_t type) {
if (nof_cw > MAX_CODEWORDS) {
fprintf(stderr, "Maximum number of codewords is %d (nof_cw=%d)\n", MAX_CODEWORDS, nof_cw);

@ -85,7 +85,7 @@ int precoding_diversity(cf_t *x[MAX_LAYERS], cf_t *y[MAX_PORTS], int nof_ports,
/* 36.211 v10.3.0 Section 6.3.4 */
int precoding_type(cf_t *x[MAX_LAYERS], cf_t *y[MAX_PORTS], int nof_layers, int nof_ports, int nof_symbols,
mimo_type_t type) {
lte_mimo_type_t type) {
if (nof_ports > MAX_PORTS) {
fprintf(stderr, "Maximum number of ports is %d (nof_ports=%d)\n", MAX_PORTS, nof_ports);
@ -177,7 +177,7 @@ int predecoding_diversity_zf(cf_t *y[MAX_PORTS], cf_t *ce[MAX_PORTS],
/* 36.211 v10.3.0 Section 6.3.4 */
int predecoding_type(cf_t *y[MAX_PORTS], cf_t *ce[MAX_PORTS],
cf_t *x[MAX_LAYERS], int nof_ports, int nof_layers, int nof_symbols, mimo_type_t type) {
cf_t *x[MAX_LAYERS], int nof_ports, int nof_layers, int nof_symbols, lte_mimo_type_t type) {
if (nof_ports > MAX_PORTS) {
fprintf(stderr, "Maximum number of ports is %d (nof_ports=%d)\n", MAX_PORTS, nof_ports);

@ -75,7 +75,7 @@ void parse_args(int argc, char **argv) {
int main(int argc, char **argv) {
int i, j, num_errors, symbols_layer;
cf_t *d[MAX_CODEWORDS], *x[MAX_LAYERS], *dp[MAX_CODEWORDS];
mimo_type_t type;
lte_mimo_type_t type;
int nof_symb_cw[MAX_CODEWORDS];
int n[2];

@ -78,7 +78,7 @@ int main(int argc, char **argv) {
int i, j;
float mse;
cf_t *x[MAX_LAYERS], *r[MAX_PORTS], *y[MAX_PORTS], *h[MAX_PORTS], *xr[MAX_LAYERS];
mimo_type_t type;
lte_mimo_type_t type;
parse_args(argc, argv);

@ -47,7 +47,7 @@ void demod_soft_alg_set(demod_soft_t *q, enum alg alg_type) {
}
void demod_soft_sigma_set(demod_soft_t *q, float sigma) {
q->sigma = sigma;
q->sigma = 2*sigma;
}
int demod_soft_demodulate(demod_soft_t *q, const cf_t* symbols, float* llr, int nsymbols) {

@ -41,14 +41,14 @@
#include "lte/utils/vector.h"
#include "lte/utils/debug.h"
int dci_init(dci_t *q, int nof_dcis) {
q->msg = calloc(sizeof(dci_msg_t), nof_dcis);
int dci_init(dci_t *q, int max_dcis) {
q->msg = calloc(sizeof(dci_msg_t), max_dcis);
if (!q->msg) {
perror("malloc");
return -1;
}
q->nof_dcis = nof_dcis;
q->nof_dcis = 0;
q->max_dcis = max_dcis;
return 0;
}
@ -63,60 +63,755 @@ void dci_candidate_fprint(FILE *f, dci_candidate_t *q) {
q->L, q->ncce, q->rnti, q->nof_bits);
}
int dci_format1_add(dci_t *q, dci_format1_t *msg, int L, int nCCE, unsigned short rnti) {
int i, j;
i=0;
while(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");
int dci_msg_candidate_set(dci_msg_t *msg, int L, int nCCE, unsigned short rnti) {
if (L >= 0 && L <=3) {
msg->location.L = (unsigned char) L;
} else {
fprintf(stderr, "Invalid L %d\n", L);
return -1;
}
q->msg[i].location.L = L;
q->msg[i].location.ncce = nCCE;
q->msg[i].location.nof_bits = dci_format1_sizeof(6, 1);
q->msg[i].location.rnti = rnti;
for (j=0;j<q->msg[i].location.nof_bits;j++) {
q->msg[i].data[j] = rand()%2;
if (nCCE >= 0 && nCCE <= 87) {
msg->location.ncce = (unsigned char) nCCE;
} else {
fprintf(stderr, "Invalid nCCE %d\n", nCCE);
return -1;
}
msg->location.rnti = rnti;
return 0;
}
int dci_format0_add(dci_t *q, dci_format0_t *msg, int L, int nCCE, unsigned short rnti) {
int i, j;
i=0;
while(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");
int riv_nbits(int nof_prb) {
return (int) ceilf(log2f((float) nof_prb*((float) nof_prb+1)/2));
}
const int ambiguous_sizes[10] = {12, 14, 16, 20, 24, 26, 32, 40, 44, 56};
bool is_ambiguous_size(int size) {
int i;
for (i=0;i<10;i++) {
if (size == ambiguous_sizes[i]) {
return true;
}
}
return false;
}
/**********************************
* PAYLOAD sizeof functions
* ********************************/
int dci_format0_sizeof_(int nof_prb) {
return 1+1+riv_nbits(nof_prb)+5+1+2+3+1;
}
int dci_format1A_sizeof(int nof_prb) {
int n;
n = 1+1+riv_nbits(nof_prb)+5+3+1+2+2;
while(n < dci_format0_sizeof_(nof_prb)) {
n++;
}
if (is_ambiguous_size(n)) {
n++;
}
return n;
}
int dci_format0_sizeof(int nof_prb) {
int n = dci_format0_sizeof_(nof_prb);
while (n < dci_format1A_sizeof(nof_prb)) {
n++;
}
return n;
}
int dci_format1_sizeof(int nof_prb) {
int n = (int) ceilf((float) nof_prb/ra_type0_P(nof_prb))+5+3+1+2+2;
if (nof_prb > 10) {
n++;
}
while(n == dci_format0_sizeof(nof_prb)
|| n == dci_format1A_sizeof(nof_prb)
|| is_ambiguous_size(n)) {
n++;
}
return n;
}
int dci_format1C_sizeof(int nof_prb) {
int n_vrb_dl_gap1 = ra_type2_n_vrb_dl(nof_prb, true);
int n_step = ra_type2_n_rb_step(nof_prb);
int n = + riv_nbits((int) n_vrb_dl_gap1/n_step) + 5;
if (nof_prb >= 50) {
n++;
}
return n;
}
int dci_format_sizeof(dci_format_t format, int nof_prb) {
switch(format) {
case Format0:
return dci_format0_sizeof(nof_prb);
case Format1:
return dci_format1_sizeof(nof_prb);
case Format1A:
return dci_format1A_sizeof(nof_prb);
case Format1C:
return dci_format1C_sizeof(nof_prb);
default:
return -1;
}
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;
}
/**********************************
* DCI Resource Allocation functions
* ********************************/
/* Packs DCI format 0 data to a sequence of bits and store them in msg according
* to 36.212 5.3.3.1.1
*
* TODO: TPC and cyclic shift for DM RS not implemented
*/
int dci_format0_pack(ra_pusch_t *data, dci_msg_t *msg, int nof_prb) {
/* pack bits */
char *y = msg->data;
int n_ul_hop;
*y++ = 0; // format differentiation
if (data->freq_hop_fl == hop_disabled) { // frequency hopping
*y++ = 0;
n_ul_hop = 0;
} else {
*y++ = 1;
if (nof_prb < 50) {
n_ul_hop = 1; // Table 8.4-1 of 36.213
*y++ = data->freq_hop_fl & 1;
} else {
n_ul_hop = 2; // Table 8.4-1 of 36.213
*y++ = (data->freq_hop_fl & 2) >> 1;
*y++ = data->freq_hop_fl & 1;
}
}
/* pack RIV according to 8.1 of 36.213 */
uint32_t riv;
if (data->type2_alloc.L_crb) {
riv = ra_type2_to_riv(data->type2_alloc.L_crb, data->type2_alloc.RB_start, nof_prb);
} else {
riv = data->type2_alloc.riv;
}
bit_pack(riv, &y, riv_nbits(nof_prb) - n_ul_hop);
/* pack MCS according to 8.6.1 of 36.213 */
uint32_t mcs;
if (data->cqi_request) {
mcs = 29;
} else {
if (data->rv_idx) {
mcs = 28 + data->rv_idx;
} else {
if (data->mcs.mod == MOD_NULL) {
mcs = data->mcs.mcs_idx;
} else {
if (data->mcs.tbs) {
if (data->mcs.tbs) {
data->mcs.tbs_idx = ra_tbs_to_table_idx(data->mcs.tbs, ra_nprb_ul(data, nof_prb));
}
}
mcs = ra_mcs_to_table_idx(&data->mcs);
}
}
}
bit_pack(mcs, &y, 5);
*y++ = data->ndi;
// TCP commands not implemented
*y++ = 0;
*y++ = 0;
// DM RS not implemented
*y++ = 0;
*y++ = 0;
*y++ = 0;
// CQI request
*y++ = data->cqi_request;
// Padding with zeros
int n = dci_format0_sizeof(nof_prb);
while (y-msg->data < n) {
*y++ = 0;
}
msg->location.nof_bits = (y - msg->data);
return 0;
}
/* Unpacks DCI format 0 data and store result in msg according
* to 36.212 5.3.3.1.1
*
* TODO: TPC and cyclic shift for DM RS not implemented
*/
int dci_format0_unpack(dci_msg_t *msg, ra_pusch_t *data, int nof_prb) {
int dci_format0_sizeof(int nof_prb) {
return 1+1+(int) ceilf(log2f(nof_prb*(nof_prb+1)/2))+2+3+1;
/* pack bits */
char *y = msg->data;
int n_ul_hop;
/* Make sure it's a Format0 message */
if (msg->location.nof_bits != dci_format_sizeof(Format0, nof_prb)) {
fprintf(stderr, "Invalid message length for format 0\n");
return -1;
}
if (*y++ != 0) {
fprintf(stderr, "Invalid format differentiation field value. This is Format1A\n");
return -1;
}
if (*y++ == 0) {
data->freq_hop_fl = hop_disabled;
n_ul_hop = 0;
} else {
if (nof_prb < 50) {
n_ul_hop = 1; // Table 8.4-1 of 36.213
data->freq_hop_fl = *y++;
} else {
n_ul_hop = 2; // Table 8.4-1 of 36.213
data->freq_hop_fl = y[0]<<1 | y[1];
y += 2;
}
}
/* unpack RIV according to 8.1 of 36.213 */
uint32_t riv = bit_unpack(&y, riv_nbits(nof_prb) - n_ul_hop);
ra_type2_from_riv(riv, &data->type2_alloc.L_crb, &data->type2_alloc.RB_start, nof_prb, nof_prb);
bit_pack(riv, &y, riv_nbits(nof_prb) - n_ul_hop);
data->type2_alloc.riv = riv;
/* unpack MCS according to 8.6 of 36.213 */
uint32_t mcs = bit_unpack(&y, 5);
data->ndi = *y++?true:false;
// TCP and DM RS commands not implemented
y+= 5;
// CQI request
data->cqi_request = *y++?true:false;
// 8.6.2 First paragraph
if (mcs <= 28) {
ra_mcs_from_idx_ul(mcs, &data->mcs);
data->mcs.tbs = ra_tbs_from_idx(data->mcs.tbs_idx, ra_nprb_ul(data, nof_prb));
}
// 8.6.1 and 8.6.2 36.213 second paragraph
if (mcs == 29 && data->cqi_request && ra_nprb_ul(data, nof_prb) <= 4) {
data->mcs.mod = QPSK;
}
if (mcs > 29) {
// Else leave MOD_NULL and use the previously used PUSCH modulation
data->mcs.mod = MOD_NULL;
data->rv_idx = mcs - 28;
}
return 0;
}
/* Packs DCI format 1 data to a sequence of bits and store them in msg according
* to 36.212 5.3.3.1.2
*
* TODO: TPC commands
*/
int dci_format1_pack(ra_pdsch_t *data, dci_msg_t *msg, int nof_prb) {
/* pack bits */
char *y = msg->data;
if (nof_prb > 10) {
*y++ = data->alloc_type;
}
/* Resource allocation: type0 or type 1 */
int P = ra_type0_P(nof_prb);
int alloc_size = (int) ceilf((float) nof_prb/P);
switch(data->alloc_type) {
case alloc_type0:
bit_pack(data->type0_alloc.rbg_bitmask, &y, alloc_size);
break;
case alloc_type1:
bit_pack(data->type1_alloc.rbg_subset, &y, (int) ceilf(log2f(P)));
*y++ = data->type1_alloc.shift?1:0;
bit_pack(data->type1_alloc.vrb_bitmask, &y, alloc_size - (int) ceilf(log2f(P)) - 1);
break;
default:
fprintf(stderr, "Format 1 accepts type0 or type1 resource allocation only\n");
return -1;
}
/* pack MCS according to 7.1.7 of 36.213 */
uint32_t mcs;
if (data->mcs.mod == MOD_NULL) {
mcs = data->mcs.mcs_idx;
} else {
if (data->mcs.tbs) {
data->mcs.tbs_idx = ra_tbs_to_table_idx(data->mcs.tbs, ra_nprb_dl(data, nof_prb));
}
mcs = ra_mcs_to_table_idx(&data->mcs);
}
bit_pack(mcs, &y, 5);
/* harq process number */
bit_pack(data->harq_process, &y, 3);
*y++ = data->ndi;
// rv version
bit_pack(data->rv_idx, &y, 2);
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;
// TPC not implemented
*y++ = 0;
*y++ = 0;
// Padding with zeros
int n = dci_format1_sizeof(nof_prb);
while (y-msg->data < n) {
*y++ = 0;
}
msg->location.nof_bits = (y - msg->data);
return 0;
}
int dci_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;
int dci_format1_unpack(dci_msg_t *msg, ra_pdsch_t *data, int nof_prb) {
/* pack bits */
char *y = msg->data;
/* Make sure it's a Format1 message */
if (msg->location.nof_bits != dci_format_sizeof(Format1, nof_prb)) {
fprintf(stderr, "Invalid message length for format 1\n");
return -1;
}
if (nof_prb > 10) {
data->alloc_type = *y++;
} else {
return 1+(int) ceilf(log2f(nof_prb*(nof_prb+1)/2))+5+3+1+2+2;
data->alloc_type = alloc_type0;
}
/* Resource allocation: type0 or type 1 */
int P = ra_type0_P(nof_prb);
int alloc_size = (int) ceilf((float) nof_prb/P);
switch(data->alloc_type) {
case alloc_type0:
data->type0_alloc.rbg_bitmask = bit_unpack(&y, alloc_size);
break;
case alloc_type1:
data->type1_alloc.rbg_subset = bit_unpack(&y, (int) ceilf(log2f(P)));
data->type1_alloc.shift = *y++?true:false;
data->type1_alloc.vrb_bitmask = bit_unpack(&y, alloc_size - (int) ceilf(log2f(P)) - 1);
break;
default:
fprintf(stderr, "Format 1 accepts type0 or type1 resource allocation only\n");
return -1;
}
/* pack MCS according to 7.1.7 of 36.213 */
uint32_t mcs = bit_unpack(&y, 5);
data->mcs.mcs_idx = mcs;
ra_mcs_from_idx_dl(mcs, &data->mcs);
data->mcs.tbs = ra_tbs_from_idx(data->mcs.tbs_idx, ra_nprb_dl(data, nof_prb));
int dci_format1C_sizeof() {
return 10;
/* harq process number */
data->harq_process = bit_unpack(&y, 3);
data->ndi = *y++?true:false;
// rv version
data->rv_idx = bit_unpack(&y, 2);
// TPC not implemented
return 0;
}
/* Packs DCI format 1A for compact scheduling of PDSCH words according to 36.212 5.3.3.1.3
*
* TODO: RA procedure initiated by PDCCH, TPC commands
*/
int dci_format1As_pack(ra_pdsch_t *data, dci_msg_t *msg, int nof_prb, bool crc_is_crnti) {
/* pack bits */
char *y = msg->data;
*y++ = 1; // format differentiation
if (data->alloc_type != alloc_type2) {
fprintf(stderr, "Format 1A accepts type2 resource allocation only\n");
return -1;
}
*y++ = data->type2_alloc.mode; // localized or distributed VRB assignment
if (data->type2_alloc.mode == t2_loc) {
if (data->type2_alloc.L_crb > nof_prb) {
fprintf(stderr, "L_CRB=%d can not exceed system BW for localized type2\n", data->type2_alloc.L_crb);
return -1;
}
} else {
int n_vrb_dl;
if (crc_is_crnti && nof_prb > 50) {
n_vrb_dl = 16;
} else {
n_vrb_dl = ra_type2_n_vrb_dl(nof_prb, data->type2_alloc.n_gap==t2_ng1);
}
if (data->type2_alloc.L_crb > n_vrb_dl) {
fprintf(stderr, "L_CRB=%d can not exceed N_vrb_dl=%d for distributed type2\n", data->type2_alloc.L_crb, n_vrb_dl);
return -1;
}
}
/* pack RIV according to 7.1.6.3 of 36.213 */
uint32_t riv;
if (data->type2_alloc.L_crb) {
riv = ra_type2_to_riv(data->type2_alloc.L_crb, data->type2_alloc.RB_start, nof_prb);
} else {
riv = data->type2_alloc.riv;
}
int nb_gap = 0;
if (crc_is_crnti && data->type2_alloc.mode == t2_dist && nof_prb >= 50) {
nb_gap = 1;
*y++ = data->type2_alloc.n_gap;
}
bit_pack(riv, &y, riv_nbits(nof_prb)-nb_gap);
// in format1A, MCS = TBS according to 7.1.7.2 of 36.213
uint32_t mcs;
if (data->mcs.mod == MOD_NULL) {
mcs = data->mcs.mcs_idx;
} else {
if (data->mcs.tbs) {
// In format 1A, n_prb_1a is 2 or 3 if crc is not scrambled with C-RNTI
int n_prb;
if (!crc_is_crnti) {
n_prb = ra_nprb_dl(data, nof_prb);
} else {
n_prb = data->type2_alloc.n_prb1a==nprb1a_2?2:3;
}
data->mcs.tbs_idx = ra_tbs_to_table_idx(data->mcs.tbs, n_prb);
}
mcs = data->mcs.tbs_idx;
}
bit_pack(mcs, &y, 5);
bit_pack(data->harq_process, &y, 3);
if (!crc_is_crnti && nof_prb >= 50 && data->type2_alloc.mode == t2_dist) {
*y++ = data->type2_alloc.n_gap;
} else {
y++; // bit reserved
}
// rv version
bit_pack(data->rv_idx, &y, 2);
if (crc_is_crnti) {
// TPC not implemented
*y++ = 0;
*y++ = 0;
} else {
y++; // MSB of TPC is reserved
*y++ = data->type2_alloc.n_prb1a; // LSB indicates N_prb_1a for TBS
}
// Padding with zeros
int n = dci_format1A_sizeof(nof_prb);
while (y-msg->data < n) {
*y++ = 0;
}
msg->location.nof_bits = (y - msg->data);
return 0;
}
/* Unpacks DCI format 1A for compact scheduling of PDSCH words according to 36.212 5.3.3.1.3
*
*/
int dci_format1As_unpack(dci_msg_t *msg, ra_pdsch_t *data, int nof_prb, bool crc_is_crnti) {
/* pack bits */
char *y = msg->data;
/* Make sure it's a Format0 message */
if (msg->location.nof_bits != dci_format_sizeof(Format1A, nof_prb)) {
fprintf(stderr, "Invalid message length for format 1A\n");
return -1;
}
if (*y++ != 1) {
fprintf(stderr, "Invalid format differentiation field value. This is Format0\n");
return -1;
}
data->alloc_type = alloc_type2;
data->type2_alloc.mode = *y++;
// by default, set N_gap to 1
data->type2_alloc.n_gap = t2_ng1;
/* unpack RIV according to 7.1.6.3 of 36.213 */
int nb_gap = 0;
if (crc_is_crnti && data->type2_alloc.mode == t2_dist && nof_prb >= 50) {
nb_gap = 1;
data->type2_alloc.n_gap = *y++;
}
int nof_vrb;
if (data->type2_alloc.mode == t2_loc) {
nof_vrb = nof_prb;
} else {
nof_vrb = ra_type2_n_vrb_dl(nof_prb, data->type2_alloc.n_gap == t2_ng1);
}
uint32_t riv = bit_unpack(&y, riv_nbits(nof_prb) - nb_gap);
ra_type2_from_riv(riv, &data->type2_alloc.L_crb, &data->type2_alloc.RB_start, nof_prb, nof_vrb);
data->type2_alloc.riv = riv;
// unpack MCS
data->mcs.mcs_idx = bit_unpack(&y, 5);
data->harq_process = bit_unpack(&y, 3);
if (!crc_is_crnti && nof_prb >= 50 && data->type2_alloc.mode == t2_dist) {
data->type2_alloc.n_gap = *y++;
} else {
y++; // bit reserved
}
// rv version
bit_pack(data->rv_idx, &y, 2);
if (crc_is_crnti) {
// TPC not implemented
y++;
y++;
} else {
y++; // MSB of TPC is reserved
*y++ = data->type2_alloc.n_prb1a; // LSB indicates N_prb_1a for TBS
}
data->mcs.tbs_idx = data->mcs.mcs_idx;
int n_prb;
if (crc_is_crnti) {
n_prb = ra_nprb_dl(data, nof_prb);
} else {
n_prb = data->type2_alloc.n_prb1a==nprb1a_2?2:3;
}
data->mcs.tbs = ra_tbs_from_idx(data->mcs.tbs_idx, n_prb);
data->mcs.mod = QPSK;
return 0;
}
/* Format 1C for compact scheduling of PDSCH words
*
*/
int dci_format1Cs_pack(ra_pdsch_t *data, dci_msg_t *msg, int nof_prb) {
/* pack bits */
char *y = msg->data;
if (data->alloc_type != alloc_type2 || data->type2_alloc.mode != t2_dist) {
fprintf(stderr, "Format 1C accepts distributed type2 resource allocation only\n");
return -1;
}
if (nof_prb >= 50) {
*y++ = data->type2_alloc.n_gap;
}
int n_step = ra_type2_n_rb_step(nof_prb);
int n_vrb_dl = ra_type2_n_vrb_dl(nof_prb, data->type2_alloc.n_gap==t2_ng1);
if (data->type2_alloc.L_crb > ((int) n_vrb_dl/n_step)*n_step) {
fprintf(stderr, "L_CRB=%d can not exceed N_vrb_dl=%d for distributed type2\n", data->type2_alloc.L_crb,
((int) n_vrb_dl/n_step)*n_step);
return -1;
}
if (data->type2_alloc.L_crb % n_step) {
fprintf(stderr, "L_crb must be multiple of n_step\n");
return -1;
}
if (data->type2_alloc.RB_start % n_step) {
fprintf(stderr, "RB_start must be multiple of n_step\n");
return -1;
}
int L_p = data->type2_alloc.L_crb/n_step;
int RB_p = data->type2_alloc.RB_start/n_step;
int n_vrb_p = (int) n_vrb_dl / n_step;
uint32_t riv;
if (data->type2_alloc.L_crb) {
riv = ra_type2_to_riv(L_p, RB_p, n_vrb_p);
} else {
riv = data->type2_alloc.riv;
}
bit_pack(riv, &y, riv_nbits((int) n_vrb_dl/n_step));
// in format1C, MCS = TBS according to 7.1.7.2 of 36.213
uint32_t mcs;
if (data->mcs.mod == MOD_NULL) {
mcs = data->mcs.mcs_idx;
} else {
if (data->mcs.tbs) {
data->mcs.tbs_idx = ra_tbs_to_table_idx_format1c(data->mcs.tbs);
}
mcs = data->mcs.tbs_idx;
}
bit_pack(mcs, &y, 5);
msg->location.nof_bits = (y - msg->data);
return 0;
}
int dci_format1Cs_unpack(dci_msg_t *msg, ra_pdsch_t *data, int nof_prb) {
uint16_t L_p, RB_p;
/* pack bits */
char *y = msg->data;
if (msg->location.nof_bits != dci_format_sizeof(Format1C, nof_prb)) {
fprintf(stderr, "Invalid message length for format 1C\n");
return -1;
}
data->alloc_type = alloc_type2;
data->type2_alloc.mode = t2_dist;
if (nof_prb >= 50) {
data->type2_alloc.n_gap = *y++;
}
int n_step = ra_type2_n_rb_step(nof_prb);
int n_vrb_dl = ra_type2_n_vrb_dl(nof_prb, data->type2_alloc.n_gap==t2_ng1);
uint32_t riv = bit_unpack(&y, riv_nbits((int) n_vrb_dl/n_step));
int n_vrb_p = (int) n_vrb_dl / n_step;
ra_type2_from_riv(riv, &L_p, &RB_p, n_vrb_p, n_vrb_p);
data->type2_alloc.L_crb = L_p * n_step;
data->type2_alloc.RB_start = RB_p * n_step;
data->type2_alloc.riv = riv;
data->mcs.mcs_idx = bit_unpack(&y, 5);
data->mcs.tbs_idx = data->mcs.mcs_idx;
data->mcs.tbs = ra_tbs_from_idx_format1c(data->mcs.tbs_idx);
data->mcs.mod = QPSK;
msg->location.nof_bits = (y - msg->data);
return 0;
}
int dci_msg_pack_pdsch(ra_pdsch_t *data, dci_msg_t *msg, dci_format_t format, int nof_prb, bool crc_is_crnti) {
switch(format) {
case Format1:
return dci_format1_pack(data, msg, nof_prb);
case Format1A:
return dci_format1As_pack(data, msg, nof_prb, crc_is_crnti);
case Format1C:
return dci_format1Cs_pack(data, msg, nof_prb);
default:
fprintf(stderr, "Invalid DCI format %s for PDSCH resource allocation\n", dci_format_string(format));
return -1;
}
}
int dci_msg_unpack_pdsch(dci_msg_t *msg, ra_pdsch_t *data, int nof_prb, bool crc_is_crnti) {
if (msg->location.nof_bits == dci_format_sizeof(Format1, nof_prb)) {
return dci_format1_unpack(msg, data, nof_prb);
} else if (msg->location.nof_bits == dci_format_sizeof(Format1A, nof_prb)) {
return dci_format1As_unpack(msg, data, nof_prb, crc_is_crnti);
} else if (msg->location.nof_bits == dci_format_sizeof(Format1C, nof_prb)) {
return dci_format1Cs_unpack(msg, data, nof_prb);
} else {
return -1;
}
}
int dci_msg_pack_pusch(ra_pusch_t *data, dci_msg_t *msg, int nof_prb) {
return dci_format0_pack(data, msg, nof_prb);
}
int dci_msg_unpack_pusch(dci_msg_t *msg, ra_pusch_t *data, int nof_prb) {
return dci_format0_unpack(msg, data, nof_prb);
}
char* dci_format_string(dci_format_t format) {
switch(format) {
case Format0:
return "Format0";
case Format1:
return "Format1";
case Format1A:
return "Format1A";
case Format1C:
return "Format1C";
default:
return "N/A"; // fatal error
}
}
void dci_msg_type_fprint(FILE *f, dci_msg_type_t type) {
switch(type.type) {
case PUSCH_SCHED:
fprintf(f,"%s PUSCH Scheduling\n", dci_format_string(type.format));
break;
case PDSCH_SCHED:
fprintf(f,"%s PDSCH Scheduling\n", dci_format_string(type.format));
break;
case RA_PROC_PDCCH:
fprintf(f,"%s Random access initiated by PDCCH\n", dci_format_string(type.format));
break;
case MCCH_CHANGE:
fprintf(f,"%s MCCH change notification\n", dci_format_string(type.format));
break;
case TPC_COMMAND:
fprintf(f,"%s TPC command\n", dci_format_string(type.format));
break;
}
}
int dci_msg_get_type(dci_msg_t *msg, dci_msg_type_t *type, int nof_prb, unsigned short crnti) {
if (msg->location.nof_bits == dci_format_sizeof(Format0, nof_prb)
&& !msg->data[0]) {
type->type = PUSCH_SCHED;
type->format = Format0;
return 0;
} else if (msg->location.nof_bits == dci_format_sizeof(Format1, nof_prb)) {
type->type = PDSCH_SCHED; // only these 2 types supported
type->format = Format1;
return 0;
} else if (msg->location.nof_bits == dci_format_sizeof(Format1A, nof_prb)) {
if (msg->location.rnti == crnti) {
type->type = RA_PROC_PDCCH;
type->format = Format1A;
} else {
type->type = PDSCH_SCHED; // only these 2 types supported
type->format = Format1A;
}
return 0;
} else if (msg->location.nof_bits == dci_format_sizeof(Format1C, nof_prb)) {
if (msg->location.rnti == MRNTI) {
type->type = MCCH_CHANGE;
type->format = Format1C;
} else {
type->type = PDSCH_SCHED; // only these 2 types supported
type->format = Format1C;
}
return 0;
}
return -1;
}

@ -133,6 +133,9 @@ int pbch_init(pbch_t *q, int nof_prb, int cell_id, lte_cp_t cp) {
if (viterbi_init(&q->decoder, viterbi_37, poly, 40, true)) {
goto clean;
}
if (crc_init(&q->crc, LTE_CRC16, 16)) {
goto clean;
}
q->encoder.K = 7;
q->encoder.R = 3;
q->encoder.tail_biting = true;
@ -356,11 +359,11 @@ void crc_set_mask(char *data, int nof_ports) {
*
* Returns 0 if the data is correct, -1 otherwise
*/
int pbch_crc_check(char *bits, int nof_ports) {
int pbch_crc_check(pbch_t *q, char *bits, int nof_ports) {
char data[40];
memcpy(data, bits, 40 * sizeof(char));
crc_set_mask(data, nof_ports);
return crc(0, data, 40, 16, LTE_CRC16, 0);
return crc_checksum(&q->crc, data, 40);
}
int pbch_decode_frame(pbch_t *q, pbch_mib_t *mib, int src, int dst, int n, int nof_bits, int nof_ports) {
@ -379,7 +382,7 @@ int pbch_decode_frame(pbch_t *q, pbch_mib_t *mib, int src, int dst, int n, int n
}
/* unrate matching */
rm_conv_rx(q->temp, q->pbch_rm_f, 4 * nof_bits, 120);
rm_conv_rx(q->temp, 4 * nof_bits, q->pbch_rm_f, 120);
/* FIXME: If channel estimates are zero, received LLR are NaN. Check and return error */
for (j=0;j<120;j++) {
@ -399,7 +402,7 @@ int pbch_decode_frame(pbch_t *q, pbch_mib_t *mib, int src, int dst, int n, int n
c=1;
}
if (!pbch_crc_check(q->data, nof_ports)) {
if (!pbch_crc_check(q, q->data, nof_ports)) {
/* unpack MIB */
pbch_mib_unpack(q->data, mib);
@ -523,12 +526,12 @@ void pbch_encode(pbch_t *q, pbch_mib_t *mib, cf_t *slot1_symbols[MAX_PORTS_CTRL]
pbch_mib_pack(mib, q->data);
/* encode & modulate */
crc(0, q->data, 24, 16, 0x11021, 1);
crc_attach(&q->crc, q->data, 24);
crc_set_mask(q->data, nof_ports);
convcoder_encode(&q->encoder, q->data, q->data_enc, 40);
rm_conv_tx(q->data_enc, q->pbch_rm_b, 120, 4 * nof_bits);
rm_conv_tx(q->data_enc, 120, q->pbch_rm_b, 4 * nof_bits);
}

@ -47,15 +47,11 @@
#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;
}
#define NOF_COMMON_FORMATS 2
const dci_format_t common_formats[NOF_COMMON_FORMATS] = {Format1A, Format1C};
int pdcch_get(cf_t *slot1_data, cf_t *pdcch, int nsymbols) {
memcpy(pdcch, slot1_data, sizeof(cf_t) * nsymbols);
return nsymbols;
}
#define NOF_UE_FORMATS 2
const dci_format_t ue_formats[NOF_UE_FORMATS] = {Format0, Format1}; // 1A has the same payload as 0
#define MIN(a,b) ((a>b)?b:a)
@ -63,18 +59,18 @@ int pdcch_get(cf_t *slot1_data, cf_t *pdcch, int nsymbols) {
* 36.213 9.1
*/
int gen_common_search(dci_candidate_t *c, int nof_cce, int nof_bits, unsigned short rnti) {
int i, L, k;
int i, l, L, k;
k = 0;
for (L = 2; L > 0; L--) {
for (i = 0; i < MIN(nof_cce,16) / (4 * L); i++) {
c[k].L = 4 * L;
for (l = 3; l > 1; l--) {
L = (1 << l);
for (i = 0; i < MIN(nof_cce,16) / (L); i++) {
c[k].L = l;
c[k].nof_bits = nof_bits;
c[k].rnti = rnti;
c[k].ncce = (4 * L) * (i % (nof_cce / (4 * L)));
k++;
INFO(
"Common SS Candidate %d: RNTI: 0x%x, nCCE: %d, Nbits: %d, L: %d\n",
c[k].ncce = (L) * (i % (nof_cce / (L)));
INFO("Common SS Candidate %d: RNTI: 0x%x, nCCE: %d, Nbits: %d, L: %d\n",
k, c[k].rnti, c[k].ncce, c[k].nof_bits, c[k].L);
k++;
}
}
return k;
@ -88,6 +84,11 @@ int gen_ue_search(dci_candidate_t *c, int nof_cce, int nof_bits, unsigned short
unsigned int Yk;
const int S[4] = { 6, 12, 8, 16 };
k = 0;
if (!subframe) {
INFO("UE-specific candidates for RNTI: 0x%x, NofBits: %d, NofCCE: %d\n",
rnti, nof_bits, nof_cce);
if (VERBOSE_ISINFO()) printf("[INFO]: ");
}
for (l = 3; l >= 0; l--) {
L = (1 << l);
for (i = 0; i < MIN(nof_cce/L,16/S[l]); i++) {
@ -99,27 +100,35 @@ int gen_ue_search(dci_candidate_t *c, int nof_cce, int nof_bits, unsigned short
Yk = (39827 * Yk) % 65537;
}
c[k].ncce = L * ((Yk + i) % (nof_cce / L));
INFO("UE-specific SS Candidate %d: SF: %d, RNTI: 0x%x, nCCE: %d, Nbits: %d, L: %d\n",
k, subframe, c[k].rnti, c[k].ncce, c[k].nof_bits, c[k].L);
if (!subframe) {
if (VERBOSE_ISINFO()) {
printf("(%d, %d), ", c[k].ncce, c[k].L);
}
}
k++;
}
}
if (!subframe) {
if (VERBOSE_ISINFO()) printf("\n");
}
return k;
}
void pdcch_init_common(pdcch_t *q, pdcch_search_t *s, unsigned short rnti) {
int k;
s->nof_candidates = 2*(MIN(q->nof_cce,16) / 4 + MIN(q->nof_cce,16) / 8);
int k, i;
s->nof_candidates = NOF_COMMON_FORMATS*(MIN(q->nof_cce,16) / 4 + MIN(q->nof_cce,16) / 8);
if (s->nof_candidates) {
s->candidates[0] = malloc(sizeof(dci_candidate_t) * s->nof_candidates);
dci_candidate_t *c = s->candidates[0];
s->nof_candidates = 0;
if (c) {
// Format 1A and 1C L=4 and L=8, 4 and 2 candidates, only if nof_cce > 16
k = 0;
for(i=0;i<NOF_COMMON_FORMATS;i++) {
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);
dci_format_sizeof(common_formats[i], q->nof_prb), SIRNTI);
s->nof_candidates++;
}
}
}
}
@ -137,11 +146,11 @@ void pdcch_init_search_si(pdcch_t *q) {
* DCI Format 1A and 1 + PUSCH scheduling format 0
*/
void pdcch_init_search_ue(pdcch_t *q, unsigned short c_rnti) {
int l, n, k;
int l, n, k, i;
pdcch_search_t *s = &q->search_mode[SEARCH_UE];
s->nof_candidates = 0;
for (l=0;l<3;l++) {
s->nof_candidates += 3*(MIN(q->nof_cce,16) / (1<<l));
s->nof_candidates += NOF_UE_FORMATS*(MIN(q->nof_cce,16) / (1<<l));
}
INFO("Initiating %d candidate(s) in the UE-specific search space for C-RNTI: 0x%x\n", s->nof_candidates, c_rnti);
if (s->nof_candidates) {
@ -152,12 +161,10 @@ void pdcch_init_search_ue(pdcch_t *q, unsigned short c_rnti) {
if (c) {
// Expect Formats 1, 1A, 0
k = 0;
for(i=0;i<NOF_UE_FORMATS;i++) {
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);
dci_format_sizeof(ue_formats[i], q->nof_prb), c_rnti, n);
}
}
}
}
@ -200,19 +207,23 @@ int pdcch_init(pdcch_t *q, regs_t *regs, int nof_prb, int nof_ports,
q->cp = cp;
q->regs = regs;
q->nof_ports = nof_ports;
q->nof_prb = nof_prb;
q->current_search_mode = SEARCH_NONE;
q->nof_regs = regs_pdcch_nregs(q->regs);
q->nof_regs = (regs_pdcch_nregs(q->regs)/9)*9;
q->nof_cce = q->nof_regs / 9;
q->nof_symbols = 4 * q->nof_regs;
q->nof_bits = 2 * q->nof_symbols;
INFO("Init PDCCH: %d REGs, %d bits, %d symbols, %d ports\n", q->nof_regs,
q->nof_bits, q->nof_symbols, q->nof_ports);
INFO("Init PDCCH: %d CCEs (%d REGs), %d bits, %d symbols, %d ports\n", q->nof_cce,
q->nof_regs, q->nof_bits, q->nof_symbols, q->nof_ports);
if (modem_table_std(&q->mod, LTE_QPSK, true)) {
goto clean;
}
if (crc_init(&q->crc, LTE_CRC16, 16)) {
goto clean;
}
demod_soft_init(&q->demod);
demod_soft_table_set(&q->demod, &q->mod);
@ -310,17 +321,24 @@ void pdcch_free(pdcch_t *q) {
*
* TODO: UE transmit antenna selection CRC mask
*/
unsigned short dci_decode(viterbi_t *decoder, float *e, char *data, int E,
unsigned short dci_decode(pdcch_t *q, float *e, char *data, int E,
int nof_bits) {
float tmp[3 * (DCI_MAX_BITS + 16)];
unsigned short p_bits;
unsigned short p_bits, crc_res;
char *x;
assert(nof_bits < DCI_MAX_BITS);
/* char a[] = {1,1,0,0,1,0,0,0,0,0,0,1,1,0,0,1,0,0,0,0,0,0,1,1,1,1,0,0,0,0,1,1,0,1,0,1,1,0,1,1,1,1,1,0,1,0,1,1,0,1,0,0,0,1,0,0,1,1,1,1,0,1,0,1,1,0,0,0,0,0,1,1,0,0,0,0,1,0,0,1,0,0,0,0,1,1,1,1,1,0,1,1,1,0,1,1,1,1,0,0,1,1,0,0,1,0,1,1,1,0,0,1,1,0,1,0,1,1,0,0,1,0,0,1,1,0,0,1,0,0,0,0,0,0,1,1,0,0,1,0,0,0,0,0,0,1,1,1,1,0,0,0,0,1,1,0,1,0,1,1,0,1,1,1,1,1,0,1,0,1,1,0,1,0,0,0,1,0,0,1,1,1,1,0,1,0,1,1,0,0,0,0,0,1,1,0,0,0,0,1,0,0,1,0,0,0,0,1,1,1,1,1,0,1,1,1,0,1,1,1,1,0,0,1,1,0,0,1,0,1,1,1,0,0,1,1,0,1,0,1,1,0,0,1,0,0,1,1,0,0,1,0,0,0,0,0,0,1,1,0,0,1,0,0,0,0,0,0,1,1,1,1,0,0,0,0,1,1,0,1,0,1,1,0,1,1,1,1,1,0,1,0,1,1,0,1,0,0,0,1,0,0,1,1,1,1,0,1,0,1,1,0,0,0,0,0,1,1,0,0,0,0,1,0,0,1,0,0,0,0,1,1,1,1,1,0,1,1,1,0,1,1,1,1,0,0,1,1,0,0,1,0,1,1,1,0,0,1,1,0,1,0,1,1,0,0,1,0,0,1,1,0,0,1,0,0,0,0,0,0,1,1,0,0,1,0,0,0,0,0,0,1,1,1,1,0,0,0,0,1,1,0,1,0,1,1,0,1,1,1,1,1,0,1,0,1,1,0,1,0,0,0,1,0,0,1,1,1,1,0,1,0,1,1,0,0,0,0,0,1,1,0,0,0,0,1,0,0,1,0,0,0,0,1,1,1,1,1,0,1,1,1,0,1,1,1,1,0,0,1,1,0,0,1,0,1,1,1,0,0,1,1,0,1,0,1,1,0,0,1,0,0,1,1,0,0,1,0,0,0,0,0,0,1,1,0,0,1,0,0,0,0,0,0,1,1,1,1,0,0,0,0,1,1,0,1,0,1,1,0,1,1,1,1,1,0,1,0,1,1,0,1,0,0,0,1,0,0,1,1,1,1,0,1,0,1,1,0,0,0,0,0,1,1,0,0,0,0,1,0,0,1,0,0,0,0};
float *b = malloc(sizeof(E));
for (int i=0;i<E;i++) {
b[i] = a[i]?1:-1;
}
*/
/* unrate matching */
rm_conv_rx(e, tmp, E, 3 * (nof_bits + 16));
rm_conv_rx(e, E, tmp, 3 * (nof_bits + 16));
DEBUG("Viterbi input: ", 0);
if (VERBOSE_ISDEBUG()) {
@ -328,26 +346,32 @@ unsigned short dci_decode(viterbi_t *decoder, float *e, char *data, int E,
}
/* viterbi decoder */
viterbi_decode_f(decoder, tmp, data, nof_bits + 16);
viterbi_decode_f(&q->decoder, tmp, data, nof_bits + 16);
if (VERBOSE_ISDEBUG()) {
bit_fprint(stdout, data, nof_bits+16);
}
x = &data[nof_bits];
p_bits = (unsigned short) bit_unpack(&x, 16);
return (p_bits
^ ((unsigned short) crc(0, data, nof_bits, 16, LTE_CRC16, 0)
& 0xffff));
crc_res = ((unsigned short) crc_checksum(&q->crc, data, nof_bits) & 0xffff);
DEBUG("p_bits: 0x%x, crc_res: 0x%x, tot: 0x%x\n", p_bits, crc_res, p_bits ^ crc_res);
return (p_bits ^ crc_res);
}
int pdcch_decode_candidate(pdcch_t *q, float *llr, dci_candidate_t *c,
dci_msg_t *msg) {
unsigned short crc_res;
crc_res = dci_decode(&q->decoder, &llr[72 * c->ncce], msg->data,
DEBUG("Trying Candidate: Nbits: %d, E: %d, nCCE: %d, L: %d, RNTI: 0x%x\n",
c->nof_bits, PDCCH_FORMAT_NOF_BITS(c->L), c->ncce, c->L,
c->rnti);
crc_res = dci_decode(q, &llr[72 * c->ncce], msg->data,
PDCCH_FORMAT_NOF_BITS(c->L), c->nof_bits);
if (c->rnti == crc_res) {
memcpy(&msg->location, c, sizeof(dci_candidate_t));
INFO(
"FOUND CAND: Nbits: %d, E: %d, nCCE: %d, L: %d, RNTI: 0x%x\n",
"FOUND Candidate: Nbits: %d, E: %d, nCCE: %d, L: %d, RNTI: 0x%x\n",
c->nof_bits, PDCCH_FORMAT_NOF_BITS(c->L), c->ncce, c->L,
c->rnti);
return 1;
@ -379,25 +403,21 @@ int pdcch_extract_llr(pdcch_t *q, cf_t *slot1_symbols, cf_t *ce[MAX_PORTS_CTRL],
memset(&x[q->nof_ports], 0, sizeof(cf_t*) * (MAX_LAYERS - q->nof_ports));
/* extract symbols */
if (q->nof_symbols
!= pdcch_get(slot1_symbols, q->pdcch_symbols[0], q->nof_symbols)) {
fprintf(stderr, "There was an error getting the PDCCH symbols\n");
int n = regs_pdcch_get(q->regs, slot1_symbols, q->pdcch_symbols[0]);
if (q->nof_symbols != n) {
fprintf(stderr, "Expected %d PDCCH symbols but got %d symbols\n", q->nof_symbols, n);
return -1;
}
/* extract channel estimates */
for (i = 0; i < q->nof_ports; i++) {
if (q->nof_symbols != pdcch_get(ce[i], q->ce[i], q->nof_symbols)) {
fprintf(stderr, "There was an error getting the PDCCH symbols\n");
n = regs_pdcch_get(q->regs, ce[i], q->ce[i]);
if (q->nof_symbols != n) {
fprintf(stderr, "Expected %d PDCCH symbols but got %d symbols\n", q->nof_symbols, n);
return -1;
}
}
DEBUG("pdcch_symbols: ", 0);
if (VERBOSE_ISDEBUG()) {
vec_fprint_c(stdout, q->pdcch_symbols[0], q->nof_symbols);
}
/* in control channels, only diversity is supported */
if (q->nof_ports == 1) {
/* no need for layer demapping */
@ -410,13 +430,18 @@ int pdcch_extract_llr(pdcch_t *q, cf_t *slot1_symbols, cf_t *ce[MAX_PORTS_CTRL],
q->nof_symbols / q->nof_ports);
}
DEBUG("pdcch d symbols: ", 0);
if (VERBOSE_ISDEBUG()) {
vec_fprint_c(stdout, q->pdcch_d, q->nof_symbols);
}
/* demodulate symbols */
demod_soft_sigma_set(&q->demod, ebno);
demod_soft_demodulate(&q->demod, q->pdcch_d, q->pdcch_llr, q->nof_symbols);
DEBUG("llr: ", 0);
if (VERBOSE_ISDEBUG()) {
vec_fprint_f(stdout, q->pdcch_llr, q->nof_symbols);
vec_fprint_f(stdout, q->pdcch_llr, q->nof_bits);
}
/* descramble */
@ -426,7 +451,6 @@ int pdcch_extract_llr(pdcch_t *q, cf_t *slot1_symbols, cf_t *ce[MAX_PORTS_CTRL],
}
int pdcch_decode_current_mode(pdcch_t *q, float *llr, dci_t *dci, int subframe) {
int dci_cnt;
int k, i;
if (q->current_search_mode == SEARCH_UE) {
@ -435,16 +459,15 @@ int pdcch_decode_current_mode(pdcch_t *q, float *llr, dci_t *dci, int subframe)
k = 0;
}
dci_cnt = 0;
for (i = 0; i < q->search_mode[q->current_search_mode].nof_candidates
&& dci_cnt < dci->nof_dcis; i++) {
&& dci->nof_dcis < dci->max_dcis; i++) {
if (pdcch_decode_candidate(q, q->pdcch_llr,
&q->search_mode[q->current_search_mode].candidates[k][i],
&dci->msg[dci_cnt])) {
dci_cnt++;
&dci->msg[dci->nof_dcis])) {
dci->nof_dcis++;
}
}
return dci_cnt;
return dci->nof_dcis;
}
int pdcch_decode_si(pdcch_t *q, float *llr, dci_t *dci) {
@ -498,7 +521,7 @@ void crc_set_mask_rnti(char *crc, unsigned short rnti) {
/** 36.212 5.3.3.2 to 5.3.3.4
* TODO: UE transmit antenna selection CRC mask
*/
void dci_encode(char *data, char *e, int nof_bits, int E, unsigned short rnti) {
void dci_encode(pdcch_t *q, char *data, char *e, int nof_bits, int E, unsigned short rnti) {
convcoder_t encoder;
char tmp[3 * (DCI_MAX_BITS + 16)];
@ -510,7 +533,7 @@ void dci_encode(char *data, char *e, int nof_bits, int E, unsigned short rnti) {
encoder.tail_biting = true;
memcpy(encoder.poly, poly, 3 * sizeof(int));
crc(0, data, nof_bits, 16, LTE_CRC16, 1);
crc_attach(&q->crc, data, nof_bits);
crc_set_mask_rnti(&data[nof_bits], rnti);
convcoder_encode(&encoder, data, tmp, nof_bits + 16);
@ -520,7 +543,7 @@ void dci_encode(char *data, char *e, int nof_bits, int E, unsigned short rnti) {
vec_fprint_b(stdout, tmp, 3 * (nof_bits + 16));
}
rm_conv_tx(tmp, e, 3 * (nof_bits + 16), E);
rm_conv_tx(tmp, 3 * (nof_bits + 16), e, E);
}
/** Converts the MIB message to symbols mapped to SLOT #1 ready for transmission
@ -558,7 +581,7 @@ int pdcch_encode(pdcch_t *q, dci_t *dci, cf_t *slot1_symbols[MAX_PORTS_CTRL],
i, dci->msg[i].location.nof_bits, PDCCH_FORMAT_NOF_BITS(dci->msg[i].location.L),
dci->msg[i].location.ncce, dci->msg[i].location.L, dci->msg[i].location.rnti);
dci_encode(dci->msg[i].data, &q->pdcch_e[72 * dci->msg[i].location.ncce],
dci_encode(q, dci->msg[i].data, &q->pdcch_e[72 * dci->msg[i].location.ncce],
dci->msg[i].location.nof_bits, PDCCH_FORMAT_NOF_BITS(dci->msg[i].location.L),
dci->msg[i].location.rnti);
}
@ -578,7 +601,7 @@ int pdcch_encode(pdcch_t *q, dci_t *dci, cf_t *slot1_symbols[MAX_PORTS_CTRL],
/* mapping to resource elements */
for (i = 0; i < q->nof_ports; i++) {
pdcch_put(q->pdcch_symbols[i], slot1_symbols[i], q->nof_symbols);
regs_pdcch_put(q->regs, q->pdcch_symbols[i], slot1_symbols[i]);
}
return 0;
}

@ -0,0 +1,518 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2014 The libLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the libLTE library.
*
* libLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* libLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* A copy of the GNU Lesser General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#include <stdio.h>
#include <strings.h>
#include <math.h>
#include "lte/common/base.h"
#include "lte/utils/bit.h"
#include "lte/utils/vector.h"
#include "lte/utils/debug.h"
#include "lte/phch/ra.h"
#include "lte/utils/bit.h"
#include "tbs_tables.h"
#define min(a,b) (a<b?a:b)
void ra_prb_fprint(FILE *f, ra_prb_slot_t *prb) {
int i, j, nrows;
nrows = (prb->nof_prb - 1)/ 25 + 1;
for (j=0;j<nrows;j++) {
for (i=0;i<min(25, prb->nof_prb-j*25);i++) {
fprintf(f, "%3d, ", prb->prb_idx[j*25+i]);
}
fprintf(f, "\n");
}
}
/** Compute PRB allocation for Downlink as defined in 8.1 of 36.213 */
int ra_prb_get_ul(ra_prb_slot_t *prb, ra_pusch_t *ra, int nof_prb) {
int i;
if (ra->type2_alloc.mode != t2_loc) {
fprintf(stderr, "Uplink only accepts type2 localized scheduling\n");
return -1;
}
for (i=0;i<ra->type2_alloc.L_crb;i++) {
prb->prb_idx[i] = i+ra->type2_alloc.RB_start;
prb->nof_prb++;
}
return 0;
}
/** Compute PRB allocation for Downlink as defined in 7.1.6 of 36.213 */
int ra_prb_get_dl(ra_prb_t *prb_dist, ra_pdsch_t *ra, int nof_prb) {
int i, j;
uint32_t bitmask;
int P = ra_type0_P(nof_prb);
ra_prb_slot_t *prb;
bzero(prb_dist, sizeof(ra_prb_t));
switch(ra->alloc_type) {
case alloc_type0:
prb = &prb_dist->slot1;
prb_dist->is_dist = false;
bitmask = ra->type0_alloc.rbg_bitmask;
int nb = (int) ceilf((float)nof_prb/P);
for (i=0;i<nb;i++) {
if (bitmask & (1<<(nb-i-1))) {
for (j=0;j<P;j++) {
prb->prb_idx[prb->nof_prb] = i*P+j;
prb->nof_prb++;
}
}
}
break;
case alloc_type1:
prb = &prb_dist->slot1;
prb_dist->is_dist = false;
int n_rb_type1 = ra_type1_N_rb(nof_prb);
int n_rb_rbg_subset;
if (ra->type1_alloc.rbg_subset < (nof_prb/P) % P) {
n_rb_rbg_subset = ((nof_prb-1)/(P*P)) * P + P;
} else if (ra->type1_alloc.rbg_subset == ((nof_prb/P) % P)) {
n_rb_rbg_subset = ((nof_prb-1)/(P*P)) * P + ((nof_prb-1)%P)+1;
} else {
n_rb_rbg_subset = ((nof_prb-1)/(P*P)) * P;
}
int shift = ra->type1_alloc.shift?(n_rb_rbg_subset-n_rb_type1):0;
bitmask = ra->type1_alloc.vrb_bitmask;
for (i=0;i<n_rb_type1;i++) {
if (bitmask & (1<<(n_rb_type1-i-1))) {
prb->prb_idx[prb->nof_prb] = ((i+shift)/P)*P*P+
ra->type1_alloc.rbg_subset*P+(i+shift)%P;
prb->nof_prb++;
}
}
break;
case alloc_type2:
if (ra->type2_alloc.mode == t2_loc) {
prb = &prb_dist->slot1;
prb_dist->is_dist = false;
for (i=0;i<ra->type2_alloc.L_crb;i++) {
prb->prb_idx[i] = i+ra->type2_alloc.RB_start;
prb->nof_prb++;
}
} else {
/* Mapping of Virtual to Physical RB for distributed type is defined in
* 6.2.3.2 of 36.211
*/
prb_dist->is_dist = true;
int N_gap, N_tilde_vrb, n_tilde_vrb, n_tilde_prb, n_tilde2_prb, N_null, N_row, n_vrb;
int n_tilde_prb_odd, n_tilde_prb_even;
if (ra->type2_alloc.n_gap == t2_ng1) {
N_tilde_vrb = nof_prb;
N_gap = ra_type2_ngap(nof_prb, true);
} else {
N_tilde_vrb = 2*nof_prb;
N_gap = ra_type2_ngap(nof_prb, false);
}
N_row = (int) ceilf((float) N_tilde_vrb/(4*P))*P;
N_null = 4*N_row-N_tilde_vrb;
for (i=0;i<ra->type2_alloc.L_crb;i++) {
n_vrb = i+ra->type2_alloc.RB_start;
n_tilde_vrb = n_vrb%N_tilde_vrb;
n_tilde_prb = 2*N_row*(n_tilde_vrb % 2)+n_tilde_vrb/2+N_tilde_vrb*(n_vrb/N_tilde_vrb);
n_tilde2_prb = N_row*(n_tilde_vrb % 4)+n_tilde_vrb/4+N_tilde_vrb*(n_vrb/N_tilde_vrb);
if (N_null != 0 && n_tilde_vrb >= (N_tilde_vrb - N_null) && (n_tilde_vrb%2) == 1) {
n_tilde_prb_odd = n_tilde_prb-N_row;
} else if (N_null != 0 && n_tilde_vrb >= (N_tilde_vrb - N_null) && (n_tilde_vrb%2) == 0) {
n_tilde_prb_odd = n_tilde_prb-N_row+N_null/2;
} else if (N_null != 0 && n_tilde_vrb < (N_tilde_vrb - N_null) && (n_tilde_vrb%4) >= 2) {
n_tilde_prb_odd = n_tilde2_prb-N_null/2;
} else {
n_tilde_prb_odd = n_tilde2_prb;
}
n_tilde_prb_even = (n_tilde_prb_odd+N_tilde_vrb/2)%N_tilde_vrb+N_tilde_vrb*(n_vrb/N_tilde_vrb);
if (n_tilde_prb_odd < N_tilde_vrb/2) {
prb_dist->slot1.prb_idx[i] = n_tilde_prb_odd;
} else {
prb_dist->slot1.prb_idx[i] = n_tilde_prb_odd+N_gap-N_tilde_vrb/2;
}
prb_dist->slot1.nof_prb++;
if (n_tilde_prb_even < N_tilde_vrb/2) {
prb_dist->slot2.prb_idx[i] = n_tilde_prb_even;
} else {
prb_dist->slot2.prb_idx[i] = n_tilde_prb_even+N_gap-N_tilde_vrb/2;
}
prb_dist->slot2.nof_prb++;
}
}
break;
default:
return -1;
}
return 0;
}
/* Returns the number of allocated PRB for Uplink */
int ra_nprb_ul(ra_pusch_t *ra, int nof_prb) {
return ra->type2_alloc.L_crb;
}
/* Returns the number of allocated PRB for Downlink */
int ra_nprb_dl(ra_pdsch_t *ra, int nof_prb) {
int nprb;
int nof_rbg, P;
switch(ra->alloc_type) {
case alloc_type0:
// Get the number of allocated RBG except the last RBG
nof_rbg = bit_count(ra->type0_alloc.rbg_bitmask & 0xFFFFFFFE);
P = ra_type0_P(nof_prb);
if (nof_rbg > (int) ceilf((float)nof_prb/P)) {
fprintf(stderr, "Number of RGB (%d) can not exceed %d\n", nof_prb,
(int) ceilf((float)nof_prb/P));
return -1;
}
nprb = nof_rbg * P;
// last RBG may have smaller size. Add if set
int P_last = (nof_prb%P);
if (!P_last) P_last = P;
nprb += P_last*(ra->type0_alloc.rbg_bitmask&1);
break;
case alloc_type1:
nprb = bit_count(ra->type1_alloc.vrb_bitmask);
if (nprb > ra_type1_N_rb(nof_prb)) {
fprintf(stderr, "Number of RB (%d) can not exceed %d\n", nprb,
ra_type1_N_rb(nof_prb));
return -1;
}
break;
case alloc_type2:
nprb = ra->type2_alloc.L_crb;
break;
default:
return -1;
}
return nprb;
}
/* RBG size for type0 scheduling as in table 7.1.6.1-1 of 36.213 */
int ra_type0_P(int nof_prb) {
if (nof_prb <= 10) {
return 1;
} else if (nof_prb <= 26) {
return 2;
} else if (nof_prb <= 63) {
return 3;
} else {
return 4;
}
}
/* Returns N_rb_type1 according to section 7.1.6.2 */
int ra_type1_N_rb(int nof_prb) {
int P = ra_type0_P(nof_prb);
return (int) ceilf((float) nof_prb/P) - (int) ceilf(log2f((float) P)) - 1;
}
/* Convert Type2 scheduling L_crb and RB_start to RIV value */
uint32_t ra_type2_to_riv(uint16_t L_crb, uint16_t RB_start, int nof_prb) {
uint32_t riv;
if (L_crb <= (int) nof_prb/2) {
riv = nof_prb*(L_crb-1) + RB_start;
} else {
riv = nof_prb*(nof_prb-L_crb+1) + nof_prb - 1 - RB_start;
}
return riv;
}
/* Convert Type2 scheduling RIV value to L_crb and RB_start values */
void ra_type2_from_riv(uint32_t riv, uint16_t *L_crb, uint16_t *RB_start, int nof_prb, int nof_vrb) {
*L_crb = (int) (riv/nof_prb) + 1;
*RB_start = riv%nof_prb;
if (*L_crb > nof_vrb - *RB_start) {
*L_crb = nof_prb - (int) (riv/nof_prb) + 1;
*RB_start = nof_prb - riv%nof_prb - 1;
}
}
/* Table 6.2.3.2-1 in 36.211 */
int ra_type2_ngap(int nof_prb, bool ngap_is_1) {
if (nof_prb <= 10) {
return nof_prb/2;
} else if (nof_prb == 11) {
return 4;
} else if (nof_prb <= 19) {
return 8;
} else if (nof_prb <= 26) {
return 12;
} else if (nof_prb <= 44) {
return 18;
} else if (nof_prb <= 49) {
return 27;
} else if (nof_prb <= 63) {
return ngap_is_1?27:9;
} else if (nof_prb <= 79) {
return ngap_is_1?32:16;
} else {
return ngap_is_1?48:16;
}
}
/* Table 7.1.6.3-1 in 36.213 */
int ra_type2_n_rb_step(int nof_prb) {
if (nof_prb < 50) {
return 2;
} else {
return 4;
}
}
/* as defined in 6.2.3.2 of 36.211 */
int ra_type2_n_vrb_dl(int nof_prb, bool ngap_is_1) {
int ngap = ra_type2_ngap(nof_prb, ngap_is_1);
if (ngap_is_1) {
return 2*(ngap<(nof_prb-ngap)?ngap:nof_prb-ngap);
} else {
return ((int) nof_prb/ngap)*2*ngap;
}
}
/* Converts ra_mcs_t structure to MCS index for both Uplink and Downlink */
uint8_t ra_mcs_to_table_idx(ra_mcs_t *mcs) {
switch (mcs->mod) {
case QPSK:
return mcs->tbs_idx;
case QAM16:
return mcs->tbs_idx + 1;
case QAM64:
return mcs->tbs_idx + 2;
default:
return 0;
}
}
/* Converts MCS index to ra_mcs_t structure for Downlink as defined inTable 7.1.7.1-1 on 36.213 */
int ra_mcs_from_idx_dl(uint8_t idx, ra_mcs_t *mcs) {
if (idx < 10) {
mcs->mod = QPSK;
mcs->tbs_idx = idx;
} else if (idx < 17) {
mcs->mod = QAM16;
mcs->tbs_idx = idx-1;
} else if (idx < 29) {
mcs->mod = QAM64;
mcs->tbs_idx = idx-2;
} else if (idx == 29) {
mcs->mod = QPSK;
mcs->tbs_idx = 0;
} else if (idx == 30) {
mcs->mod = QAM16;
mcs->tbs_idx = 0;
} else if (idx == 31) {
mcs->mod = QAM64;
mcs->tbs_idx = 0;
} else {
mcs->mod = MOD_NULL;
mcs->tbs_idx = 0;
return -1;
}
return 0;
}
/* Converts MCS index to ra_mcs_t structure for Uplink as defined in Table 8.6.1-1 on 36.213 */
int ra_mcs_from_idx_ul(uint8_t idx, ra_mcs_t *mcs) {
if (idx < 11) {
mcs->mod = QPSK;
mcs->tbs_idx = idx;
} else if (idx < 21) {
mcs->mod = QAM16;
mcs->tbs_idx = idx-1;
} else if (idx < 29) {
mcs->mod = QAM64;
mcs->tbs_idx = idx-2;
} else {
mcs->mod = MOD_NULL;
mcs->tbs_idx = 0;
return -1;
}
return 0;
}
/* Downlink Transport Block size for Format 1C as defined in 7.1.7.2.2-1 on 36.213 */
int ra_tbs_from_idx_format1c(uint8_t tbs_idx) {
if (tbs_idx < 32) {
return tbs_format1c_table[tbs_idx];
} else {
return -1;
}
}
/* Returns lowest nearest index of TBS value in table 7.1.7.2.2-1 on 36.213
* or -1 if the TBS value is not within the valid TBS values
*/
int ra_tbs_to_table_idx_format1c(int tbs) {
int idx;
if (tbs < tbs_format1c_table[0]) {
return -1;
}
for (idx=1;idx<32;idx++) {
if (tbs_format1c_table[idx-1] <= tbs &&
tbs_format1c_table[idx] >= tbs) {
return idx;
}
}
return -1;
}
/* Downlink Transport Block size determination as defined in 7.1.7.2 on 36.213 */
int ra_tbs_from_idx(uint8_t tbs_idx, int n_prb ) {
if (tbs_idx < 27 && n_prb > 0 && n_prb <= 110) {
return tbs_table[tbs_idx][n_prb-1];
} else {
return -1;
}
}
/* Returns lowest nearest index of TBS value in table 7.1.7.2 on 36.213
* or -1 if the TBS value is not within the valid TBS values
*/
int ra_tbs_to_table_idx(int tbs, int n_prb) {
int idx;
if (n_prb > 0 && n_prb <= 110) {
return -1;
}
if (tbs < tbs_table[0][n_prb]) {
return -1;
}
for (idx=1;idx<28;idx++) {
if (tbs_table[idx-1][n_prb] <= tbs &&
tbs_table[idx][n_prb] >= tbs) {
return idx;
}
}
return -1;
}
char *ra_mod_string(ra_mod_t mod) {
switch (mod) {
case QPSK:
return "QPSK";
case QAM16:
return "QAM16";
case QAM64:
return "QAM64";
default:
return "N/A";
}
}
void ra_pusch_fprint(FILE *f, ra_pusch_t *ra, int nof_prb) {
fprintf(f, "Frequency Hopping:\t");
if (ra->freq_hop_fl == hop_disabled) {
fprintf(f, "No");
} else {
fprintf(f, "Yes");
}
}
char *ra_type_string(ra_type_t alloc_type) {
switch(alloc_type) {
case alloc_type0:
return "Type 0";
case alloc_type1:
return "Type 1";
case alloc_type2:
return "Type 2";
default:
return "N/A";
}
}
void ra_pdsch_set_mcs_index(ra_pdsch_t *ra, uint8_t mcs_idx) {
ra->mcs.mod = MOD_NULL;
ra->mcs.mcs_idx = mcs_idx;
}
void ra_pdsch_set_mcs(ra_pdsch_t *ra, ra_mod_t mod, uint8_t tbs_idx) {
ra->mcs.mod = mod;
ra->mcs.tbs_idx = tbs_idx;
}
void ra_pdsch_fprint(FILE *f, ra_pdsch_t *ra, int nof_prb) {
fprintf(f, " - Resource Allocation Type:\t\t%s\n",ra_type_string(ra->alloc_type));
switch(ra->alloc_type) {
case alloc_type0:
fprintf(f, " + Resource Block Group Size:\t\t%d\n",ra_type0_P(nof_prb));
fprintf(f, " + RBG Bitmap:\t\t\t0x%x\n",ra->type0_alloc.rbg_bitmask);
break;
case alloc_type1:
fprintf(f, " + Resource Block Group Size:\t\t%d\n",ra_type0_P(nof_prb));
fprintf(f, " + RBG Bitmap:\t\t\t0x%x\n",ra->type1_alloc.vrb_bitmask);
fprintf(f, " + RBG Subset:\t\t\t%d\n",ra->type1_alloc.rbg_subset);
fprintf(f, " + RBG Shift:\t\t\t\t%s\n",ra->type1_alloc.shift?"Yes":"No");
break;
case alloc_type2:
fprintf(f, " + Type:\t\t\t\t%s\n",
ra->type2_alloc.mode==t2_loc?"Localized":"Distributed");
fprintf(f, " + Resource Indicator Value:\t\t%d\n",ra->type2_alloc.riv);
if (ra->type2_alloc.mode == t2_loc) {
fprintf(f, " + VRB Assignment:\t\t\t%d VRB starting with VRB %d\n",
ra->type2_alloc.L_crb, ra->type2_alloc.RB_start);
} else {
fprintf(f, " + VRB Assignment:\t\t\t%d VRB starting with VRB %d\n",
ra->type2_alloc.L_crb, ra->type2_alloc.RB_start);
fprintf(f, " + VRB gap selection:\t\t\tGap %d\n",
ra->type2_alloc.n_gap == t2_ng1?1:2);
fprintf(f, " + VRB gap:\t\t\t\t%d\n",
ra_type2_ngap(nof_prb, ra->type2_alloc.n_gap == t2_ng1));
}
break;
}
ra_prb_t alloc;
ra_prb_get_dl(&alloc, ra, nof_prb);
if (alloc.is_dist) {
fprintf(f, " - PRB Bitmap Assignment 1st slot:\n");
ra_prb_fprint(f, &alloc.slot1);
fprintf(f, " - PRB Bitmap Assignment 2nd slot:\n");
ra_prb_fprint(f, &alloc.slot2);
} else {
fprintf(f, " - PRB Bitmap Assignment:\n");
ra_prb_fprint(f, &alloc.slot1);
}
fprintf(f, " - Number of PRBs:\t\t\t%d\n", ra_nprb_dl(ra, nof_prb));
fprintf(f, " - Modulation and coding scheme index:\t%d\n", ra->mcs.mcs_idx);
fprintf(f, " - Modulation type:\t\t\t%s\n", ra_mod_string(ra->mcs.mod));
fprintf(f, " - Transport block size:\t\t%d\n", ra->mcs.tbs);
fprintf(f, " - HARQ process:\t\t\t%d\n", ra->harq_process);
fprintf(f, " - New data indicator:\t\t\t%s\n", ra->ndi?"Yes":"No");
fprintf(f, " - Redundancy version:\t\t\t%d\n", ra->rv_idx);
fprintf(f, " - TPC command for PUCCH:\t\t--\n");
}

@ -37,29 +37,144 @@
regs_reg_t *regs_find_reg(regs_t *h, int k, int l);
/***************************************************************
*
* PDCCH REG ALLOCATION
*
***************************************************************/
void regs_pdcch_free(regs_t *h) {
int i;
for (i=0;i<3;i++) {
if (h->pdcch[i].regs) {
free(h->pdcch[i].regs);
}
}
}
#define PDCCH_NCOLS 32
const unsigned char PDCCH_PERM[PDCCH_NCOLS] =
{ 1, 17, 9, 25, 5, 21, 13, 29, 3, 19, 11, 27, 7, 23, 15, 31, 0, 16, 8,
24, 4, 20, 12, 28, 2, 18, 10, 26, 6, 22, 14, 30 };
/** Initialize REGs for PDCCH
* 36.211 10.3 section 6.8.5
*/
int regs_pdcch_init(regs_t *h) {
return 0;
int i, m, cfi, nof_ctrl_symbols;
int ret = -1;
int nrows, ndummy, j, k, kp;
regs_reg_t **tmp = NULL;
bzero(&h->pdcch, sizeof(regs_ch_t));
for (cfi=0;cfi<3;cfi++) {
if (h->nof_prb < 10) {
nof_ctrl_symbols = cfi+2;
} else {
nof_ctrl_symbols = cfi+1;
}
void regs_pdcch_free(regs_t *h) {
if (h->pdcch) {
free(h->pdcch);
tmp = malloc(sizeof(regs_reg_t*) * h->nof_regs);
if (!tmp) {
perror("malloc");
goto clean_and_exit;
}
/* Number and count REGs for this CFI */
m=0;
for (i=0;i<h->nof_regs;i++) {
if (h->regs[i].l < nof_ctrl_symbols && !h->regs[i].assigned) {
tmp[m] = &h->regs[i];
m++;
}
}
h->pdcch[cfi].nof_regs = m;
h->pdcch[cfi].regs = malloc(sizeof(regs_reg_t*) * h->pdcch[cfi].nof_regs);
if (!h->pdcch[cfi].regs) {
perror("malloc");
goto clean_and_exit;
}
/* Interleave REGs */
nrows = (h->pdcch[cfi].nof_regs-1)/PDCCH_NCOLS+1;
ndummy = PDCCH_NCOLS*nrows - h->pdcch[cfi].nof_regs;
if (ndummy < 0) {
ndummy = 0;
}
k=0;
for (j = 0; j < PDCCH_NCOLS; j++) {
for (i = 0; i < nrows; i++) {
if (i*PDCCH_NCOLS + PDCCH_PERM[j] >= ndummy) {
m = i*PDCCH_NCOLS + PDCCH_PERM[j]-ndummy;
kp = (k-h->cell_id)%h->pdcch[cfi].nof_regs;
if (kp < 0) {
kp += h->pdcch[cfi].nof_regs;
}
h->pdcch[cfi].regs[m] = tmp[kp];
k++;
}
}
}
h->pdcch[cfi].nof_regs = (h->pdcch[cfi].nof_regs/9)*9;
free(tmp);
tmp = NULL;
if (VERBOSE_ISINFO() && cfi == 1) {
for (i=0;i<h->pdcch[cfi].nof_regs;i++) {
INFO("Logical PDCCH REG#%d:%d (%d,%d)\n", i%9,i/9,
h->pdcch[cfi].regs[i]->k0, h->pdcch[cfi].regs[i]->l);
}
}
}
ret = 0;
clean_and_exit:
if (tmp) {
free(tmp);
}
if (ret == -1) {
regs_pdcch_free(h);
}
return ret;
}
int regs_pdcch_nregs(regs_t *h) {
return 9;
if (h->cfi == -1) {
fprintf(stderr, "Must call regs_set_cfi() first\n");
return -1;
} else {
return h->pdcch[h->cfi].nof_regs;
}
}
/** Copy quadruplets to REGs and cyclic shift them, according to the
* second part of 6.8.5 in 36.211
*/
int regs_pdcch_put(regs_t *h, cf_t *pdcch_symbols, cf_t *slot_symbols) {
if (h->cfi == -1) {
fprintf(stderr, "Must call regs_set_cfi() first\n");
return -1;
}
int i;
for (i=0;i<h->pdcch[h->cfi].nof_regs;i++) {
regs_put_reg(h->pdcch[h->cfi].regs[i], &pdcch_symbols[i*4], slot_symbols, h->nof_prb);
}
return h->pdcch[h->cfi].nof_regs*4;
}
int regs_pdcch_get(regs_t *h, cf_t *slot_symbols, cf_t *pdcch_symbols) {
if (h->cfi == -1) {
fprintf(stderr, "Must call regs_set_cfi() first\n");
return -1;
}
int i;
for (i=0;i<h->pdcch[h->cfi].nof_regs;i++) {
regs_get_reg(h->pdcch[h->cfi].regs[i], slot_symbols, &pdcch_symbols[i*4], h->nof_prb);
}
return h->pdcch[h->cfi].nof_regs*4;
}
@ -195,6 +310,16 @@ void regs_phich_free(regs_t *h) {
}
}
int regs_phich_nregs(regs_t *h) {
int i, n;
n=0;
for (i=0;i<h->ngroups_phich;i++) {
n += h->phich[i].nof_regs;
}
return n;
}
int regs_phich_ngroups(regs_t *h) {
return h->ngroups_phich;
}
@ -274,10 +399,6 @@ int regs_phich_get(regs_t *h, cf_t *slot_symbols, cf_t phich_symbols[REGS_PHICH_
/***************************************************************
*
* PCFICH REG ALLOCATION
@ -330,6 +451,10 @@ void regs_pcfich_free(regs_t *h) {
}
}
int regs_pcfich_nregs(regs_t *h) {
return h->pcfich.nof_regs;
}
/**
* Maps the PCFICH symbols to the resource grid pointed by slot_symbols
*
@ -392,13 +517,13 @@ regs_reg_t *regs_find_reg(regs_t *h, int k, int l) {
* Returns the number of REGs in a PRB
* 36.211 Section 6.2.4
*/
int regs_num_x_symbol(int symbol, int refs_in_symbol1, lte_cp_t cp) {
int regs_num_x_symbol(int symbol, int nof_port, lte_cp_t cp) {
switch (symbol) {
case 0:
return 2;
case 1:
switch (refs_in_symbol1) {
switch (nof_port) {
case 1:
case 2:
return 3;
@ -430,10 +555,10 @@ int regs_reg_init(regs_reg_t *reg, int symbol, int nreg, int k0, int maxreg, int
reg->l = symbol;
reg->assigned = false;
reg->k0 = k0 + nreg * 6;
switch (maxreg) {
case 2:
reg->k0 = k0 + nreg * 6;
/* there are two references in the middle */
j = z = 0;
for (i = 0; i < vo; i++) {
@ -456,6 +581,7 @@ int regs_reg_init(regs_reg_t *reg, int symbol, int nreg, int k0, int maxreg, int
break;
case 3:
reg->k0 = k0 + nreg * 4;
/* there is no reference */
for (i = 0; i < 4; i++) {
reg->k[i] = k0 + nreg * 4 + i;
@ -479,15 +605,33 @@ void regs_free(regs_t *h) {
bzero(h, sizeof(regs_t));
}
/** Sets the CFI value for this subframe (CFI must be in the range 1..3).
*/
int regs_set_cfi(regs_t *h, int cfi) {
if (cfi > 0 && cfi <= 3) {
if (h->phich_len == PHICH_EXT &&
((h->nof_prb < 10 && cfi < 2) || (h->nof_prb >= 10 && cfi < 3))) {
fprintf(stderr, "PHICH length is extended. The number of control symbols should be at least 3.\n");
return -1;
} else {
h->cfi = cfi - 1;
return 0;
}
} else {
fprintf(stderr, "Invalid CFI %d\n", cfi);
return -1;
}
}
/**
* Initializes REGs structure.
* Sets all REG indices and initializes PCFICH, PHICH and PDCCH REGs
* Returns 0 if OK, -1 on error
*/
int regs_init(regs_t *h, int cell_id, int nof_prb, int refs_in_symbol1,
int regs_init(regs_t *h, int cell_id, int nof_prb, int nof_ports,
phich_resources_t phich_res, phich_length_t phich_len, lte_cp_t cp) {
int ret = -1;
int i, j, n, p, k;
int i, j[4], jmax, n[4], prb, k;
int vo = cell_id % 3;
int max_ctrl_symbols = nof_prb<10?4:3;
@ -496,18 +640,19 @@ int regs_init(regs_t *h, int cell_id, int nof_prb, int refs_in_symbol1,
h->cell_id = cell_id;
h->nof_prb = nof_prb;
h->max_ctrl_symbols = max_ctrl_symbols;
h->cfi = -1; // not yet initialized
h->phich_res = phich_res;
h->phich_len = phich_len;
h->cp = cp;
h->refs_in_symbol1 = refs_in_symbol1;
h->nof_ports = nof_ports;
h->nof_regs = 0;
for (i = 0; i < max_ctrl_symbols; i++) {
n = regs_num_x_symbol(i, refs_in_symbol1, cp);
if (n == -1) {
n[i] = regs_num_x_symbol(i, nof_ports, cp);
if (n[i] == -1) {
return -1;
}
h->nof_regs += nof_prb * n;
h->nof_regs += nof_prb * n[i];
}
INFO("Indexing %d REGs. CellId: %d, %d PRB, CP: %s\n", h->nof_regs, h->cell_id, h->nof_prb,
CP_ISNORM(cp)?"Normal":"Extended");
@ -517,26 +662,36 @@ int regs_init(regs_t *h, int cell_id, int nof_prb, int refs_in_symbol1,
goto clean_and_exit;
}
k = 0;
for (i = 0; i < max_ctrl_symbols; i++) {
n = regs_num_x_symbol(i, refs_in_symbol1, cp);
for (p = 0; p < nof_prb; p++) {
for (j = 0; j < n; j++) {
if (regs_reg_init(&h->regs[k], i, j, p * RE_X_RB, n, vo)) {
/* Sort REGs according to PDCCH mapping, beggining from the lowest l index then k */
bzero(j, sizeof(int) * 4);
k = i = prb = jmax = 0;
while (k < h->nof_regs) {
if (n[i] == 3 || (n[i] == 2 && jmax != 1)) {
if (regs_reg_init(&h->regs[k], i, j[i], prb * RE_X_RB, n[i], vo)) {
fprintf(stderr, "Error initializing REGs\n");
goto clean_and_exit;
}
DEBUG("Available REG #%3d: %d:%d:%d (k0=%d)\n", k, i, p, j,
DEBUG("Available REG #%3d: l=%d, prb=%d, nreg=%d (k0=%d)\n", k, i, prb, j[i],
h->regs[k].k0);
j[i]++;
k++;
}
i++;
if (i == max_ctrl_symbols) {
i = 0;
jmax++;
}
if (jmax == 3) {
prb++;
bzero(j, sizeof(int) * 4);
jmax = 0;
}
}
if (regs_pcfich_init(h)) {
fprintf(stderr, "Error initializing PCFICH REGs\n");
goto clean_and_exit;
}
if (regs_phich_init(h)) {
fprintf(stderr, "Error initializing PHICH REGs\n");
goto clean_and_exit;
@ -548,7 +703,8 @@ int regs_init(regs_t *h, int cell_id, int nof_prb, int refs_in_symbol1,
ret = 0;
clean_and_exit: if (ret == -1) {
clean_and_exit:
if (ret == -1) {
regs_free(h);
}
return ret;
@ -562,13 +718,8 @@ int regs_init(regs_t *h, int cell_id, int nof_prb, int refs_in_symbol1,
int regs_put_reg(regs_reg_t *reg, cf_t *reg_data, cf_t *slot_symbols, int nof_prb) {
int i;
for (i = 0; i < REGS_RE_X_REG; i++) {
if (reg->assigned) {
DEBUG("PUT REG: i=%d, (k=%d,l=%d)\n", i, REG_IDX(reg, i, nof_prb),reg->l);
slot_symbols[REG_IDX(reg, i, nof_prb)] = reg_data[i];
} else {
fprintf(stderr, "Error REG not assigned\n");
return -1;
}
}
return REGS_RE_X_REG;
}
@ -580,15 +731,10 @@ int regs_put_reg(regs_reg_t *reg, cf_t *reg_data, cf_t *slot_symbols, int nof_pr
int regs_add_reg(regs_reg_t *reg, cf_t *reg_data, cf_t *slot_symbols, int nof_prb) {
int i;
for (i = 0; i < REGS_RE_X_REG; i++) {
if (reg->assigned) {
slot_symbols[REG_IDX(reg, i, nof_prb)] += reg_data[i];
DEBUG("ADD REG: i=%d, (k=%d,l=%d): %.1f+%.1fi\n", i, REG_IDX(reg, i, nof_prb),reg->l,
__real__ slot_symbols[REG_IDX(reg, i, nof_prb)],
__imag__ slot_symbols[REG_IDX(reg, i, nof_prb)]);
} else {
fprintf(stderr, "Error REG not assigned\n");
return -1;
}
}
return REGS_RE_X_REG;
}
@ -600,13 +746,8 @@ int regs_add_reg(regs_reg_t *reg, cf_t *reg_data, cf_t *slot_symbols, int nof_pr
int regs_reset_reg(regs_reg_t *reg, cf_t *slot_symbols, int nof_prb) {
int i;
for (i = 0; i < REGS_RE_X_REG; i++) {
if (reg->assigned) {
DEBUG("RESET REG: i=%d, (k=%d,l=%d)\n", i, REG_IDX(reg, i, nof_prb),reg->l);
slot_symbols[REG_IDX(reg, i, nof_prb)] = 0;
} else {
fprintf(stderr, "Error REG not assigned\n");
return -1;
}
}
return REGS_RE_X_REG;
}
@ -617,14 +758,9 @@ int regs_reset_reg(regs_reg_t *reg, cf_t *slot_symbols, int nof_prb) {
int regs_get_reg(regs_reg_t *reg, cf_t *slot_symbols, cf_t *reg_data, int nof_prb) {
int i;
for (i = 0; i < REGS_RE_X_REG; i++) {
if (reg->assigned) {
reg_data[i] = slot_symbols[REG_IDX(reg, i, nof_prb)];
DEBUG("GET REG: i=%d, (k=%d,l=%d): %.1f+%.1fi\n", i, REG_IDX(reg, i, nof_prb),reg->l,
__real__ reg_data[i], __imag__ reg_data[i]);
} else {
fprintf(stderr, "Error REG not assigned\n");
return -1;
}
//DEBUG("GET REG: i=%d, (k=%d,l=%d): %.1f+%.1fi\n", i, REG_IDX(reg, i, nof_prb),reg->l,
// __real__ reg_data[i], __imag__ reg_data[i]);
}
return REGS_RE_X_REG;
}

@ -0,0 +1,278 @@
const int tbs_format1c_table[32] = {
40, 56, 72, 120, 136, 144, 176, 208, 224, 256, 280, 296, 328, 336, 392, 488,
552, 600, 632, 696, 776, 840, 904, 1000, 1064, 1128, 1224, 1288, 1384, 1480, 1608, 1736
};
/* Transport Block Size from 3GPP TS 36.213 v10.3.0 table 7.1.7.2.1-1 */
const int tbs_table[27][110] = {{ 16, 32, 56, 88, 120, 152, 176, 208, 224, 256, 288,
328, 344, 376, 392, 424, 456, 488, 504, 536, 568, 600,
616, 648, 680, 712, 744, 776, 776, 808, 840, 872, 904,
936, 968, 1000, 1032, 1032, 1064, 1096, 1128, 1160, 1192, 1224,
1256, 1256, 1288, 1320, 1352, 1384, 1416, 1416, 1480, 1480, 1544,
1544, 1608, 1608, 1608, 1672, 1672, 1736, 1736, 1800, 1800, 1800,
1864, 1864, 1928, 1928, 1992, 1992, 2024, 2088, 2088, 2088, 2152,
2152, 2216, 2216, 2280, 2280, 2280, 2344, 2344, 2408, 2408, 2472,
2472, 2536, 2536, 2536, 2600, 2600, 2664, 2664, 2728, 2728, 2728,
2792, 2792, 2856, 2856, 2856, 2984, 2984, 2984, 2984, 2984, 3112},
{ 24, 56, 88, 144, 176, 208, 224, 256, 328, 344, 376,
424, 456, 488, 520, 568, 600, 632, 680, 712, 744, 776,
808, 872, 904, 936, 968, 1000, 1032, 1064, 1128, 1160, 1192,
1224, 1256, 1288, 1352, 1384, 1416, 1416, 1480, 1544, 1544, 1608,
1608, 1672, 1736, 1736, 1800, 1800, 1864, 1864, 1928, 1992, 1992,
2024, 2088, 2088, 2152, 2152, 2216, 2280, 2280, 2344, 2344, 2408,
2472, 2472, 2536, 2536, 2600, 2600, 2664, 2728, 2728, 2792, 2792,
2856, 2856, 2856, 2984, 2984, 2984, 3112, 3112, 3112, 3240, 3240,
3240, 3240, 3368, 3368, 3368, 3496, 3496, 3496, 3496, 3624, 3624,
3624, 3752, 3752, 3752, 3752, 3880, 3880, 3880, 4008, 4008, 4008},
{ 32, 72, 144, 176, 208, 256, 296, 328, 376, 424, 472,
520, 568, 616, 648, 696, 744, 776, 840, 872, 936, 968,
1000, 1064, 1096, 1160, 1192, 1256, 1288, 1320, 1384, 1416, 1480,
1544, 1544, 1608, 1672, 1672, 1736, 1800, 1800, 1864, 1928, 1992,
2024, 2088, 2088, 2152, 2216, 2216, 2280, 2344, 2344, 2408, 2472,
2536, 2536, 2600, 2664, 2664, 2728, 2792, 2856, 2856, 2856, 2984,
2984, 3112, 3112, 3112, 3240, 3240, 3240, 3368, 3368, 3368, 3496,
3496, 3496, 3624, 3624, 3624, 3752, 3752, 3880, 3880, 3880, 4008,
4008, 4008, 4136, 4136, 4136, 4264, 4264, 4264, 4392, 4392, 4392,
4584, 4584, 4584, 4584, 4584, 4776, 4776, 4776, 4776, 4968, 4968},
{ 40, 104, 176, 208, 256, 328, 392, 440, 504, 568, 616,
680, 744, 808, 872, 904, 968, 1032, 1096, 1160, 1224, 1256,
1320, 1384, 1416, 1480, 1544, 1608, 1672, 1736, 1800, 1864, 1928,
1992, 2024, 2088, 2152, 2216, 2280, 2344, 2408, 2472, 2536, 2536,
2600, 2664, 2728, 2792, 2856, 2856, 2984, 2984, 3112, 3112, 3240,
3240, 3368, 3368, 3496, 3496, 3624, 3624, 3624, 3752, 3752, 3880,
3880, 4008, 4008, 4136, 4136, 4264, 4264, 4392, 4392, 4392, 4584,
4584, 4584, 4776, 4776, 4776, 4776, 4968, 4968, 4968, 5160, 5160,
5160, 5352, 5352, 5352, 5352, 5544, 5544, 5544, 5736, 5736, 5736,
5736, 5992, 5992, 5992, 5992, 6200, 6200, 6200, 6200, 6456, 6456},
{ 56, 120, 208, 256, 328, 408, 488, 552, 632, 696, 776,
840, 904, 1000, 1064, 1128, 1192, 1288, 1352, 1416, 1480, 1544,
1608, 1736, 1800, 1864, 1928, 1992, 2088, 2152, 2216, 2280, 2344,
2408, 2472, 2600, 2664, 2728, 2792, 2856, 2984, 2984, 3112, 3112,
3240, 3240, 3368, 3496, 3496, 3624, 3624, 3752, 3752, 3880, 4008,
4008, 4136, 4136, 4264, 4264, 4392, 4392, 4584, 4584, 4584, 4776,
4776, 4968, 4968, 4968, 5160, 5160, 5160, 5352, 5352, 5544, 5544,
5544, 5736, 5736, 5736, 5992, 5992, 5992, 5992, 6200, 6200, 6200,
6456, 6456, 6456, 6456, 6712, 6712, 6712, 6968, 6968, 6968, 6968,
7224, 7224, 7224, 7480, 7480, 7480, 7480, 7736, 7736, 7736, 7992},
{ 72, 144, 224, 328, 424, 504, 600, 680, 776, 872, 968,
1032, 1128, 1224, 1320, 1384, 1480, 1544, 1672, 1736, 1864, 1928,
2024, 2088, 2216, 2280, 2344, 2472, 2536, 2664, 2728, 2792, 2856,
2984, 3112, 3112, 3240, 3368, 3496, 3496, 3624, 3752, 3752, 3880,
4008, 4008, 4136, 4264, 4392, 4392, 4584, 4584, 4776, 4776, 4776,
4968, 4968, 5160, 5160, 5352, 5352, 5544, 5544, 5736, 5736, 5736,
5992, 5992, 5992, 6200, 6200, 6200, 6456, 6456, 6712, 6712, 6712,
6968, 6968, 6968, 7224, 7224, 7224, 7480, 7480, 7480, 7736, 7736,
7736, 7992, 7992, 7992, 8248, 8248, 8248, 8504, 8504, 8760, 8760,
8760, 8760, 9144, 9144, 9144, 9144, 9528, 9528, 9528, 9528, 9528},
{ 328, 176, 256, 392, 504, 600, 712, 808, 936, 1032, 1128,
1224, 1352, 1480, 1544, 1672, 1736, 1864, 1992, 2088, 2216, 2280,
2408, 2472, 2600, 2728, 2792, 2984, 2984, 3112, 3240, 3368, 3496,
3496, 3624, 3752, 3880, 4008, 4136, 4136, 4264, 4392, 4584, 4584,
4776, 4776, 4968, 4968, 5160, 5160, 5352, 5352, 5544, 5736, 5736,
5992, 5992, 5992, 6200, 6200, 6456, 6456, 6456, 6712, 6712, 6968,
6968, 6968, 7224, 7224, 7480, 7480, 7736, 7736, 7736, 7992, 7992,
8248, 8248, 8248, 8504, 8504, 8760, 8760, 8760, 9144, 9144, 9144,
9144, 9528, 9528, 9528, 9528, 9912, 9912, 9912,10296,10296,10296,
10296,10680,10680,10680,10680,11064,11064,11064,11448,11448,11448},
{ 104, 224, 328, 472, 584, 712, 840, 968, 1096, 1224, 1320,
1480, 1608, 1672, 1800, 1928, 2088, 2216, 2344, 2472, 2536, 2664,
2792, 2984, 3112, 3240, 3368, 3368, 3496, 3624, 3752, 3880, 4008,
4136, 4264, 4392, 4584, 4584, 4776, 4968, 4968, 5160, 5352, 5352,
5544, 5736, 5736, 5992, 5992, 6200, 6200, 6456, 6456, 6712, 6712,
6712, 6968, 6968, 7224, 7224, 7480, 7480, 7736, 7736, 7992, 7992,
8248, 8248, 8504, 8504, 8760, 8760, 8760, 9144, 9144, 9144, 9528,
9528, 9528, 9912, 9912, 9912,10296,10296,10296,10680,10680,10680,
11064,11064,11064,11448,11448,11448,11448,11832,11832,11832,12216,
12216,12216,12576,12576,12576,12960,12960,12960,12960,13536,13536},
{ 120, 256, 392, 536, 680, 808, 968, 1096, 1256, 1384, 1544,
1672, 1800, 1928, 2088, 2216, 2344, 2536, 2664, 2792, 2984, 3112,
3240, 3368, 3496, 3624, 3752, 3880, 4008, 4264, 4392, 4584, 4584,
4776, 4968, 4968, 5160, 5352, 5544, 5544, 5736, 5992, 5992, 6200,
6200, 6456, 6456, 6712, 6968, 6968, 7224, 7224, 7480, 7480, 7736,
7736, 7992, 7992, 8248, 8504, 8504, 8760, 8760, 9144, 9144, 9144,
9528, 9528, 9528, 9912, 9912, 9912,10296,10296,10680,10680,10680,
11064,11064,11064,11448,11448,11448,11832,11832,12216,12216,12216,
12576,12576,12576,12960,12960,12960,13536,13536,13536,13536,14112,
14112,14112,14112,14688,14688,14688,14688,15264,15264,15264,15264},
{ 136, 296, 456, 616, 776, 936, 1096, 1256, 1416, 1544, 1736,
1864, 2024, 2216, 2344, 2536, 2664, 2856, 2984, 3112, 3368, 3496,
3624, 3752, 4008, 4136, 4264, 4392, 4584, 4776, 4968, 5160, 5160,
5352, 5544, 5736, 5736, 5992, 6200, 6200, 6456, 6712, 6712, 6968,
6968, 7224, 7480, 7480, 7736, 7992, 7992, 8248, 8248, 8504, 8760,
8760, 9144, 9144, 9144, 9528, 9528, 9912, 9912,10296,10296,10296,
10680,10680,11064,11064,11064,11448,11448,11832,11832,11832,12216,
12216,12576,12576,12960,12960,12960,13536,13536,13536,13536,14112,
14112,14112,14112,14688,14688,14688,15264,15264,15264,15264,15840,
15840,15840,16416,16416,16416,16416,16992,16992,16992,16992,17568},
{ 144, 328, 504, 680, 872, 1032, 1224, 1384, 1544, 1736, 1928,
2088, 2280, 2472, 2664, 2792, 2984, 3112, 3368, 3496, 3752, 3880,
4008, 4264, 4392, 4584, 4776, 4968, 5160, 5352, 5544, 5736, 5736,
5992, 6200, 6200, 6456, 6712, 6712, 6968, 7224, 7480, 7480, 7736,
7992, 7992, 8248, 8504, 8504, 8760, 9144, 9144, 9144, 9528, 9528,
9912, 9912,10296,10296,10680,10680,11064,11064,11448,11448,11448,
11832,11832,12216,12216,12576,12576,12960,12960,12960,13536,13536,
13536,14112,14112,14112,14688,14688,14688,14688,15264,15264,15264,
15840,15840,15840,16416,16416,16416,16992,16992,16992,16992,17568,
17568,17568,18336,18336,18336,18336,18336,19080,19080,19080,19080},
{ 176, 376, 584, 776, 1000, 1192, 1384, 1608, 1800, 2024, 2216,
2408, 2600, 2792, 2984, 3240, 3496, 3624, 3880, 4008, 4264, 4392,
4584, 4776, 4968, 5352, 5544, 5736, 5992, 5992, 6200, 6456, 6712,
6968, 6968, 7224, 7480, 7736, 7736, 7992, 8248, 8504, 8760, 8760,
9144, 9144, 9528, 9528, 9912, 9912,10296,10680,10680,11064,11064,
11448,11448,11832,11832,12216,12216,12576,12576,12960,12960,13536,
13536,13536,14112,14112,14112,14688,14688,14688,15264,15264,15840,
15840,15840,16416,16416,16416,16992,16992,16992,17568,17568,17568,
18336,18336,18336,18336,19080,19080,19080,19080,19848,19848,19848,
19848,20616,20616,20616,21384,21384,21384,21384,22152,22152,22152},
{ 208, 440, 680, 904, 1128, 1352, 1608, 1800, 2024, 2280, 2472,
2728, 2984, 3240, 3368, 3624, 3880, 4136, 4392, 4584, 4776, 4968,
5352, 5544, 5736, 5992, 6200, 6456, 6712, 6712, 6968, 7224, 7480,
7736, 7992, 8248, 8504, 8760, 8760, 9144, 9528, 9528, 9912, 9912,
10296,10680,10680,11064,11064,11448,11832,11832,12216,12216,12576,
12576,12960,12960,13536,13536,14112,14112,14112,14688,14688,15264,
15264,15264,15840,15840,16416,16416,16416,16992,16992,17568,17568,
17568,18336,18336,18336,19080,19080,19080,19080,19848,19848,19848,
20616,20616,20616,21384,21384,21384,21384,22152,22152,22152,22920,
22920,22920,23688,23688,23688,23688,24496,24496,24496,24496,25456},
{ 224, 488, 744, 1000, 1256, 1544, 1800, 2024, 2280, 2536, 2856,
3112, 3368, 3624, 3880, 4136, 4392, 4584, 4968, 5160, 5352, 5736,
5992, 6200, 6456, 6712, 6968, 7224, 7480, 7736, 7992, 8248, 8504,
8760, 9144, 9144, 9528, 9912, 9912,10296,10680,10680,11064,11448,
11448,11832,12216,12216,12576,12960,12960,13536,13536,14112,14112,
14688,14688,14688,15264,15264,15840,15840,16416,16416,16992,16992,
16992,17568,17568,18336,18336,18336,19080,19080,19080,19848,19848,
19848,20616,20616,20616,21384,21384,21384,22152,22152,22152,22920,
22920,22920,23688,23688,23688,24496,24496,24496,25456,25456,25456,
25456,26416,26416,26416,26416,27376,27376,27376,27376,28336,28336},
{ 256, 552, 840, 1128, 1416, 1736, 1992, 2280, 2600, 2856, 3112,
3496, 3752, 4008, 4264, 4584, 4968, 5160, 5544, 5736, 5992, 6200,
6456, 6968, 7224, 7480, 7736, 7992, 8248, 8504, 8760, 9144, 9528,
9912, 9912,10296,10680,11064,11064,11448,11832,12216,12216,12576,
12960,12960,13536,13536,14112,14112,14688,14688,15264,15264,15840,
15840,16416,16416,16992,16992,17568,17568,18336,18336,18336,19080,
19080,19848,19848,19848,20616,20616,20616,21384,21384,22152,22152,
22152,22920,22920,22920,23688,23688,24496,24496,24496,25456,25456,
25456,25456,26416,26416,26416,27376,27376,27376,28336,28336,28336,
28336,29296,29296,29296,29296,30576,30576,30576,30576,31704,31704},
{ 280, 600, 904, 1224, 1544, 1800, 2152, 2472, 2728, 3112, 3368,
3624, 4008, 4264, 4584, 4968, 5160, 5544, 5736, 6200, 6456, 6712,
6968, 7224, 7736, 7992, 8248, 8504, 8760, 9144, 9528, 9912,10296,
10296,10680,11064,11448,11832,11832,12216,12576,12960,12960,13536,
13536,14112,14688,14688,15264,15264,15840,15840,16416,16416,16992,
16992,17568,17568,18336,18336,18336,19080,19080,19848,19848,20616,
20616,20616,21384,21384,22152,22152,22152,22920,22920,23688,23688,
23688,24496,24496,24496,25456,25456,25456,26416,26416,26416,27376,
27376,27376,28336,28336,28336,29296,29296,29296,29296,30576,30576,
30576,30576,31704,31704,31704,31704,32856,32856,32856,34008,34008},
{ 328, 632, 968, 1288, 1608, 1928, 2280, 2600, 2984, 3240, 3624,
3880, 4264, 4584, 4968, 5160, 5544, 5992, 6200, 6456, 6712, 7224,
7480, 7736, 7992, 8504, 8760, 9144, 9528, 9912, 9912,10296,10680,
11064,11448,11832,12216,12216,12576,12960,13536,13536,14112,14112,
14688,14688,15264,15840,15840,16416,16416,16992,16992,17568,17568,
18336,18336,19080,19080,19848,19848,19848,20616,20616,21384,21384,
22152,22152,22152,22920,22920,23688,23688,24496,24496,24496,25456,
25456,25456,26416,26416,26416,27376,27376,27376,28336,28336,28336,
29296,29296,29296,30576,30576,30576,30576,31704,31704,31704,31704,
32856,32856,32856,34008,34008,34008,34008,35160,35160,35160,35160},
{ 336, 696, 1064, 1416, 1800, 2152, 2536, 2856, 3240, 3624, 4008,
4392, 4776, 5160, 5352, 5736, 6200, 6456, 6712, 7224, 7480, 7992,
8248, 8760, 9144, 9528, 9912,10296,10296,10680,11064,11448,11832,
12216,12576,12960,13536,13536,14112,14688,14688,15264,15264,15840,
16416,16416,16992,17568,17568,18336,18336,19080,19080,19848,19848,
20616,20616,20616,21384,21384,22152,22152,22920,22920,23688,23688,
24496,24496,24496,25456,25456,26416,26416,26416,27376,27376,27376,
28336,28336,29296,29296,29296,30576,30576,30576,30576,31704,31704,
31704,32856,32856,32856,34008,34008,34008,35160,35160,35160,35160,
36696,36696,36696,36696,37888,37888,37888,39232,39232,39232,39232},
{ 376, 776, 1160, 1544, 1992, 2344, 2792, 3112, 3624, 4008, 4392,
4776, 5160, 5544, 5992, 6200, 6712, 7224, 7480, 7992, 8248, 8760,
9144, 9528, 9912,10296,10680,11064,11448,11832,12216,12576,12960,
13536,14112,14112,14688,15264,15264,15840,16416,16416,16992,17568,
17568,18336,18336,19080,19080,19848,19848,20616,21384,21384,22152,
22152,22920,22920,23688,23688,24496,24496,24496,25456,25456,26416,
26416,27376,27376,27376,28336,28336,29296,29296,29296,30576,30576,
30576,31704,31704,31704,32856,32856,32856,34008,34008,34008,35160,
35160,35160,36696,36696,36696,37888,37888,37888,37888,39232,39232,
39232,40576,40576,40576,40576,42368,42368,42368,42368,43816,43816},
{ 408, 840, 1288, 1736, 2152, 2600, 2984, 3496, 3880, 4264, 4776,
5160, 5544, 5992, 6456, 6968, 7224, 7736, 8248, 8504, 9144, 9528,
9912,10296,10680,11064,11448,12216,12576,12960,13536,13536,14112,
14688,15264,15264,15840,16416,16992,16992,17568,18336,18336,19080,
19080,19848,20616,20616,21384,21384,22152,22152,22920,22920,23688,
24496,24496,25456,25456,25456,26416,26416,27376,27376,28336,28336,
29296,29296,29296,30576,30576,30576,31704,31704,32856,32856,32856,
34008,34008,34008,35160,35160,35160,36696,36696,36696,37888,37888,
37888,39232,39232,39232,40576,40576,40576,40576,42368,42368,42368,
43816,43816,43816,43816,45352,45352,45352,46888,46888,46888,46888},
{ 440, 904, 1384, 1864, 2344, 2792, 3240, 3752, 4136, 4584, 5160,
5544, 5992, 6456, 6968, 7480, 7992, 8248, 8760, 9144, 9912,10296,
10680,11064,11448,12216,12576,12960,13536,14112,14688,14688,15264,
15840,16416,16992,16992,17568,18336,18336,19080,19848,19848,20616,
20616,21384,22152,22152,22920,22920,23688,24496,24496,25456,25456,
26416,26416,27376,27376,28336,28336,29296,29296,29296,30576,30576,
31704,31704,31704,32856,32856,34008,34008,34008,35160,35160,35160,
36696,36696,36696,37888,37888,39232,39232,39232,40576,40576,40576,
42368,42368,42368,42368,43816,43816,43816,45352,45352,45352,46888,
46888,46888,46888,48936,48936,48936,48936,48936,51024,51024,51024},
{ 488, 1000, 1480, 1992, 2472, 2984, 3496, 4008, 4584, 4968, 5544,
5992, 6456, 6968, 7480, 7992, 8504, 9144, 9528, 9912,10680,11064,
11448,12216,12576,12960,13536,14112,14688,15264,15840,15840,16416,
16992,17568,18336,18336,19080,19848,19848,20616,21384,21384,22152,
22920,22920,23688,24496,24496,25456,25456,26416,26416,27376,27376,
28336,28336,29296,29296,30576,30576,31704,31704,31704,32856,32856,
34008,34008,35160,35160,35160,36696,36696,36696,37888,37888,39232,
39232,39232,40576,40576,40576,42368,42368,42368,43816,43816,43816,
45352,45352,45352,46888,46888,46888,46888,48936,48936,48936,48936,
51024,51024,51024,51024,52752,52752,52752,52752,55056,55056,55056},
{ 520, 1064, 1608, 2152, 2664, 3240, 3752, 4264, 4776, 5352, 5992,
6456, 6968, 7480, 7992, 8504, 9144, 9528,10296,10680,11448,11832,
12576,12960,13536,14112,14688,15264,15840,16416,16992,16992,17568,
18336,19080,19080,19848,20616,21384,21384,22152,22920,22920,23688,
24496,24496,25456,25456,26416,27376,27376,28336,28336,29296,29296,
30576,30576,31704,31704,32856,32856,34008,34008,34008,35160,35160,
36696,36696,36696,37888,37888,39232,39232,40576,40576,40576,42368,
42368,42368,43816,43816,43816,45352,45352,45352,46888,46888,46888,
48936,48936,48936,48936,51024,51024,51024,51024,52752,52752,52752,
55056,55056,55056,55056,57336,57336,57336,57336,59256,59256,59256},
{ 552, 1128, 1736, 2280, 2856, 3496, 4008, 4584, 5160, 5736, 6200,
6968, 7480, 7992, 8504, 9144, 9912,10296,11064,11448,12216,12576,
12960,13536,14112,14688,15264,15840,16416,16992,17568,18336,19080,
19848,19848,20616,21384,22152,22152,22920,23688,24496,24496,25456,
25456,26416,27376,27376,28336,28336,29296,29296,30576,30576,31704,
31704,32856,32856,34008,34008,35160,35160,36696,36696,37888,37888,
37888,39232,39232,40576,40576,40576,42368,42368,43816,43816,43816,
45352,45352,45352,46888,46888,46888,48936,48936,48936,51024,51024,
51024,51024,52752,52752,52752,55056,55056,55056,55056,57336,57336,
57336,57336,59256,59256,59256,59256,61664,61664,61664,61664,63776},
{ 584, 1192, 1800, 2408, 2984, 3624, 4264, 4968, 5544, 5992, 6712,
7224, 7992, 8504, 9144, 9912,10296,11064,11448,12216,12960,13536,
14112,14688,15264,15840,16416,16992,17568,18336,19080,19848,19848,
20616,21384,22152,22920,22920,23688,24496,25456,25456,26416,26416,
27376,28336,28336,29296,29296,30576,31704,31704,32856,32856,34008,
34008,35160,35160,36696,36696,36696,37888,37888,39232,39232,40576,
40576,42368,42368,42368,43816,43816,45352,45352,45352,46888,46888,
46888,48936,48936,48936,51024,51024,51024,52752,52752,52752,52752,
55056,55056,55056,57336,57336,57336,57336,59256,59256,59256,61664,
61664,61664,61664,63776,63776,63776,63776,66592,66592,66592,66592},
{ 616, 1256, 1864, 2536, 3112, 3752, 4392, 5160, 5736, 6200, 6968,
7480, 8248, 8760, 9528,10296,10680,11448,12216,12576,13536,14112,
14688,15264,15840,16416,16992,17568,18336,19080,19848,20616,20616,
21384,22152,22920,23688,24496,24496,25456,26416,26416,27376,28336,
28336,29296,29296,30576,31704,31704,32856,32856,34008,34008,35160,
35160,36696,36696,37888,37888,39232,39232,40576,40576,40576,42368,
42368,43816,43816,43816,45352,45352,46888,46888,46888,48936,48936,
48936,51024,51024,51024,52752,52752,52752,55056,55056,55056,55056,
57336,57336,57336,59256,59256,59256,61664,61664,61664,61664,63776,
63776,63776,63776,66592,66592,66592,66592,68808,68808,68808,71112},
{ 712, 1480, 2216, 2984, 3752, 4392, 5160, 5992, 6712, 7480, 8248,
8760, 9528,10296,11064,11832,12576,13536,14112,14688,15264,16416,
16992,17568,18336,19080,19848,20616,21384,22152,22920,23688,24496,
25456,25456,26416,27376,28336,29296,29296,30576,30576,31704,32856,
32856,34008,35160,35160,36696,36696,37888,37888,39232,40576,40576,
40576,42368,42368,43816,43816,45352,45352,46888,46888,48936,48936,
48936,51024,51024,52752,52752,52752,55056,55056,55056,55056,57336,
57336,57336,59256,59256,59256,61664,61664,61664,63776,63776,63776,
66592,66592,66592,68808,68808,68808,71112,71112,71112,73712,73712,
75376,75376,75376,75376,75376,75376,75376,75376,75376,75376,75376}};

@ -75,6 +75,11 @@ ADD_TEST(phich_test_104 phich_test -p 4 -n 10 -e -l -g 1/2)
ADD_EXECUTABLE(pdcch_test pdcch_test.c)
TARGET_LINK_LIBRARIES(pdcch_test lte)
ADD_TEST(pdcch_test pdcch_test)
ADD_EXECUTABLE(dci_unpacking dci_unpacking.c)
TARGET_LINK_LIBRARIES(dci_unpacking lte)
########################################################################
# FILE TEST
########################################################################
@ -88,7 +93,11 @@ TARGET_LINK_LIBRARIES(pcfich_file_test lte)
ADD_EXECUTABLE(phich_file_test phich_file_test.c)
TARGET_LINK_LIBRARIES(phich_file_test lte)
ADD_EXECUTABLE(pdcch_file_test pdcch_file_test.c)
TARGET_LINK_LIBRARIES(pdcch_file_test lte)
ADD_TEST(pbch_file_test pbch_file_test -i ${CMAKE_CURRENT_SOURCE_DIR}/signal.1.92M.dat)
ADD_TEST(pcfich_file_test pcfich_file_test -c 150 -n 50 -p 2 -i ${CMAKE_CURRENT_SOURCE_DIR}/signal.10M.dat)
ADD_TEST(phich_file_test phich_file_test -c 150 -n 50 -p 2 -i ${CMAKE_CURRENT_SOURCE_DIR}/signal.10M.dat)
ADD_TEST(pdcch_file_test pdcch_file_test -c 1 -f 3 -n 6 -p 1 -i ${CMAKE_CURRENT_SOURCE_DIR}/signal.1.92M.amar.dat)

@ -0,0 +1,105 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2014 The libLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the libLTE library.
*
* libLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* libLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* A copy of the GNU Lesser General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <unistd.h>
#include "lte.h"
void usage(char *prog) {
printf("Usage: %s nof_prb length_bits Word0 Word1 ...\n", prog);
}
int main(int argc, char **argv) {
dci_msg_t msg;
ra_pdsch_t ra_dl;
ra_pdsch_t ra_ul;
int len, rlen;
int nof_prb;
int nwords;
int i;
char *y;
if (argc < 3) {
usage(argv[0]);
exit(-1);
}
nof_prb = atoi(argv[1]);
len = atoi(argv[2]);
nwords = (len-1)/32+1;
if (argc < 3 + nwords) {
usage(argv[0]);
exit(-1);
}
y = msg.data;
rlen = 0;
unsigned int x;
for (i=0;i<nwords;i++) {
x = strtoul(argv[i+3],NULL,16);
if (len-rlen < 32) {
bit_pack(x, &y, len - rlen);
} else {
bit_pack(x, &y, 32);
}
}
printf("DCI message len %d:\n",len);
for (i=0;i<len;i++) {
printf("%d, ", msg.data[i]);
}
printf("\n");
dci_msg_type_t dci_type;
msg.location.rnti = SIRNTI;
msg.location.nof_bits = len;
if (dci_msg_get_type(&msg, &dci_type, nof_prb, 1234)) {
fprintf(stderr, "Can't obtain DCI message type\n");
exit(-1);
}
printf("\n");
printf("Message type:");
dci_msg_type_fprint(stdout, dci_type);
switch(dci_type.type) {
case PDSCH_SCHED:
bzero(&ra_dl, sizeof(ra_pdsch_t));
dci_msg_unpack_pdsch(&msg, &ra_dl, nof_prb, false);
ra_pdsch_fprint(stdout, &ra_dl, nof_prb);
break;
default:
printf("Error expected PDSCH\n");
exit(-1);
}
printf("\n");
}

@ -223,7 +223,8 @@ int main(int argc, char **argv) {
} else {
if (mib.nof_ports == 2 && mib.nof_prb == 50 && mib.phich_length == PHICH_NORM
&& mib.phich_resources == R_1 && mib.sfn == 28) {
printf("This is the pbch_test.dat file\n");
pbch_mib_fprint(stdout, &mib);
printf("This is the signal.1.92M.dat file\n");
exit(0);
} else {
pbch_mib_fprint(stdout, &mib);

@ -0,0 +1,309 @@
/**
*
* \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 = 0;
int cfi = 2;
lte_cp_t cp = CPNORM;
int nof_prb = 6;
int nof_ports = 1;
int flen;
unsigned short rnti = SIRNTI;
int max_frames = 10;
FILE *fmatlab = NULL;
filesource_t fsrc;
pdcch_t pdcch;
cf_t *input_buffer, *fft_buffer, *ce[MAX_PORTS_CTRL];
regs_t regs;
lte_fft_t fft;
chest_t chest;
dci_t dci_rx;
void usage(char *prog) {
printf("Usage: %s [vcfoe] -i input_file\n", prog);
printf("\t-o output matlab file name [Default Disabled]\n");
printf("\t-c cell_id [Default %d]\n", cell_id);
printf("\t-f cfi [Default %d]\n", cfi);
printf("\t-r rnti [Default SI-RNTI]\n");
printf("\t-p nof_ports [Default %d]\n", nof_ports);
printf("\t-n nof_prb [Default %d]\n", nof_prb);
printf("\t-m max_frames [Default %d]\n", max_frames);
printf("\t-e Set extended prefix [Default Normal]\n");
printf("\t-v [set verbose to debug, default none]\n");
}
void parse_args(int argc, char **argv) {
int opt;
while ((opt = getopt(argc, argv, "irovfcenmp")) != -1) {
switch(opt) {
case 'i':
input_file_name = argv[optind];
break;
case 'c':
cell_id = atoi(argv[optind]);
break;
case 'r':
rnti = strtoul(argv[optind], NULL, 0);
break;
case 'm':
max_frames = strtoul(argv[optind], NULL, 0);
break;
case 'f':
cfi = atoi(argv[optind]);
break;
case 'n':
nof_prb = atoi(argv[optind]);
break;
case 'p':
nof_ports = atoi(argv[optind]);
break;
case 'o':
matlab_file_name = argv[optind];
break;
case 'v':
verbose++;
break;
case 'e':
cp = CPEXT;
break;
default:
usage(argv[0]);
exit(-1);
}
}
if (!input_file_name) {
usage(argv[0]);
exit(-1);
}
}
int base_init() {
int i;
if (filesource_init(&fsrc, input_file_name, COMPLEX_FLOAT_BIN)) {
fprintf(stderr, "Error opening file %s\n", input_file_name);
exit(-1);
}
if (matlab_file_name) {
fmatlab = fopen(matlab_file_name, "w");
if (!fmatlab) {
perror("fopen");
return -1;
}
} else {
fmatlab = NULL;
}
flen = 2 * (SLOT_LEN(lte_symbol_sz(nof_prb), cp));
input_buffer = malloc(flen * sizeof(cf_t));
if (!input_buffer) {
perror("malloc");
exit(-1);
}
fft_buffer = malloc(CP_NSYMB(cp) * nof_prb * RE_X_RB * sizeof(cf_t));
if (!fft_buffer) {
perror("malloc");
return -1;
}
for (i=0;i<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, R_1, PHICH_NORM, cp)) {
fprintf(stderr, "Error initiating regs\n");
return -1;
}
if (regs_set_cfi(&regs, cfi)) {
fprintf(stderr, "Error setting CFI %d\n", cfi);
return -1;
}
if (pdcch_init(&pdcch, &regs, nof_prb, nof_ports, cell_id, cp)) {
fprintf(stderr, "Error creating PDCCH object\n");
exit(-1);
}
dci_init(&dci_rx, 10);
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);
dci_free(&dci_rx);
pdcch_free(&pdcch);
regs_free(&regs);
}
int main(int argc, char **argv) {
ra_pdsch_t ra_dl;
int i;
int nof_dcis;
int nof_frames;
int ret;
if (argc < 3) {
usage(argv[0]);
exit(-1);
}
parse_args(argc,argv);
if (base_init()) {
fprintf(stderr, "Error initializing memory\n");
exit(-1);
}
if (rnti == SIRNTI) {
INFO("Initializing common search space for SI-RNTI\n",0);
pdcch_init_search_si(&pdcch);
} else {
INFO("Initializing user-specific search space for RNTI: 0x%x\n", rnti);
pdcch_init_search_ue(&pdcch, rnti);
}
ret = -1;
nof_frames = 0;
do {
filesource_read(&fsrc, input_buffer, flen);
if (nof_frames == 5) {
INFO("Reading %d samples sub-frame %d\n", flen, nof_frames);
lte_fft_run(&fft, input_buffer, fft_buffer);
if (fmatlab) {
fprintf(fmatlab, "infft%d=", nof_frames);
vec_fprint_c(fmatlab, input_buffer, flen);
fprintf(fmatlab, ";\n");
fprintf(fmatlab, "outfft%d=", nof_frames);
vec_sc_prod_cfc(fft_buffer, 1000.0, fft_buffer, CP_NSYMB(cp) * nof_prb * RE_X_RB);
vec_fprint_c(fmatlab, fft_buffer, CP_NSYMB(cp) * nof_prb * RE_X_RB);
fprintf(fmatlab, ";\n");
vec_sc_prod_cfc(fft_buffer, 0.001, fft_buffer, CP_NSYMB(cp) * nof_prb * RE_X_RB);
}
/* Get channel estimates for each port */
for (i=0;i<nof_ports;i++) {
chest_ce_slot_port(&chest, fft_buffer, ce[i], 2*nof_frames, i);
if (fmatlab) {
chest_fprint(&chest, fmatlab, 2*nof_frames, i);
}
}
nof_dcis = pdcch_decode(&pdcch, fft_buffer, ce, &dci_rx, nof_frames%10, 1);
INFO("Received %d DCI messages\n", nof_dcis);
for (i=0;i<nof_dcis;i++) {
dci_msg_type_t type;
if (dci_msg_get_type(&dci_rx.msg[i], &type, nof_prb, 1234)) {
fprintf(stderr, "Can't get DCI message type\n");
exit(-1);
}
printf("MSG %d: ",i);
dci_msg_type_fprint(stdout, type);
switch(type.type) {
case PDSCH_SCHED:
bzero(&ra_dl, sizeof(ra_pdsch_t));
if (dci_msg_unpack_pdsch(&dci_rx.msg[i], &ra_dl, nof_prb, rnti != SIRNTI)) {
fprintf(stderr, "Can't unpack PDSCH message\n");
} else {
ra_pdsch_fprint(stdout, &ra_dl, nof_prb);
if (ra_dl.alloc_type == alloc_type2 && ra_dl.type2_alloc.mode == t2_loc
&& ra_dl.type2_alloc.riv == 11 && ra_dl.rv_idx == 0
&& ra_dl.harq_process == 0 && ra_dl.mcs.mcs_idx == 2) {
printf("This is the file signal.1.92M.amar.dat\n");
ret = 0;
}
}
break;
default:
fprintf(stderr, "Unsupported message type\n");
break;
}
}
}
nof_frames++;
} while (nof_frames <= max_frames);
base_free();
fftwf_cleanup();
exit(ret);
}

@ -36,10 +36,12 @@
int cell_id = 1;
int nof_prb = 6;
int nof_ports = 1;
int cfi = 1;
void usage(char *prog) {
printf("Usage: %s [cpv]\n", prog);
printf("\t-c cell id [Default %d]\n", cell_id);
printf("\t-f cfi [Default %d]\n", cfi);
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");
@ -47,11 +49,14 @@ void usage(char *prog) {
void parse_args(int argc, char **argv) {
int opt;
while ((opt = getopt(argc, argv, "cpnv")) != -1) {
while ((opt = getopt(argc, argv, "cpnfv")) != -1) {
switch(opt) {
case 'p':
nof_ports = atoi(argv[optind]);
break;
case 'f':
cfi = atoi(argv[optind]);
break;
case 'n':
nof_prb = atoi(argv[optind]);
break;
@ -68,10 +73,42 @@ void parse_args(int argc, char **argv) {
}
}
int test_dci_payload_size() {
int i, j;
int x[4];
const dci_format_t formats[4] = {Format0, Format1, Format1A, Format1C};
const int prb[6]={6, 15, 25, 50, 75, 100};
const int dci_sz[6][5] = {
{21, 19, 21, 8},
{22, 23, 22, 10},
{25, 27, 25, 12},
{27, 31, 27, 13},
{27, 33, 27, 14},
{28, 39, 28, 15}
};
printf("Testing DCI payload sizes...\n");
printf(" PRB\t0\t1\t1A\t1C\n");
for (i=0;i<6;i++) {
int n=prb[i];
for (j=0;j<4;j++) {
x[j] = dci_format_sizeof(formats[j], n);
if (x[j] != dci_sz[i][j]) {
fprintf(stderr, "Invalid DCI payload size for %s\n", dci_format_string(formats[j]));
return -1;
}
}
printf(" %2d:\t%2d\t%2d\t%2d\t%2d\n",n,x[0],x[1],x[2],x[3]);
}
printf("Ok\n");
return 0;
}
int main(int argc, char **argv) {
pdcch_t pdcch;
dci_t dci_tx, dci_rx;
dci_format1_t dci_msg;
ra_pdsch_t ra_dl;
regs_t regs;
int i, j;
cf_t *ce[MAX_PORTS_CTRL];
@ -84,6 +121,10 @@ int main(int argc, char **argv) {
nof_re = CPNORM_NSYMB * nof_prb * RE_X_RB;
if (test_dci_payload_size()) {
exit(-1);
}
/* init memory */
for (i=0;i<MAX_PORTS_CTRL;i++) {
ce[i] = malloc(sizeof(cf_t) * nof_re);
@ -106,13 +147,34 @@ int main(int argc, char **argv) {
exit(-1);
}
if (regs_set_cfi(&regs, cfi)) {
fprintf(stderr, "Error setting CFI\n");
exit(-1);
}
if (pdcch_init(&pdcch, &regs, nof_prb, nof_ports, cell_id, CPNORM)) {
fprintf(stderr, "Error creating PBCH object\n");
fprintf(stderr, "Error creating PDCCH object\n");
exit(-1);
}
dci_init(&dci_tx, 1);
dci_format1_add(&dci_tx, &dci_msg, 1, 0, 1234);
dci_init(&dci_tx, 2);
bzero(&ra_dl, sizeof(ra_pdsch_t));
ra_dl.harq_process = 0;
//ra_pdsch_set_mcs_index(&ra_dl, 6);
ra_pdsch_set_mcs(&ra_dl, QAM16, 5);
ra_dl.ndi = 0;
ra_dl.rv_idx = 0;
ra_dl.alloc_type = alloc_type0;
ra_dl.type0_alloc.rbg_bitmask = 0x5;
dci_msg_pack_pdsch(&ra_dl, &dci_tx.msg[0], Format1, nof_prb, false);
dci_msg_candidate_set(&dci_tx.msg[0], 0, 0, 1234);
dci_tx.nof_dcis++;
ra_pdsch_set_mcs(&ra_dl, QAM16, 15);
dci_msg_pack_pdsch(&ra_dl, &dci_tx.msg[1], Format1, nof_prb, false);
dci_msg_candidate_set(&dci_tx.msg[1], 0, 1, 1234);
dci_tx.nof_dcis++;
pdcch_encode(&pdcch, &dci_tx, slot1_symbols, 0);
@ -125,13 +187,12 @@ int main(int argc, char **argv) {
pdcch_init_search_ue(&pdcch, 1234);
dci_init(&dci_rx, 1);
dci_init(&dci_rx, 2);
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
@ -146,7 +207,6 @@ int main(int argc, char **argv) {
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);

@ -1,33 +0,0 @@
#
# Copyright 2012-2013 The libLTE Developers. See the
# COPYRIGHT file at the top-level directory of this distribution.
#
# 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/.
#
########################################################################
# RATEMATCHING TEST
########################################################################
ADD_EXECUTABLE(rm_conv_test rm_conv_test.c)
TARGET_LINK_LIBRARIES(rm_conv_test lte)
ADD_TEST(rm_conv_test_1 rm_conv_test -t 480 -r 1920)
ADD_TEST(rm_conv_test_2 rm_conv_test -t 1920 -r 480)

@ -23,7 +23,7 @@ int main(int argc, char **argv) {
resample_arb_init(&r, rate);
clock_t start = clock(), diff;
int n_out = resample_arb_compute(&r, in, out, N);
//int n_out = resample_arb_compute(&r, in, out, N);
diff = clock() - start;
int msec = diff * 1000 / CLOCKS_PER_SEC;

@ -71,3 +71,11 @@ unsigned int bit_diff(char *x, char *y, int nbits) {
}
return errors;
}
// Counts the number of ones in a word. K&R book exercise 2.9
int bit_count(unsigned int n) {
int c;
for (c = 0; n; c++)
n &= n - 1;
return c;
}

Loading…
Cancel
Save