mirror of https://github.com/PentHertz/srsLTE.git
Merge branch 'master' of https://github.com/suttonpd/liblte
This commit is contained in:
commit
8c0b3f0e2a
|
@ -14,6 +14,16 @@
|
||||||
# CMAKE_REQUIRED_INCLUDES = list of include directories
|
# CMAKE_REQUIRED_INCLUDES = list of include directories
|
||||||
# CMAKE_REQUIRED_LIBRARIES = list of libraries to link
|
# 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)
|
MACRO(CHECK_FUNCTION_EXISTS_MATH FUNCTION VARIABLE)
|
||||||
IF("${VARIABLE}" MATCHES "^${VARIABLE}$")
|
IF("${VARIABLE}" MATCHES "^${VARIABLE}$")
|
||||||
|
|
|
@ -25,6 +25,7 @@ IF(UHD_FOUND)
|
||||||
|
|
||||||
ADD_LIBRARY(cuhd cuhd_imp.cpp cuhd_utils.c)
|
ADD_LIBRARY(cuhd cuhd_imp.cpp cuhd_utils.c)
|
||||||
INCLUDE_DIRECTORIES(${UHD_INCLUDE_DIRS})
|
INCLUDE_DIRECTORIES(${UHD_INCLUDE_DIRS})
|
||||||
|
LINK_DIRECTORIES(${UHD_LIBRARY_DIRS})
|
||||||
TARGET_LINK_LIBRARIES(cuhd ${UHD_LIBRARIES})
|
TARGET_LINK_LIBRARIES(cuhd ${UHD_LIBRARIES})
|
||||||
|
|
||||||
LIBLTE_SET_PIC(cuhd)
|
LIBLTE_SET_PIC(cuhd)
|
||||||
|
@ -38,6 +39,3 @@ ELSE(UHD_FOUND)
|
||||||
MESSAGE(STATUS " UHD driver not found. CUHD library is not generated")
|
MESSAGE(STATUS " UHD driver not found. CUHD library is not generated")
|
||||||
|
|
||||||
ENDIF(UHD_FOUND)
|
ENDIF(UHD_FOUND)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -46,7 +46,18 @@ typedef _Complex float complex_t;
|
||||||
bool isLocked(void *h)
|
bool isLocked(void *h)
|
||||||
{
|
{
|
||||||
cuhd_handler* handler = static_cast<cuhd_handler*>(h);
|
cuhd_handler* handler = static_cast<cuhd_handler*>(h);
|
||||||
return handler->usrp->get_rx_sensor("lo_locked", 0).to_bool();
|
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)
|
bool cuhd_rx_wait_lo_locked(void *h)
|
||||||
|
@ -89,12 +100,14 @@ int cuhd_start_rx_stream_nsamples(void *h, int nsamples) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int cuhd_open(char *args, void **h) {
|
int cuhd_open(char *args, void **h) {
|
||||||
cuhd_handler* handler = new cuhd_handler();
|
cuhd_handler* handler = new cuhd_handler();
|
||||||
std::string _args=std::string(args);
|
std::string _args=std::string(args);
|
||||||
handler->usrp = uhd::usrp::multi_usrp::make(_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");
|
handler->usrp->set_clock_source("internal");
|
||||||
|
|
||||||
std::string otw, cpu;
|
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);
|
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)
|
add_executable(synch_file synch_file.c)
|
||||||
target_link_libraries(synch_file lte)
|
target_link_libraries(synch_file lte)
|
||||||
|
|
||||||
|
LINK_DIRECTORIES(${UHD_LIBRARY_DIRS})
|
||||||
|
|
||||||
#################################################################
|
#################################################################
|
||||||
# Check if UHD C-API and Graphics library are available
|
# Check if UHD C-API and Graphics library are available
|
||||||
|
@ -60,7 +61,7 @@ IF(${CUHD_FIND} EQUAL -1)
|
||||||
SET_TARGET_PROPERTIES(pbch_ue PROPERTIES COMPILE_DEFINITIONS "DISABLE_UHD")
|
SET_TARGET_PROPERTIES(pbch_ue PROPERTIES COMPILE_DEFINITIONS "DISABLE_UHD")
|
||||||
SET_TARGET_PROPERTIES(pbch_enodeb PROPERTIES COMPILE_DEFINITIONS "DISABLE_UHD")
|
SET_TARGET_PROPERTIES(pbch_enodeb PROPERTIES COMPILE_DEFINITIONS "DISABLE_UHD")
|
||||||
ELSE(${CUHD_FIND} EQUAL -1)
|
ELSE(${CUHD_FIND} EQUAL -1)
|
||||||
target_link_libraries(pbch_ue cuhd)
|
target_link_libraries(pbch_ue cuhd)
|
||||||
target_link_libraries(pbch_enodeb cuhd)
|
target_link_libraries(pbch_enodeb cuhd)
|
||||||
ENDIF(${CUHD_FIND} EQUAL -1)
|
ENDIF(${CUHD_FIND} EQUAL -1)
|
||||||
|
|
||||||
|
@ -94,4 +95,3 @@ IF(${CUHD_FIND} GREATER -1)
|
||||||
ELSE(${CUHD_FIND} GREATER -1)
|
ELSE(${CUHD_FIND} GREATER -1)
|
||||||
MESSAGE(STATUS " UHD examples NOT INSTALLED: CUHD library not compiled.")
|
MESSAGE(STATUS " UHD examples NOT INSTALLED: CUHD library not compiled.")
|
||||||
ENDIF(${CUHD_FIND} GREATER -1)
|
ENDIF(${CUHD_FIND} GREATER -1)
|
||||||
|
|
||||||
|
|
|
@ -39,7 +39,7 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
char *output_file_name = NULL;
|
char *output_file_name = NULL;
|
||||||
int nof_slots=-1;
|
int nof_frames=-1;
|
||||||
int cell_id = 1;
|
int cell_id = 1;
|
||||||
int nof_prb = 6;
|
int nof_prb = 6;
|
||||||
char *uhd_args = "";
|
char *uhd_args = "";
|
||||||
|
@ -66,7 +66,7 @@ void usage(char *prog) {
|
||||||
printf("\t UHD is disabled. CUHD library not available\n");
|
printf("\t UHD is disabled. CUHD library not available\n");
|
||||||
#endif
|
#endif
|
||||||
printf("\t-o output_file [Default USRP]\n");
|
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-c cell id [Default %d]\n", cell_id);
|
||||||
printf("\t-p nof_prb [Default %d]\n", nof_prb);
|
printf("\t-p nof_prb [Default %d]\n", nof_prb);
|
||||||
printf("\t-v [set verbose to debug, default none]\n");
|
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];
|
output_file_name = argv[optind];
|
||||||
break;
|
break;
|
||||||
case 'n':
|
case 'n':
|
||||||
nof_slots = atoi(argv[optind]);
|
nof_frames = atoi(argv[optind]);
|
||||||
break;
|
break;
|
||||||
case 'p':
|
case 'p':
|
||||||
nof_prb = atoi(argv[optind]);
|
nof_prb = atoi(argv[optind]);
|
||||||
|
@ -238,7 +238,7 @@ int main(int argc, char **argv) {
|
||||||
|
|
||||||
nf = 0;
|
nf = 0;
|
||||||
|
|
||||||
while(nf<nof_slots || nof_slots == -1) {
|
while(nf<nof_frames || nof_frames == -1) {
|
||||||
for (ns=0;ns<NSLOTS_X_FRAME;ns++) {
|
for (ns=0;ns<NSLOTS_X_FRAME;ns++) {
|
||||||
bzero(slot_buffer, sizeof(cf_t) * slot_n_re);
|
bzero(slot_buffer, sizeof(cf_t) * slot_n_re);
|
||||||
|
|
||||||
|
|
|
@ -57,8 +57,8 @@
|
||||||
|
|
||||||
#define NOF_PORTS 2
|
#define NOF_PORTS 2
|
||||||
|
|
||||||
float find_threshold = 30.0, track_threshold = 10.0;
|
float find_threshold = 20.0, track_threshold = 10.0;
|
||||||
int max_track_lost = 20, nof_slots = -1;
|
int max_track_lost = 20, nof_frames = -1;
|
||||||
int track_len=300;
|
int track_len=300;
|
||||||
char *input_file_name = NULL;
|
char *input_file_name = NULL;
|
||||||
int disable_plots = 0;
|
int disable_plots = 0;
|
||||||
|
@ -89,7 +89,7 @@ void usage(char *prog) {
|
||||||
#else
|
#else
|
||||||
printf("\t UHD is disabled. CUHD library not available\n");
|
printf("\t UHD is disabled. CUHD library not available\n");
|
||||||
#endif
|
#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);
|
printf("\t-p PSS threshold [Default %f]\n", find_threshold);
|
||||||
#ifndef DISABLE_GRAPHICS
|
#ifndef DISABLE_GRAPHICS
|
||||||
printf("\t-d disable plots [Default enabled]\n");
|
printf("\t-d disable plots [Default enabled]\n");
|
||||||
|
@ -119,7 +119,7 @@ void parse_args(int argc, char **argv) {
|
||||||
find_threshold = atof(argv[optind]);
|
find_threshold = atof(argv[optind]);
|
||||||
break;
|
break;
|
||||||
case 'n':
|
case 'n':
|
||||||
nof_slots = atoi(argv[optind]);
|
nof_frames = atoi(argv[optind]);
|
||||||
break;
|
break;
|
||||||
case 'd':
|
case 'd':
|
||||||
disable_plots = 1;
|
disable_plots = 1;
|
||||||
|
@ -375,7 +375,7 @@ int main(int argc, char **argv) {
|
||||||
sync_set_threshold(&sfind, find_threshold);
|
sync_set_threshold(&sfind, find_threshold);
|
||||||
sync_force_N_id_2(&sfind, -1);
|
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);
|
INFO(" ----- RECEIVING %d SAMPLES ---- \n", FLEN);
|
||||||
if (input_file_name) {
|
if (input_file_name) {
|
||||||
n = filesource_read(&fsrc, input_buffer, FLEN);
|
n = filesource_read(&fsrc, input_buffer, FLEN);
|
||||||
|
|
|
@ -35,7 +35,7 @@
|
||||||
#include "lte.h"
|
#include "lte.h"
|
||||||
#include "cuhd.h"
|
#include "cuhd.h"
|
||||||
|
|
||||||
int nof_slots=1000;
|
int nof_frames=1000;
|
||||||
int band;
|
int band;
|
||||||
|
|
||||||
cf_t *input_buffer, *fft_buffer;
|
cf_t *input_buffer, *fft_buffer;
|
||||||
|
@ -52,7 +52,7 @@ void usage(char *prog) {
|
||||||
printf("Usage: %s [nvse] -b band\n", prog);
|
printf("Usage: %s [nvse] -b band\n", prog);
|
||||||
printf("\t-s earfcn_start [Default All]\n");
|
printf("\t-s earfcn_start [Default All]\n");
|
||||||
printf("\t-e earfcn_end [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");
|
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]);
|
earfcn_end = atoi(argv[optind]);
|
||||||
break;
|
break;
|
||||||
case 'n':
|
case 'n':
|
||||||
nof_slots = atoi(argv[optind]);
|
nof_frames = atoi(argv[optind]);
|
||||||
break;
|
break;
|
||||||
case 'v':
|
case 'v':
|
||||||
verbose++;
|
verbose++;
|
||||||
|
@ -132,7 +132,7 @@ int main(int argc, char **argv) {
|
||||||
frame_cnt = 0;
|
frame_cnt = 0;
|
||||||
nsamples=0;
|
nsamples=0;
|
||||||
rssi[i]=0;
|
rssi[i]=0;
|
||||||
while(frame_cnt < nof_slots) {
|
while(frame_cnt < nof_frames) {
|
||||||
nsamples += cuhd_recv(uhd, input_buffer, 1920, 1);
|
nsamples += cuhd_recv(uhd, input_buffer, 1920, 1);
|
||||||
rssi[i] += vec_avg_power_cf(input_buffer, 1920);
|
rssi[i] += vec_avg_power_cf(input_buffer, 1920);
|
||||||
frame_cnt++;
|
frame_cnt++;
|
||||||
|
|
|
@ -35,7 +35,7 @@
|
||||||
|
|
||||||
char *input_file_name;
|
char *input_file_name;
|
||||||
char *output_file_name="abs_corr.txt";
|
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;
|
float corr_peak_threshold=25.0;
|
||||||
int out_N_id_2 = 0, force_N_id_2=-1;
|
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("Usage: %s [olntsNfcv] -i input_file\n", prog);
|
||||||
printf("\t-o output_file [Default %s]\n", output_file_name);
|
printf("\t-o output_file [Default %s]\n", output_file_name);
|
||||||
printf("\t-l frame_length [Default %d]\n", frame_length);
|
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-t correlation threshold [Default %g]\n", corr_peak_threshold);
|
||||||
printf("\t-s symbol_sz [Default %d]\n", symbol_sz);
|
printf("\t-s symbol_sz [Default %d]\n", symbol_sz);
|
||||||
printf("\t-N out_N_id_2 [Default %d]\n", out_N_id_2);
|
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];
|
output_file_name = argv[optind];
|
||||||
break;
|
break;
|
||||||
case 'n':
|
case 'n':
|
||||||
nof_slots = atoi(argv[optind]);
|
nof_frames = atoi(argv[optind]);
|
||||||
break;
|
break;
|
||||||
case 'l':
|
case 'l':
|
||||||
frame_length = atoi(argv[optind]);
|
frame_length = atoi(argv[optind]);
|
||||||
|
@ -143,12 +143,12 @@ int main(int argc, char **argv) {
|
||||||
perror("malloc");
|
perror("malloc");
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
cfo = malloc(nof_slots*sizeof(float));
|
cfo = malloc(nof_frames*sizeof(float));
|
||||||
if (!cfo) {
|
if (!cfo) {
|
||||||
perror("malloc");
|
perror("malloc");
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
exec_time = malloc(nof_slots*sizeof(int));
|
exec_time = malloc(nof_frames*sizeof(int));
|
||||||
if (!exec_time) {
|
if (!exec_time) {
|
||||||
perror("malloc");
|
perror("malloc");
|
||||||
exit(-1);
|
exit(-1);
|
||||||
|
@ -192,7 +192,7 @@ int main(int argc, char **argv) {
|
||||||
/* read all file or nof_frames */
|
/* read all file or nof_frames */
|
||||||
frame_cnt = 0;
|
frame_cnt = 0;
|
||||||
while (frame_length == filesource_read(&fsrc, input, frame_length)
|
while (frame_length == filesource_read(&fsrc, input, frame_length)
|
||||||
&& frame_cnt < nof_slots) {
|
&& frame_cnt < nof_frames) {
|
||||||
|
|
||||||
gettimeofday(&tdata[1], NULL);
|
gettimeofday(&tdata[1], NULL);
|
||||||
if (force_cfo != CFO_AUTO) {
|
if (force_cfo != CFO_AUTO) {
|
||||||
|
|
|
@ -58,6 +58,11 @@
|
||||||
#include "lte/fec/viterbi.h"
|
#include "lte/fec/viterbi.h"
|
||||||
#include "lte/fec/convcoder.h"
|
#include "lte/fec/convcoder.h"
|
||||||
#include "lte/fec/crc.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"
|
#include "lte/filter/filter2d.h"
|
||||||
|
|
||||||
|
@ -82,8 +87,6 @@
|
||||||
#include "lte/phch/pcfich.h"
|
#include "lte/phch/pcfich.h"
|
||||||
#include "lte/phch/phich.h"
|
#include "lte/phch/phich.h"
|
||||||
|
|
||||||
#include "lte/ratematching/rm_conv.h"
|
|
||||||
|
|
||||||
#include "lte/scrambling/scrambling.h"
|
#include "lte/scrambling/scrambling.h"
|
||||||
|
|
||||||
#include "lte/resampling/interp.h"
|
#include "lte/resampling/interp.h"
|
||||||
|
|
|
@ -39,10 +39,16 @@
|
||||||
#define MAX_LAYERS 8
|
#define MAX_LAYERS 8
|
||||||
#define MAX_CODEWORDS 2
|
#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;
|
typedef enum {CPNORM, CPEXT} lte_cp_t;
|
||||||
|
|
||||||
#define SIRNTI 0xFFFF
|
#define SIRNTI 0xFFFF
|
||||||
#define PRNTI 0xFFFE
|
#define PRNTI 0xFFFE
|
||||||
|
#define MRNTI 0xFFFD
|
||||||
|
|
||||||
#define MAX_NSYMB 7
|
#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_LTE_BANDS 29
|
||||||
|
|
||||||
|
#define NOF_TC_CB_SIZES 188
|
||||||
|
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
SINGLE_ANTENNA,TX_DIVERSITY, SPATIAL_MULTIPLEX
|
SINGLE_ANTENNA,TX_DIVERSITY, SPATIAL_MULTIPLEX
|
||||||
} mimo_type_t;
|
} lte_mimo_type_t;
|
||||||
|
|
||||||
typedef enum { PHICH_NORM, PHICH_EXT} phich_length_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;
|
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
|
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);
|
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(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_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_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);
|
int lte_str2mimotype(char *mimo_type_str, lte_mimo_type_t *type);
|
||||||
char *lte_mimotype2str(mimo_type_t type);
|
char *lte_mimotype2str(lte_mimo_type_t type);
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -26,17 +26,23 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef CRC_
|
#ifndef CRC_
|
||||||
#define CRC_
|
#define CRC_
|
||||||
|
|
||||||
#define LTE_CRC24A 0x1864CFB
|
typedef struct {
|
||||||
#define LTE_CRC24B 0X1800063
|
unsigned long table[256];
|
||||||
#define LTE_CRC16 0x11021
|
unsigned char byte;
|
||||||
#define LTE_CRC8 0x19B
|
int polynom;
|
||||||
|
int order;
|
||||||
|
unsigned long crcinit;
|
||||||
|
unsigned long crcmask;
|
||||||
|
unsigned long crchighbit;
|
||||||
|
unsigned int crc_out;
|
||||||
|
} crc_t;
|
||||||
|
|
||||||
|
int crc_init(crc_t *h, unsigned int crc_poly, int crc_order);
|
||||||
unsigned int crc(unsigned int crc, char *bufptr, int len,
|
int crc_set_init(crc_t *h, unsigned long crc_init_value);
|
||||||
int long_crc,unsigned int poly, int paste_word);
|
void crc_attach(crc_t *h, char *data, int len);
|
||||||
|
unsigned int crc_checksum(crc_t *h, char *data, int len);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -33,8 +33,8 @@
|
||||||
#define TX_NULL 80
|
#define TX_NULL 80
|
||||||
|
|
||||||
|
|
||||||
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);
|
||||||
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);
|
||||||
|
|
||||||
|
|
||||||
/* High-level API */
|
/* 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 layermap_multiplex(cf_t *d[MAX_CODEWORDS], cf_t *x[MAX_LAYERS], int nof_cw, int nof_layers,
|
||||||
int nof_symbols[MAX_CODEWORDS]);
|
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 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"
|
/* 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 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 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 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
|
#endif
|
||||||
|
|
|
@ -41,7 +41,7 @@ typedef _Complex float cf_t;
|
||||||
int precoding_single(cf_t *x, cf_t *y, int nof_symbols);
|
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_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 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"
|
/* 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);
|
cf_t *x[MAX_LAYERS], int nof_ports, int nof_symbols);
|
||||||
int predecoding_type(cf_t *y[MAX_PORTS], cf_t *ce[MAX_PORTS],
|
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,
|
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_ */
|
#endif /* PRECODING_H_ */
|
||||||
|
|
|
@ -40,7 +40,7 @@ typedef struct {
|
||||||
}soft_table_t;
|
}soft_table_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
cf_t* symbol_table; // bit-to-symbol mapping
|
cf_t* symbol_table; // bit-to-symbol mapping
|
||||||
soft_table_t soft_table; // symbol-to-bit mapping (used in soft demodulating)
|
soft_table_t soft_table; // symbol-to-bit mapping (used in soft demodulating)
|
||||||
int nsymbols; // number of modulation symbols
|
int nsymbols; // number of modulation symbols
|
||||||
int nbits_x_symbol; // number of bits per symbol
|
int nbits_x_symbol; // number of bits per symbol
|
||||||
|
@ -49,7 +49,7 @@ typedef struct {
|
||||||
|
|
||||||
// Modulation standards
|
// Modulation standards
|
||||||
enum modem_std {
|
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);
|
void modem_table_init(modem_table_t* q);
|
||||||
|
|
|
@ -25,11 +25,12 @@
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#ifndef DCI_
|
#ifndef DCI_
|
||||||
#define DCI_
|
#define DCI_
|
||||||
|
|
||||||
#include "lte/common/base.h"
|
#include "lte/common/base.h"
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "lte/phch/ra.h"
|
||||||
|
|
||||||
typedef _Complex float cf_t;
|
typedef _Complex float cf_t;
|
||||||
|
|
||||||
|
@ -37,77 +38,63 @@ typedef _Complex float cf_t;
|
||||||
* DCI message generation according to the formats, as specified in
|
* DCI message generation according to the formats, as specified in
|
||||||
* 36.212 Section 5.3.3.1
|
* 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 {
|
typedef enum {
|
||||||
FORMAT0,
|
Format0, Format1, Format1A, Format1C
|
||||||
FORMAT1,
|
} dci_format_t;
|
||||||
FORMAT1A,
|
|
||||||
/* ... */
|
// Each type is for a different interface to packing/unpacking functions
|
||||||
}dci_format_t;
|
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 {
|
typedef enum {
|
||||||
DCI_COMMON=0, DCI_UE=1
|
DCI_COMMON = 0, DCI_UE = 1
|
||||||
}dci_spec_t;
|
} 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 {
|
typedef struct {
|
||||||
unsigned char nof_bits;
|
unsigned char nof_bits;
|
||||||
unsigned char L; // Aggregation level
|
unsigned char L; // Aggregation level
|
||||||
unsigned char ncce; // Position of first CCE of the dci
|
unsigned char ncce; // Position of first CCE of the dci
|
||||||
unsigned short rnti;
|
unsigned short rnti;
|
||||||
}dci_candidate_t;
|
} dci_candidate_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char data[DCI_MAX_BITS];
|
char data[DCI_MAX_BITS];
|
||||||
dci_candidate_t location;
|
dci_candidate_t location;
|
||||||
}dci_msg_t;
|
} dci_msg_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
dci_msg_t *msg;
|
dci_msg_t *msg;
|
||||||
int nof_dcis;
|
int nof_dcis;
|
||||||
}dci_t;
|
int max_dcis;
|
||||||
|
} dci_t;
|
||||||
|
|
||||||
|
int dci_init(dci_t *q, int max_dci);
|
||||||
int dci_init(dci_t *q, int nof_dci);
|
|
||||||
void dci_free(dci_t *q);
|
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);
|
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_msg_get_type(dci_msg_t *msg, dci_msg_type_t *type, int nof_prb, unsigned short crnti);
|
||||||
int dci_format0_sizeof(int nof_prb);
|
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);
|
// For dci_msg_type_t = PUSCH_SCHED
|
||||||
int dci_format1_sizeof(int nof_prb, int P);
|
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);
|
// For dci_msg_type_t = PDSCH_SCHED
|
||||||
int dci_format1A_sizeof(int nof_prb, bool random_access_initiated);
|
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_format_sizeof(dci_format_t format, int nof_prb);
|
||||||
int dci_format1C_sizeof();
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -35,7 +35,7 @@
|
||||||
#include "lte/modem/mod.h"
|
#include "lte/modem/mod.h"
|
||||||
#include "lte/modem/demod_soft.h"
|
#include "lte/modem/demod_soft.h"
|
||||||
#include "lte/scrambling/scrambling.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/convcoder.h"
|
||||||
#include "lte/fec/viterbi.h"
|
#include "lte/fec/viterbi.h"
|
||||||
#include "lte/fec/crc.h"
|
#include "lte/fec/crc.h"
|
||||||
|
@ -79,6 +79,7 @@ typedef struct {
|
||||||
demod_soft_t demod;
|
demod_soft_t demod;
|
||||||
sequence_t seq_pbch;
|
sequence_t seq_pbch;
|
||||||
viterbi_t decoder;
|
viterbi_t decoder;
|
||||||
|
crc_t crc;
|
||||||
convcoder_t encoder;
|
convcoder_t encoder;
|
||||||
|
|
||||||
}pbch_t;
|
}pbch_t;
|
||||||
|
|
|
@ -35,7 +35,7 @@
|
||||||
#include "lte/modem/mod.h"
|
#include "lte/modem/mod.h"
|
||||||
#include "lte/modem/demod_soft.h"
|
#include "lte/modem/demod_soft.h"
|
||||||
#include "lte/scrambling/scrambling.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/convcoder.h"
|
||||||
#include "lte/fec/viterbi.h"
|
#include "lte/fec/viterbi.h"
|
||||||
#include "lte/fec/crc.h"
|
#include "lte/fec/crc.h"
|
||||||
|
@ -88,7 +88,7 @@ typedef struct {
|
||||||
demod_soft_t demod;
|
demod_soft_t demod;
|
||||||
sequence_t seq_pdcch[NSUBFRAMES_X_FRAME];
|
sequence_t seq_pdcch[NSUBFRAMES_X_FRAME];
|
||||||
viterbi_t decoder;
|
viterbi_t decoder;
|
||||||
|
crc_t crc;
|
||||||
}pdcch_t;
|
}pdcch_t;
|
||||||
|
|
||||||
int pdcch_init(pdcch_t *q, regs_t *regs, int nof_prb, int nof_ports, int cell_id, lte_cp_t cp);
|
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 cell_id;
|
||||||
int nof_prb;
|
int nof_prb;
|
||||||
int max_ctrl_symbols;
|
int max_ctrl_symbols;
|
||||||
|
int cfi;
|
||||||
int ngroups_phich;
|
int ngroups_phich;
|
||||||
int refs_in_symbol1;
|
int nof_ports;
|
||||||
lte_cp_t cp;
|
lte_cp_t cp;
|
||||||
phich_resources_t phich_res;
|
phich_resources_t phich_res;
|
||||||
phich_length_t phich_len;
|
phich_length_t phich_len;
|
||||||
int nof_cce;
|
|
||||||
regs_ch_t pcfich;
|
regs_ch_t pcfich;
|
||||||
regs_ch_t *phich; // there are several phich
|
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;
|
int nof_regs;
|
||||||
regs_reg_t *regs;
|
regs_reg_t *regs;
|
||||||
}regs_t;
|
}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);
|
phich_resources_t phich_res, phich_length_t phich_len, lte_cp_t cp);
|
||||||
void regs_free(regs_t *h);
|
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_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_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_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_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_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_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_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_ngroups(regs_t *h);
|
||||||
int regs_phich_reset(regs_t *h, cf_t *slot_symbols);
|
int regs_phich_reset(regs_t *h, cf_t *slot_symbols);
|
||||||
|
|
||||||
int regs_pdcch_nregs(regs_t *h);
|
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
|
#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_pack(uint32_t value, char **bits, int nof_bits);
|
||||||
void bit_fprint(FILE *stream, 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);
|
unsigned int bit_diff(char *x, char *y, int nbits);
|
||||||
|
int bit_count(unsigned int n);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -41,8 +41,8 @@ void get_time_interval(struct timeval * tdata);
|
||||||
|
|
||||||
extern int verbose;
|
extern int verbose;
|
||||||
|
|
||||||
#define VERBOSE_ISINFO() (verbose==VERBOSE_INFO)
|
#define VERBOSE_ISINFO() (verbose>=VERBOSE_INFO)
|
||||||
#define VERBOSE_ISDEBUG() (verbose==VERBOSE_DEBUG)
|
#define VERBOSE_ISDEBUG() (verbose>=VERBOSE_DEBUG)
|
||||||
|
|
||||||
#define PRINT_DEBUG verbose=VERBOSE_DEBUG
|
#define PRINT_DEBUG verbose=VERBOSE_DEBUG
|
||||||
#define PRINT_INFO verbose=VERBOSE_INFO
|
#define PRINT_INFO verbose=VERBOSE_INFO
|
||||||
|
|
|
@ -34,6 +34,43 @@
|
||||||
|
|
||||||
#include "lte/common/base.h"
|
#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) {
|
const int lte_symbol_sz(int nof_prb) {
|
||||||
if (nof_prb<=0) {
|
if (nof_prb<=0) {
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -135,7 +172,7 @@ struct lte_band lte_bands[NOF_LTE_BANDS] = {
|
||||||
};
|
};
|
||||||
#define EOF_BAND 9919
|
#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")) {
|
if (!strcmp(mimo_type_str, "single")) {
|
||||||
*type = SINGLE_ANTENNA;
|
*type = SINGLE_ANTENNA;
|
||||||
} else if (!strcmp(mimo_type_str, "diversity")) {
|
} else if (!strcmp(mimo_type_str, "diversity")) {
|
||||||
|
@ -148,7 +185,7 @@ int lte_str2mimotype(char *mimo_type_str, mimo_type_t *type) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *lte_mimotype2str(mimo_type_t type) {
|
char *lte_mimotype2str(lte_mimo_type_t type) {
|
||||||
switch(type) {
|
switch(type) {
|
||||||
case SINGLE_ANTENNA:
|
case SINGLE_ANTENNA:
|
||||||
return "single";
|
return "single";
|
||||||
|
|
|
@ -122,7 +122,7 @@ int main(int argc, char **argv) {
|
||||||
}
|
}
|
||||||
printf("MSE=%f\n", mse);
|
printf("MSE=%f\n", mse);
|
||||||
|
|
||||||
if (mse >= 0.05) {
|
if (mse >= 0.07) {
|
||||||
printf("MSE too large\n");
|
printf("MSE too large\n");
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,66 +25,141 @@
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
unsigned int cword;
|
#include "lte/utils/pack.h"
|
||||||
|
#include "lte/fec/crc.h"
|
||||||
|
|
||||||
unsigned int icrc1(unsigned int crc, unsigned short onech,int long_crc,
|
void gen_crc_table(crc_t *h) {
|
||||||
int left_shift,unsigned int poly)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
unsigned int tmp=(unsigned int) (crc ^ (onech << (long_crc >> 1) ));
|
|
||||||
|
|
||||||
for (i=0;i<left_shift;i++) {
|
int i, j, ord = (h->order - 8);
|
||||||
if (tmp & (0x1<<(long_crc-1)))
|
unsigned long bit, crc;
|
||||||
tmp=(tmp<<1)^poly;
|
|
||||||
else
|
|
||||||
tmp <<= 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return tmp;
|
for (i = 0; i < 256; i++) {
|
||||||
|
crc = ((unsigned long) i) << ord;
|
||||||
|
for (j = 0; j < 8; j++) {
|
||||||
|
bit = crc & h->crchighbit;
|
||||||
|
crc <<= 1;
|
||||||
|
if (bit)
|
||||||
|
crc ^= h->polynom;
|
||||||
|
}
|
||||||
|
h->table[i] = crc & h->crcmask;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int crc(unsigned int crc, char *bufptr, int len,
|
unsigned long crctable(crc_t *h) {
|
||||||
int long_crc,unsigned int poly, int paste_word) {
|
|
||||||
|
|
||||||
int i,k;
|
// Polynom order 8, 16, 24 or 32 only.
|
||||||
unsigned int data;
|
int ord = h->order - 8;
|
||||||
int stop;
|
unsigned long crc = h->crcinit;
|
||||||
unsigned int ret;
|
unsigned char byte = h->byte;
|
||||||
|
|
||||||
cword=crc;
|
crc = (crc << 8) ^ h->table[((crc >> (ord)) & 0xff) ^ byte];
|
||||||
|
h->crcinit = crc;
|
||||||
k=0;
|
return (crc & h->crcmask);
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cword=(unsigned int) (icrc1((unsigned int) (cword<<long_crc>>long_crc),
|
|
||||||
data,long_crc,i,poly)<<long_crc)>>long_crc;
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return (ret);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned long reversecrcbit(unsigned int crc, int nbits, crc_t *h) {
|
||||||
|
|
||||||
|
unsigned long m, rmask = 0x1;
|
||||||
|
|
||||||
|
for (m = 0; m < nbits; m++) {
|
||||||
|
if ((rmask & crc) == 0x01)
|
||||||
|
crc = (crc ^ h->polynom) >> 1;
|
||||||
|
else
|
||||||
|
crc = crc >> 1;
|
||||||
|
}
|
||||||
|
return (crc & h->crcmask);
|
||||||
|
}
|
||||||
|
|
||||||
|
int crc_set_init(crc_t *crc_par, unsigned long crc_init_value) {
|
||||||
|
|
||||||
|
crc_par->crcinit = crc_init_value;
|
||||||
|
if (crc_par->crcinit != (crc_par->crcinit & crc_par->crcmask)) {
|
||||||
|
printf("ERROR, invalid crcinit in crc_set_init().\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int crc_init(crc_t *h, unsigned int crc_poly, int crc_order) {
|
||||||
|
|
||||||
|
// Set crc working default parameters
|
||||||
|
h->polynom = crc_poly;
|
||||||
|
h->order = crc_order;
|
||||||
|
h->crcinit = 0x00000000;
|
||||||
|
|
||||||
|
// Compute bit masks for whole CRC and CRC high bit
|
||||||
|
h->crcmask = ((((unsigned long) 1 << (h->order - 1)) - 1) << 1)
|
||||||
|
| 1;
|
||||||
|
h->crchighbit = (unsigned long) 1 << (h->order - 1);
|
||||||
|
|
||||||
|
// check parameters
|
||||||
|
if (h->order % 8 != 0) {
|
||||||
|
fprintf(stderr, "ERROR, invalid order=%d, it must be 8, 16, 24 or 32.\n",
|
||||||
|
h->order);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (crc_set_init(h, h->crcinit)) {
|
||||||
|
fprintf(stderr, "Error setting CRC init word\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// generate lookup table
|
||||||
|
gen_crc_table(h);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int crc_checksum(crc_t *h, char *data, int len) {
|
||||||
|
int i, k, len8, res8, a = 0;
|
||||||
|
unsigned int crc = 0;
|
||||||
|
char *pter;
|
||||||
|
|
||||||
|
crc_set_init(h, 0);
|
||||||
|
|
||||||
|
// Pack bits into bytes
|
||||||
|
len8 = (len >> 3);
|
||||||
|
res8 = (len - (len8 << 3));
|
||||||
|
if (res8 > 0) {
|
||||||
|
a = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate CRC
|
||||||
|
for (i = 0; i < len8 + a; i++) {
|
||||||
|
pter = (char *) (data + 8 * i);
|
||||||
|
if (i == len8) {
|
||||||
|
h->byte = 0x00;
|
||||||
|
for (k = 0; k < res8; k++) {
|
||||||
|
h->byte |= ((unsigned char) *(pter + k)) << (7 - k);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
h->byte = (unsigned char) (unpack_bits(&pter, 8) & 0xFF);
|
||||||
|
}
|
||||||
|
crc = crctable(h);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reverse CRC res8 positions
|
||||||
|
if (a == 1) {
|
||||||
|
crc = reversecrcbit(crc, 8 - res8, h);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Return CRC value
|
||||||
|
return crc;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Appends crc_order checksum bits to the buffer data.
|
||||||
|
* The buffer data must be len + crc_order bytes
|
||||||
|
*/
|
||||||
|
void crc_attach(crc_t *h, char *data, int len) {
|
||||||
|
unsigned int checksum = crc_checksum(h, data, len);
|
||||||
|
|
||||||
|
// Add CRC
|
||||||
|
char *ptr = &data[len];
|
||||||
|
pack_bits(checksum, &ptr, h->order);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
/* Determine parity of argument: 1 = odd, 0 = even */
|
/* Determine parity of argument: 1 = odd, 0 = even */
|
||||||
#ifdef __i386__
|
#ifdef __i386__
|
||||||
static inline int parityb(unsigned char x){
|
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;
|
return x;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
|
|
|
@ -28,20 +28,20 @@
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include "lte/ratematching/rm_conv.h"
|
#include "lte/fec/rm_conv.h"
|
||||||
|
|
||||||
#define NCOLS 32
|
#define NCOLS 32
|
||||||
#define NROWS_MAX NCOLS
|
#define NROWS_MAX NCOLS
|
||||||
#define RATE 3
|
#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,
|
{ 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 };
|
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,
|
10, 22, 6, 30, 14, 17, 1, 25, 9, 21, 5, 29, 13, 19, 3, 27, 11, 23, 7,
|
||||||
31, 15 };
|
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];
|
char tmp[RATE * NCOLS * NROWS_MAX];
|
||||||
int nrows, ndummy, K_p;
|
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) {
|
if (ndummy < 0) {
|
||||||
ndummy = 0;
|
ndummy = 0;
|
||||||
}
|
}
|
||||||
|
/* Sub-block interleaver 5.1.4.2.1 */
|
||||||
k=0;
|
k=0;
|
||||||
for (s = 0; s < 3; s++) {
|
for (s = 0; s < 3; s++) {
|
||||||
for (j = 0; j < NCOLS; j++) {
|
for (j = 0; j < NCOLS; j++) {
|
||||||
for (i = 0; i < nrows; i++) {
|
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;
|
tmp[k] = TX_NULL;
|
||||||
} else {
|
} 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++;
|
k++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/* Bit collection, selection and transmission 5.1.4.2.2 */
|
||||||
k = 0;
|
k = 0;
|
||||||
j = 0;
|
j = 0;
|
||||||
while (k < out_len) {
|
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.
|
/* Undoes Convolutional Code Rate Matching.
|
||||||
* 3GPP TS 36.212 v10.1.0 section 5.1.4.2
|
* 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 nrows, ndummy, K_p;
|
||||||
int i, j, k;
|
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_i = (j % K_p) / nrows;
|
||||||
d_j = (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) {
|
if (tmp[j] == RX_NULL) {
|
||||||
tmp[j] = input[k];
|
tmp[j] = input[k];
|
||||||
} else if (input[k] != RX_NULL) {
|
} 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_i = (i + ndummy) / NCOLS;
|
||||||
d_j = (i + ndummy) % NCOLS;
|
d_j = (i + ndummy) % NCOLS;
|
||||||
for (j = 0; j < RATE; j++) {
|
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];
|
+ d_i];
|
||||||
|
if (o != RX_NULL) {
|
||||||
|
output[i * RATE + j] = o;
|
||||||
|
} else {
|
||||||
|
output[i * RATE + j] = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 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/.
|
# 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
|
# 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)
|
ADD_EXECUTABLE(crc_test crc_test.c)
|
||||||
TARGET_LINK_LIBRARIES(crc_test lte)
|
TARGET_LINK_LIBRARIES(crc_test lte)
|
||||||
|
|
||||||
ADD_TEST(crc_24A crc_test -n 5000 -l 24 -p 0x1864CFB -s 1)
|
ADD_TEST(crc_24A crc_test -n 5001 -l 24 -p 0x1864CFB -s 1)
|
||||||
ADD_TEST(crc_24B crc_test -n 5000 -l 24 -p 0x1800063 -s 1)
|
ADD_TEST(crc_24B crc_test -n 5001 -l 24 -p 0x1800063 -s 1)
|
||||||
ADD_TEST(crc_16 crc_test -n 5000 -l 16 -p 0x11021 -s 1)
|
ADD_TEST(crc_16 crc_test -n 5001 -l 16 -p 0x11021 -s 1)
|
||||||
ADD_TEST(crc_8 crc_test -n 5000 -l 8 -p 0x19B -s 1)
|
ADD_TEST(crc_8 crc_test -n 5001 -l 8 -p 0x19B -s 1)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,6 @@
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
@ -35,13 +34,11 @@
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
#include "lte.h"
|
#include "lte.h"
|
||||||
|
|
||||||
#include "crc_test.h"
|
#include "crc_test.h"
|
||||||
|
|
||||||
int num_bits = 1000, crc_length = 16;
|
int num_bits = 5001, crc_length = 24;
|
||||||
unsigned int crc_poly = 0x11021;
|
unsigned int crc_poly = 0x1864CFB;
|
||||||
unsigned int seed = 0;
|
unsigned int seed = 1;
|
||||||
|
|
||||||
|
|
||||||
void usage(char *prog) {
|
void usage(char *prog) {
|
||||||
printf("Usage: %s [nlps]\n", prog);
|
printf("Usage: %s [nlps]\n", prog);
|
||||||
|
@ -78,10 +75,11 @@ int main(int argc, char **argv) {
|
||||||
int i;
|
int i;
|
||||||
char *data;
|
char *data;
|
||||||
unsigned int crc_word, expected_word;
|
unsigned int crc_word, expected_word;
|
||||||
|
crc_t crc_p;
|
||||||
|
|
||||||
parse_args(argc, argv);
|
parse_args(argc, argv);
|
||||||
|
|
||||||
data = malloc(sizeof(char) * (num_bits+crc_length));
|
data = malloc(sizeof(char) * (num_bits + crc_length * 2));
|
||||||
if (!data) {
|
if (!data) {
|
||||||
perror("malloc");
|
perror("malloc");
|
||||||
exit(-1);
|
exit(-1);
|
||||||
|
@ -93,25 +91,23 @@ int main(int argc, char **argv) {
|
||||||
srand(seed);
|
srand(seed);
|
||||||
|
|
||||||
// Generate data
|
// Generate data
|
||||||
for (i=0;i<num_bits;i++) {
|
for (i = 0; i < num_bits; i++) {
|
||||||
data[i] = rand()%2;
|
data[i] = rand() % 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
// generate CRC word
|
//Initialize CRC params and tables
|
||||||
crc_word = crc(0, data, num_bits, crc_length, crc_poly, 1);
|
if (crc_init(&crc_p, crc_poly, crc_length)) {
|
||||||
|
|
||||||
// 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");
|
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// generate CRC word
|
||||||
|
crc_word = crc_checksum(&crc_p, data, num_bits);
|
||||||
|
|
||||||
free(data);
|
free(data);
|
||||||
|
|
||||||
printf("CRC word: 0x%x\n", crc_word);
|
|
||||||
|
|
||||||
// check if generated word is as expected
|
// 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");
|
fprintf(stderr, "Test parameters not defined in test_results.h\n");
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,10 +39,11 @@ typedef struct {
|
||||||
|
|
||||||
|
|
||||||
static expected_word_t expected_words[] = {
|
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
|
{5001, 24, LTE_CRC24A, 1, 0x1C5C97}, // LTE CRC24A (36.212 Sec 5.1.1)
|
||||||
{5000, 16, LTE_CRC16, 1, 0xBFFA}, // LTE CRC16
|
{5001, 24, LTE_CRC24B, 1, 0x36D1F0}, // LTE CRC24B
|
||||||
{5000, 8, LTE_CRC8, 1, 0xF8}, // LTE CRC8
|
{5001, 16, LTE_CRC16, 1, 0x7FF4}, // LTE CRC16: 0x7FF4
|
||||||
|
{5001, 8, LTE_CRC8, 1, 0xF0}, // LTE CRC8 0xF8
|
||||||
|
|
||||||
{-1, -1, 0, 0, 0}
|
{-1, -1, 0, 0, 0}
|
||||||
};
|
};
|
||||||
|
|
|
@ -100,7 +100,7 @@ int main(int argc, char **argv) {
|
||||||
bits[i] = rand()%2;
|
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);
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -108,7 +108,7 @@ int main(int argc, char **argv) {
|
||||||
rm_symbols[i] = rm_bits[i]?1:-1;
|
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);
|
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;
|
typedef _Complex float cf_t;
|
||||||
|
|
||||||
int frame_length = 1000, nof_slots = 128;
|
int frame_length = 1000, nof_frames = 128;
|
||||||
float ebno_db = 100.0;
|
float ebno_db = 100.0;
|
||||||
unsigned int seed = 0;
|
unsigned int seed = 0;
|
||||||
bool tail_biting = false;
|
bool tail_biting = false;
|
||||||
|
@ -54,7 +54,7 @@ int K = -1;
|
||||||
|
|
||||||
void usage(char *prog) {
|
void usage(char *prog) {
|
||||||
printf("Usage: %s [nlestk]\n", 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-l frame_length [Default %d]\n", frame_length);
|
||||||
printf("\t-e ebno in dB [Default scan]\n");
|
printf("\t-e ebno in dB [Default scan]\n");
|
||||||
printf("\t-s seed [Default 0=time]\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) {
|
while ((opt = getopt(argc, argv, "nlstek")) != -1) {
|
||||||
switch (opt) {
|
switch (opt) {
|
||||||
case 'n':
|
case 'n':
|
||||||
nof_slots = atoi(argv[optind]);
|
nof_frames = atoi(argv[optind]);
|
||||||
break;
|
break;
|
||||||
case 'l':
|
case 'l':
|
||||||
frame_length = atoi(argv[optind]);
|
frame_length = atoi(argv[optind]);
|
||||||
|
@ -254,7 +254,7 @@ int main(int argc, char **argv) {
|
||||||
for (j = 0; j < NTYPES; j++) {
|
for (j = 0; j < NTYPES; j++) {
|
||||||
errors[j] = 0;
|
errors[j] = 0;
|
||||||
}
|
}
|
||||||
while (frame_cnt < nof_slots) {
|
while (frame_cnt < nof_frames) {
|
||||||
|
|
||||||
/* generate data_tx */
|
/* generate data_tx */
|
||||||
for (j = 0; j < frame_length; j++) {
|
for (j = 0; j < frame_length; j++) {
|
||||||
|
@ -291,7 +291,7 @@ int main(int argc, char **argv) {
|
||||||
}
|
}
|
||||||
frame_cnt++;
|
frame_cnt++;
|
||||||
printf("Eb/No: %3.2f %10d/%d ",
|
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++) {
|
for (n=0;n<1+ncods;n++) {
|
||||||
printf("BER: %.2e ",(float) errors[n] / (frame_cnt * frame_length));
|
printf("BER: %.2e ",(float) errors[n] / (frame_cnt * frame_length));
|
||||||
}
|
}
|
||||||
|
@ -324,7 +324,7 @@ int main(int argc, char **argv) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (snr_points == 1) {
|
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);
|
seed, frame_length, K, tail_biting, ebno_db);
|
||||||
if (expected_errors == -1) {
|
if (expected_errors == -1) {
|
||||||
fprintf(stderr, "Test parameters not defined in test_results.h\n");
|
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)
|
* 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 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) {
|
if (nof_cw > MAX_CODEWORDS) {
|
||||||
fprintf(stderr, "Maximum number of codewords is %d (nof_cw=%d)\n", MAX_CODEWORDS, nof_cw);
|
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
|
* 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 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) {
|
if (nof_cw > MAX_CODEWORDS) {
|
||||||
fprintf(stderr, "Maximum number of codewords is %d (nof_cw=%d)\n", MAX_CODEWORDS, nof_cw);
|
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 */
|
/* 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,
|
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) {
|
if (nof_ports > MAX_PORTS) {
|
||||||
fprintf(stderr, "Maximum number of ports is %d (nof_ports=%d)\n", MAX_PORTS, nof_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 */
|
/* 36.211 v10.3.0 Section 6.3.4 */
|
||||||
int predecoding_type(cf_t *y[MAX_PORTS], cf_t *ce[MAX_PORTS],
|
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) {
|
if (nof_ports > MAX_PORTS) {
|
||||||
fprintf(stderr, "Maximum number of ports is %d (nof_ports=%d)\n", MAX_PORTS, nof_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 main(int argc, char **argv) {
|
||||||
int i, j, num_errors, symbols_layer;
|
int i, j, num_errors, symbols_layer;
|
||||||
cf_t *d[MAX_CODEWORDS], *x[MAX_LAYERS], *dp[MAX_CODEWORDS];
|
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 nof_symb_cw[MAX_CODEWORDS];
|
||||||
int n[2];
|
int n[2];
|
||||||
|
|
||||||
|
|
|
@ -78,7 +78,7 @@ int main(int argc, char **argv) {
|
||||||
int i, j;
|
int i, j;
|
||||||
float mse;
|
float mse;
|
||||||
cf_t *x[MAX_LAYERS], *r[MAX_PORTS], *y[MAX_PORTS], *h[MAX_PORTS], *xr[MAX_LAYERS];
|
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);
|
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) {
|
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) {
|
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/vector.h"
|
||||||
#include "lte/utils/debug.h"
|
#include "lte/utils/debug.h"
|
||||||
|
|
||||||
|
int dci_init(dci_t *q, int max_dcis) {
|
||||||
int dci_init(dci_t *q, int nof_dcis) {
|
q->msg = calloc(sizeof(dci_msg_t), max_dcis);
|
||||||
q->msg = calloc(sizeof(dci_msg_t), nof_dcis);
|
|
||||||
if (!q->msg) {
|
if (!q->msg) {
|
||||||
perror("malloc");
|
perror("malloc");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
q->nof_dcis = nof_dcis;
|
q->nof_dcis = 0;
|
||||||
|
q->max_dcis = max_dcis;
|
||||||
return 0;
|
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);
|
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 dci_msg_candidate_set(dci_msg_t *msg, int L, int nCCE, unsigned short rnti) {
|
||||||
int i, j;
|
if (L >= 0 && L <=3) {
|
||||||
i=0;
|
msg->location.L = (unsigned char) L;
|
||||||
while(i<q->nof_dcis && q->msg[i].location.nof_bits)
|
} else {
|
||||||
i++;
|
fprintf(stderr, "Invalid L %d\n", L);
|
||||||
if (i == q->nof_dcis) {
|
|
||||||
fprintf(stderr, "No more space in DCI container\n");
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
q->msg[i].location.L = L;
|
if (nCCE >= 0 && nCCE <= 87) {
|
||||||
q->msg[i].location.ncce = nCCE;
|
msg->location.ncce = (unsigned char) nCCE;
|
||||||
q->msg[i].location.nof_bits = dci_format1_sizeof(6, 1);
|
} else {
|
||||||
q->msg[i].location.rnti = rnti;
|
fprintf(stderr, "Invalid nCCE %d\n", nCCE);
|
||||||
for (j=0;j<q->msg[i].location.nof_bits;j++) {
|
return -1;
|
||||||
q->msg[i].data[j] = rand()%2;
|
|
||||||
}
|
}
|
||||||
|
msg->location.rnti = rnti;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int dci_format0_add(dci_t *q, dci_format0_t *msg, int L, int nCCE, unsigned short rnti) {
|
int riv_nbits(int nof_prb) {
|
||||||
int i, j;
|
return (int) ceilf(log2f((float) nof_prb*((float) nof_prb+1)/2));
|
||||||
i=0;
|
|
||||||
while(i<q->nof_dcis && q->msg[i].location.nof_bits)
|
|
||||||
i++;
|
|
||||||
if (i == q->nof_dcis) {
|
|
||||||
fprintf(stderr, "No more space in DCI container\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
q->msg[i].location.L = L;
|
|
||||||
q->msg[i].location.ncce = nCCE;
|
|
||||||
q->msg[i].location.nof_bits = dci_format0_sizeof(msg->n_rb_ul);
|
|
||||||
q->msg[i].location.rnti = rnti;
|
|
||||||
for (j=0;j<q->msg[i].location.nof_bits;j++) {
|
|
||||||
q->msg[i].data[j] = rand()%2;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 dci_format0_sizeof(int nof_prb) {
|
||||||
return 1+1+(int) ceilf(log2f(nof_prb*(nof_prb+1)/2))+2+3+1;
|
int n = dci_format0_sizeof_(nof_prb);
|
||||||
|
while (n < dci_format1A_sizeof(nof_prb)) {
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
int dci_format1_sizeof(int nof_prb, int P) {
|
int dci_format1_sizeof(int nof_prb) {
|
||||||
return (nof_prb>10)?1:0+(int) ceilf(log2f(nof_prb/P))+5+3+1+2+2;
|
|
||||||
|
int n = (int) ceilf((float) nof_prb/ra_type0_P(nof_prb))+5+3+1+2+2;
|
||||||
|
if (nof_prb > 10) {
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
while(n == dci_format0_sizeof(nof_prb)
|
||||||
|
|| n == dci_format1A_sizeof(nof_prb)
|
||||||
|
|| is_ambiguous_size(n)) {
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
int dci_format1A_sizeof(int nof_prb, bool random_access_initiated) {
|
int dci_format1C_sizeof(int nof_prb) {
|
||||||
if (random_access_initiated) {
|
int n_vrb_dl_gap1 = ra_type2_n_vrb_dl(nof_prb, true);
|
||||||
return 1+(int) ceilf(log2f(nof_prb*(nof_prb+1)/2))+6+4;
|
int n_step = ra_type2_n_rb_step(nof_prb);
|
||||||
} else {
|
int n = + riv_nbits((int) n_vrb_dl_gap1/n_step) + 5;
|
||||||
return 1+(int) ceilf(log2f(nof_prb*(nof_prb+1)/2))+5+3+1+2+2;
|
if (nof_prb >= 50) {
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dci_format_sizeof(dci_format_t format, int nof_prb) {
|
||||||
|
switch(format) {
|
||||||
|
case Format0:
|
||||||
|
return dci_format0_sizeof(nof_prb);
|
||||||
|
case Format1:
|
||||||
|
return dci_format1_sizeof(nof_prb);
|
||||||
|
case Format1A:
|
||||||
|
return dci_format1A_sizeof(nof_prb);
|
||||||
|
case Format1C:
|
||||||
|
return dci_format1C_sizeof(nof_prb);
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int dci_format1C_sizeof() {
|
|
||||||
return 10;
|
|
||||||
|
/**********************************
|
||||||
|
* DCI Resource Allocation functions
|
||||||
|
* ********************************/
|
||||||
|
|
||||||
|
|
||||||
|
/* Packs DCI format 0 data to a sequence of bits and store them in msg according
|
||||||
|
* to 36.212 5.3.3.1.1
|
||||||
|
*
|
||||||
|
* TODO: TPC and cyclic shift for DM RS not implemented
|
||||||
|
*/
|
||||||
|
int dci_format0_pack(ra_pusch_t *data, dci_msg_t *msg, int nof_prb) {
|
||||||
|
|
||||||
|
/* pack bits */
|
||||||
|
char *y = msg->data;
|
||||||
|
int n_ul_hop;
|
||||||
|
|
||||||
|
*y++ = 0; // format differentiation
|
||||||
|
if (data->freq_hop_fl == hop_disabled) { // frequency hopping
|
||||||
|
*y++ = 0;
|
||||||
|
n_ul_hop = 0;
|
||||||
|
} else {
|
||||||
|
*y++ = 1;
|
||||||
|
if (nof_prb < 50) {
|
||||||
|
n_ul_hop = 1; // Table 8.4-1 of 36.213
|
||||||
|
*y++ = data->freq_hop_fl & 1;
|
||||||
|
} else {
|
||||||
|
n_ul_hop = 2; // Table 8.4-1 of 36.213
|
||||||
|
*y++ = (data->freq_hop_fl & 2) >> 1;
|
||||||
|
*y++ = data->freq_hop_fl & 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* pack RIV according to 8.1 of 36.213 */
|
||||||
|
uint32_t riv;
|
||||||
|
if (data->type2_alloc.L_crb) {
|
||||||
|
riv = ra_type2_to_riv(data->type2_alloc.L_crb, data->type2_alloc.RB_start, nof_prb);
|
||||||
|
} else {
|
||||||
|
riv = data->type2_alloc.riv;
|
||||||
|
}
|
||||||
|
bit_pack(riv, &y, riv_nbits(nof_prb) - n_ul_hop);
|
||||||
|
|
||||||
|
/* pack MCS according to 8.6.1 of 36.213 */
|
||||||
|
uint32_t mcs;
|
||||||
|
if (data->cqi_request) {
|
||||||
|
mcs = 29;
|
||||||
|
} else {
|
||||||
|
if (data->rv_idx) {
|
||||||
|
mcs = 28 + data->rv_idx;
|
||||||
|
} else {
|
||||||
|
if (data->mcs.mod == MOD_NULL) {
|
||||||
|
mcs = data->mcs.mcs_idx;
|
||||||
|
} else {
|
||||||
|
if (data->mcs.tbs) {
|
||||||
|
if (data->mcs.tbs) {
|
||||||
|
data->mcs.tbs_idx = ra_tbs_to_table_idx(data->mcs.tbs, ra_nprb_ul(data, nof_prb));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mcs = ra_mcs_to_table_idx(&data->mcs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bit_pack(mcs, &y, 5);
|
||||||
|
|
||||||
|
*y++ = data->ndi;
|
||||||
|
|
||||||
|
// TCP commands not implemented
|
||||||
|
*y++ = 0;
|
||||||
|
*y++ = 0;
|
||||||
|
|
||||||
|
// DM RS not implemented
|
||||||
|
*y++ = 0;
|
||||||
|
*y++ = 0;
|
||||||
|
*y++ = 0;
|
||||||
|
|
||||||
|
// CQI request
|
||||||
|
*y++ = data->cqi_request;
|
||||||
|
|
||||||
|
// Padding with zeros
|
||||||
|
int n = dci_format0_sizeof(nof_prb);
|
||||||
|
while (y-msg->data < n) {
|
||||||
|
*y++ = 0;
|
||||||
|
}
|
||||||
|
msg->location.nof_bits = (y - msg->data);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
/* Unpacks DCI format 0 data and store result in msg according
|
||||||
|
* to 36.212 5.3.3.1.1
|
||||||
|
*
|
||||||
|
* TODO: TPC and cyclic shift for DM RS not implemented
|
||||||
|
*/
|
||||||
|
int dci_format0_unpack(dci_msg_t *msg, ra_pusch_t *data, int nof_prb) {
|
||||||
|
|
||||||
|
/* pack bits */
|
||||||
|
char *y = msg->data;
|
||||||
|
int n_ul_hop;
|
||||||
|
|
||||||
|
/* Make sure it's a Format0 message */
|
||||||
|
if (msg->location.nof_bits != dci_format_sizeof(Format0, nof_prb)) {
|
||||||
|
fprintf(stderr, "Invalid message length for format 0\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (*y++ != 0) {
|
||||||
|
fprintf(stderr, "Invalid format differentiation field value. This is Format1A\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (*y++ == 0) {
|
||||||
|
data->freq_hop_fl = hop_disabled;
|
||||||
|
n_ul_hop = 0;
|
||||||
|
} else {
|
||||||
|
if (nof_prb < 50) {
|
||||||
|
n_ul_hop = 1; // Table 8.4-1 of 36.213
|
||||||
|
data->freq_hop_fl = *y++;
|
||||||
|
} else {
|
||||||
|
n_ul_hop = 2; // Table 8.4-1 of 36.213
|
||||||
|
data->freq_hop_fl = y[0]<<1 | y[1];
|
||||||
|
y += 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* unpack RIV according to 8.1 of 36.213 */
|
||||||
|
uint32_t riv = bit_unpack(&y, riv_nbits(nof_prb) - n_ul_hop);
|
||||||
|
ra_type2_from_riv(riv, &data->type2_alloc.L_crb, &data->type2_alloc.RB_start, nof_prb, nof_prb);
|
||||||
|
bit_pack(riv, &y, riv_nbits(nof_prb) - n_ul_hop);
|
||||||
|
data->type2_alloc.riv = riv;
|
||||||
|
|
||||||
|
/* unpack MCS according to 8.6 of 36.213 */
|
||||||
|
uint32_t mcs = bit_unpack(&y, 5);
|
||||||
|
|
||||||
|
data->ndi = *y++?true:false;
|
||||||
|
|
||||||
|
// TCP and DM RS commands not implemented
|
||||||
|
y+= 5;
|
||||||
|
|
||||||
|
// CQI request
|
||||||
|
data->cqi_request = *y++?true:false;
|
||||||
|
|
||||||
|
// 8.6.2 First paragraph
|
||||||
|
if (mcs <= 28) {
|
||||||
|
ra_mcs_from_idx_ul(mcs, &data->mcs);
|
||||||
|
data->mcs.tbs = ra_tbs_from_idx(data->mcs.tbs_idx, ra_nprb_ul(data, nof_prb));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 8.6.1 and 8.6.2 36.213 second paragraph
|
||||||
|
if (mcs == 29 && data->cqi_request && ra_nprb_ul(data, nof_prb) <= 4) {
|
||||||
|
data->mcs.mod = QPSK;
|
||||||
|
}
|
||||||
|
if (mcs > 29) {
|
||||||
|
// Else leave MOD_NULL and use the previously used PUSCH modulation
|
||||||
|
data->mcs.mod = MOD_NULL;
|
||||||
|
data->rv_idx = mcs - 28;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Packs DCI format 1 data to a sequence of bits and store them in msg according
|
||||||
|
* to 36.212 5.3.3.1.2
|
||||||
|
*
|
||||||
|
* TODO: TPC commands
|
||||||
|
*/
|
||||||
|
|
||||||
|
int dci_format1_pack(ra_pdsch_t *data, dci_msg_t *msg, int nof_prb) {
|
||||||
|
|
||||||
|
/* pack bits */
|
||||||
|
char *y = msg->data;
|
||||||
|
|
||||||
|
if (nof_prb > 10) {
|
||||||
|
*y++ = data->alloc_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Resource allocation: type0 or type 1 */
|
||||||
|
int P = ra_type0_P(nof_prb);
|
||||||
|
int alloc_size = (int) ceilf((float) nof_prb/P);
|
||||||
|
switch(data->alloc_type) {
|
||||||
|
case alloc_type0:
|
||||||
|
bit_pack(data->type0_alloc.rbg_bitmask, &y, alloc_size);
|
||||||
|
break;
|
||||||
|
case alloc_type1:
|
||||||
|
bit_pack(data->type1_alloc.rbg_subset, &y, (int) ceilf(log2f(P)));
|
||||||
|
*y++ = data->type1_alloc.shift?1:0;
|
||||||
|
bit_pack(data->type1_alloc.vrb_bitmask, &y, alloc_size - (int) ceilf(log2f(P)) - 1);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
fprintf(stderr, "Format 1 accepts type0 or type1 resource allocation only\n");
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
}
|
||||||
|
/* pack MCS according to 7.1.7 of 36.213 */
|
||||||
|
uint32_t mcs;
|
||||||
|
if (data->mcs.mod == MOD_NULL) {
|
||||||
|
mcs = data->mcs.mcs_idx;
|
||||||
|
} else {
|
||||||
|
if (data->mcs.tbs) {
|
||||||
|
data->mcs.tbs_idx = ra_tbs_to_table_idx(data->mcs.tbs, ra_nprb_dl(data, nof_prb));
|
||||||
|
}
|
||||||
|
mcs = ra_mcs_to_table_idx(&data->mcs);
|
||||||
|
}
|
||||||
|
bit_pack(mcs, &y, 5);
|
||||||
|
|
||||||
|
/* harq process number */
|
||||||
|
bit_pack(data->harq_process, &y, 3);
|
||||||
|
|
||||||
|
*y++ = data->ndi;
|
||||||
|
|
||||||
|
// rv version
|
||||||
|
bit_pack(data->rv_idx, &y, 2);
|
||||||
|
|
||||||
|
// TPC not implemented
|
||||||
|
*y++ = 0;
|
||||||
|
*y++ = 0;
|
||||||
|
|
||||||
|
// Padding with zeros
|
||||||
|
int n = dci_format1_sizeof(nof_prb);
|
||||||
|
while (y-msg->data < n) {
|
||||||
|
*y++ = 0;
|
||||||
|
}
|
||||||
|
msg->location.nof_bits = (y - msg->data);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dci_format1_unpack(dci_msg_t *msg, ra_pdsch_t *data, int nof_prb) {
|
||||||
|
|
||||||
|
/* pack bits */
|
||||||
|
char *y = msg->data;
|
||||||
|
|
||||||
|
/* Make sure it's a Format1 message */
|
||||||
|
if (msg->location.nof_bits != dci_format_sizeof(Format1, nof_prb)) {
|
||||||
|
fprintf(stderr, "Invalid message length for format 1\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nof_prb > 10) {
|
||||||
|
data->alloc_type = *y++;
|
||||||
|
} else {
|
||||||
|
data->alloc_type = alloc_type0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Resource allocation: type0 or type 1 */
|
||||||
|
int P = ra_type0_P(nof_prb);
|
||||||
|
int alloc_size = (int) ceilf((float) nof_prb/P);
|
||||||
|
switch(data->alloc_type) {
|
||||||
|
case alloc_type0:
|
||||||
|
data->type0_alloc.rbg_bitmask = bit_unpack(&y, alloc_size);
|
||||||
|
break;
|
||||||
|
case alloc_type1:
|
||||||
|
data->type1_alloc.rbg_subset = bit_unpack(&y, (int) ceilf(log2f(P)));
|
||||||
|
data->type1_alloc.shift = *y++?true:false;
|
||||||
|
data->type1_alloc.vrb_bitmask = bit_unpack(&y, alloc_size - (int) ceilf(log2f(P)) - 1);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
fprintf(stderr, "Format 1 accepts type0 or type1 resource allocation only\n");
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
}
|
||||||
|
/* pack MCS according to 7.1.7 of 36.213 */
|
||||||
|
uint32_t mcs = bit_unpack(&y, 5);
|
||||||
|
data->mcs.mcs_idx = mcs;
|
||||||
|
ra_mcs_from_idx_dl(mcs, &data->mcs);
|
||||||
|
data->mcs.tbs = ra_tbs_from_idx(data->mcs.tbs_idx, ra_nprb_dl(data, nof_prb));
|
||||||
|
|
||||||
|
/* harq process number */
|
||||||
|
data->harq_process = bit_unpack(&y, 3);
|
||||||
|
|
||||||
|
data->ndi = *y++?true:false;
|
||||||
|
|
||||||
|
// rv version
|
||||||
|
data->rv_idx = bit_unpack(&y, 2);
|
||||||
|
|
||||||
|
// TPC not implemented
|
||||||
|
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Packs DCI format 1A for compact scheduling of PDSCH words according to 36.212 5.3.3.1.3
|
||||||
|
*
|
||||||
|
* TODO: RA procedure initiated by PDCCH, TPC commands
|
||||||
|
*/
|
||||||
|
int dci_format1As_pack(ra_pdsch_t *data, dci_msg_t *msg, int nof_prb, bool crc_is_crnti) {
|
||||||
|
|
||||||
|
/* pack bits */
|
||||||
|
char *y = msg->data;
|
||||||
|
|
||||||
|
*y++ = 1; // format differentiation
|
||||||
|
|
||||||
|
if (data->alloc_type != alloc_type2) {
|
||||||
|
fprintf(stderr, "Format 1A accepts type2 resource allocation only\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
*y++ = data->type2_alloc.mode; // localized or distributed VRB assignment
|
||||||
|
|
||||||
|
if (data->type2_alloc.mode == t2_loc) {
|
||||||
|
if (data->type2_alloc.L_crb > nof_prb) {
|
||||||
|
fprintf(stderr, "L_CRB=%d can not exceed system BW for localized type2\n", data->type2_alloc.L_crb);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
int n_vrb_dl;
|
||||||
|
if (crc_is_crnti && nof_prb > 50) {
|
||||||
|
n_vrb_dl = 16;
|
||||||
|
} else {
|
||||||
|
n_vrb_dl = ra_type2_n_vrb_dl(nof_prb, data->type2_alloc.n_gap==t2_ng1);
|
||||||
|
}
|
||||||
|
if (data->type2_alloc.L_crb > n_vrb_dl) {
|
||||||
|
fprintf(stderr, "L_CRB=%d can not exceed N_vrb_dl=%d for distributed type2\n", data->type2_alloc.L_crb, n_vrb_dl);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* pack RIV according to 7.1.6.3 of 36.213 */
|
||||||
|
uint32_t riv;
|
||||||
|
if (data->type2_alloc.L_crb) {
|
||||||
|
riv = ra_type2_to_riv(data->type2_alloc.L_crb, data->type2_alloc.RB_start, nof_prb);
|
||||||
|
} else {
|
||||||
|
riv = data->type2_alloc.riv;
|
||||||
|
}
|
||||||
|
int nb_gap = 0;
|
||||||
|
if (crc_is_crnti && data->type2_alloc.mode == t2_dist && nof_prb >= 50) {
|
||||||
|
nb_gap = 1;
|
||||||
|
*y++ = data->type2_alloc.n_gap;
|
||||||
|
}
|
||||||
|
bit_pack(riv, &y, riv_nbits(nof_prb)-nb_gap);
|
||||||
|
|
||||||
|
// in format1A, MCS = TBS according to 7.1.7.2 of 36.213
|
||||||
|
uint32_t mcs;
|
||||||
|
if (data->mcs.mod == MOD_NULL) {
|
||||||
|
mcs = data->mcs.mcs_idx;
|
||||||
|
} else {
|
||||||
|
if (data->mcs.tbs) {
|
||||||
|
// In format 1A, n_prb_1a is 2 or 3 if crc is not scrambled with C-RNTI
|
||||||
|
int n_prb;
|
||||||
|
if (!crc_is_crnti) {
|
||||||
|
n_prb = ra_nprb_dl(data, nof_prb);
|
||||||
|
} else {
|
||||||
|
n_prb = data->type2_alloc.n_prb1a==nprb1a_2?2:3;
|
||||||
|
}
|
||||||
|
data->mcs.tbs_idx = ra_tbs_to_table_idx(data->mcs.tbs, n_prb);
|
||||||
|
}
|
||||||
|
mcs = data->mcs.tbs_idx;
|
||||||
|
}
|
||||||
|
bit_pack(mcs, &y, 5);
|
||||||
|
|
||||||
|
bit_pack(data->harq_process, &y, 3);
|
||||||
|
|
||||||
|
if (!crc_is_crnti && nof_prb >= 50 && data->type2_alloc.mode == t2_dist) {
|
||||||
|
*y++ = data->type2_alloc.n_gap;
|
||||||
|
} else {
|
||||||
|
y++; // bit reserved
|
||||||
|
}
|
||||||
|
|
||||||
|
// rv version
|
||||||
|
bit_pack(data->rv_idx, &y, 2);
|
||||||
|
|
||||||
|
if (crc_is_crnti) {
|
||||||
|
// TPC not implemented
|
||||||
|
*y++ = 0;
|
||||||
|
*y++ = 0;
|
||||||
|
} else {
|
||||||
|
y++; // MSB of TPC is reserved
|
||||||
|
*y++ = data->type2_alloc.n_prb1a; // LSB indicates N_prb_1a for TBS
|
||||||
|
}
|
||||||
|
|
||||||
|
// Padding with zeros
|
||||||
|
int n = dci_format1A_sizeof(nof_prb);
|
||||||
|
while (y-msg->data < n) {
|
||||||
|
*y++ = 0;
|
||||||
|
}
|
||||||
|
msg->location.nof_bits = (y - msg->data);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Unpacks DCI format 1A for compact scheduling of PDSCH words according to 36.212 5.3.3.1.3
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
int dci_format1As_unpack(dci_msg_t *msg, ra_pdsch_t *data, int nof_prb, bool crc_is_crnti) {
|
||||||
|
|
||||||
|
/* pack bits */
|
||||||
|
char *y = msg->data;
|
||||||
|
|
||||||
|
/* Make sure it's a Format0 message */
|
||||||
|
if (msg->location.nof_bits != dci_format_sizeof(Format1A, nof_prb)) {
|
||||||
|
fprintf(stderr, "Invalid message length for format 1A\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (*y++ != 1) {
|
||||||
|
fprintf(stderr, "Invalid format differentiation field value. This is Format0\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
data->alloc_type = alloc_type2;
|
||||||
|
data->type2_alloc.mode = *y++;
|
||||||
|
|
||||||
|
// by default, set N_gap to 1
|
||||||
|
data->type2_alloc.n_gap = t2_ng1;
|
||||||
|
|
||||||
|
/* unpack RIV according to 7.1.6.3 of 36.213 */
|
||||||
|
int nb_gap = 0;
|
||||||
|
if (crc_is_crnti && data->type2_alloc.mode == t2_dist && nof_prb >= 50) {
|
||||||
|
nb_gap = 1;
|
||||||
|
data->type2_alloc.n_gap = *y++;
|
||||||
|
}
|
||||||
|
int nof_vrb;
|
||||||
|
if (data->type2_alloc.mode == t2_loc) {
|
||||||
|
nof_vrb = nof_prb;
|
||||||
|
} else {
|
||||||
|
nof_vrb = ra_type2_n_vrb_dl(nof_prb, data->type2_alloc.n_gap == t2_ng1);
|
||||||
|
}
|
||||||
|
uint32_t riv = bit_unpack(&y, riv_nbits(nof_prb) - nb_gap);
|
||||||
|
ra_type2_from_riv(riv, &data->type2_alloc.L_crb, &data->type2_alloc.RB_start, nof_prb, nof_vrb);
|
||||||
|
data->type2_alloc.riv = riv;
|
||||||
|
|
||||||
|
// unpack MCS
|
||||||
|
data->mcs.mcs_idx = bit_unpack(&y, 5);
|
||||||
|
|
||||||
|
data->harq_process = bit_unpack(&y, 3);
|
||||||
|
|
||||||
|
if (!crc_is_crnti && nof_prb >= 50 && data->type2_alloc.mode == t2_dist) {
|
||||||
|
data->type2_alloc.n_gap = *y++;
|
||||||
|
} else {
|
||||||
|
y++; // bit reserved
|
||||||
|
}
|
||||||
|
|
||||||
|
// rv version
|
||||||
|
bit_pack(data->rv_idx, &y, 2);
|
||||||
|
|
||||||
|
if (crc_is_crnti) {
|
||||||
|
// TPC not implemented
|
||||||
|
y++;
|
||||||
|
y++;
|
||||||
|
} else {
|
||||||
|
y++; // MSB of TPC is reserved
|
||||||
|
*y++ = data->type2_alloc.n_prb1a; // LSB indicates N_prb_1a for TBS
|
||||||
|
}
|
||||||
|
data->mcs.tbs_idx = data->mcs.mcs_idx;
|
||||||
|
int n_prb;
|
||||||
|
if (crc_is_crnti) {
|
||||||
|
n_prb = ra_nprb_dl(data, nof_prb);
|
||||||
|
} else {
|
||||||
|
n_prb = data->type2_alloc.n_prb1a==nprb1a_2?2:3;
|
||||||
|
}
|
||||||
|
data->mcs.tbs = ra_tbs_from_idx(data->mcs.tbs_idx, n_prb);
|
||||||
|
data->mcs.mod = QPSK;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Format 1C for compact scheduling of PDSCH words
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
int dci_format1Cs_pack(ra_pdsch_t *data, dci_msg_t *msg, int nof_prb) {
|
||||||
|
|
||||||
|
/* pack bits */
|
||||||
|
char *y = msg->data;
|
||||||
|
|
||||||
|
if (data->alloc_type != alloc_type2 || data->type2_alloc.mode != t2_dist) {
|
||||||
|
fprintf(stderr, "Format 1C accepts distributed type2 resource allocation only\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nof_prb >= 50) {
|
||||||
|
*y++ = data->type2_alloc.n_gap;
|
||||||
|
}
|
||||||
|
int n_step = ra_type2_n_rb_step(nof_prb);
|
||||||
|
int n_vrb_dl = ra_type2_n_vrb_dl(nof_prb, data->type2_alloc.n_gap==t2_ng1);
|
||||||
|
|
||||||
|
if (data->type2_alloc.L_crb > ((int) n_vrb_dl/n_step)*n_step) {
|
||||||
|
fprintf(stderr, "L_CRB=%d can not exceed N_vrb_dl=%d for distributed type2\n", data->type2_alloc.L_crb,
|
||||||
|
((int) n_vrb_dl/n_step)*n_step);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (data->type2_alloc.L_crb % n_step) {
|
||||||
|
fprintf(stderr, "L_crb must be multiple of n_step\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (data->type2_alloc.RB_start % n_step) {
|
||||||
|
fprintf(stderr, "RB_start must be multiple of n_step\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
int L_p = data->type2_alloc.L_crb/n_step;
|
||||||
|
int RB_p = data->type2_alloc.RB_start/n_step;
|
||||||
|
int n_vrb_p = (int) n_vrb_dl / n_step;
|
||||||
|
|
||||||
|
uint32_t riv;
|
||||||
|
if (data->type2_alloc.L_crb) {
|
||||||
|
riv = ra_type2_to_riv(L_p, RB_p, n_vrb_p);
|
||||||
|
} else {
|
||||||
|
riv = data->type2_alloc.riv;
|
||||||
|
}
|
||||||
|
bit_pack(riv, &y, riv_nbits((int) n_vrb_dl/n_step));
|
||||||
|
|
||||||
|
// in format1C, MCS = TBS according to 7.1.7.2 of 36.213
|
||||||
|
uint32_t mcs;
|
||||||
|
if (data->mcs.mod == MOD_NULL) {
|
||||||
|
mcs = data->mcs.mcs_idx;
|
||||||
|
} else {
|
||||||
|
if (data->mcs.tbs) {
|
||||||
|
data->mcs.tbs_idx = ra_tbs_to_table_idx_format1c(data->mcs.tbs);
|
||||||
|
}
|
||||||
|
mcs = data->mcs.tbs_idx;
|
||||||
|
}
|
||||||
|
bit_pack(mcs, &y, 5);
|
||||||
|
|
||||||
|
msg->location.nof_bits = (y - msg->data);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dci_format1Cs_unpack(dci_msg_t *msg, ra_pdsch_t *data, int nof_prb) {
|
||||||
|
uint16_t L_p, RB_p;
|
||||||
|
|
||||||
|
/* pack bits */
|
||||||
|
char *y = msg->data;
|
||||||
|
|
||||||
|
if (msg->location.nof_bits != dci_format_sizeof(Format1C, nof_prb)) {
|
||||||
|
fprintf(stderr, "Invalid message length for format 1C\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
data->alloc_type = alloc_type2;
|
||||||
|
data->type2_alloc.mode = t2_dist;
|
||||||
|
if (nof_prb >= 50) {
|
||||||
|
data->type2_alloc.n_gap = *y++;
|
||||||
|
}
|
||||||
|
int n_step = ra_type2_n_rb_step(nof_prb);
|
||||||
|
int n_vrb_dl = ra_type2_n_vrb_dl(nof_prb, data->type2_alloc.n_gap==t2_ng1);
|
||||||
|
|
||||||
|
uint32_t riv = bit_unpack(&y, riv_nbits((int) n_vrb_dl/n_step));
|
||||||
|
int n_vrb_p = (int) n_vrb_dl / n_step;
|
||||||
|
|
||||||
|
ra_type2_from_riv(riv, &L_p, &RB_p, n_vrb_p, n_vrb_p);
|
||||||
|
data->type2_alloc.L_crb = L_p * n_step;
|
||||||
|
data->type2_alloc.RB_start = RB_p * n_step;
|
||||||
|
data->type2_alloc.riv = riv;
|
||||||
|
|
||||||
|
data->mcs.mcs_idx = bit_unpack(&y, 5);
|
||||||
|
data->mcs.tbs_idx = data->mcs.mcs_idx;
|
||||||
|
data->mcs.tbs = ra_tbs_from_idx_format1c(data->mcs.tbs_idx);
|
||||||
|
data->mcs.mod = QPSK;
|
||||||
|
|
||||||
|
msg->location.nof_bits = (y - msg->data);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dci_msg_pack_pdsch(ra_pdsch_t *data, dci_msg_t *msg, dci_format_t format, int nof_prb, bool crc_is_crnti) {
|
||||||
|
switch(format) {
|
||||||
|
case Format1:
|
||||||
|
return dci_format1_pack(data, msg, nof_prb);
|
||||||
|
case Format1A:
|
||||||
|
return dci_format1As_pack(data, msg, nof_prb, crc_is_crnti);
|
||||||
|
case Format1C:
|
||||||
|
return dci_format1Cs_pack(data, msg, nof_prb);
|
||||||
|
default:
|
||||||
|
fprintf(stderr, "Invalid DCI format %s for PDSCH resource allocation\n", dci_format_string(format));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int dci_msg_unpack_pdsch(dci_msg_t *msg, ra_pdsch_t *data, int nof_prb, bool crc_is_crnti) {
|
||||||
|
if (msg->location.nof_bits == dci_format_sizeof(Format1, nof_prb)) {
|
||||||
|
return dci_format1_unpack(msg, data, nof_prb);
|
||||||
|
} else if (msg->location.nof_bits == dci_format_sizeof(Format1A, nof_prb)) {
|
||||||
|
return dci_format1As_unpack(msg, data, nof_prb, crc_is_crnti);
|
||||||
|
} else if (msg->location.nof_bits == dci_format_sizeof(Format1C, nof_prb)) {
|
||||||
|
return dci_format1Cs_unpack(msg, data, nof_prb);
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int dci_msg_pack_pusch(ra_pusch_t *data, dci_msg_t *msg, int nof_prb) {
|
||||||
|
return dci_format0_pack(data, msg, nof_prb);
|
||||||
|
}
|
||||||
|
|
||||||
|
int dci_msg_unpack_pusch(dci_msg_t *msg, ra_pusch_t *data, int nof_prb) {
|
||||||
|
return dci_format0_unpack(msg, data, nof_prb);
|
||||||
|
}
|
||||||
|
|
||||||
|
char* dci_format_string(dci_format_t format) {
|
||||||
|
switch(format) {
|
||||||
|
case Format0:
|
||||||
|
return "Format0";
|
||||||
|
case Format1:
|
||||||
|
return "Format1";
|
||||||
|
case Format1A:
|
||||||
|
return "Format1A";
|
||||||
|
case Format1C:
|
||||||
|
return "Format1C";
|
||||||
|
default:
|
||||||
|
return "N/A"; // fatal error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void dci_msg_type_fprint(FILE *f, dci_msg_type_t type) {
|
||||||
|
switch(type.type) {
|
||||||
|
case PUSCH_SCHED:
|
||||||
|
fprintf(f,"%s PUSCH Scheduling\n", dci_format_string(type.format));
|
||||||
|
break;
|
||||||
|
case PDSCH_SCHED:
|
||||||
|
fprintf(f,"%s PDSCH Scheduling\n", dci_format_string(type.format));
|
||||||
|
break;
|
||||||
|
case RA_PROC_PDCCH:
|
||||||
|
fprintf(f,"%s Random access initiated by PDCCH\n", dci_format_string(type.format));
|
||||||
|
break;
|
||||||
|
case MCCH_CHANGE:
|
||||||
|
fprintf(f,"%s MCCH change notification\n", dci_format_string(type.format));
|
||||||
|
break;
|
||||||
|
case TPC_COMMAND:
|
||||||
|
fprintf(f,"%s TPC command\n", dci_format_string(type.format));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int dci_msg_get_type(dci_msg_t *msg, dci_msg_type_t *type, int nof_prb, unsigned short crnti) {
|
||||||
|
if (msg->location.nof_bits == dci_format_sizeof(Format0, nof_prb)
|
||||||
|
&& !msg->data[0]) {
|
||||||
|
type->type = PUSCH_SCHED;
|
||||||
|
type->format = Format0;
|
||||||
|
return 0;
|
||||||
|
} else if (msg->location.nof_bits == dci_format_sizeof(Format1, nof_prb)) {
|
||||||
|
type->type = PDSCH_SCHED; // only these 2 types supported
|
||||||
|
type->format = Format1;
|
||||||
|
return 0;
|
||||||
|
} else if (msg->location.nof_bits == dci_format_sizeof(Format1A, nof_prb)) {
|
||||||
|
if (msg->location.rnti == crnti) {
|
||||||
|
type->type = RA_PROC_PDCCH;
|
||||||
|
type->format = Format1A;
|
||||||
|
} else {
|
||||||
|
type->type = PDSCH_SCHED; // only these 2 types supported
|
||||||
|
type->format = Format1A;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
} else if (msg->location.nof_bits == dci_format_sizeof(Format1C, nof_prb)) {
|
||||||
|
if (msg->location.rnti == MRNTI) {
|
||||||
|
type->type = MCCH_CHANGE;
|
||||||
|
type->format = Format1C;
|
||||||
|
} else {
|
||||||
|
type->type = PDSCH_SCHED; // only these 2 types supported
|
||||||
|
type->format = Format1C;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -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)) {
|
if (viterbi_init(&q->decoder, viterbi_37, poly, 40, true)) {
|
||||||
goto clean;
|
goto clean;
|
||||||
}
|
}
|
||||||
|
if (crc_init(&q->crc, LTE_CRC16, 16)) {
|
||||||
|
goto clean;
|
||||||
|
}
|
||||||
q->encoder.K = 7;
|
q->encoder.K = 7;
|
||||||
q->encoder.R = 3;
|
q->encoder.R = 3;
|
||||||
q->encoder.tail_biting = true;
|
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
|
* 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];
|
char data[40];
|
||||||
memcpy(data, bits, 40 * sizeof(char));
|
memcpy(data, bits, 40 * sizeof(char));
|
||||||
crc_set_mask(data, nof_ports);
|
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) {
|
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 */
|
/* 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 */
|
/* FIXME: If channel estimates are zero, received LLR are NaN. Check and return error */
|
||||||
for (j=0;j<120;j++) {
|
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;
|
c=1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!pbch_crc_check(q->data, nof_ports)) {
|
if (!pbch_crc_check(q, q->data, nof_ports)) {
|
||||||
/* unpack MIB */
|
/* unpack MIB */
|
||||||
pbch_mib_unpack(q->data, 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);
|
pbch_mib_pack(mib, q->data);
|
||||||
|
|
||||||
/* encode & modulate */
|
/* encode & modulate */
|
||||||
crc(0, q->data, 24, 16, 0x11021, 1);
|
crc_attach(&q->crc, q->data, 24);
|
||||||
crc_set_mask(q->data, nof_ports);
|
crc_set_mask(q->data, nof_ports);
|
||||||
|
|
||||||
convcoder_encode(&q->encoder, q->data, q->data_enc, 40);
|
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_REGS(i) ((1<<i)*9)
|
||||||
#define PDCCH_FORMAT_NOF_BITS(i) ((1<<i)*72)
|
#define PDCCH_FORMAT_NOF_BITS(i) ((1<<i)*72)
|
||||||
|
|
||||||
int pdcch_put(cf_t *pdcch, cf_t *slot1_data, int nsymbols) {
|
#define NOF_COMMON_FORMATS 2
|
||||||
memcpy(slot1_data, pdcch, sizeof(cf_t) * nsymbols);
|
const dci_format_t common_formats[NOF_COMMON_FORMATS] = {Format1A, Format1C};
|
||||||
return nsymbols;
|
|
||||||
}
|
|
||||||
|
|
||||||
int pdcch_get(cf_t *slot1_data, cf_t *pdcch, int nsymbols) {
|
#define NOF_UE_FORMATS 2
|
||||||
memcpy(pdcch, slot1_data, sizeof(cf_t) * nsymbols);
|
const dci_format_t ue_formats[NOF_UE_FORMATS] = {Format0, Format1}; // 1A has the same payload as 0
|
||||||
return nsymbols;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define MIN(a,b) ((a>b)?b:a)
|
#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
|
* 36.213 9.1
|
||||||
*/
|
*/
|
||||||
int gen_common_search(dci_candidate_t *c, int nof_cce, int nof_bits, unsigned short rnti) {
|
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;
|
k = 0;
|
||||||
for (L = 2; L > 0; L--) {
|
for (l = 3; l > 1; l--) {
|
||||||
for (i = 0; i < MIN(nof_cce,16) / (4 * L); i++) {
|
L = (1 << l);
|
||||||
c[k].L = 4 * L;
|
for (i = 0; i < MIN(nof_cce,16) / (L); i++) {
|
||||||
|
c[k].L = l;
|
||||||
c[k].nof_bits = nof_bits;
|
c[k].nof_bits = nof_bits;
|
||||||
c[k].rnti = rnti;
|
c[k].rnti = rnti;
|
||||||
c[k].ncce = (4 * L) * (i % (nof_cce / (4 * L)));
|
c[k].ncce = (L) * (i % (nof_cce / (L)));
|
||||||
k++;
|
INFO("Common SS Candidate %d: RNTI: 0x%x, nCCE: %d, Nbits: %d, L: %d\n",
|
||||||
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, c[k].rnti, c[k].ncce, c[k].nof_bits, c[k].L);
|
||||||
|
k++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 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;
|
unsigned int Yk;
|
||||||
const int S[4] = { 6, 12, 8, 16 };
|
const int S[4] = { 6, 12, 8, 16 };
|
||||||
k = 0;
|
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--) {
|
for (l = 3; l >= 0; l--) {
|
||||||
L = (1 << l);
|
L = (1 << l);
|
||||||
for (i = 0; i < MIN(nof_cce/L,16/S[l]); i++) {
|
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;
|
Yk = (39827 * Yk) % 65537;
|
||||||
}
|
}
|
||||||
c[k].ncce = L * ((Yk + i) % (nof_cce / L));
|
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",
|
if (!subframe) {
|
||||||
k, subframe, c[k].rnti, c[k].ncce, c[k].nof_bits, c[k].L);
|
if (VERBOSE_ISINFO()) {
|
||||||
|
printf("(%d, %d), ", c[k].ncce, c[k].L);
|
||||||
|
}
|
||||||
|
}
|
||||||
k++;
|
k++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!subframe) {
|
||||||
|
if (VERBOSE_ISINFO()) printf("\n");
|
||||||
|
}
|
||||||
return k;
|
return k;
|
||||||
}
|
}
|
||||||
|
|
||||||
void pdcch_init_common(pdcch_t *q, pdcch_search_t *s, unsigned short rnti) {
|
void pdcch_init_common(pdcch_t *q, pdcch_search_t *s, unsigned short rnti) {
|
||||||
int k;
|
int k, i;
|
||||||
s->nof_candidates = 2*(MIN(q->nof_cce,16) / 4 + MIN(q->nof_cce,16) / 8);
|
s->nof_candidates = NOF_COMMON_FORMATS*(MIN(q->nof_cce,16) / 4 + MIN(q->nof_cce,16) / 8);
|
||||||
if (s->nof_candidates) {
|
if (s->nof_candidates) {
|
||||||
s->candidates[0] = malloc(sizeof(dci_candidate_t) * s->nof_candidates);
|
s->candidates[0] = malloc(sizeof(dci_candidate_t) * s->nof_candidates);
|
||||||
dci_candidate_t *c = s->candidates[0];
|
dci_candidate_t *c = s->candidates[0];
|
||||||
|
s->nof_candidates = 0;
|
||||||
if (c) {
|
if (c) {
|
||||||
// Format 1A and 1C L=4 and L=8, 4 and 2 candidates, only if nof_cce > 16
|
// Format 1A and 1C L=4 and L=8, 4 and 2 candidates, only if nof_cce > 16
|
||||||
k = 0;
|
k = 0;
|
||||||
k += gen_common_search(&c[k], q->nof_cce,
|
for(i=0;i<NOF_COMMON_FORMATS;i++) {
|
||||||
dci_format1A_sizeof(q->nof_prb, true), SIRNTI);
|
k += gen_common_search(&c[k], q->nof_cce,
|
||||||
k += gen_common_search(&c[k], q->nof_cce,
|
dci_format_sizeof(common_formats[i], q->nof_prb), SIRNTI);
|
||||||
dci_format1C_sizeof(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
|
* DCI Format 1A and 1 + PUSCH scheduling format 0
|
||||||
*/
|
*/
|
||||||
void pdcch_init_search_ue(pdcch_t *q, unsigned short c_rnti) {
|
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];
|
pdcch_search_t *s = &q->search_mode[SEARCH_UE];
|
||||||
s->nof_candidates = 0;
|
s->nof_candidates = 0;
|
||||||
for (l=0;l<3;l++) {
|
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);
|
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) {
|
if (s->nof_candidates) {
|
||||||
|
@ -152,12 +161,10 @@ void pdcch_init_search_ue(pdcch_t *q, unsigned short c_rnti) {
|
||||||
if (c) {
|
if (c) {
|
||||||
// Expect Formats 1, 1A, 0
|
// Expect Formats 1, 1A, 0
|
||||||
k = 0;
|
k = 0;
|
||||||
k += gen_ue_search(&c[k], q->nof_cce,
|
for(i=0;i<NOF_UE_FORMATS;i++) {
|
||||||
dci_format0_sizeof(q->nof_prb), c_rnti, n);
|
k += gen_ue_search(&c[k], q->nof_cce,
|
||||||
k += gen_ue_search(&c[k], q->nof_cce,
|
dci_format_sizeof(ue_formats[i], q->nof_prb), c_rnti, n);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -200,19 +207,23 @@ int pdcch_init(pdcch_t *q, regs_t *regs, int nof_prb, int nof_ports,
|
||||||
q->cp = cp;
|
q->cp = cp;
|
||||||
q->regs = regs;
|
q->regs = regs;
|
||||||
q->nof_ports = nof_ports;
|
q->nof_ports = nof_ports;
|
||||||
|
q->nof_prb = nof_prb;
|
||||||
q->current_search_mode = SEARCH_NONE;
|
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_cce = q->nof_regs / 9;
|
||||||
q->nof_symbols = 4 * q->nof_regs;
|
q->nof_symbols = 4 * q->nof_regs;
|
||||||
q->nof_bits = 2 * q->nof_symbols;
|
q->nof_bits = 2 * q->nof_symbols;
|
||||||
|
|
||||||
INFO("Init PDCCH: %d REGs, %d bits, %d symbols, %d ports\n", q->nof_regs,
|
INFO("Init PDCCH: %d CCEs (%d REGs), %d bits, %d symbols, %d ports\n", q->nof_cce,
|
||||||
q->nof_bits, q->nof_symbols, q->nof_ports);
|
q->nof_regs, q->nof_bits, q->nof_symbols, q->nof_ports);
|
||||||
|
|
||||||
if (modem_table_std(&q->mod, LTE_QPSK, true)) {
|
if (modem_table_std(&q->mod, LTE_QPSK, true)) {
|
||||||
goto clean;
|
goto clean;
|
||||||
}
|
}
|
||||||
|
if (crc_init(&q->crc, LTE_CRC16, 16)) {
|
||||||
|
goto clean;
|
||||||
|
}
|
||||||
|
|
||||||
demod_soft_init(&q->demod);
|
demod_soft_init(&q->demod);
|
||||||
demod_soft_table_set(&q->demod, &q->mod);
|
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
|
* 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) {
|
int nof_bits) {
|
||||||
|
|
||||||
float tmp[3 * (DCI_MAX_BITS + 16)];
|
float tmp[3 * (DCI_MAX_BITS + 16)];
|
||||||
unsigned short p_bits;
|
unsigned short p_bits, crc_res;
|
||||||
char *x;
|
char *x;
|
||||||
|
|
||||||
assert(nof_bits < DCI_MAX_BITS);
|
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 */
|
/* 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);
|
DEBUG("Viterbi input: ", 0);
|
||||||
if (VERBOSE_ISDEBUG()) {
|
if (VERBOSE_ISDEBUG()) {
|
||||||
|
@ -328,26 +346,32 @@ unsigned short dci_decode(viterbi_t *decoder, float *e, char *data, int E,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* viterbi decoder */
|
/* 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];
|
x = &data[nof_bits];
|
||||||
p_bits = (unsigned short) bit_unpack(&x, 16);
|
p_bits = (unsigned short) bit_unpack(&x, 16);
|
||||||
|
crc_res = ((unsigned short) crc_checksum(&q->crc, data, nof_bits) & 0xffff);
|
||||||
return (p_bits
|
DEBUG("p_bits: 0x%x, crc_res: 0x%x, tot: 0x%x\n", p_bits, crc_res, p_bits ^ crc_res);
|
||||||
^ ((unsigned short) crc(0, data, nof_bits, 16, LTE_CRC16, 0)
|
return (p_bits ^ crc_res);
|
||||||
& 0xffff));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int pdcch_decode_candidate(pdcch_t *q, float *llr, dci_candidate_t *c,
|
int pdcch_decode_candidate(pdcch_t *q, float *llr, dci_candidate_t *c,
|
||||||
dci_msg_t *msg) {
|
dci_msg_t *msg) {
|
||||||
unsigned short crc_res;
|
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);
|
PDCCH_FORMAT_NOF_BITS(c->L), c->nof_bits);
|
||||||
|
|
||||||
if (c->rnti == crc_res) {
|
if (c->rnti == crc_res) {
|
||||||
memcpy(&msg->location, c, sizeof(dci_candidate_t));
|
memcpy(&msg->location, c, sizeof(dci_candidate_t));
|
||||||
INFO(
|
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->nof_bits, PDCCH_FORMAT_NOF_BITS(c->L), c->ncce, c->L,
|
||||||
c->rnti);
|
c->rnti);
|
||||||
return 1;
|
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));
|
memset(&x[q->nof_ports], 0, sizeof(cf_t*) * (MAX_LAYERS - q->nof_ports));
|
||||||
|
|
||||||
/* extract symbols */
|
/* extract symbols */
|
||||||
if (q->nof_symbols
|
int n = regs_pdcch_get(q->regs, slot1_symbols, q->pdcch_symbols[0]);
|
||||||
!= pdcch_get(slot1_symbols, q->pdcch_symbols[0], q->nof_symbols)) {
|
if (q->nof_symbols != n) {
|
||||||
fprintf(stderr, "There was an error getting the PDCCH symbols\n");
|
fprintf(stderr, "Expected %d PDCCH symbols but got %d symbols\n", q->nof_symbols, n);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* extract channel estimates */
|
/* extract channel estimates */
|
||||||
for (i = 0; i < q->nof_ports; i++) {
|
for (i = 0; i < q->nof_ports; i++) {
|
||||||
if (q->nof_symbols != pdcch_get(ce[i], q->ce[i], q->nof_symbols)) {
|
n = regs_pdcch_get(q->regs, ce[i], q->ce[i]);
|
||||||
fprintf(stderr, "There was an error getting the PDCCH symbols\n");
|
if (q->nof_symbols != n) {
|
||||||
|
fprintf(stderr, "Expected %d PDCCH symbols but got %d symbols\n", q->nof_symbols, n);
|
||||||
return -1;
|
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 */
|
/* in control channels, only diversity is supported */
|
||||||
if (q->nof_ports == 1) {
|
if (q->nof_ports == 1) {
|
||||||
/* no need for layer demapping */
|
/* 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);
|
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 */
|
/* demodulate symbols */
|
||||||
demod_soft_sigma_set(&q->demod, ebno);
|
demod_soft_sigma_set(&q->demod, ebno);
|
||||||
demod_soft_demodulate(&q->demod, q->pdcch_d, q->pdcch_llr, q->nof_symbols);
|
demod_soft_demodulate(&q->demod, q->pdcch_d, q->pdcch_llr, q->nof_symbols);
|
||||||
|
|
||||||
DEBUG("llr: ", 0);
|
DEBUG("llr: ", 0);
|
||||||
if (VERBOSE_ISDEBUG()) {
|
if (VERBOSE_ISDEBUG()) {
|
||||||
vec_fprint_f(stdout, q->pdcch_llr, q->nof_symbols);
|
vec_fprint_f(stdout, q->pdcch_llr, q->nof_bits);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* descramble */
|
/* 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 pdcch_decode_current_mode(pdcch_t *q, float *llr, dci_t *dci, int subframe) {
|
||||||
int dci_cnt;
|
|
||||||
int k, i;
|
int k, i;
|
||||||
|
|
||||||
if (q->current_search_mode == SEARCH_UE) {
|
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;
|
k = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
dci_cnt = 0;
|
|
||||||
for (i = 0; i < q->search_mode[q->current_search_mode].nof_candidates
|
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,
|
if (pdcch_decode_candidate(q, q->pdcch_llr,
|
||||||
&q->search_mode[q->current_search_mode].candidates[k][i],
|
&q->search_mode[q->current_search_mode].candidates[k][i],
|
||||||
&dci->msg[dci_cnt])) {
|
&dci->msg[dci->nof_dcis])) {
|
||||||
dci_cnt++;
|
dci->nof_dcis++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return dci_cnt;
|
return dci->nof_dcis;
|
||||||
}
|
}
|
||||||
|
|
||||||
int pdcch_decode_si(pdcch_t *q, float *llr, dci_t *dci) {
|
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
|
/** 36.212 5.3.3.2 to 5.3.3.4
|
||||||
* TODO: UE transmit antenna selection CRC mask
|
* 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;
|
convcoder_t encoder;
|
||||||
char tmp[3 * (DCI_MAX_BITS + 16)];
|
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;
|
encoder.tail_biting = true;
|
||||||
memcpy(encoder.poly, poly, 3 * sizeof(int));
|
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);
|
crc_set_mask_rnti(&data[nof_bits], rnti);
|
||||||
|
|
||||||
convcoder_encode(&encoder, data, tmp, nof_bits + 16);
|
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));
|
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
|
/** 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),
|
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->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.nof_bits, PDCCH_FORMAT_NOF_BITS(dci->msg[i].location.L),
|
||||||
dci->msg[i].location.rnti);
|
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 */
|
/* mapping to resource elements */
|
||||||
for (i = 0; i < q->nof_ports; i++) {
|
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;
|
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);
|
regs_reg_t *regs_find_reg(regs_t *h, int k, int l);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/***************************************************************
|
/***************************************************************
|
||||||
*
|
*
|
||||||
* PDCCH REG ALLOCATION
|
* 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
|
/** Initialize REGs for PDCCH
|
||||||
* 36.211 10.3 section 6.8.5
|
* 36.211 10.3 section 6.8.5
|
||||||
*/
|
*/
|
||||||
int regs_pdcch_init(regs_t *h) {
|
int regs_pdcch_init(regs_t *h) {
|
||||||
return 0;
|
int i, m, cfi, nof_ctrl_symbols;
|
||||||
}
|
int ret = -1;
|
||||||
|
int nrows, ndummy, j, k, kp;
|
||||||
|
regs_reg_t **tmp = NULL;
|
||||||
|
|
||||||
void regs_pdcch_free(regs_t *h) {
|
bzero(&h->pdcch, sizeof(regs_ch_t));
|
||||||
if (h->pdcch) {
|
|
||||||
free(h->pdcch);
|
for (cfi=0;cfi<3;cfi++) {
|
||||||
|
if (h->nof_prb < 10) {
|
||||||
|
nof_ctrl_symbols = cfi+2;
|
||||||
|
} else {
|
||||||
|
nof_ctrl_symbols = cfi+1;
|
||||||
|
}
|
||||||
|
|
||||||
|
tmp = malloc(sizeof(regs_reg_t*) * h->nof_regs);
|
||||||
|
if (!tmp) {
|
||||||
|
perror("malloc");
|
||||||
|
goto clean_and_exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Number and count REGs for this CFI */
|
||||||
|
m=0;
|
||||||
|
for (i=0;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) {
|
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) {
|
int regs_phich_ngroups(regs_t *h) {
|
||||||
return h->ngroups_phich;
|
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
|
* 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
|
* 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
|
* Returns the number of REGs in a PRB
|
||||||
* 36.211 Section 6.2.4
|
* 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) {
|
switch (symbol) {
|
||||||
case 0:
|
case 0:
|
||||||
return 2;
|
return 2;
|
||||||
case 1:
|
case 1:
|
||||||
switch (refs_in_symbol1) {
|
switch (nof_port) {
|
||||||
case 1:
|
case 1:
|
||||||
case 2:
|
case 2:
|
||||||
return 3;
|
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->l = symbol;
|
||||||
reg->assigned = false;
|
reg->assigned = false;
|
||||||
reg->k0 = k0 + nreg * 6;
|
|
||||||
|
|
||||||
switch (maxreg) {
|
switch (maxreg) {
|
||||||
case 2:
|
case 2:
|
||||||
|
reg->k0 = k0 + nreg * 6;
|
||||||
/* there are two references in the middle */
|
/* there are two references in the middle */
|
||||||
j = z = 0;
|
j = z = 0;
|
||||||
for (i = 0; i < vo; i++) {
|
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;
|
break;
|
||||||
|
|
||||||
case 3:
|
case 3:
|
||||||
|
reg->k0 = k0 + nreg * 4;
|
||||||
/* there is no reference */
|
/* there is no reference */
|
||||||
for (i = 0; i < 4; i++) {
|
for (i = 0; i < 4; i++) {
|
||||||
reg->k[i] = k0 + nreg * 4 + i;
|
reg->k[i] = k0 + nreg * 4 + i;
|
||||||
|
@ -479,15 +605,33 @@ void regs_free(regs_t *h) {
|
||||||
bzero(h, sizeof(regs_t));
|
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.
|
* Initializes REGs structure.
|
||||||
* Sets all REG indices and initializes PCFICH, PHICH and PDCCH REGs
|
* Sets all REG indices and initializes PCFICH, PHICH and PDCCH REGs
|
||||||
* Returns 0 if OK, -1 on error
|
* 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) {
|
phich_resources_t phich_res, phich_length_t phich_len, lte_cp_t cp) {
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
int i, j, n, p, k;
|
int i, j[4], jmax, n[4], prb, k;
|
||||||
int vo = cell_id % 3;
|
int vo = cell_id % 3;
|
||||||
int max_ctrl_symbols = nof_prb<10?4: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->cell_id = cell_id;
|
||||||
h->nof_prb = nof_prb;
|
h->nof_prb = nof_prb;
|
||||||
h->max_ctrl_symbols = max_ctrl_symbols;
|
h->max_ctrl_symbols = max_ctrl_symbols;
|
||||||
|
h->cfi = -1; // not yet initialized
|
||||||
h->phich_res = phich_res;
|
h->phich_res = phich_res;
|
||||||
h->phich_len = phich_len;
|
h->phich_len = phich_len;
|
||||||
h->cp = cp;
|
h->cp = cp;
|
||||||
h->refs_in_symbol1 = refs_in_symbol1;
|
h->nof_ports = nof_ports;
|
||||||
|
|
||||||
h->nof_regs = 0;
|
h->nof_regs = 0;
|
||||||
for (i = 0; i < max_ctrl_symbols; i++) {
|
for (i = 0; i < max_ctrl_symbols; i++) {
|
||||||
n = regs_num_x_symbol(i, refs_in_symbol1, cp);
|
n[i] = regs_num_x_symbol(i, nof_ports, cp);
|
||||||
if (n == -1) {
|
if (n[i] == -1) {
|
||||||
return -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,
|
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");
|
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;
|
goto clean_and_exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
k = 0;
|
/* Sort REGs according to PDCCH mapping, beggining from the lowest l index then k */
|
||||||
for (i = 0; i < max_ctrl_symbols; i++) {
|
bzero(j, sizeof(int) * 4);
|
||||||
n = regs_num_x_symbol(i, refs_in_symbol1, cp);
|
k = i = prb = jmax = 0;
|
||||||
for (p = 0; p < nof_prb; p++) {
|
while (k < h->nof_regs) {
|
||||||
for (j = 0; j < n; j++) {
|
if (n[i] == 3 || (n[i] == 2 && jmax != 1)) {
|
||||||
if (regs_reg_init(&h->regs[k], i, j, p * RE_X_RB, n, vo)) {
|
if (regs_reg_init(&h->regs[k], i, j[i], prb * RE_X_RB, n[i], vo)) {
|
||||||
fprintf(stderr, "Error initializing REGs\n");
|
fprintf(stderr, "Error initializing REGs\n");
|
||||||
goto clean_and_exit;
|
goto clean_and_exit;
|
||||||
}
|
|
||||||
DEBUG("Available REG #%3d: %d:%d:%d (k0=%d)\n", k, i, p, j,
|
|
||||||
h->regs[k].k0);
|
|
||||||
k++;
|
|
||||||
}
|
}
|
||||||
|
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)) {
|
if (regs_pcfich_init(h)) {
|
||||||
fprintf(stderr, "Error initializing PCFICH REGs\n");
|
fprintf(stderr, "Error initializing PCFICH REGs\n");
|
||||||
goto clean_and_exit;
|
goto clean_and_exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (regs_phich_init(h)) {
|
if (regs_phich_init(h)) {
|
||||||
fprintf(stderr, "Error initializing PHICH REGs\n");
|
fprintf(stderr, "Error initializing PHICH REGs\n");
|
||||||
goto clean_and_exit;
|
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;
|
ret = 0;
|
||||||
|
|
||||||
clean_and_exit: if (ret == -1) {
|
clean_and_exit:
|
||||||
|
if (ret == -1) {
|
||||||
regs_free(h);
|
regs_free(h);
|
||||||
}
|
}
|
||||||
return ret;
|
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 regs_put_reg(regs_reg_t *reg, cf_t *reg_data, cf_t *slot_symbols, int nof_prb) {
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < REGS_RE_X_REG; 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);
|
||||||
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];
|
||||||
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;
|
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 regs_add_reg(regs_reg_t *reg, cf_t *reg_data, cf_t *slot_symbols, int nof_prb) {
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < REGS_RE_X_REG; i++) {
|
for (i = 0; i < REGS_RE_X_REG; i++) {
|
||||||
if (reg->assigned) {
|
slot_symbols[REG_IDX(reg, i, nof_prb)] += reg_data[i];
|
||||||
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,
|
||||||
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)],
|
||||||
__real__ slot_symbols[REG_IDX(reg, i, nof_prb)],
|
__imag__ 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;
|
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 regs_reset_reg(regs_reg_t *reg, cf_t *slot_symbols, int nof_prb) {
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < REGS_RE_X_REG; 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);
|
||||||
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;
|
||||||
slot_symbols[REG_IDX(reg, i, nof_prb)] = 0;
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "Error REG not assigned\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return REGS_RE_X_REG;
|
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 regs_get_reg(regs_reg_t *reg, cf_t *slot_symbols, cf_t *reg_data, int nof_prb) {
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < REGS_RE_X_REG; i++) {
|
for (i = 0; i < REGS_RE_X_REG; i++) {
|
||||||
if (reg->assigned) {
|
reg_data[i] = slot_symbols[REG_IDX(reg, i, nof_prb)];
|
||||||
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,
|
||||||
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]);
|
||||||
__real__ reg_data[i], __imag__ reg_data[i]);
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "Error REG not assigned\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return REGS_RE_X_REG;
|
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)
|
ADD_EXECUTABLE(pdcch_test pdcch_test.c)
|
||||||
TARGET_LINK_LIBRARIES(pdcch_test lte)
|
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
|
# FILE TEST
|
||||||
########################################################################
|
########################################################################
|
||||||
|
@ -88,7 +93,11 @@ TARGET_LINK_LIBRARIES(pcfich_file_test lte)
|
||||||
ADD_EXECUTABLE(phich_file_test phich_file_test.c)
|
ADD_EXECUTABLE(phich_file_test phich_file_test.c)
|
||||||
TARGET_LINK_LIBRARIES(phich_file_test lte)
|
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(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(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(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 {
|
} else {
|
||||||
if (mib.nof_ports == 2 && mib.nof_prb == 50 && mib.phich_length == PHICH_NORM
|
if (mib.nof_ports == 2 && mib.nof_prb == 50 && mib.phich_length == PHICH_NORM
|
||||||
&& mib.phich_resources == R_1 && mib.sfn == 28) {
|
&& 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);
|
exit(0);
|
||||||
} else {
|
} else {
|
||||||
pbch_mib_fprint(stdout, &mib);
|
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(®s, cell_id, nof_prb, nof_ports, R_1, PHICH_NORM, cp)) {
|
||||||
|
fprintf(stderr, "Error initiating regs\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (regs_set_cfi(®s, cfi)) {
|
||||||
|
fprintf(stderr, "Error setting CFI %d\n", cfi);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pdcch_init(&pdcch, ®s, 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(®s);
|
||||||
|
}
|
||||||
|
|
||||||
|
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 cell_id = 1;
|
||||||
int nof_prb = 6;
|
int nof_prb = 6;
|
||||||
int nof_ports = 1;
|
int nof_ports = 1;
|
||||||
|
int cfi = 1;
|
||||||
|
|
||||||
void usage(char *prog) {
|
void usage(char *prog) {
|
||||||
printf("Usage: %s [cpv]\n", prog);
|
printf("Usage: %s [cpv]\n", prog);
|
||||||
printf("\t-c cell id [Default %d]\n", cell_id);
|
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-p nof_ports [Default %d]\n", nof_ports);
|
||||||
printf("\t-n nof_prb [Default %d]\n", nof_prb);
|
printf("\t-n nof_prb [Default %d]\n", nof_prb);
|
||||||
printf("\t-v [set verbose to debug, default none]\n");
|
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) {
|
void parse_args(int argc, char **argv) {
|
||||||
int opt;
|
int opt;
|
||||||
while ((opt = getopt(argc, argv, "cpnv")) != -1) {
|
while ((opt = getopt(argc, argv, "cpnfv")) != -1) {
|
||||||
switch(opt) {
|
switch(opt) {
|
||||||
case 'p':
|
case 'p':
|
||||||
nof_ports = atoi(argv[optind]);
|
nof_ports = atoi(argv[optind]);
|
||||||
break;
|
break;
|
||||||
|
case 'f':
|
||||||
|
cfi = atoi(argv[optind]);
|
||||||
|
break;
|
||||||
case 'n':
|
case 'n':
|
||||||
nof_prb = atoi(argv[optind]);
|
nof_prb = atoi(argv[optind]);
|
||||||
break;
|
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) {
|
int main(int argc, char **argv) {
|
||||||
pdcch_t pdcch;
|
pdcch_t pdcch;
|
||||||
dci_t dci_tx, dci_rx;
|
dci_t dci_tx, dci_rx;
|
||||||
dci_format1_t dci_msg;
|
ra_pdsch_t ra_dl;
|
||||||
regs_t regs;
|
regs_t regs;
|
||||||
int i, j;
|
int i, j;
|
||||||
cf_t *ce[MAX_PORTS_CTRL];
|
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;
|
nof_re = CPNORM_NSYMB * nof_prb * RE_X_RB;
|
||||||
|
|
||||||
|
if (test_dci_payload_size()) {
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
/* init memory */
|
/* init memory */
|
||||||
for (i=0;i<MAX_PORTS_CTRL;i++) {
|
for (i=0;i<MAX_PORTS_CTRL;i++) {
|
||||||
ce[i] = malloc(sizeof(cf_t) * nof_re);
|
ce[i] = malloc(sizeof(cf_t) * nof_re);
|
||||||
|
@ -106,13 +147,34 @@ int main(int argc, char **argv) {
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pdcch_init(&pdcch, ®s, nof_prb, nof_ports, cell_id, CPNORM)) {
|
if (regs_set_cfi(®s, cfi)) {
|
||||||
fprintf(stderr, "Error creating PBCH object\n");
|
fprintf(stderr, "Error setting CFI\n");
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
dci_init(&dci_tx, 1);
|
if (pdcch_init(&pdcch, ®s, nof_prb, nof_ports, cell_id, CPNORM)) {
|
||||||
dci_format1_add(&dci_tx, &dci_msg, 1, 0, 1234);
|
fprintf(stderr, "Error creating PDCCH object\n");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
pdcch_encode(&pdcch, &dci_tx, slot1_symbols, 0);
|
||||||
|
|
||||||
|
@ -125,13 +187,12 @@ int main(int argc, char **argv) {
|
||||||
|
|
||||||
pdcch_init_search_ue(&pdcch, 1234);
|
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);
|
nof_dcis = pdcch_decode(&pdcch, slot1_symbols[0], ce, &dci_rx, 0, 1);
|
||||||
if (nof_dcis < 0) {
|
if (nof_dcis < 0) {
|
||||||
printf("Error decoding\n");
|
printf("Error decoding\n");
|
||||||
} else if (nof_dcis == dci_tx.nof_dcis) {
|
} else if (nof_dcis == dci_tx.nof_dcis) {
|
||||||
for (i=0;i<nof_dcis;i++) {
|
for (i=0;i<nof_dcis;i++) {
|
||||||
|
|
||||||
if (dci_tx.msg[i].location.L != dci_rx.msg[i].location.L
|
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.ncce != dci_rx.msg[i].location.ncce
|
||||||
|| dci_tx.msg[i].location.nof_bits != dci_rx.msg[i].location.nof_bits
|
|| dci_tx.msg[i].location.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);
|
printf("Error in DCI %d: Received data does not match\n", i);
|
||||||
goto quit;
|
goto quit;
|
||||||
}
|
}
|
||||||
/* check more things ... */
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
printf("Transmitted %d DCIs but got %d\n", dci_tx.nof_dcis, nof_dcis);
|
printf("Transmitted %d DCIs but got %d\n", dci_tx.nof_dcis, nof_dcis);
|
||||||
|
|
Binary file not shown.
|
@ -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);
|
resample_arb_init(&r, rate);
|
||||||
|
|
||||||
clock_t start = clock(), diff;
|
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;
|
diff = clock() - start;
|
||||||
|
|
||||||
int msec = diff * 1000 / CLOCKS_PER_SEC;
|
int msec = diff * 1000 / CLOCKS_PER_SEC;
|
||||||
|
|
|
@ -71,3 +71,11 @@ unsigned int bit_diff(char *x, char *y, int nbits) {
|
||||||
}
|
}
|
||||||
return errors;
|
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…
Reference in New Issue