resolved merge conflicts

master
Ismael Gomez 7 years ago
parent 283cb115ac
commit b0639ab394

@ -7,6 +7,7 @@ include(CheckCSourceRuns)
option(ENABLE_SSE "Enable compile-time SSE4.1 support." ON)
option(ENABLE_AVX "Enable compile-time AVX support." ON)
option(ENABLE_AVX2 "Enable compile-time AVX2 support." ON)
option(ENABLE_FMA "Enable compile-time FMA support." ON)
if (ENABLE_SSE)
#
@ -97,8 +98,43 @@ if (ENABLE_SSE)
if (HAVE_AVX2)
message(STATUS "AVX2 is enabled - target CPU must support it")
endif()
endif()
endif()
if (ENABLE_FMA)
#
# Check compiler for AVX intrinsics
#
if (CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_CLANG )
set(CMAKE_REQUIRED_FLAGS "-mfma")
check_c_source_runs("
#include <immintrin.h>
int main()
{
__m256 a, b, c, r;
const float src[8] = { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f };
float dst[8];
a = _mm256_loadu_ps( src );
b = _mm256_loadu_ps( src );
c = _mm256_loadu_ps( src );
r = _mm256_fmadd_ps( a, b, c );
_mm256_storeu_ps( dst, r );
int i = 0;
for( i = 0; i < 8; i++ ){
if( ( src[i] * src[i] + src[i] ) != dst[i] ){
return -1;
}
}
return 0;
}"
HAVE_FMA)
endif()
if (HAVE_FMA)
message(STATUS "FMA is enabled - target CPU must support it")
endif()
endif()
endif()
mark_as_advanced(HAVE_SSE, HAVE_AVX, HAVE_AVX2)
mark_as_advanced(HAVE_SSE, HAVE_AVX, HAVE_AVX2, HAVE_FMA)

@ -118,7 +118,7 @@ int parse_args(prog_args_t *args, int argc, char **argv) {
/**********************************************************************/
/* TODO: Do something with the output data */
uint8_t data[1000000];
uint8_t *data[SRSLTE_MAX_CODEWORDS];
bool go_exit = false;
void sig_int_handler(int signo)
@ -160,7 +160,8 @@ int main(int argc, char **argv) {
int sfn_offset;
float rssi_utra=0,rssi=0, rsrp=0, rsrq=0, snr=0;
cf_t *ce[SRSLTE_MAX_PORTS];
float cfo = 0;
float cfo = 0;
bool acks[SRSLTE_MAX_CODEWORDS] = {false};
if (parse_args(&prog_args, argc, argv)) {
exit(-1);
@ -183,6 +184,9 @@ int main(int argc, char **argv) {
}
sf_buffer[0] = srslte_vec_malloc(3*sizeof(cf_t)*SRSLTE_SF_LEN_PRB(100));
for (int i = 0; i < SRSLTE_MAX_CODEWORDS; i++) {
data[i] = srslte_vec_malloc(sizeof(uint8_t) * 1500*8);
}
sigset_t sigset;
sigemptyset(&sigset);
@ -245,7 +249,7 @@ int main(int argc, char **argv) {
fprintf(stderr, "Error initiating ue_sync\n");
return -1;
}
if (srslte_ue_dl_init_multi(&ue_dl, cell.nof_prb, 1)) {
if (srslte_ue_dl_init(&ue_dl, cell.nof_prb, 1)) {
fprintf(stderr, "Error initiating UE downlink processing module\n");
return -1;
}
@ -326,19 +330,19 @@ int main(int argc, char **argv) {
case DECODE_SIB:
/* We are looking for SI Blocks, search only in appropiate places */
if ((srslte_ue_sync_get_sfidx(&ue_sync) == 5 && (sfn%2)==0)) {
n = srslte_ue_dl_decode_multi(&ue_dl, sf_buffer, data, sfn*10+srslte_ue_sync_get_sfidx(&ue_sync));
n = srslte_ue_dl_decode(&ue_dl, sf_buffer, data, 0, sfn*10+srslte_ue_sync_get_sfidx(&ue_sync), acks);
if (n < 0) {
fprintf(stderr, "Error decoding UE DL\n");fflush(stdout);
return -1;
} else if (n == 0) {
printf("CFO: %+6.4f kHz, SFO: %+6.4f kHz, NOI: %.2f, PDCCH-Det: %.3f\r",
srslte_ue_sync_get_cfo(&ue_sync)/1000, srslte_ue_sync_get_sfo(&ue_sync)/1000,
srslte_sch_average_noi(&ue_dl.pdsch.dl_sch),
srslte_pdsch_average_noi(&ue_dl.pdsch),
(float) ue_dl.nof_detected/nof_trials);
nof_trials++;
} else {
printf("Decoded SIB1. Payload: ");
srslte_vec_fprint_byte(stdout, data, n/8);;
srslte_vec_fprint_byte(stdout, data[0], n/8);;
state = MEASURE;
}
}
@ -402,6 +406,12 @@ int main(int argc, char **argv) {
sf_cnt++;
} // Main loop
for (int i = 0; i < SRSLTE_MAX_CODEWORDS; i++) {
if (data[i]) {
free(data[i]);
}
}
srslte_ue_sync_free(&ue_sync);
srslte_rf_close(&rf);
printf("\nBye\n");

@ -27,12 +27,12 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <unistd.h>
#include <sys/select.h>
#include <pthread.h>
#include <semaphore.h>
#include <signal.h>
#include <srslte/phy/common/phy_common.h>
#include <srslte/phy/phch/pdsch_cfg.h>
#include "srslte/srslte.h"
@ -55,19 +55,23 @@ char *output_file_name = NULL;
#define DOWN_KEY 66
srslte_cell_t cell = {
25, // nof_prb
1, // nof_ports
0, // cell_id
SRSLTE_CP_NORM, // cyclic prefix
SRSLTE_PHICH_R_1, // PHICH resources
SRSLTE_PHICH_NORM // PHICH length
25, // nof_prb
1, // nof_ports
0, // cell_id
SRSLTE_CP_NORM, // cyclic prefix
SRSLTE_PHICH_NORM, // PHICH length
SRSLTE_PHICH_R_1 // PHICH resources
};
int net_port = -1; // -1 generates random dataThat means there is some problem sending samples to the device
uint32_t cfi=3;
uint32_t cfi = 1;
uint32_t mcs_idx = 1, last_mcs_idx = 1;
int nof_frames = -1;
char mimo_type_str[32] = "single";
uint32_t nof_tb = 1;
uint32_t multiplex_pmi = 0;
uint32_t multiplex_nof_layers = 1;
char *rf_args = "";
float rf_amp = 0.8, rf_gain = 70.0, rf_freq = 2400000000;
@ -80,14 +84,15 @@ srslte_pcfich_t pcfich;
srslte_pdcch_t pdcch;
srslte_pdsch_t pdsch;
srslte_pdsch_cfg_t pdsch_cfg;
srslte_softbuffer_tx_t softbuffer;
srslte_softbuffer_tx_t *softbuffers[SRSLTE_MAX_CODEWORDS];
srslte_regs_t regs;
srslte_ra_dl_dci_t ra_dl;
srslte_ra_dl_dci_t ra_dl;
int rvidx[SRSLTE_MAX_CODEWORDS] = {0, 0};
cf_t *sf_buffer = NULL, *output_buffer = NULL;
cf_t *sf_buffer[SRSLTE_MAX_PORTS] = {NULL}, *output_buffer [SRSLTE_MAX_PORTS] = {NULL};
int sf_n_re, sf_n_samples;
pthread_t net_thread;
pthread_t net_thread;
void *net_thread_fnc(void *arg);
sem_t net_sem;
bool net_packet_ready = false;
@ -97,9 +102,12 @@ srslte_netsink_t net_sink;
int prbset_num = 1, last_prbset_num = 1;
int prbset_orig = 0;
#define DATA_BUFF_SZ 1024*1024
uint8_t *data[2], data2[DATA_BUFF_SZ];
uint8_t data_tmp[DATA_BUFF_SZ];
void usage(char *prog) {
printf("Usage: %s [agmfoncvpu]\n", prog);
printf("Usage: %s [agmfoncvpuxb]\n", prog);
#ifndef DISABLE_RF
printf("\t-a RF args [Default %s]\n", rf_args);
printf("\t-l RF amplitude [Default %.2f]\n", rf_amp);
@ -113,13 +121,18 @@ void usage(char *prog) {
printf("\t-n number of frames [Default %d]\n", nof_frames);
printf("\t-c cell id [Default %d]\n", cell.id);
printf("\t-p nof_prb [Default %d]\n", cell.nof_prb);
printf("\t-x Transmission mode[single|diversity|cdd|multiplex] [Default %s]\n", mimo_type_str);
printf("\t-b Precoding Matrix Index (multiplex mode only)* [Default %d]\n", multiplex_pmi);
printf("\t-w Number of codewords/layers (multiplex mode only)* [Default %d]\n", multiplex_nof_layers);
printf("\t-u listen TCP port for input data (-1 is random) [Default %d]\n", net_port);
printf("\t-v [set srslte_verbose to debug, default none]\n");
printf("\n");
printf("\t*: See 3GPP 36.212 Table 5.3.3.1.5-4 for more information\n");
}
void parse_args(int argc, char **argv) {
int opt;
while ((opt = getopt(argc, argv, "aglfmoncpvu")) != -1) {
while ((opt = getopt(argc, argv, "aglfmoncpvutxbw")) != -1) {
switch (opt) {
case 'a':
rf_args = argv[optind];
@ -151,6 +164,15 @@ void parse_args(int argc, char **argv) {
case 'c':
cell.id = atoi(argv[optind]);
break;
case 'x':
strncpy(mimo_type_str, argv[optind], 32);
break;
case 'b':
multiplex_pmi = (uint32_t) atoi(argv[optind]);
break;
case 'w':
multiplex_nof_layers = (uint32_t) atoi(argv[optind]);
break;
case 'v':
srslte_verbose++;
break;
@ -168,18 +190,61 @@ void parse_args(int argc, char **argv) {
}
void base_init() {
/* init memory */
sf_buffer = srslte_vec_malloc(sizeof(cf_t) * sf_n_re);
if (!sf_buffer) {
perror("malloc");
int i;
/* Select transmission mode */
if (srslte_str2mimotype(mimo_type_str, &pdsch_cfg.mimo_type)) {
ERROR("Wrong transmission mode! Allowed modes: single, diversity, cdd and multiplex");
exit(-1);
}
output_buffer = srslte_vec_malloc(sizeof(cf_t) * sf_n_samples);
if (!output_buffer) {
perror("malloc");
exit(-1);
/* Configure cell and PDSCH in function of the transmission mode */
switch(pdsch_cfg.mimo_type) {
case SRSLTE_MIMO_TYPE_SINGLE_ANTENNA:
cell.nof_ports = 1;
break;
case SRSLTE_MIMO_TYPE_TX_DIVERSITY:
cell.nof_ports = 2;
break;
case SRSLTE_MIMO_TYPE_CDD:
cell.nof_ports = 2;
break;
case SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX:
cell.nof_ports = 2;
break;
default:
ERROR("Transmission mode not implemented.");
exit(-1);
}
/* Allocate memory */
for(i = 0; i < SRSLTE_MAX_CODEWORDS; i++) {
data[i] = srslte_vec_malloc(sizeof(uint8_t) * SOFTBUFFER_SIZE);
if (!data[i]) {
perror("malloc");
exit(-1);
}
bzero(data[i], sizeof(uint8_t) * SOFTBUFFER_SIZE);
}
/* init memory */
for (i = 0; i < SRSLTE_MAX_PORTS; i++) {
sf_buffer[i] = srslte_vec_malloc(sizeof(cf_t) * sf_n_re);
if (!sf_buffer[i]) {
perror("malloc");
exit(-1);
}
}
for (i = 0; i < SRSLTE_MAX_PORTS; i++) {
output_buffer[i] = srslte_vec_malloc(sizeof(cf_t) * sf_n_samples);
if (!output_buffer[i]) {
perror("malloc");
exit(-1);
}
bzero(output_buffer[i], sizeof(cf_t) * sf_n_samples);
}
/* open file or USRP */
if (output_file_name) {
if (strcmp(output_file_name, "NULL")) {
@ -194,7 +259,7 @@ void base_init() {
} else {
#ifndef DISABLE_RF
printf("Opening RF device...\n");
if (srslte_rf_open(&rf, rf_args)) {
if (srslte_rf_open_multi(&rf, rf_args, cell.nof_ports)) {
fprintf(stderr, "Error opening rf\n");
exit(-1);
}
@ -241,7 +306,7 @@ void base_init() {
exit(-1);
}
if (srslte_pcfich_init(&pcfich)) {
if (srslte_pcfich_init(&pcfich, 1)) {
fprintf(stderr, "Error creating PBCH object\n");
exit(-1);
}
@ -255,7 +320,7 @@ void base_init() {
exit(-1);
}
if (srslte_pdcch_init(&pdcch, cell.nof_prb)) {
if (srslte_pdcch_init_enb(&pdcch, cell.nof_prb)) {
fprintf(stderr, "Error creating PDCCH object\n");
exit(-1);
}
@ -274,16 +339,29 @@ void base_init() {
}
srslte_pdsch_set_rnti(&pdsch, UE_CRNTI);
if (srslte_softbuffer_tx_init(&softbuffer, cell.nof_prb)) {
fprintf(stderr, "Error initiating soft buffer\n");
exit(-1);
for (i = 0; i < SRSLTE_MAX_CODEWORDS; i++) {
softbuffers[i] = calloc(sizeof(srslte_softbuffer_tx_t), 1);
if (!softbuffers[i]) {
fprintf(stderr, "Error allocating soft buffer\n");
exit(-1);
}
if (srslte_softbuffer_tx_init(softbuffers[i], cell.nof_prb)) {
fprintf(stderr, "Error initiating soft buffer\n");
exit(-1);
}
}
}
void base_free() {
srslte_softbuffer_tx_free(&softbuffer);
int i;
for (i = 0; i < SRSLTE_MAX_CODEWORDS; i++) {
srslte_softbuffer_tx_free(softbuffers[i]);
if (softbuffers[i]) {
free(softbuffers[i]);
}
}
srslte_pdsch_free(&pdsch);
srslte_pdcch_free(&pdcch);
srslte_regs_free(&regs);
@ -291,11 +369,20 @@ void base_free() {
srslte_ofdm_tx_free(&ifft);
if (sf_buffer) {
free(sf_buffer);
for (i = 0; i < SRSLTE_MAX_CODEWORDS; i++) {
if (data[i]) {
free(data[i]);
}
}
if (output_buffer) {
free(output_buffer);
for (i = 0; i < SRSLTE_MAX_PORTS; i++) {
if (sf_buffer[i]) {
free(sf_buffer[i]);
}
if (output_buffer[i]) {
free(output_buffer[i]);
}
}
if (output_file_name) {
if (!null_file_sink) {
@ -348,15 +435,45 @@ uint32_t prbset_to_bitmask() {
}
int update_radl() {
/* Configure cell and PDSCH in function of the transmission mode */
switch(pdsch_cfg.mimo_type) {
case SRSLTE_MIMO_TYPE_SINGLE_ANTENNA:
pdsch_cfg.nof_layers = 1;
nof_tb = 1;
break;
case SRSLTE_MIMO_TYPE_TX_DIVERSITY:
pdsch_cfg.nof_layers = 2;
nof_tb = 1;
break;
case SRSLTE_MIMO_TYPE_CDD:
pdsch_cfg.nof_layers = 2;
nof_tb = 2;
break;
case SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX:
pdsch_cfg.nof_layers = multiplex_nof_layers;
nof_tb = multiplex_nof_layers;
break;
default:
ERROR("Transmission mode not implemented.");
exit(-1);
}
bzero(&ra_dl, sizeof(srslte_ra_dl_dci_t));
ra_dl.harq_process = 0;
ra_dl.mcs_idx = mcs_idx;
ra_dl.ndi = 0;
ra_dl.rv_idx = 0;
ra_dl.rv_idx = rvidx[0];
ra_dl.alloc_type = SRSLTE_RA_ALLOC_TYPE0;
ra_dl.type0_alloc.rbg_bitmask = prbset_to_bitmask();
ra_dl.tb_en[0] = 1;
ra_dl.tb_en[0] = 1;
if (nof_tb > 1) {
ra_dl.mcs_idx_1 = mcs_idx;
ra_dl.ndi_1 = 0;
ra_dl.rv_idx_1 = rvidx[1];
ra_dl.tb_en[1] = 1;
}
srslte_ra_pdsch_fprint(stdout, &ra_dl, cell.nof_prb);
srslte_ra_dl_grant_t dummy_grant;
@ -364,8 +481,21 @@ int update_radl() {
srslte_ra_dl_dci_to_grant(&ra_dl, cell.nof_prb, UE_CRNTI, &dummy_grant);
srslte_ra_dl_grant_to_nbits(&dummy_grant, cfi, cell, 0, &dummy_nbits);
srslte_ra_dl_grant_fprint(stdout, &dummy_grant);
printf("Type new MCS index and press Enter: "); fflush(stdout);
if (pdsch_cfg.mimo_type != SRSLTE_MIMO_TYPE_SINGLE_ANTENNA) {
printf("\nTransmission mode key table:\n");
printf(" Mode | 1TB | 2TB |\n");
printf("----------+---------+-----+\n");
printf("Diversity | x | |\n");
printf(" CDD | | z |\n");
printf("Multiplex | q,w,e,r | a,s |\n");
printf("\n");
printf("Type new MCS index (0-28) or mode key and press Enter: ");
} else {
printf("Type new MCS index (0-28) and press Enter: ");
}
fflush(stdout);
return 0;
}
@ -406,8 +536,47 @@ int update_control() {
break;
}
} else {
last_mcs_idx = mcs_idx;
mcs_idx = atoi(input);
switch (input[0]) {
case 'q':
pdsch_cfg.mimo_type = SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX;
multiplex_pmi = 0;
multiplex_nof_layers = 1;
break;
case 'w':
pdsch_cfg.mimo_type = SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX;
multiplex_pmi = 1;
multiplex_nof_layers = 1;
break;
case 'e':
pdsch_cfg.mimo_type = SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX;
multiplex_pmi = 2;
multiplex_nof_layers = 1;
break;
case 'r':
pdsch_cfg.mimo_type = SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX;
multiplex_pmi = 3;
multiplex_nof_layers = 1;
break;
case 'a':
pdsch_cfg.mimo_type = SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX;
multiplex_pmi = 0;
multiplex_nof_layers = 2;
break;
case 's':
pdsch_cfg.mimo_type = SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX;
multiplex_pmi = 1;
multiplex_nof_layers = 2;
break;
case 'z':
pdsch_cfg.mimo_type = SRSLTE_MIMO_TYPE_CDD;
break;
case 'x':
pdsch_cfg.mimo_type = SRSLTE_MIMO_TYPE_TX_DIVERSITY;
break;
default:
last_mcs_idx = mcs_idx;
mcs_idx = atoi(input);
}
}
bzero(input,sizeof(input));
if (update_radl()) {
@ -427,10 +596,6 @@ int update_control() {
}
}
#define DATA_BUFF_SZ 1024*128
uint8_t data[8*DATA_BUFF_SZ], data2[DATA_BUFF_SZ];
uint8_t data_tmp[DATA_BUFF_SZ];
/** Function run in a separate thread to receive UDP data */
void *net_thread_fnc(void *arg) {
int n;
@ -439,14 +604,16 @@ void *net_thread_fnc(void *arg) {
do {
n = srslte_netsource_read(&net_source, &data2[rpm], DATA_BUFF_SZ-rpm);
if (n > 0) {
int nbytes = 1+(pdsch_cfg.grant.mcs.tbs-1)/8;
// FIXME: I assume that both transport blocks have same size in case of 2 tb are active
int nbytes = 1 + (pdsch_cfg.grant.mcs[0].tbs + pdsch_cfg.grant.mcs[1].tbs - 1) / 8;
rpm += n;
INFO("received %d bytes. rpm=%d/%d\n",n,rpm,nbytes);
wpm = 0;
while (rpm >= nbytes) {
// wait for packet to be transmitted
sem_wait(&net_sem);
memcpy(data, &data2[wpm], nbytes);
memcpy(data[0], &data2[wpm], nbytes / (size_t) 2);
memcpy(data[1], &data2[wpm], nbytes / (size_t) 2);
INFO("Sent %d/%d bytes ready\n", nbytes, rpm);
rpm -= nbytes;
wpm += nbytes;
@ -517,9 +684,9 @@ int main(int argc, char **argv) {
exit(-1);
}
for (i = 0; i < SRSLTE_MAX_PORTS; i++) { // now there's only 1 port
sf_symbols[i] = sf_buffer;
slot1_symbols[i] = &sf_buffer[SRSLTE_SLOT_LEN_RE(cell.nof_prb, cell.cp)];
for (i = 0; i < SRSLTE_MAX_PORTS; i++) {
sf_symbols[i] = sf_buffer[i%cell.nof_ports];
slot1_symbols[i] = &sf_buffer[i%cell.nof_ports][SRSLTE_SLOT_LEN_RE(cell.nof_prb, cell.cp)];
}
#ifndef DISABLE_RF
@ -576,7 +743,9 @@ int main(int argc, char **argv) {
nf = 0;
bool send_data = false;
srslte_softbuffer_tx_reset(&softbuffer);
for (i = 0; i < SRSLTE_MAX_CODEWORDS; i++) {
srslte_softbuffer_tx_reset(softbuffers[i]);
}
#ifndef DISABLE_RF
bool start_of_burst = true;
@ -584,15 +753,25 @@ int main(int argc, char **argv) {
while ((nf < nof_frames || nof_frames == -1) && !go_exit) {
for (sf_idx = 0; sf_idx < SRSLTE_NSUBFRAMES_X_FRAME && (nf < nof_frames || nof_frames == -1); sf_idx++) {
bzero(sf_buffer, sizeof(cf_t) * sf_n_re);
/* Set Antenna port resource elements to zero */
bzero(sf_symbols[0], sizeof(cf_t) * sf_n_re);
/* Populate Synchronization signals if required */
if (sf_idx == 0 || sf_idx == 5) {
srslte_pss_put_slot(pss_signal, sf_buffer, cell.nof_prb, SRSLTE_CP_NORM);
srslte_sss_put_slot(sf_idx ? sss_signal5 : sss_signal0, sf_buffer, cell.nof_prb,
srslte_pss_put_slot(pss_signal, sf_symbols[0], cell.nof_prb, SRSLTE_CP_NORM);
srslte_sss_put_slot(sf_idx ? sss_signal5 : sss_signal0, sf_symbols[0], cell.nof_prb,
SRSLTE_CP_NORM);
}
srslte_refsignal_cs_put_sf(cell, 0, est.csr_signal.pilots[0][sf_idx], sf_buffer);
/* Copy zeros, SSS, PSS into the rest of antenna ports */
for (i = 1; i < cell.nof_ports; i++) {
memcpy(sf_symbols[i], sf_symbols[0], sizeof(cf_t) * sf_n_re);
}
/* Put reference signals */
for (i = 0; i < cell.nof_ports; i++) {
srslte_refsignal_cs_put_sf(cell, (uint32_t) i, est.csr_signal.pilots[i / 2][sf_idx], sf_symbols[i]);
}
srslte_pbch_mib_pack(&cell, sfn, bch_payload);
if (sf_idx == 0) {
@ -613,9 +792,11 @@ int main(int argc, char **argv) {
INFO("Transmitting packet\n",0);
}
} else {
INFO("SF: %d, Generating %d random bits\n", sf_idx, pdsch_cfg.grant.mcs.tbs);
for (i=0;i<pdsch_cfg.grant.mcs.tbs/8;i++) {
data[i] = rand()%256;
INFO("SF: %d, Generating %d random bits\n", sf_idx, pdsch_cfg.grant.mcs[0].tbs + pdsch_cfg.grant.mcs[1].tbs);
for (uint32_t tb = 0; tb < pdsch_cfg.grant.nof_tb; tb++) {
for (i = 0; i < pdsch_cfg.grant.mcs[tb].tbs / 8; i++) {
data[tb][i] = (uint8_t) rand();
}
}
/* Uncomment this to transmit on sf 0 and 5 only */
if (sf_idx != 0 && sf_idx != 5) {
@ -626,10 +807,30 @@ int main(int argc, char **argv) {
}
if (send_data) {
srslte_dci_format_t dci_format;
switch(pdsch_cfg.mimo_type) {
case SRSLTE_MIMO_TYPE_SINGLE_ANTENNA:
dci_format = SRSLTE_DCI_FORMAT1;
break;
case SRSLTE_MIMO_TYPE_TX_DIVERSITY:
case SRSLTE_MIMO_TYPE_CDD:
dci_format = SRSLTE_DCI_FORMAT2A;
break;
case SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX:
dci_format = SRSLTE_DCI_FORMAT2;
if (multiplex_nof_layers == 1) {
ra_dl.pinfo = (uint8_t) (multiplex_pmi + 1);
} else {
ra_dl.pinfo = (uint8_t) multiplex_pmi;
}
break;
default:
fprintf(stderr, "Wrong MIMO configuration\n");
exit(SRSLTE_ERROR);
}
/* Encode PDCCH */
INFO("Putting DCI to location: n=%d, L=%d\n", locations[sf_idx][0].ncce, locations[sf_idx][0].L);
srslte_dci_msg_pack_pdsch(&ra_dl, SRSLTE_DCI_FORMAT1, &dci_msg, cell.nof_prb, cell.nof_ports, false);
srslte_dci_msg_pack_pdsch(&ra_dl, dci_format, &dci_msg, cell.nof_prb, cell.nof_ports, false);
if (srslte_pdcch_encode(&pdcch, &dci_msg, locations[sf_idx][0], UE_CRNTI, sf_symbols, sf_idx, cfi)) {
fprintf(stderr, "Error encoding DCI message\n");
exit(-1);
@ -638,22 +839,24 @@ int main(int argc, char **argv) {
/* Configure pdsch_cfg parameters */
srslte_ra_dl_grant_t grant;
srslte_ra_dl_dci_to_grant(&ra_dl, cell.nof_prb, UE_CRNTI, &grant);
if (srslte_pdsch_cfg(&pdsch_cfg, cell, &grant, cfi, sf_idx, 0)) {
if (srslte_pdsch_cfg_mimo(&pdsch_cfg, cell, &grant, cfi, sf_idx, rvidx, pdsch_cfg.mimo_type, multiplex_pmi)) {
fprintf(stderr, "Error configuring PDSCH\n");
exit(-1);
}
/* Encode PDSCH */
if (srslte_pdsch_encode(&pdsch, &pdsch_cfg, &softbuffer, data, UE_CRNTI, sf_symbols)) {
if (srslte_pdsch_encode(&pdsch, &pdsch_cfg, softbuffers, data, UE_CRNTI, sf_symbols)) {
fprintf(stderr, "Error encoding PDSCH\n");
exit(-1);
}
if (net_port > 0 && net_packet_ready) {
if (null_file_sink) {
srslte_bit_pack_vector(data, data_tmp, pdsch_cfg.grant.mcs.tbs);
if (srslte_netsink_write(&net_sink, data_tmp, 1+(pdsch_cfg.grant.mcs.tbs-1)/8) < 0) {
fprintf(stderr, "Error sending data through UDP socket\n");
}
for (uint32_t tb = 0; tb < pdsch_cfg.grant.nof_tb; tb++) {
srslte_bit_pack_vector(data[tb], data_tmp, pdsch_cfg.grant.mcs[tb].tbs);
if (srslte_netsink_write(&net_sink, data_tmp, 1 + (pdsch_cfg.grant.mcs[tb].tbs - 1) / 8) < 0) {
fprintf(stderr, "Error sending data through UDP socket\n");
}
}
}
net_packet_ready = false;
sem_post(&net_sem);
@ -661,21 +864,24 @@ int main(int argc, char **argv) {
}
/* Transform to OFDM symbols */
srslte_ofdm_tx_sf(&ifft, sf_buffer, output_buffer);
for (i = 0; i < cell.nof_ports; i++) {
srslte_ofdm_tx_sf(&ifft, sf_buffer[i], output_buffer[i]);
}
/* send to file or usrp */
if (output_file_name) {
if (!null_file_sink) {
srslte_filesink_write(&fsink, output_buffer, sf_n_samples);
srslte_filesink_write_multi(&fsink, (void**) output_buffer, sf_n_samples, cell.nof_ports);
}
usleep(1000);
} else {
#ifndef DISABLE_RF
// FIXME
float norm_factor = (float) cell.nof_prb/15/sqrtf(pdsch_cfg.grant.nof_prb);
srslte_vec_sc_prod_cfc(output_buffer, rf_amp*norm_factor, output_buffer, SRSLTE_SF_LEN_PRB(cell.nof_prb));
srslte_rf_send2(&rf, output_buffer, sf_n_samples, true, start_of_burst, false);
start_of_burst=false;
for (i = 0; i < cell.nof_ports; i++) {
srslte_vec_sc_prod_cfc(output_buffer[i], rf_amp * norm_factor, output_buffer[i], SRSLTE_SF_LEN_PRB(cell.nof_prb));
}
srslte_rf_send_multi(&rf, (void**) output_buffer, sf_n_samples, true, start_of_burst, false);
start_of_burst=false;
#endif
}
}

@ -36,6 +36,9 @@
#include <signal.h>
#include <pthread.h>
#include <semaphore.h>
#include <srslte/srslte.h>
#include <srslte/phy/phch/pdsch_cfg.h>
#include <srslte/phy/phch/ra.h>
#include "srslte/srslte.h"
@ -98,6 +101,7 @@ typedef struct {
int net_port_signal;
char *net_address_signal;
int decimate;
int verbose;
}prog_args_t;
void args_default(prog_args_t *args) {
@ -238,6 +242,7 @@ void parse_args(prog_args_t *args, int argc, char **argv) {
break;
case 'v':
srslte_verbose++;
args->verbose = srslte_verbose;
break;
case 'Z':
args->decimate = atoi(argv[optind]);
@ -258,7 +263,7 @@ void parse_args(prog_args_t *args, int argc, char **argv) {
/**********************************************************************/
/* TODO: Do something with the output data */
uint8_t data[20000];
uint8_t *data[SRSLTE_MAX_CODEWORDS];
bool go_exit = false;
void sig_int_handler(int signo)
@ -266,10 +271,12 @@ void sig_int_handler(int signo)
printf("SIGINT received. Exiting...\n");
if (signo == SIGINT) {
go_exit = true;
} else if (signo == SIGSEGV) {
exit(1);
}
}
cf_t *sf_buffer[2] = {NULL, NULL};
cf_t *sf_buffer[SRSLTE_MAX_PORTS] = {NULL};
#ifndef DISABLE_RF
int srslte_rf_recv_wrapper(void *h, cf_t *data[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte_timestamp_t *t) {
@ -298,6 +305,12 @@ prog_args_t prog_args;
uint32_t sfn = 0; // system frame number
srslte_netsink_t net_sink, net_sink_signal;
/* Useful macros for printing lines which will disappear */
#define PRINT_LINE_INIT() int this_nof_lines = 0; static int prev_nof_lines = 0
#define PRINT_LINE(_fmt, ...) printf("\033[K" _fmt "\n", ##__VA_ARGS__); this_nof_lines++
#define PRINT_LINE_RESET_CURSOR() printf("\033[%dA", this_nof_lines); prev_nof_lines = this_nof_lines
#define PRINT_LINE_ADVANCE_CURSOR() printf("\033[%dB", prev_nof_lines + 1)
int main(int argc, char **argv) {
int ret;
int decimate = 1;
@ -308,13 +321,20 @@ int main(int argc, char **argv) {
srslte_rf_t rf;
#endif
uint32_t nof_trials = 0;
int n;
uint8_t bch_payload[SRSLTE_BCH_PAYLOAD_LEN];
int sfn_offset;
float cfo = 0;
parse_args(&prog_args, argc, argv);
for (int i = 0; i< SRSLTE_MAX_CODEWORDS; i++) {
data[i] = srslte_vec_malloc(sizeof(uint8_t)*1500*8);
if (!data[i]) {
ERROR("Allocating data");
go_exit = true;
}
}
if(prog_args.cpu_affinity > -1) {
cpu_set_t cpuset;
@ -379,8 +399,8 @@ int main(int argc, char **argv) {
srslte_rf_set_master_clock_rate(&rf, 30.72e6);
/* set receiver frequency */
printf("Tunning receiver to %.3f MHz\n", prog_args.rf_freq/1000000);
srslte_rf_set_rx_freq(&rf, prog_args.rf_freq);
printf("Tunning receiver to %.3f MHz\n", (prog_args.rf_freq + prog_args.file_offset_freq)/1000000);
srslte_rf_set_rx_freq(&rf, prog_args.rf_freq + prog_args.file_offset_freq);
srslte_rf_rx_wait_lo_locked(&rf);
uint32_t ntrial=0;
@ -435,8 +455,8 @@ int main(int argc, char **argv) {
cell.nof_ports = prog_args.file_nof_ports;
cell.nof_prb = prog_args.file_nof_prb;
if (srslte_ue_sync_init_file(&ue_sync, prog_args.file_nof_prb,
prog_args.input_file_name, prog_args.file_offset_time, prog_args.file_offset_freq)) {
if (srslte_ue_sync_init_file_multi(&ue_sync, prog_args.file_nof_prb,
prog_args.input_file_name, prog_args.file_offset_time, prog_args.file_offset_freq, prog_args.rf_nof_rx_ant)) {
fprintf(stderr, "Error initiating ue_sync\n");
exit(-1);
}
@ -482,7 +502,7 @@ int main(int argc, char **argv) {
exit(-1);
}
if (srslte_ue_dl_init_multi(&ue_dl, cell.nof_prb, prog_args.rf_nof_rx_ant)) {
if (srslte_ue_dl_init(&ue_dl, cell.nof_prb, prog_args.rf_nof_rx_ant)) {
fprintf(stderr, "Error initiating UE downlink processing module\n");
exit(-1);
}
@ -517,9 +537,15 @@ int main(int argc, char **argv) {
// Variables for measurements
uint32_t nframes=0;
float rsrp=0.0, rsrq=0.0, noise=0.0;
uint32_t ri = 0, pmi = 0;
float rsrp0=0.0, rsrp1=0.0, rsrq=0.0, noise=0.0, enodebrate = 0.0, uerate = 0.0,
sinr[SRSLTE_MAX_LAYERS][SRSLTE_MAX_CODEBOOKS], cn = 0.0;
bool decode_pdsch = false;
for (int i = 0; i < SRSLTE_MAX_LAYERS; i++) {
bzero(sinr[i], sizeof(float)*SRSLTE_MAX_CODEBOOKS);
}
#ifndef DISABLE_RF
if (prog_args.rf_gain < 0) {
srslte_ue_sync_start_agc(&ue_sync, srslte_rf_set_rx_gain_th_wrapper_, cell_detect_config.init_agc);
@ -540,7 +566,29 @@ int main(int argc, char **argv) {
INFO("\nEntering main loop...\n\n", 0);
/* Main loop */
while (!go_exit && (sf_cnt < prog_args.nof_subframes || prog_args.nof_subframes == -1)) {
bool acks [SRSLTE_MAX_CODEWORDS] = {false};
char input[128];
PRINT_LINE_INIT();
fd_set set;
FD_ZERO(&set);
FD_SET(0, &set);
struct timeval to;
to.tv_sec = 0;
to.tv_usec = 0;
/* Set default verbose level */
srslte_verbose = prog_args.verbose;
int n = select(1, &set, NULL, NULL, &to);
if (n == 1) {
/* If a new line is detected set verbose level to Debug */
if (fgets(input, sizeof(input), stdin)) {
srslte_verbose = SRSLTE_VERBOSE_DEBUG;
}
}
ret = srslte_ue_sync_zerocopy_multi(&ue_sync, sf_buffer);
if (ret < 0) {
fprintf(stderr, "Error calling srslte_ue_sync_work()\n");
@ -580,12 +628,30 @@ int main(int argc, char **argv) {
decode_pdsch = false;
}
}
if (decode_pdsch) {
INFO("Attempting DL decode SFN=%d\n", sfn);
n = srslte_ue_dl_decode_multi(&ue_dl,
sf_buffer,
data,
sfn*10+srslte_ue_sync_get_sfidx(&ue_sync));
INFO("Attempting DL decode SFN=%d\n", sfn);
if (decode_pdsch) {
if (cell.nof_ports == 1) {
/* Transmission mode 1 */
n = srslte_ue_dl_decode(&ue_dl, sf_buffer, data, 0, sfn*10+srslte_ue_sync_get_sfidx(&ue_sync), acks);
} else {
if (prog_args.rf_nof_rx_ant == 1) {
/* Transmission mode 2 */
n = srslte_ue_dl_decode(&ue_dl, sf_buffer, data, 1, sfn * 10 + srslte_ue_sync_get_sfidx(&ue_sync),
acks);
} else {
/* Transmission mode 3 */
n = srslte_ue_dl_decode(&ue_dl, sf_buffer, data, 2, sfn * 10 + srslte_ue_sync_get_sfidx(&ue_sync),
acks);
if (n < 1) {
/* Transmission mode 4 */
n = srslte_ue_dl_decode(&ue_dl, sf_buffer, data, 3, sfn * 10 + srslte_ue_sync_get_sfidx(&ue_sync),
acks);
}
}
}
if (n < 0) {
// fprintf(stderr, "Error decoding UE DL\n");fflush(stdout);
@ -593,7 +659,11 @@ int main(int argc, char **argv) {
/* Send data if socket active */
if (prog_args.net_port > 0) {
srslte_netsink_write(&net_sink, data, 1+(n-1)/8);
// FIXME: UDP Data transmission does not work
for (uint32_t tb = 0; tb < ue_dl.pdsch_cfg.grant.nof_tb; tb++) {
srslte_netsink_write(&net_sink, data[tb], 1 + (ue_dl.pdsch_cfg.grant.mcs[tb].tbs - 1) / 8);
}
}
#ifdef PRINT_CHANGE_SCHEDULIGN
@ -614,9 +684,13 @@ int main(int argc, char **argv) {
nof_trials++;
rsrq = SRSLTE_VEC_EMA(srslte_chest_dl_get_rsrq(&ue_dl.chest), rsrq, 0.1);
rsrp = SRSLTE_VEC_EMA(srslte_chest_dl_get_rsrp(&ue_dl.chest), rsrp, 0.05);
noise = SRSLTE_VEC_EMA(srslte_chest_dl_get_noise_estimate(&ue_dl.chest), noise, 0.05);
rsrq = SRSLTE_VEC_EMA(srslte_chest_dl_get_rsrq(&ue_dl.chest), rsrq, 0.1f);
rsrp0 = SRSLTE_VEC_EMA(srslte_chest_dl_get_rsrp_port(&ue_dl.chest, 0), rsrp0, 0.05f);
rsrp1 = SRSLTE_VEC_EMA(srslte_chest_dl_get_rsrp_port(&ue_dl.chest, 1), rsrp1, 0.05f);
noise = SRSLTE_VEC_EMA(srslte_chest_dl_get_noise_estimate(&ue_dl.chest), noise, 0.05f);
enodebrate = SRSLTE_VEC_EMA((ue_dl.pdsch_cfg.grant.mcs[0].tbs + ue_dl.pdsch_cfg.grant.mcs[1].tbs)/1000.0f, enodebrate, 0.05f);
uerate = SRSLTE_VEC_EMA(((acks[0]?ue_dl.pdsch_cfg.grant.mcs[0].tbs:0) + (acks[1]?ue_dl.pdsch_cfg.grant.mcs[1].tbs:0))/1000.0f, uerate, 0.01f);
nframes++;
if (isnan(rsrq)) {
rsrq = 0;
@ -624,25 +698,78 @@ int main(int argc, char **argv) {
if (isnan(noise)) {
noise = 0;
}
if (isnan(rsrp)) {
rsrp = 0;
}
if (isnan(rsrp0)) {
rsrp1 = 0;
}
if (isnan(rsrp0)) {
rsrp1 = 0;
}
}
// Plot and Printf
if (srslte_ue_sync_get_sfidx(&ue_sync) == 5) {
if (srslte_ue_sync_get_sfidx(&ue_sync) == 5 && sfn % 20 == 0) {
float gain = prog_args.rf_gain;
if (gain < 0) {
gain = 10*log10(srslte_agc_get_gain(&ue_sync.agc));
}
printf("CFO: %+6.2f kHz, "
"SNR: %4.1f dB, "
"PDCCH-Miss: %5.2f%%, PDSCH-BLER: %5.2f%%\r",
srslte_ue_sync_get_cfo(&ue_sync)/1000,
10*log10(rsrp/noise),
100*(1-(float) ue_dl.nof_detected/nof_trials),
(float) 100*ue_dl.pkt_errors/ue_dl.pkts_total);
/* Print transmission scheme */
if (ue_dl.pdsch_cfg.mimo_type == SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX) {
PRINT_LINE(" Tx scheme: %s (codebook_idx=%d)", srslte_mimotype2str(ue_dl.pdsch_cfg.mimo_type),
ue_dl.pdsch_cfg.codebook_idx);
} else {
PRINT_LINE(" Tx scheme: %s", srslte_mimotype2str(ue_dl.pdsch_cfg.mimo_type));
}
/* Print basic Parameters */
PRINT_LINE(" nof layers: %d", ue_dl.pdsch_cfg.nof_layers);
PRINT_LINE("nof codewords: %d", ue_dl.pdsch_cfg.grant.nof_tb);
PRINT_LINE(" CFO: %+5.2f kHz", srslte_ue_sync_get_cfo(&ue_sync) / 1000);
PRINT_LINE(" SNR: %+5.1f dB | %+5.1f dB", 10 * log10(rsrp0 / noise), 10 * log10(rsrp1 / noise));
PRINT_LINE(" Rb: %6.2f / %6.2f Mbps (net/maximum)", uerate, enodebrate);
PRINT_LINE(" PDCCH-Miss: %5.2f%%", 100 * (1 - (float) ue_dl.nof_detected / nof_trials));
PRINT_LINE(" PDSCH-BLER: %5.2f%%", (float) 100 * ue_dl.pkt_errors / ue_dl.pkts_total);
PRINT_LINE(" TB 0: mcs=%d; tbs=%d", ue_dl.pdsch_cfg.grant.mcs[0].idx,
ue_dl.pdsch_cfg.grant.mcs[0].tbs);
PRINT_LINE(" TB 1: mcs=%d; tbs=%d", ue_dl.pdsch_cfg.grant.mcs[1].idx,
ue_dl.pdsch_cfg.grant.mcs[1].tbs);
/* MIMO: if tx and rx antennas are bigger than 1 */
if (cell.nof_ports > 1 && ue_dl.pdsch.nof_rx_antennas > 1) {
/* Compute condition number */
srslte_ue_dl_ri_select(&ue_dl, NULL, &cn);
/* Print condition number */
PRINT_LINE(" κ: %.1f dB (Condition number, 0 dB => Best)", cn);
}
PRINT_LINE("");
/* Spatial multiplex only */
if (ue_dl.pdsch_cfg.mimo_type == SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX) {
/* Compute Rank Indicator (RI) and Precoding Matrix Indicator (PMI) */
srslte_ue_dl_ri_pmi_select(&ue_dl, &ri, &pmi, NULL);
for (uint32_t nl = 0; nl < SRSLTE_MAX_LAYERS; nl++) {
for (uint32_t cb = 0; cb < SRSLTE_MAX_CODEBOOKS; cb++) {
sinr[nl][cb] = SRSLTE_VEC_EMA(ue_dl.sinr[nl][cb], sinr[nl][cb], 0.5f);
}
}
/* Print Multiplex stats */
PRINT_LINE("SINR (dB) Vs RI and PMI:");
PRINT_LINE(" | RI | 1 | 2 |");
PRINT_LINE(" -------+-------+-------+");
PRINT_LINE(" P | 0 | %5.2f%c| %5.2f%c|", 10 * log10(sinr[0][0]), (ri == 1 && pmi == 0) ? '*' : ' ',
10 * log10(sinr[1][0]), (ri == 2 && pmi == 0) ? '*' : ' ');
PRINT_LINE(" M | 1 | %5.2f%c| %5.2f%c|", 10 * log10(sinr[0][1]), (ri == 1 && pmi == 1) ? '*' : ' ',
10 * log10(sinr[1][1]), (ri == 2 && pmi == 1) ? '*' : ' ');
PRINT_LINE(" I | 2 | %5.2f%c|-------+ ", 10 * log10(sinr[0][2]), (ri == 1 && pmi == 2) ? '*' : ' ');
PRINT_LINE(" | 3 | %5.2f%c| ", 10 * log10(sinr[0][3]), (ri == 1 && pmi == 3) ? '*' : ' ');
PRINT_LINE("");
}
PRINT_LINE("Press enter maximum printing debug log of 1 subframe.");
PRINT_LINE("");
PRINT_LINE_RESET_CURSOR();
}
break;
}
@ -650,7 +777,7 @@ int main(int argc, char **argv) {
sfn++;
if (sfn == 1024) {
sfn = 0;
printf("\n");
PRINT_LINE_ADVANCE_CURSOR();
ue_dl.pkt_errors = 0;
ue_dl.pkts_total = 0;
ue_dl.nof_detected = 0;
@ -682,7 +809,8 @@ int main(int argc, char **argv) {
sf_cnt++;
} // Main loop
printf("\033[30B\n");
#ifndef DISABLE_GRAPHICS
if (!prog_args.disable_plots) {
if (!pthread_kill(plot_thread, 0)) {
@ -693,6 +821,16 @@ int main(int argc, char **argv) {
#endif
srslte_ue_dl_free(&ue_dl);
srslte_ue_sync_free(&ue_sync);
for (int i = 0; i < SRSLTE_MAX_CODEWORDS; i++) {
if (data[i]) {
free(data[i]);
}
}
for (int i = 0; i < prog_args.rf_nof_rx_ant; i++) {
if (sf_buffer[i]) {
free(sf_buffer[i]);
}
}
#ifndef DISABLE_RF
if (!prog_args.input_file_name) {
@ -761,7 +899,7 @@ void *plot_thread_run(void *arg) {
while(1) {
sem_wait(&plot_sem);
uint32_t nof_symbols = ue_dl.pdsch_cfg.nbits.nof_re;
uint32_t nof_symbols = ue_dl.pdsch_cfg.nbits[0].nof_re;
if (!prog_args.disable_plots_except_constellation) {
for (i = 0; i < nof_re; i++) {
tmp_plot[i] = 20 * log10f(cabsf(ue_dl.sf_symbols[i]));
@ -803,7 +941,7 @@ void *plot_thread_run(void *arg) {
plot_scatter_setNewData(&pscatequal_pdcch, ue_dl.pdcch.d, 36*ue_dl.pdcch.nof_cce);
}
plot_scatter_setNewData(&pscatequal, ue_dl.pdsch.d, nof_symbols);
plot_scatter_setNewData(&pscatequal, ue_dl.pdsch.d[0], nof_symbols);
if (plot_sf_idx == 1) {
if (prog_args.net_port_signal > 0) {

@ -44,6 +44,7 @@ char *output_file_name;
char *rf_args="";
float rf_gain=40.0, rf_freq=-1.0, rf_rate=0.96e6;
int nof_samples = -1;
int nof_rx_antennas = 1;
void int_handler(int dummy) {
keep_running = false;
@ -55,12 +56,13 @@ void usage(char *prog) {
printf("\t-g RF Gain [Default %.2f dB]\n", rf_gain);
printf("\t-r RF Rate [Default %.6f Hz]\n", rf_rate);
printf("\t-n nof_samples [Default %d]\n", nof_samples);
printf("\t-A nof_rx_antennas [Default %d]\n", nof_rx_antennas);
printf("\t-v srslte_verbose\n");
}
void parse_args(int argc, char **argv) {
int opt;
while ((opt = getopt(argc, argv, "agrnvfo")) != -1) {
while ((opt = getopt(argc, argv, "agrnvfoA")) != -1) {
switch (opt) {
case 'o':
output_file_name = argv[optind];
@ -80,6 +82,9 @@ void parse_args(int argc, char **argv) {
case 'n':
nof_samples = atoi(argv[optind]);
break;
case 'A':
nof_rx_antennas = atoi(argv[optind]);
break;
case 'v':
srslte_verbose++;
break;
@ -95,11 +100,11 @@ void parse_args(int argc, char **argv) {
}
int main(int argc, char **argv) {
cf_t *buffer;
cf_t *buffer[SRSLTE_MAX_PORTS];
int sample_count, n;
srslte_rf_t rf;
srslte_filesink_t sink;
int32_t buflen;
uint32_t buflen;
signal(SIGINT, int_handler);
@ -107,17 +112,19 @@ int main(int argc, char **argv) {
buflen = 4800;
sample_count = 0;
buffer = malloc(sizeof(cf_t) * buflen);
if (!buffer) {
perror("malloc");
exit(-1);
for (int i = 0; i < nof_rx_antennas; i++) {
buffer[i] = malloc(sizeof(cf_t) * buflen);
if (!buffer[i]) {
perror("malloc");
exit(-1);
}
}
srslte_filesink_init(&sink, output_file_name, SRSLTE_COMPLEX_FLOAT_BIN);
printf("Opening RF device...\n");
if (srslte_rf_open(&rf, rf_args)) {
if (srslte_rf_open_multi(&rf, rf_args, nof_rx_antennas)) {
fprintf(stderr, "Error opening rf\n");
exit(-1);
}
@ -151,18 +158,23 @@ int main(int argc, char **argv) {
while((sample_count < nof_samples || nof_samples == -1)
&& keep_running){
n = srslte_rf_recv(&rf, buffer, buflen, 1);
n = srslte_rf_recv_with_time_multi(&rf, (void**) buffer, buflen, true, NULL, NULL);
if (n < 0) {
fprintf(stderr, "Error receiving samples\n");
exit(-1);
}
srslte_filesink_write(&sink, buffer, buflen);
srslte_filesink_write_multi(&sink, (void**) buffer, buflen, nof_rx_antennas);
sample_count += buflen;
}
for (int i = 0; i < nof_rx_antennas; i++) {
if (buffer[i]) {
free(buffer[i]);
}
}
srslte_filesink_free(&sink);
free(buffer);
srslte_rf_close(&rf);
printf("Ok - wrote %d samples\n", sample_count);

@ -45,6 +45,7 @@ float rf_gain=60.0, rf_freq=-1.0;
int nof_prb = 6;
int nof_subframes = -1;
int N_id_2 = -1;
uint32_t nof_rx_antennas = 1;
void int_handler(int dummy) {
keep_running = false;
@ -56,12 +57,13 @@ void usage(char *prog) {
printf("\t-g RF Gain [Default %.2f dB]\n", rf_gain);
printf("\t-p nof_prb [Default %d]\n", nof_prb);
printf("\t-n nof_subframes [Default %d]\n", nof_subframes);
printf("\t-A nof_rx_antennas [Default %d]\n", nof_rx_antennas);
printf("\t-v verbose\n");
}
void parse_args(int argc, char **argv) {
int opt;
while ((opt = getopt(argc, argv, "agpnvfol")) != -1) {
while ((opt = getopt(argc, argv, "agpnvfolA")) != -1) {
switch (opt) {
case 'o':
output_file_name = argv[optind];
@ -84,6 +86,9 @@ void parse_args(int argc, char **argv) {
case 'l':
N_id_2 = atoi(argv[optind]);
break;
case 'A':
nof_rx_antennas = (uint32_t) atoi(argv[optind]);
break;
case 'v':
srslte_verbose++;
break;
@ -100,7 +105,7 @@ void parse_args(int argc, char **argv) {
int srslte_rf_recv_wrapper(void *h, cf_t *data[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte_timestamp_t *t) {
DEBUG(" ---- Receive %d samples ---- \n", nsamples);
return srslte_rf_recv(h, data[0], nsamples, 1);
return srslte_rf_recv_with_time_multi(h, (void**) data, nsamples, true, NULL, NULL);
}
int main(int argc, char **argv) {
@ -118,13 +123,15 @@ int main(int argc, char **argv) {
srslte_filesink_init(&sink, output_file_name, SRSLTE_COMPLEX_FLOAT_BIN);
printf("Opening RF device...\n");
if (srslte_rf_open(&rf, rf_args)) {
if (srslte_rf_open_multi(&rf, rf_args, nof_rx_antennas)) {
fprintf(stderr, "Error opening rf\n");
exit(-1);
}
srslte_rf_set_master_clock_rate(&rf, 30.72e6);
buffer[0] = srslte_vec_malloc(3*sizeof(cf_t)*SRSLTE_SF_LEN_PRB(100));
for (int i = 0; i< SRSLTE_MAX_PORTS; i++) {
buffer[i] = srslte_vec_malloc(3 * sizeof(cf_t) * SRSLTE_SF_LEN_PRB(100));
}
sigset_t sigset;
sigemptyset(&sigset);
@ -158,7 +165,7 @@ int main(int argc, char **argv) {
cell.nof_prb = nof_prb;
cell.nof_ports = 1;
if (srslte_ue_sync_init_multi(&ue_sync, cell.nof_prb, cell.id==1000, srslte_rf_recv_wrapper, 1, (void*) &rf)) {
if (srslte_ue_sync_init_multi(&ue_sync, cell.nof_prb, cell.id==1000, srslte_rf_recv_wrapper, nof_rx_antennas, (void*) &rf)) {
fprintf(stderr, "Error initiating ue_sync\n");
exit(-1);
}
@ -185,7 +192,7 @@ int main(int argc, char **argv) {
}
} else {
printf("Writing to file %6d subframes...\r", subframe_count);
srslte_filesink_write(&sink, buffer[0], SRSLTE_SF_LEN_PRB(nof_prb));
srslte_filesink_write_multi(&sink, (void**) buffer, SRSLTE_SF_LEN_PRB(nof_prb),nof_rx_antennas);
subframe_count++;
}
}
@ -200,6 +207,12 @@ int main(int argc, char **argv) {
srslte_rf_close(&rf);
srslte_ue_sync_free(&ue_sync);
for (int i = 0; i < SRSLTE_MAX_PORTS; i++) {
if (buffer[i]) {
free(buffer[i]);
}
}
printf("Ok - wrote %d subframes\n", subframe_count);
exit(0);
}

@ -280,10 +280,10 @@ public:
uint32_t pid;
uint32_t tti;
uint32_t last_tti;
bool ndi;
bool last_ndi;
uint32_t n_bytes;
int rv;
bool ndi[SRSLTE_MAX_CODEWORDS];
bool last_ndi[SRSLTE_MAX_CODEWORDS];
uint32_t n_bytes[SRSLTE_MAX_CODEWORDS];
int rv[SRSLTE_MAX_CODEWORDS];
uint16_t rnti;
bool is_from_rar;
bool is_sps_release;
@ -294,28 +294,28 @@ public:
typedef struct {
bool decode_enabled;
int rv;
int rv[SRSLTE_MAX_TB];
uint16_t rnti;
bool generate_ack;
bool default_ack;
// If non-null, called after tb_decoded_ok to determine if ack needs to be sent
bool (*generate_ack_callback)(void*);
void *generate_ack_callback_arg;
uint8_t *payload_ptr;
srslte_softbuffer_rx_t *softbuffer;
uint8_t *payload_ptr[SRSLTE_MAX_TB];
srslte_softbuffer_rx_t *softbuffers[SRSLTE_MAX_TB];
srslte_phy_grant_t phy_grant;
} tb_action_dl_t;
typedef struct {
bool tx_enabled;
bool expect_ack;
uint32_t rv;
uint32_t rv[SRSLTE_MAX_TB];
uint16_t rnti;
uint32_t current_tx_nb;
int32_t tti_offset; // relative offset between grant and UL tx/HARQ rx
srslte_softbuffer_tx_t *softbuffer;
srslte_softbuffer_tx_t *softbuffers;
srslte_phy_grant_t phy_grant;
uint8_t *payload_ptr;
uint8_t *payload_ptr[SRSLTE_MAX_TB];
} tb_action_ul_t;
/* Indicate reception of UL grant.
@ -332,7 +332,7 @@ public:
virtual void new_grant_dl(mac_grant_t grant, tb_action_dl_t *action) = 0;
/* Indicate successfull decoding of PDSCH TB. */
virtual void tb_decoded(bool ack, srslte_rnti_type_t rnti_type, uint32_t harq_pid) = 0;
virtual void tb_decoded(bool ack, uint32_t tb_idx, srslte_rnti_type_t rnti_type, uint32_t harq_pid) = 0;
/* Indicate successfull decoding of BCH TB through PBCH */
virtual void bch_decoded_ok(uint8_t *payload, uint32_t len) = 0;

@ -135,6 +135,9 @@ SRSLTE_API float srslte_chest_dl_get_rssi(srslte_chest_dl_t *q);
SRSLTE_API float srslte_chest_dl_get_rsrq(srslte_chest_dl_t *q);
SRSLTE_API float srslte_chest_dl_get_rsrp_port(srslte_chest_dl_t *q,
uint32_t port);
SRSLTE_API float srslte_chest_dl_get_rsrp(srslte_chest_dl_t *q);
#endif

@ -52,9 +52,12 @@
#define SRSLTE_MAX_PORTS 4
#define SRSLTE_MAX_LAYERS 4
#define SRSLTE_MAX_CODEWORDS 2
#define SRSLTE_MAX_TB SRSLTE_MAX_CODEWORDS
#define SRSLTE_MAX_CODEBLOCKS 32
#define SRSLTE_MAX_CODEBOOKS 4
#define SRSLTE_LTE_CRC24A 0x1864CFB
#define SRSLTE_LTE_CRC24B 0X1800063
#define SRSLTE_LTE_CRC16 0x11021
@ -148,12 +151,12 @@ typedef enum SRSLTE_API {
} srslte_phich_resources_t;
typedef enum {
SRSLTE_RNTI_USER = 0,
SRSLTE_RNTI_SI,
SRSLTE_RNTI_RAR,
SRSLTE_RNTI_TEMP,
SRSLTE_RNTI_SPS,
SRSLTE_RNTI_PCH,
SRSLTE_RNTI_USER = 0, /* Cell RNTI */
SRSLTE_RNTI_SI, /* System Information RNTI */
SRSLTE_RNTI_RAR, /* Random Access RNTI */
SRSLTE_RNTI_TEMP, /* Temporary C-RNTI */
SRSLTE_RNTI_SPS, /* Semi-Persistent Scheduling C-RNTI */
SRSLTE_RNTI_PCH, /* Paging RNTI */
SRSLTE_RNTI_NOF_TYPES
} srslte_rnti_type_t;
@ -173,6 +176,11 @@ typedef enum SRSLTE_API {
SRSLTE_MIMO_TYPE_CDD
} srslte_mimo_type_t;
typedef enum SRSLTE_API {
SRSLTE_MIMO_DECODER_ZF,
SRSLTE_MIMO_DECODER_MMSE
} srslte_mimo_decoder_t;
typedef enum SRSLTE_API {
SRSLTE_MOD_BPSK = 0,
SRSLTE_MOD_QPSK,
@ -247,6 +255,8 @@ SRSLTE_API float srslte_coderate(uint32_t tbs,
SRSLTE_API char *srslte_cp_string(srslte_cp_t cp);
SRSLTE_API srslte_mod_t srslte_str2mod (char * mod_str);
SRSLTE_API char *srslte_mod_string(srslte_mod_t mod);
SRSLTE_API uint32_t srslte_mod_bits_x_symbol(srslte_mod_t mod);
@ -276,6 +286,8 @@ SRSLTE_API int srslte_band_get_fd_region(enum band_geographical_area region,
SRSLTE_API int srslte_str2mimotype(char *mimo_type_str,
srslte_mimo_type_t *type);
SRSLTE_API char *srslte_mimotype2str(srslte_mimo_type_t mimo_type);
SRSLTE_API uint32_t srslte_tti_interval(uint32_t tti1,
uint32_t tti2);

@ -155,11 +155,11 @@ SRSLTE_API void srslte_enb_dl_rem_rnti(srslte_enb_dl_t *q,
SRSLTE_API int srslte_enb_dl_put_pdsch(srslte_enb_dl_t *q,
srslte_ra_dl_grant_t *grant,
srslte_softbuffer_tx_t *softbuffer,
srslte_softbuffer_tx_t *softbuffer[SRSLTE_MAX_CODEWORDS],
uint16_t rnti,
uint32_t rv_idx,
uint32_t sf_idx,
uint8_t *data);
uint8_t *data[SRSLTE_MAX_CODEWORDS]);
SRSLTE_API int srslte_enb_dl_put_pdcch_dl(srslte_enb_dl_t *q,
srslte_ra_dl_dci_t *grant,

@ -59,4 +59,9 @@ SRSLTE_API int srslte_filesink_write(srslte_filesink_t *q,
void *buffer,
int nsamples);
SRSLTE_API int srslte_filesink_write_multi(srslte_filesink_t *q,
void **buffer,
int nsamples,
int nchannels);
#endif // FILESINK_

@ -62,4 +62,9 @@ SRSLTE_API int srslte_filesource_read(srslte_filesource_t *q,
void *buffer,
int nsamples);
SRSLTE_API int srslte_filesource_read_multi(srslte_filesource_t *q,
void **buffer,
int nsamples,
int nof_channels);
#endif // FILESOURCE_

@ -65,8 +65,9 @@ SRSLTE_API int srslte_precoding_cdd(cf_t *x[SRSLTE_MAX_LAYERS],
SRSLTE_API int srslte_precoding_type(cf_t *x[SRSLTE_MAX_LAYERS],
cf_t *y[SRSLTE_MAX_PORTS],
int nof_layers,
int nof_ports,
int nof_symbols,
int nof_ports,
int codebook_idx,
int nof_symbols,
srslte_mimo_type_t type);
/* Estimates the vector "x" based on the received signal "y" and the channel estimates "h"
@ -106,14 +107,31 @@ SRSLTE_API int srslte_predecoding_type(cf_t *y,
srslte_mimo_type_t type,
float noise_estimate);
SRSLTE_API void srslte_predecoding_set_mimo_decoder (srslte_mimo_decoder_t _mimo_decoder);
SRSLTE_API int srslte_predecoding_type_multi(cf_t *y[SRSLTE_MAX_PORTS],
cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS],
cf_t *x[SRSLTE_MAX_LAYERS],
int nof_rxant,
int nof_ports,
int nof_layers,
int codebook_idx,
int nof_symbols,
srslte_mimo_type_t type,
float noise_estimate);
SRSLTE_API int srslte_precoding_pmi_select(cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS],
uint32_t nof_symbols,
float noise_estimate,
int nof_layers,
uint32_t *pmi,
float sinr[SRSLTE_MAX_CODEBOOKS]);
SRSLTE_API int srslte_precoding_cn(cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS],
uint32_t nof_tx_antennas,
uint32_t nof_rx_antennas,
uint32_t nof_symbols,
float *cn);
#endif /* PRECODING_H_ */

@ -45,7 +45,8 @@
typedef struct {
bool configured;
uint32_t pmi_idx;
bool simul_cqi_ack;
uint32_t ri_idx;
bool simul_cqi_ack;
bool format_is_subband;
uint32_t subband_size;
} srslte_cqi_periodic_cfg_t;
@ -137,7 +138,11 @@ SRSLTE_API int srslte_cqi_format2_subband_unpack(uint8_t buff[SRSLTE_CQI_MAX_BIT
srslte_cqi_format2_subband_t *msg);
SRSLTE_API bool srslte_cqi_send(uint32_t I_cqi_pmi,
uint32_t tti);
uint32_t tti);
SRSLTE_API bool srslte_ri_send(uint32_t I_cqi_pmi,
uint32_t I_ri,
uint32_t tti);
SRSLTE_API uint8_t srslte_cqi_from_snr(float snr);

@ -78,10 +78,8 @@ typedef struct SRSLTE_API {
} srslte_pcfich_t;
SRSLTE_API int srslte_pcfich_init(srslte_pcfich_t *q);
SRSLTE_API int srslte_pcfich_init_multi(srslte_pcfich_t *q,
uint32_t nof_rx_antennas);
SRSLTE_API int srslte_pcfich_init(srslte_pcfich_t *q,
uint32_t nof_rx_antennas);
SRSLTE_API int srslte_pcfich_set_cell(srslte_pcfich_t *q,
srslte_regs_t *regs,

@ -64,6 +64,7 @@ typedef struct SRSLTE_API {
uint32_t nof_cce;
uint32_t max_bits;
uint32_t nof_rx_antennas;
bool is_ue;
srslte_regs_t *regs;
@ -84,12 +85,12 @@ typedef struct SRSLTE_API {
} srslte_pdcch_t;
SRSLTE_API int srslte_pdcch_init(srslte_pdcch_t *q,
uint32_t max_prb);
SRSLTE_API int srslte_pdcch_init_ue(srslte_pdcch_t *q,
uint32_t max_prb,
uint32_t nof_rx_antennas);
SRSLTE_API int srslte_pdcch_init_multi(srslte_pdcch_t *q,
uint32_t max_prb,
uint32_t nof_rx_antennas);
SRSLTE_API int srslte_pdcch_init_enb(srslte_pdcch_t *q,
uint32_t max_prb);
SRSLTE_API int srslte_pdcch_set_cell(srslte_pdcch_t *q,
srslte_regs_t *regs,

@ -48,7 +48,7 @@
#include "srslte/phy/phch/pdsch_cfg.h"
typedef struct {
srslte_sequence_t seq[SRSLTE_NSUBFRAMES_X_FRAME];
srslte_sequence_t seq[SRSLTE_MAX_CODEWORDS][SRSLTE_NSUBFRAMES_X_FRAME];
uint32_t cell_id;
bool sequence_generated;
} srslte_pdsch_user_t;
@ -65,11 +65,11 @@ typedef struct SRSLTE_API {
/* buffers */
// void buffers are shared for tx and rx
cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS];
cf_t *symbols[SRSLTE_MAX_PORTS];
cf_t *x[SRSLTE_MAX_PORTS];
cf_t *d;
void *e;
cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS]; /* Channel estimation (Rx only) */
cf_t *symbols[SRSLTE_MAX_PORTS]; /* PDSCH Encoded/Decoded Symbols */
cf_t *x[SRSLTE_MAX_LAYERS]; /* Layer mapped */
cf_t *d[SRSLTE_MAX_CODEWORDS]; /* Modulated/Demodulated codewords */
void *e[SRSLTE_MAX_CODEWORDS];
/* tx & rx objects */
srslte_modem_table_t mod[4];
@ -80,23 +80,17 @@ typedef struct SRSLTE_API {
srslte_sequence_t tmp_seq;
srslte_sch_t dl_sch;
} srslte_pdsch_t;
SRSLTE_API int srslte_pdsch_init_ue(srslte_pdsch_t *q,
uint32_t max_prb);
uint32_t max_prb,
uint32_t nof_rx_antennas);
SRSLTE_API int srslte_pdsch_init_enb(srslte_pdsch_t *q,
uint32_t max_prb);
SRSLTE_API int srslte_pdsch_init_multi_ue(srslte_pdsch_t *q,
uint32_t max_prb,
uint32_t nof_rx_antennas);
SRSLTE_API int srslte_pdsch_init_multi_enb(srslte_pdsch_t *q,
uint32_t max_prb,
uint32_t nof_rx_antennas);
SRSLTE_API void srslte_pdsch_free(srslte_pdsch_t *q);
SRSLTE_API int srslte_pdsch_set_cell(srslte_pdsch_t *q,
@ -113,34 +107,50 @@ SRSLTE_API int srslte_pdsch_cfg(srslte_pdsch_cfg_t *cfg,
srslte_ra_dl_grant_t *grant,
uint32_t cfi,
uint32_t sf_idx,
uint32_t rvidx);
int rvidx);
SRSLTE_API int srslte_pdsch_cfg_mimo(srslte_pdsch_cfg_t *cfg,
srslte_cell_t cell,
srslte_ra_dl_grant_t *grant,
uint32_t cfi,
uint32_t sf_idx,
int rvidx[SRSLTE_MAX_CODEWORDS],
srslte_mimo_type_t mimo_type,
uint32_t pmi);
SRSLTE_API int srslte_pdsch_encode(srslte_pdsch_t *q,
srslte_pdsch_cfg_t *cfg,
srslte_softbuffer_tx_t *softbuffer,
uint8_t *data,
uint16_t rnti,
cf_t *sf_symbols[SRSLTE_MAX_PORTS]);
srslte_pdsch_cfg_t *cfg,
srslte_softbuffer_tx_t *softbuffers[SRSLTE_MAX_CODEWORDS],
uint8_t *data[SRSLTE_MAX_CODEWORDS],
uint16_t rnti,
cf_t *sf_symbols[SRSLTE_MAX_PORTS]);
SRSLTE_API int srslte_pdsch_decode(srslte_pdsch_t *q,
srslte_pdsch_cfg_t *cfg,
srslte_softbuffer_rx_t *softbuffer,
cf_t *sf_symbols,
cf_t *ce[SRSLTE_MAX_PORTS],
float noise_estimate,
srslte_pdsch_cfg_t *cfg,
srslte_softbuffer_rx_t *softbuffers[SRSLTE_MAX_CODEWORDS],
cf_t *sf_symbols[SRSLTE_MAX_PORTS],
cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS],
float noise_estimate,
uint16_t rnti,
uint8_t *data);
SRSLTE_API int srslte_pdsch_decode_multi(srslte_pdsch_t *q,
srslte_pdsch_cfg_t *cfg,
srslte_softbuffer_rx_t *softbuffer,
cf_t *sf_symbols[SRSLTE_MAX_PORTS],
cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS],
float noise_estimate,
uint16_t rnti,
uint8_t *data);
uint8_t *data[SRSLTE_MAX_CODEWORDS],
bool acks[SRSLTE_MAX_CODEWORDS]);
SRSLTE_API int srslte_pdsch_pmi_select(srslte_pdsch_t *q,
srslte_pdsch_cfg_t *cfg,
cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS],
float noise_estimate,
uint32_t nof_ce,
uint32_t pmi[SRSLTE_MAX_LAYERS],
float sinr[SRSLTE_MAX_LAYERS][SRSLTE_MAX_CODEBOOKS]);
SRSLTE_API int srslte_pdsch_cn_compute(srslte_pdsch_t *q,
cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS],
uint32_t nof_ce,
float *cn);
SRSLTE_API void srslte_pdsch_set_max_noi(srslte_pdsch_t *q, uint32_t max_iter);
SRSLTE_API float srslte_pdsch_average_noi(srslte_pdsch_t *q);
SRSLTE_API float srslte_pdsch_average_noi(srslte_pdsch_t *q);
SRSLTE_API uint32_t srslte_pdsch_last_noi(srslte_pdsch_t *q);

@ -40,11 +40,14 @@
#include "srslte/phy/fec/cbsegm.h"
typedef struct SRSLTE_API {
srslte_cbsegm_t cb_segm;
srslte_ra_dl_grant_t grant;
srslte_ra_nbits_t nbits;
uint32_t rv;
uint32_t sf_idx;
srslte_cbsegm_t cb_segm[SRSLTE_MAX_CODEWORDS];
srslte_ra_dl_grant_t grant;
srslte_ra_nbits_t nbits[SRSLTE_MAX_CODEWORDS];
uint32_t rv[SRSLTE_MAX_CODEWORDS];
uint32_t sf_idx;
uint32_t nof_layers;
uint32_t codebook_idx;
srslte_mimo_type_t mimo_type;
} srslte_pdsch_cfg_t;
#endif

@ -85,10 +85,8 @@ typedef struct SRSLTE_API {
} srslte_phich_t;
SRSLTE_API int srslte_phich_init(srslte_phich_t *q);
SRSLTE_API int srslte_phich_init_multi(srslte_phich_t *q,
uint32_t nof_rx_antennas);
SRSLTE_API int srslte_phich_init(srslte_phich_t *q,
uint32_t nof_rx_antennas);
SRSLTE_API void srslte_phich_free(srslte_phich_t *q);

@ -100,9 +100,9 @@ typedef struct SRSLTE_API {
uint32_t f_gh[SRSLTE_NSLOTS_X_FRAME];
float tmp_arg[SRSLTE_PUCCH_N_SEQ];
cf_t z[SRSLTE_PUCCH_MAX_SYMBOLS];
cf_t z_tmp[SRSLTE_PUCCH_MAX_SYMBOLS];
cf_t ce[SRSLTE_PUCCH_MAX_SYMBOLS];
cf_t *z;
cf_t *z_tmp;
cf_t *ce;
bool shortened;
bool group_hopping_en;

@ -102,11 +102,10 @@ typedef struct SRSLTE_API {
typedef struct SRSLTE_API {
bool prb_idx[2][SRSLTE_MAX_PRB];
uint32_t nof_prb;
uint32_t Qm;
uint32_t Qm2;
srslte_ra_mcs_t mcs;
srslte_ra_mcs_t mcs2;
uint32_t Qm[SRSLTE_MAX_CODEWORDS];
srslte_ra_mcs_t mcs[SRSLTE_MAX_CODEWORDS];
uint32_t nof_tb;
uint32_t pinfo;
} srslte_ra_dl_grant_t;
/** Unpacked DCI message for DL grant */
@ -206,10 +205,10 @@ SRSLTE_API int srslte_ra_dl_dci_to_grant(srslte_ra_dl_dci_t *dci,
SRSLTE_API void srslte_ra_dl_grant_to_nbits(srslte_ra_dl_grant_t *grant,
uint32_t cfi,
srslte_cell_t cell,
uint32_t sf_idx,
srslte_ra_nbits_t *nbits);
uint32_t sf_idx,
srslte_ra_nbits_t nbits[SRSLTE_MAX_CODEWORDS]);
SRSLTE_API uint32_t srslte_ra_dl_approx_nof_re(srslte_cell_t cell,
SRSLTE_API uint32_t srslte_ra_dl_approx_nof_re(srslte_cell_t cell,
uint32_t nof_prb,
uint32_t nof_ctrl_symbols);

@ -96,12 +96,26 @@ SRSLTE_API int srslte_dlsch_encode(srslte_sch_t *q,
uint8_t *data,
uint8_t *e_bits);
SRSLTE_API int srslte_dlsch_encode2(srslte_sch_t *q,
srslte_pdsch_cfg_t *cfg,
srslte_softbuffer_tx_t *softbuffer,
uint8_t *data,
uint8_t *e_bits,
int codeword_idx);
SRSLTE_API int srslte_dlsch_decode(srslte_sch_t *q,
srslte_pdsch_cfg_t *cfg,
srslte_softbuffer_rx_t *softbuffer,
int16_t *e_bits,
uint8_t *data);
SRSLTE_API int srslte_dlsch_decode2(srslte_sch_t *q,
srslte_pdsch_cfg_t *cfg,
srslte_softbuffer_rx_t *softbuffer,
int16_t *e_bits,
uint8_t *data,
int codeword_idx);
SRSLTE_API int srslte_ulsch_encode(srslte_sch_t *q,
srslte_pusch_cfg_t *cfg,
srslte_softbuffer_tx_t *softbuffer,

@ -73,9 +73,9 @@ SRSLTE_API int srslte_rf_open(srslte_rf_t *h,
SRSLTE_API int srslte_rf_open_multi(srslte_rf_t *h,
char *args,
uint32_t nof_rx_antennas);
uint32_t nof_rx_antennas);
SRSLTE_API int srslte_rf_open_devname(srslte_rf_t *h,
SRSLTE_API int srslte_rf_open_devname(srslte_rf_t *h,
char *devname,
char *args);
@ -200,5 +200,21 @@ SRSLTE_API int srslte_rf_send_timed2(srslte_rf_t *h,
bool is_start_of_burst,
bool is_end_of_burst);
SRSLTE_API int srslte_rf_send_timed_multi(srslte_rf_t *rf,
void *data[4],
int nsamples,
time_t secs,
double frac_secs,
bool blocking,
bool is_start_of_burst,
bool is_end_of_burst);
SRSLTE_API int srslte_rf_send_multi(srslte_rf_t *rf,
void *data[4],
int nsamples,
bool blocking,
bool is_start_of_burst,
bool is_end_of_burst);
#endif

@ -84,7 +84,7 @@ typedef struct SRSLTE_API {
srslte_cfo_t sfo_correct;
srslte_pdsch_cfg_t pdsch_cfg;
srslte_softbuffer_rx_t softbuffer;
srslte_softbuffer_rx_t *softbuffers[SRSLTE_MAX_CODEWORDS];
srslte_ra_dl_dci_t dl_dci;
srslte_cell_t cell;
@ -94,7 +94,12 @@ typedef struct SRSLTE_API {
cf_t *sf_symbols_m[SRSLTE_MAX_PORTS];
cf_t *ce[SRSLTE_MAX_PORTS]; // compatibility
cf_t *ce_m[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS];
/* RI, PMI and SINR for MIMO statistics */
float sinr[SRSLTE_MAX_LAYERS][SRSLTE_MAX_CODEBOOKS];
uint32_t pmi[SRSLTE_MAX_LAYERS];
uint32_t ri;
srslte_dci_format_t dci_format;
uint64_t pkt_errors;
uint64_t pkts_total;
@ -113,25 +118,17 @@ typedef struct SRSLTE_API {
}srslte_ue_dl_t;
/* This function shall be called just after the initial synchronization */
SRSLTE_API int srslte_ue_dl_init(srslte_ue_dl_t *q,
uint32_t max_prb);
SRSLTE_API int srslte_ue_dl_init_multi(srslte_ue_dl_t *q,
uint32_t max_prb,
uint32_t nof_rx_antennas);
SRSLTE_API int srslte_ue_dl_init(srslte_ue_dl_t *q,
uint32_t max_prb,
uint32_t nof_rx_antennas);
SRSLTE_API void srslte_ue_dl_free(srslte_ue_dl_t *q);
SRSLTE_API int srslte_ue_dl_set_cell(srslte_ue_dl_t *q,
srslte_cell_t cell);
SRSLTE_API int srslte_ue_dl_decode_fft_estimate(srslte_ue_dl_t *q,
cf_t *input,
uint32_t sf_idx,
uint32_t *cfi);
SRSLTE_API int srslte_ue_dl_decode_fft_estimate_multi(srslte_ue_dl_t *q,
cf_t *input[SRSLTE_MAX_PORTS],
SRSLTE_API int srslte_ue_dl_decode_fft_estimate(srslte_ue_dl_t *q,
cf_t *input[SRSLTE_MAX_PORTS],
uint32_t sf_idx,
uint32_t *cfi);
@ -139,11 +136,12 @@ SRSLTE_API int srslte_ue_dl_decode_estimate(srslte_ue_dl_t *q,
uint32_t sf_idx,
uint32_t *cfi);
SRSLTE_API int srslte_ue_dl_cfg_grant(srslte_ue_dl_t *q,
srslte_ra_dl_grant_t *grant,
uint32_t cfi,
uint32_t sf_idx,
uint32_t rvidx);
SRSLTE_API int srslte_ue_dl_cfg_grant(srslte_ue_dl_t *q,
srslte_ra_dl_grant_t *grant,
uint32_t cfi,
uint32_t sf_idx,
int rvidx[SRSLTE_MAX_CODEWORDS],
srslte_mimo_type_t mimo_type);
SRSLTE_API int srslte_ue_dl_find_ul_dci(srslte_ue_dl_t *q,
uint32_t cfi,
@ -152,12 +150,14 @@ SRSLTE_API int srslte_ue_dl_find_ul_dci(srslte_ue_dl_t *q,
srslte_dci_msg_t *dci_msg);
SRSLTE_API int srslte_ue_dl_find_dl_dci(srslte_ue_dl_t *q,
uint32_t tm,
uint32_t cfi,
uint32_t sf_idx,
uint16_t rnti,
srslte_dci_msg_t *dci_msg);
SRSLTE_API int srslte_ue_dl_find_dl_dci_type(srslte_ue_dl_t *q,
uint32_t tm,
uint32_t cfi,
uint32_t sf_idx,
uint16_t rnti,
@ -169,27 +169,29 @@ SRSLTE_API uint32_t srslte_ue_dl_get_ncce(srslte_ue_dl_t *q);
SRSLTE_API void srslte_ue_dl_set_sample_offset(srslte_ue_dl_t * q,
float sample_offset);
SRSLTE_API int srslte_ue_dl_decode(srslte_ue_dl_t * q,
cf_t *input,
uint8_t *data,
uint32_t tti);
SRSLTE_API int srslte_ue_dl_decode_multi(srslte_ue_dl_t * q,
cf_t *input[SRSLTE_MAX_PORTS],
uint8_t *data,
uint32_t tti);
SRSLTE_API int srslte_ue_dl_decode_rnti(srslte_ue_dl_t * q,
cf_t *input,
uint8_t *data,
SRSLTE_API int srslte_ue_dl_decode(srslte_ue_dl_t *q,
cf_t *input[SRSLTE_MAX_PORTS],
uint8_t *data[SRSLTE_MAX_CODEWORDS],
uint32_t tm,
uint32_t tti,
bool acks[SRSLTE_MAX_CODEWORDS]);
SRSLTE_API int srslte_ue_dl_decode_rnti(srslte_ue_dl_t *q,
cf_t *input[SRSLTE_MAX_PORTS],
uint8_t *data[SRSLTE_MAX_CODEWORDS],
uint32_t tm,
uint32_t tti,
uint16_t rnti);
uint16_t rnti,
bool acks[SRSLTE_MAX_CODEWORDS]);
SRSLTE_API int srslte_ue_dl_ri_pmi_select(srslte_ue_dl_t *q,
uint32_t *ri,
uint32_t *pmi,
float *current_sinr);
SRSLTE_API int srslte_ue_dl_decode_rnti_multi(srslte_ue_dl_t * q,
cf_t *input[SRSLTE_MAX_PORTS],
uint8_t *data,
uint32_t tti,
uint16_t rnti);
SRSLTE_API int srslte_ue_dl_ri_select(srslte_ue_dl_t *q,
uint32_t *ri,
float *cn);
SRSLTE_API bool srslte_ue_dl_decode_phich(srslte_ue_dl_t *q,
uint32_t sf_idx,

@ -153,6 +153,13 @@ SRSLTE_API int srslte_ue_sync_init_file(srslte_ue_sync_t *q,
int offset_time,
float offset_freq);
SRSLTE_API int srslte_ue_sync_init_file_multi(srslte_ue_sync_t *q,
uint32_t nof_prb,
char *file_name,
int offset_time,
float offset_freq,
uint32_t nof_rx_ant);
SRSLTE_API void srslte_ue_sync_free(srslte_ue_sync_t *q);
SRSLTE_API int srslte_ue_sync_set_cell(srslte_ue_sync_t *q,

@ -58,10 +58,16 @@ SRSLTE_API extern int srslte_verbose;
#define PRINT_NONE srslte_verbose=SRSLTE_VERBOSE_NONE
#define DEBUG(_fmt, ...) if (SRSLTE_DEBUG_ENABLED && srslte_verbose >= SRSLTE_VERBOSE_DEBUG) \
fprintf(stdout, "[DEBUG]: " _fmt, __VA_ARGS__)
fprintf(stdout, "[DEBUG]: " _fmt, ##__VA_ARGS__)
#define INFO(_fmt, ...) if (SRSLTE_DEBUG_ENABLED && srslte_verbose >= SRSLTE_VERBOSE_INFO) \
fprintf(stdout, "[INFO]: " _fmt, __VA_ARGS__)
fprintf(stdout, "[INFO]: " _fmt, ##__VA_ARGS__)
#if CMAKE_BUILD_TYPE==Debug
/* In debug mode, it prints out the */
#define ERROR(_fmt, ...) fprintf(stderr, "%s.%d: " _fmt "\n", __FILE__, __LINE__, ##__VA_ARGS__)
#else
#define ERROR(_fmt, ...) fprintf(stderr, "[ERROR in %s]:" _fmt "\n", __FUNCTION__, ##__VA_ARGS__)
#endif /* CMAKE_BUILD_TYPE==Debug */
#endif // DEBUG_H

@ -0,0 +1,115 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 Software Radio Systems Limited
*
* \section LICENSE
*
* This file is part of the srsLTE library.
*
* srsLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsLTE 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 Affero General Public License for more details.
*
* A copy of the GNU Affero 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 SRSLTE_MAT_H
#define SRSLTE_MAT_H
#include "srslte/phy/utils/simd.h"
#include "srslte/config.h"
/*
* Generic Macros
*/
#define RANDOM_CF() (((float)rand())/((float)RAND_MAX) + _Complex_I*((float)rand())/((float)RAND_MAX))
/* Generic implementation for complex reciprocal */
SRSLTE_API cf_t srslte_mat_cf_recip_gen(cf_t a);
/* Generic implementation for 2x2 determinant */
SRSLTE_API cf_t srslte_mat_2x2_det_gen(cf_t a00, cf_t a01, cf_t a10, cf_t a11);
/* Generic implementation for 2x2 Matrix Inversion */
SRSLTE_API void srslte_mat_2x2_inv_gen(cf_t a00, cf_t a01, cf_t a10, cf_t a11,
cf_t *r00, cf_t *r01, cf_t *r10, cf_t *r11);
/* Generic implementation for Zero Forcing (ZF) solver */
SRSLTE_API void srslte_mat_2x2_zf_gen(cf_t y0, cf_t y1,
cf_t h00, cf_t h01, cf_t h10, cf_t h11,
cf_t *x0, cf_t *x1,
float norm);
/* Generic implementation for Minimum Mean Squared Error (MMSE) solver */
SRSLTE_API void srslte_mat_2x2_mmse_gen(cf_t y0, cf_t y1,
cf_t h00, cf_t h01, cf_t h10, cf_t h11,
cf_t *x0, cf_t *x1,
float noise_estimate,
float norm);
SRSLTE_API float srslte_mat_2x2_cn(cf_t h00,
cf_t h01,
cf_t h10,
cf_t h11);
#ifdef LV_HAVE_SSE
#include <smmintrin.h>
/* SSE implementation for complex reciprocal */
SRSLTE_API __m128 srslte_mat_cf_recip_sse(__m128 a);
/* SSE implementation for 2x2 determinant */
SRSLTE_API __m128 srslte_mat_2x2_det_sse(__m128 a00, __m128 a01, __m128 a10, __m128 a11);
/* SSE implementation for Zero Forcing (ZF) solver */
SRSLTE_API void srslte_mat_2x2_zf_sse(__m128 y0, __m128 y1,
__m128 h00, __m128 h01, __m128 h10, __m128 h11,
__m128 *x0, __m128 *x1,
float norm);
/* SSE implementation for Minimum Mean Squared Error (MMSE) solver */
SRSLTE_API void srslte_mat_2x2_mmse_sse(__m128 y0, __m128 y1,
__m128 h00, __m128 h01, __m128 h10, __m128 h11,
__m128 *x0, __m128 *x1,
float noise_estimate, float norm);
#endif /* LV_HAVE_SSE */
#ifdef LV_HAVE_AVX
#include <immintrin.h>
/* AVX implementation for complex reciprocal */
SRSLTE_API __m256 srslte_mat_cf_recip_avx(__m256 a);
/* AVX implementation for 2x2 determinant */
SRSLTE_API __m256 srslte_mat_2x2_det_avx(__m256 a00, __m256 a01, __m256 a10, __m256 a11);
/* AVX implementation for Zero Forcing (ZF) solver */
SRSLTE_API void srslte_mat_2x2_zf_avx(__m256 y0, __m256 y1,
__m256 h00, __m256 h01, __m256 h10, __m256 h11,
__m256 *x0, __m256 *x1,
float norm);
/* AVX implementation for Minimum Mean Squared Error (MMSE) solver */
SRSLTE_API void srslte_mat_2x2_mmse_avx(__m256 y0, __m256 y1,
__m256 h00, __m256 h01, __m256 h10, __m256 h11,
__m256 *x0, __m256 *x1,
float noise_estimate, float norm);
#endif /* LV_HAVE_AVX */
#endif /* SRSLTE_MAT_H */

@ -0,0 +1,81 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 Software Radio Systems Limited
*
* \section LICENSE
*
* This file is part of the srsLTE library.
*
* srsLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsLTE 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 Affero General Public License for more details.
*
* A copy of the GNU Affero 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 SRSLTE_SIMD_H_H
#define SRSLTE_SIMD_H_H
/*
* SSE Macros
*/
#ifdef LV_HAVE_SSE
#define _MM_SWAP(X) ((__m128)_mm_shuffle_ps(X, X, _MM_SHUFFLE(2,3,0,1)))
#define _MM_PERM(X) ((__m128)_mm_shuffle_ps(X, X, _MM_SHUFFLE(2,1,3,0)))
#define _MM_MULJ_PS(X) _MM_SWAP(_MM_CONJ_PS(X))
#define _MM_CONJ_PS(X) (_mm_xor_ps(X, _mm_set_ps(-0.0f, 0.0f, -0.0f, 0.0f)))
#define _MM_SQMOD_PS(X) _MM_PERM(_mm_hadd_ps(_mm_mul_ps(X,X), _mm_set_ps(0.0f, 0.0f, 0.0f, 0.0f)))
#define _MM_PROD_PS(a, b) _mm_addsub_ps(_mm_mul_ps(a,_mm_moveldup_ps(b)),_mm_mul_ps(\
_mm_shuffle_ps(a,a,0xB1),_mm_movehdup_ps(b)))
#endif /* LV_HAVE_SSE */
/*
* AVX Macros
*/
#ifdef LV_HAVE_AVX
#define _MM256_MULJ_PS(X) _mm256_permute_ps(_MM256_CONJ_PS(X), 0b10110001)
#define _MM256_CONJ_PS(X) (_mm256_xor_ps(X, _mm256_set_ps(-0.0f, 0.0f, -0.0f, 0.0f, -0.0f, 0.0f, -0.0f, 0.0f)))
#ifdef LV_HAVE_FMA
#define _MM256_SQMOD_PS(A, B) _mm256_permute_ps(_mm256_hadd_ps(_mm256_fmadd_ps(A, A, _mm256_mul_ps(B,B)), \
_mm256_set_ps(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)), 0b11011100)
#define _MM256_PROD_PS(a, b) _mm256_fmaddsub_ps(a,_mm256_moveldup_ps(b),\
_mm256_mul_ps(_mm256_shuffle_ps(a,a,0xB1),_mm256_movehdup_ps(b)))
#else
#define _MM256_SQMOD_PS(A, B) _mm256_permute_ps(_mm256_hadd_ps(_mm256_add_ps(_mm256_mul_ps(A,A), _mm256_mul_ps(B,B)), \
_mm256_set_ps(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)), 0b11011100)
#define _MM256_PROD_PS(a, b) _mm256_addsub_ps(_mm256_mul_ps(a,_mm256_moveldup_ps(b)),\
_mm256_mul_ps(_mm256_shuffle_ps(a,a,0xB1),_mm256_movehdup_ps(b)))
#endif /* LV_HAVE_FMA */
#endif /* LV_HAVE_AVX */
/*
* AVX extension with FMA Macros
*/
#ifdef LV_HAVE_FMA
#define _MM256_SQMOD_ADD_PS(A, B, C) _mm256_permute_ps(_mm256_hadd_ps(_mm256_fmadd_ps(A, A, _mm256_fmadd_ps(B, B, C)),\
_mm256_set_ps(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)), 0b11011100)
#define _MM256_PROD_ADD_PS(A, B, C) _mm256_fmaddsub_ps(A,_mm256_moveldup_ps(B),\
_mm256_fmaddsub_ps(_mm256_shuffle_ps(A,A,0xB1),_mm256_movehdup_ps(B), C))
#define _MM256_PROD_SUB_PS(A, B, C) _mm256_fmaddsub_ps(A,_mm256_moveldup_ps(B),\
_mm256_fmsubadd_ps(_mm256_shuffle_ps(A,A,0xB1),_mm256_movehdup_ps(B), C))
#endif /* LV_HAVE_FMA */
#endif //SRSLTE_SIMD_H_H

@ -175,6 +175,9 @@ SRSLTE_API void srslte_vec_abs_square_cf(cf_t *x, float *abs_square, uint32_t le
/* argument of each vector element */
SRSLTE_API void srslte_vec_arg_cf(cf_t *x, float *arg, uint32_t len);
/* Copy 256 bit aligned vector */
SRSLTE_API void srs_vec_cf_cpy(cf_t *src, cf_t *dst, int len);
#ifdef __cplusplus
}
#endif

@ -448,12 +448,15 @@ float srslte_chest_dl_get_rsrq(srslte_chest_dl_t *q) {
}
float srslte_chest_dl_get_rsrp(srslte_chest_dl_t *q) {
// Note: use only port 0 but average across antennas
float n = 0;
for (int i=0;i<q->last_nof_antennas;i++) {
n += q->rsrp[i][0];
float srslte_chest_dl_get_rsrp_port(srslte_chest_dl_t *q, uint32_t port) {
float n = 0;
for (int i = 0; i < q->last_nof_antennas; i++) {
n += q->rsrp[i][port];
}
return n/q->last_nof_antennas;
return n / q->last_nof_antennas;
}
float srslte_chest_dl_get_rsrp(srslte_chest_dl_t *q) {
// Note: use only port 0 but average across antennas
return srslte_chest_dl_get_rsrp_port(q, 0);
}

@ -52,4 +52,3 @@ add_test(chest_test_ul_cellid1 chest_test_ul -c 2 -r 50)

@ -124,6 +124,24 @@ bool srslte_N_id_1_isvalid(uint32_t N_id_1) {
}
}
srslte_mod_t srslte_str2mod (char * mod_str) {
int i = 0;
/* Upper case */
while (mod_str[i] &= (~' '), mod_str[++i]);
if (!strcmp(mod_str, "QPSK")) {
return SRSLTE_MOD_QPSK;
} else if (!strcmp(mod_str, "16QAM")) {
return SRSLTE_MOD_16QAM;
} else if (!strcmp(mod_str, "64QAM")) {
return SRSLTE_MOD_64QAM;
} else {
return (srslte_mod_t) SRSLTE_ERROR_INVALID_INPUTS;
}
};
char *srslte_mod_string(srslte_mod_t mod) {
switch (mod) {
case SRSLTE_MOD_BPSK:
@ -424,18 +442,40 @@ struct lte_band lte_bands[SRSLTE_NOF_LTE_BANDS] = {
int srslte_str2mimotype(char *mimo_type_str, srslte_mimo_type_t *type) {
if (!strcmp(mimo_type_str, "single")) {
int i = 0;
/* Low case */
while (mimo_type_str[i] |= ' ', mimo_type_str[++i]);
if (!strcmp(mimo_type_str, "single") || !strcmp(mimo_type_str, "port0")) {
*type = SRSLTE_MIMO_TYPE_SINGLE_ANTENNA;
} else if (!strcmp(mimo_type_str, "diversity")) {
} else if (!strcmp(mimo_type_str, "diversity") || !strcmp(mimo_type_str, "txdiversity")) {
*type = SRSLTE_MIMO_TYPE_TX_DIVERSITY;
} else if (!strcmp(mimo_type_str, "multiplex")) {
} else if (!strcmp(mimo_type_str, "multiplex") || !strcmp(mimo_type_str, "spatialmux")) {
*type = SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX;
} else if (!strcmp(mimo_type_str, "cdd")) {
*type = SRSLTE_MIMO_TYPE_CDD;
} else {
return SRSLTE_ERROR;
}
return SRSLTE_SUCCESS;
}
char *srslte_mimotype2str(srslte_mimo_type_t mimo_type) {
switch (mimo_type) {
case SRSLTE_MIMO_TYPE_SINGLE_ANTENNA:
return "Single";
case SRSLTE_MIMO_TYPE_TX_DIVERSITY:
return "Diversity";
case SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX:
return "Multiplex";
case SRSLTE_MIMO_TYPE_CDD:
return "CDD";
default:
return "N/A";
}
}
float get_fd(struct lte_band *band, uint32_t dl_earfcn) {
if (dl_earfcn >= band->dl_earfcn_offset) {
return band->fd_low_mhz + 0.1*(dl_earfcn - band->dl_earfcn_offset);

@ -131,7 +131,7 @@ int srslte_dft_replan_r(srslte_dft_plan_t *plan, const int new_dft_points) {
int srslte_dft_plan_r(srslte_dft_plan_t *plan, const int dft_points, srslte_dft_dir_t dir) {
allocate(plan,sizeof(float),sizeof(float), dft_points);
int sign = (dir == SRSLTE_DFT_FORWARD) ? FFTW_R2HC : FFTW_HC2R;
plan->p = fftwf_plan_r2r_1d(dft_points, plan->in, plan->out, sign, 0U);
plan->p = fftwf_plan_r2r_1d(dft_points, plan->in, plan->out, sign, FFTW_MEASURE);
if (!plan->p) {
return -1;
}

@ -65,16 +65,16 @@ int srslte_enb_dl_init(srslte_enb_dl_t *q, uint32_t max_prb)
fprintf(stderr, "Error creating PBCH object\n");
goto clean_exit;
}
if (srslte_pcfich_init(&q->pcfich)) {
if (srslte_pcfich_init(&q->pcfich, 0)) {
fprintf(stderr, "Error creating PCFICH object\n");
goto clean_exit;
}
if (srslte_phich_init(&q->phich)) {
if (srslte_phich_init(&q->phich, 0)) {
fprintf(stderr, "Error creating PHICH object\n");
goto clean_exit;
}
if (srslte_pdcch_init(&q->pdcch, max_prb)) {
if (srslte_pdcch_init_enb(&q->pdcch, max_prb)) {
fprintf(stderr, "Error creating PDCCH object\n");
goto clean_exit;
}
@ -319,9 +319,9 @@ int srslte_enb_dl_put_pdcch_ul(srslte_enb_dl_t *q, srslte_ra_ul_dci_t *grant,
return SRSLTE_SUCCESS;
}
int srslte_enb_dl_put_pdsch(srslte_enb_dl_t *q, srslte_ra_dl_grant_t *grant, srslte_softbuffer_tx_t *softbuffer,
int srslte_enb_dl_put_pdsch(srslte_enb_dl_t *q, srslte_ra_dl_grant_t *grant, srslte_softbuffer_tx_t *softbuffer[SRSLTE_MAX_CODEWORDS],
uint16_t rnti, uint32_t rv_idx, uint32_t sf_idx,
uint8_t *data)
uint8_t *data[SRSLTE_MAX_CODEWORDS])
{
/* Configure pdsch_cfg parameters */
if (srslte_pdsch_cfg(&q->pdsch_cfg, q->cell, grant, q->cfi, sf_idx, rv_idx)) {

@ -99,3 +99,60 @@ int srslte_filesink_write(srslte_filesink_t *q, void *buffer, int nsamples) {
return i;
}
int srslte_filesink_write_multi(srslte_filesink_t *q, void **buffer, int nsamples, int nchannels) {
int i, j;
float **fbuf = (float**) buffer;
_Complex float **cbuf = (_Complex float**) buffer;
_Complex short **sbuf = (_Complex short**) buffer;
int size;
switch(q->type) {
case SRSLTE_FLOAT:
for (i=0;i<nsamples;i++) {
for (j=0;j<nchannels;j++) {
fprintf(q->f, "%g%c", fbuf[j][i], (j!=(nchannels-1))?'\t':'\n');
}
}
break;
case SRSLTE_COMPLEX_FLOAT:
for (i=0;i<nsamples;i++) {
for (j=0;j<nchannels;j++) {
fprintf(q->f, "%g%+gi%c", __real__ cbuf[j][i], __imag__ cbuf[j][i], (j!=(nchannels-1))?'\t':'\n');
}
}
break;
case SRSLTE_COMPLEX_SHORT:
for (i=0;i<nsamples;i++) {
for (j=0;j<nchannels;j++) {
fprintf(q->f, "%hd%+hdi%c", __real__ sbuf[j][i], __imag__ sbuf[j][i], (j!=(nchannels-1))?'\t':'\n');
}
}
break;
case SRSLTE_FLOAT_BIN:
case SRSLTE_COMPLEX_FLOAT_BIN:
case SRSLTE_COMPLEX_SHORT_BIN:
if (q->type == SRSLTE_FLOAT_BIN) {
size = sizeof(float);
} else if (q->type == SRSLTE_COMPLEX_FLOAT_BIN) {
size = sizeof(_Complex float);
} else if (q->type == SRSLTE_COMPLEX_SHORT_BIN) {
size = sizeof(_Complex short);
}
if (nchannels > 1) {
uint32_t count = 0;
for (i = 0; i < nsamples; i++) {
for (j = 0; j < nchannels; j++) {
count += fwrite(&cbuf[j][i], size, 1, q->f);
}
}
return count;
} else {
return fwrite(buffer[0], size, nsamples, q->f);
}
break;
default:
i = -1;
break;
}
return i;
}

@ -116,3 +116,29 @@ int srslte_filesource_read(srslte_filesource_t *q, void *buffer, int nsamples) {
return i;
}
int srslte_filesource_read_multi(srslte_filesource_t *q, void **buffer, int nsamples, int nof_channels) {
int i, j, count = 0;
_Complex float **cbuf = (_Complex float **) buffer;
switch (q->type) {
case SRSLTE_FLOAT:
case SRSLTE_COMPLEX_FLOAT:
case SRSLTE_COMPLEX_SHORT:
case SRSLTE_FLOAT_BIN:
case SRSLTE_COMPLEX_SHORT_BIN:
fprintf(stderr, "%s.%d:Read Mode not implemented\n", __FILE__, __LINE__);
count = SRSLTE_ERROR;
break;
case SRSLTE_COMPLEX_FLOAT_BIN:
for (i = 0; i < nsamples; i++) {
for (j = 0; j < nof_channels; j++) {
count += fread(&cbuf[j][i], sizeof(cf_t), (size_t) 1, q->f);
}
}
break;
default:
count = SRSLTE_ERROR;
break;
}
return count;
}

@ -28,6 +28,7 @@
#include <stdio.h>
#include <assert.h>
#include <string.h>
#include <srslte/phy/utils/vector.h>
#include "srslte/phy/common/phy_common.h"
#include "srslte/phy/mimo/layermap.h"
@ -51,7 +52,12 @@ int srslte_layermap_diversity(cf_t *d, cf_t *x[SRSLTE_MAX_LAYERS], int nof_layer
int srslte_layermap_multiplex(cf_t *d[SRSLTE_MAX_CODEWORDS], cf_t *x[SRSLTE_MAX_LAYERS], int nof_cw, int nof_layers,
int nof_symbols[SRSLTE_MAX_CODEWORDS]) {
if (nof_cw == 1) {
if (nof_cw == nof_layers) {
for (int i = 0; i < nof_cw; i++) {
srs_vec_cf_cpy(x[i], d[i], (uint32_t) nof_symbols[0]);
}
return nof_symbols[0];
} else if (nof_cw == 1) {
return srslte_layermap_diversity(d[0], x, nof_layers, nof_symbols[0]);
} else {
int n[2];

File diff suppressed because it is too large Load Diff

@ -42,7 +42,7 @@ add_test(layermap_multiplex_24 layermap_test -n 1000 -m multiplex -c 2 -l 4)
########################################################################
# LAYER MAPPING TEST
# PRECODING MAPPING TEST
########################################################################
add_executable(precoding_test precoder_test.c)
@ -52,6 +52,30 @@ add_test(precoding_single precoding_test -n 1000 -m single)
add_test(precoding_diversity2 precoding_test -n 1000 -m diversity -l 2 -p 2)
add_test(precoding_diversity4 precoding_test -n 1024 -m diversity -l 4 -p 4)
add_test(precoding_cdd_2x2_zf precoding_test -m cdd -l 2 -p 2 -r 2 -n 14000 -d zf)
add_test(precoding_cdd_2x2_mmse precoding_test -m cdd -l 2 -p 2 -r 2 -n 14000 -d mmse)
add_test(precoding_multiplex_1l_cb0 precoding_test -m multiplex -l 1 -p 2 -r 2 -n 14000 -c 0)
add_test(precoding_multiplex_1l_cb1 precoding_test -m multiplex -l 1 -p 2 -r 2 -n 14000 -c 1)
add_test(precoding_multiplex_1l_cb2 precoding_test -m multiplex -l 1 -p 2 -r 2 -n 14000 -c 2)
add_test(precoding_multiplex_1l_cb3 precoding_test -m multiplex -l 1 -p 2 -r 2 -n 14000 -c 3)
add_test(precoding_multiplex_2l_cb0_zf precoding_test -m multiplex -l 2 -p 2 -r 2 -n 14000 -c 0 -d zf)
add_test(precoding_multiplex_2l_cb1_zf precoding_test -m multiplex -l 2 -p 2 -r 2 -n 14000 -c 1 -d zf)
add_test(precoding_multiplex_2l_cb2_zf precoding_test -m multiplex -l 2 -p 2 -r 2 -n 14000 -c 2 -d zf)
add_test(precoding_multiplex_2l_cb0_mmse precoding_test -m multiplex -l 2 -p 2 -r 2 -n 14000 -c 0 -d mmse)
add_test(precoding_multiplex_2l_cb1_mmse precoding_test -m multiplex -l 2 -p 2 -r 2 -n 14000 -c 1 -d mmse)
add_test(precoding_multiplex_2l_cb2_mmse precoding_test -m multiplex -l 2 -p 2 -r 2 -n 14000 -c 2 -d mmse)
########################################################################
# PMI SELECT TEST
########################################################################
add_executable(pmi_select_test pmi_select_test.c)
target_link_libraries(pmi_select_test srslte_phy)
add_test(pmi_select_test pmi_select_test)

@ -40,7 +40,7 @@ int nof_cw = 1, nof_layers = 1;
char *mimo_type_name = NULL;
void usage(char *prog) {
printf("Usage: %s -m [single|diversity|multiplex] -c [nof_cw] -l [nof_layers]\n", prog);
printf("Usage: %s -m [single|diversity|multiplex|cdd] -c [nof_cw] -l [nof_layers]\n", prog);
printf("\t-n num_symbols [Default %d]\n", nof_symbols);
}
@ -96,19 +96,19 @@ int main(int argc, char **argv) {
}
for (i=0;i<nof_cw;i++) {
d[i] = malloc(sizeof(cf_t) * nof_symb_cw[i]);
d[i] = srslte_vec_malloc(sizeof(cf_t) * nof_symb_cw[i]);
if (!d[i]) {
perror("malloc");
exit(-1);
}
dp[i] = malloc(sizeof(cf_t) * nof_symb_cw[i]);
dp[i] = srslte_vec_malloc(sizeof(cf_t) * nof_symb_cw[i]);
if (!dp[i]) {
perror("malloc");
exit(-1);
}
}
for (i=0;i<nof_layers;i++) {
x[i] = malloc(sizeof(cf_t) * nof_symbols);
x[i] = srslte_vec_malloc(sizeof(cf_t) * nof_symbols);
if (!x[i]) {
perror("malloc");
exit(-1);

@ -0,0 +1,158 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 Software Radio Systems Limited
*
* \section LICENSE
*
* This file is part of the srsLTE library.
*
* srsLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsLTE 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 Affero General Public License for more details.
*
* A copy of the GNU Affero 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 <complex.h>
#include "srslte/phy/utils/vector.h"
#include "srslte/phy/mimo/precoding.h"
#include "pmi_select_test.h"
#include "srslte/phy/utils/debug.h"
int main(int argc, char **argv) {
cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS];
float noise_estimate;
float sinr_1l[SRSLTE_MAX_CODEBOOKS];
float sinr_2l[SRSLTE_MAX_CODEBOOKS];
float cn;
uint32_t pmi[2];
uint32_t nof_symbols = (uint32_t) SRSLTE_SF_LEN_RE(6, SRSLTE_CP_NORM);
int ret = SRSLTE_ERROR;
/* Allocate channels */
for (int i = 0; i < SRSLTE_MAX_PORTS; i++) {
for (int j = 0; j < SRSLTE_MAX_PORTS; j++) {
h[i][j] = srslte_vec_malloc(sizeof(cf_t) * nof_symbols);
if (!h[i][j]) {
goto clean;
}
bzero(h[i][j], sizeof(cf_t) * nof_symbols);
}
}
for (int c = 0; c < PMI_SELECT_TEST_NOF_CASES; c++) {
pmi_select_test_case_gold_t *gold = &pmi_select_test_case_gold[c];
/* Set channel */
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 2; j++) {
cf_t hij = gold->h[i][j];
for (int k = 0; k < nof_symbols; k++) {
h[i][j][k] = hij;
}
}
}
/* Set noise estimate */
noise_estimate = gold->n;
/* PMI select for 1 layer */
ret = srslte_precoding_pmi_select(h, nof_symbols, noise_estimate, 1, &pmi[0], sinr_1l);
if (ret < 0) {
ERROR("During PMI selection for 1 layer");
goto clean;
}
/* Check SINR for 1 layer */
for (int i = 0; i < ret; i++) {
if (fabsf(gold->snri_1l[i] - sinr_1l[i]) > 0.1) {
ERROR("Test case %d failed computing 1 layer SINR for codebook %d (test=%.2f; gold=%.2f)\n",
c + 1, i, sinr_1l[i], gold->snri_1l[i]);
goto clean;
}
}
/* Check PMI select for 1 layer*/
if (pmi[0] != gold->pmi[0]) {
ERROR("Test case %d failed computing 1 layer PMI (test=%d; gold=%d)\n", c + 1, pmi[0], gold->pmi[0]);
goto clean;
}
/* PMI select for 2 layer */
ret = srslte_precoding_pmi_select(h, nof_symbols, noise_estimate, 2, &pmi[1], sinr_2l);
if (ret < 0) {
ERROR("During PMI selection for 2 layer");
goto clean;
}
/* Check SINR for 2 layer */
for (int i = 0; i < ret; i++) {
if (fabsf(gold->snri_2l[i] - sinr_2l[i]) > 0.1) {
ERROR("Test case %d failed computing 2 layer SINR for codebook %d (test=%.2f; gold=%.2f)\n",
c + 1, i, sinr_2l[i], gold->snri_2l[i]);
goto clean;
}
}
/* Check PMI select for 2 layer*/
if (pmi[1] != gold->pmi[1]) {
ERROR("Test case %d failed computing 2 layer PMI (test=%d; gold=%d)\n", c + 1, pmi[1], gold->pmi[1]);
goto clean;
}
/* Condition number */
if (srslte_precoding_cn(h, 2, 2, nof_symbols, &cn)) {
ERROR("Test case %d condition number returned error\n");
goto clean;
}
/* Check condition number */
if (fabsf(gold->k - cn) > 0.1) {
ERROR("Test case %d failed computing condition number (test=%.2f; gold=%.2f)\n",
c + 1, cn, gold->k);
goto clean;
}
}
/* Test passed */
ret = SRSLTE_SUCCESS;
clean:
for (int i = 0; i < SRSLTE_MAX_PORTS; i++) {
for (int j = 0; j < SRSLTE_MAX_PORTS; j++) {
if (h[i][j]) {
free(h[i][j]);
}
}
}
if (ret) {
printf("Failed!\n");
} else {
printf("Passed!\n");
}
return ret;
}

@ -0,0 +1,237 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 Software Radio Systems Limited
*
* \section LICENSE
*
* This file is part of the srsLTE library.
*
* srsLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsLTE 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 Affero General Public License for more details.
*
* A copy of the GNU Affero 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 PMI_SELECT_TEST_H
#define PMI_SELECT_TEST_H
#define PMI_SELECT_TEST_NOF_CASES 16
typedef struct {
cf_t h[2][2]; /* Channel estimate */
float n; /* Noise estimation */
float snri_1l[4]; /* SINR Approximation for 1 layer (linear) */
float snri_2l[2]; /* SINR Approximation for 2 layers (linear) */
uint32_t pmi[2]; /* Precoding Matrix Indicator for 1 and 2 layers */
uint32_t ri; /* Rank indicator */
float k; /* Condition number (κ) in dB */
} pmi_select_test_case_gold_t;
static pmi_select_test_case_gold_t pmi_select_test_case_gold [PMI_SELECT_TEST_NOF_CASES] = {
{ /* Test case 1 */
.h = {
{+0.626226f+0.060103f*_Complex_I, -0.233387f-0.449860f*_Complex_I},
{+0.234558f-0.502742f*_Complex_I, +0.150990f-0.096722f*_Complex_I}
},
.n = 0.227713,
.snri_1l = {2.728043f, 1.630673f, 3.226421f, 1.132295f},
.snri_2l = {1.797660f, 1.982149f},
.pmi = {2, 1},
.ri = 1,
.k = 6.4007,
},
{ /* Test case 2 */
.h = {
{+0.608899f-0.825846f*_Complex_I, +0.972208f+0.604183f*_Complex_I},
{-0.940016f+0.978290f*_Complex_I, +0.071328f-0.866107f*_Complex_I}
},
.n = 0.939398,
.snri_1l = {0.686850f, 4.591972f, 3.773925f, 1.504897f},
.snri_2l = {2.298235f, 1.761859f},
.pmi = {1, 0},
.ri = 1,
.k = 11.1305,
},
{ /* Test case 3 */
.h = {
{-0.963645f+0.770719f*_Complex_I, +0.367677f+0.798010f*_Complex_I},
{+0.567473f+0.251875f*_Complex_I, +0.068275f-0.724262f*_Complex_I}
},
.n = 0.217802,
.snri_1l = {3.209674f, 11.525338f, 11.962786f, 2.772226f},
.snri_2l = {3.226053f, 3.526363f},
.pmi = {2, 1},
.ri = 1,
.k = 15.4589,
},
{ /* Test case 4 */
.h = {
{-0.635718f+0.879322f*_Complex_I, -0.916360f-0.291089f*_Complex_I},
{-0.786117f-0.178742f*_Complex_I, +0.232887f+0.968699f*_Complex_I}
},
.n = 0.945579,
.snri_1l = {1.818313f, 2.141519f, 1.995787f, 1.964045f},
.snri_2l = {1.965011f, 1.958537f},
.pmi = {1, 0},
.ri = 2,
.k = 1.2910,
},
{ /* Test case 5 */
.h = {
{+0.353289f+0.324764f*_Complex_I, +0.976605f-0.511669f*_Complex_I},
{+0.533663f-0.408985f*_Complex_I, -0.326601f+0.360357f*_Complex_I}
},
.n = 0.527847,
.snri_1l = {1.173803f, 2.869865f, 2.273783f, 1.769885f},
.snri_2l = {1.871430f, 1.713879f},
.pmi = {1, 0},
.ri = 2,
.k = 5.5388,
},
{ /* Test case 6 */
.h = {
{-0.176813f+0.103585f*_Complex_I, +0.205276f+0.167141f*_Complex_I},
{+0.501040f+0.023640f*_Complex_I, +0.167066f-0.834815f*_Complex_I}
},
.n = 0.719570,
.snri_1l = {0.490387f, 1.022313f, 1.111245f, 0.401456f},
.snri_2l = {0.578124f, 0.597176f},
.pmi = {2, 1},
.ri = 1,
.k = 21.8808,
},
{ /* Test case 7 */
.h = {
{+0.992312f+0.773088f*_Complex_I, -0.290931f-0.090610f*_Complex_I},
{+0.942518f-0.173145f*_Complex_I, -0.307102f-0.564536f*_Complex_I}
},
.n = 0.125655,
.snri_1l = {19.459529f, 4.467420f, 18.044021f, 5.882928f},
.snri_2l = {8.055238f, 6.832247f},
.pmi = {0, 0},
.ri = 1,
.k = 9.9136,
},
{ /* Test case 8 */
.h = {
{-0.382171f-0.980395f*_Complex_I, +0.452209f+0.686427f*_Complex_I},
{+0.565744f+0.844664f*_Complex_I, +0.387575f+0.541908f*_Complex_I}
},
.n = 0.042660,
.snri_1l = {26.560881f, 49.864772f, 33.269985f, 43.155668f},
.snri_2l = {37.201526f, 34.461078f},
.pmi = {1, 0},
.ri = 2,
.k = 3.1172,
},
{ /* Test case 9 */
.h = {
{-0.243628f-0.461891f*_Complex_I, +0.408679f+0.346062f*_Complex_I},
{+0.459026f-0.045016f*_Complex_I, -0.551446f+0.247433f*_Complex_I}
},
.n = 0.236445,
.snri_1l = {1.429443f, 3.381496f, 0.227617f, 4.583322f},
.snri_2l = {1.272903f, 2.118832f},
.pmi = {3, 1},
.ri = 1,
.k = 24.1136,
},
{ /* Test case 10 */
.h = {
{-0.645752f-0.784222f*_Complex_I, +0.659287f-0.635545f*_Complex_I},
{+0.533843f-0.801809f*_Complex_I, +0.868957f-0.020472f*_Complex_I}
},
.n = 0.193245,
.snri_1l = {13.697372f, 4.693597f, 1.561737f, 16.829232f},
.snri_2l = {2.961344f, 5.773049f},
.pmi = {3, 1},
.ri = 1,
.k = 17.5194,
},
{ /* Test case 11 */
.h = {
{+0.791783f+0.544990f*_Complex_I, -0.801821f-0.376120f*_Complex_I},
{-0.911669f-0.642035f*_Complex_I, +0.114590f-0.322089f*_Complex_I}
},
.n = 0.210146,
.snri_1l = {2.340213f, 12.261749f, 5.921675f, 8.680286f},
.snri_2l = {6.912040f, 4.520201f},
.pmi = {1, 0},
.ri = 2,
.k = 7.7819,
},
{ /* Test case 12 */
.h = {
{+0.020305f-0.218290f*_Complex_I, +0.812729f-0.890767f*_Complex_I},
{+0.257848f+0.002566f*_Complex_I, -0.796932f-0.136558f*_Complex_I}
},
.n = 0.997560,
.snri_1l = {0.591218f, 1.636514f, 1.880263f, 0.347469f},
.snri_2l = {0.869026f, 0.967991f},
.pmi = {2, 1},
.ri = 1,
.k = 12.9774,
},
{ /* Test case 13 */
.h = {
{+0.623205f-0.219990f*_Complex_I, -0.028697f+0.854712f*_Complex_I},
{+0.788896f+0.834988f*_Complex_I, -0.724907f+0.427148f*_Complex_I}
},
.n = 0.618337,
.snri_1l = {3.706176f, 1.461946f, 0.479632f, 4.688490f},
.snri_2l = {1.444336f, 2.102567f},
.pmi = {3, 1},
.ri = 1,
.k = 17.0493,
},
{ /* Test case 14 */
.h = {
{-0.313424f+0.292955f*_Complex_I, +0.872055f+0.666304f*_Complex_I},
{-0.750452f-0.203436f*_Complex_I, +0.461171f+0.499644f*_Complex_I}
},
.n = 0.835221,
.snri_1l = {2.560265f, 0.379539f, 0.976562f, 1.963242f},
.snri_2l = {1.380223f, 1.109300f},
.pmi = {0, 0},
.ri = 1,
.k = 10.1729,
},
{ /* Test case 15 */
.h = {
{-0.355079f-0.339153f*_Complex_I, +0.104523f+0.238943f*_Complex_I},
{+0.958258f-0.278727f*_Complex_I, +0.098617f+0.513019f*_Complex_I}
},
.n = 0.413901,
.snri_1l = {1.633620f, 2.178855f, 0.809297f, 3.003178f},
.snri_2l = {1.250898f, 1.512017f},
.pmi = {3, 1},
.ri = 1,
.k = 10.8925,
},
{ /* Test case 16 */
.h = {
{-0.015310f+0.675606f*_Complex_I, +0.389486f+0.478144f*_Complex_I},
{+0.945468f+0.908349f*_Complex_I, -0.344490f-0.936155f*_Complex_I}
},
.n = 0.356869,
.snri_1l = {5.024121f, 4.926495f, 7.364348f, 2.586268f},
.snri_2l = {3.165416f, 3.851590f},
.pmi = {2, 1},
.ri = 2,
.k = 7.7799,
},
};
#endif /* PMI_SELECT_TEST_H */

@ -78,9 +78,9 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
x[i] = srslte_vec_malloc(sizeof(cf_t)*nof_symbols/nof_layers);
}
output = srslte_vec_malloc(sizeof(cf_t)*nof_symbols*nof_tx_ports/nof_layers);
output = srslte_vec_malloc(sizeof(cf_t)*nof_symbols*nof_tx_ports);
for (int i=0;i<nof_tx_ports;i++) {
y[i] = &output[i*nof_symbols/nof_layers];
y[i] = &output[i*nof_symbols];
}
char *txscheme = "Port0";
@ -102,13 +102,30 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
}
int symbols_layers[SRSLTE_MAX_LAYERS];
for (int i=0;i<nof_layers;i++) {
symbols_layers[i] = nof_symbols/nof_layers;
symbols_layers[i] = nof_symbols;
}
srslte_layermap_type(d, x, nof_codewords, nof_layers, symbols_layers, type);
srslte_precoding_type(x, y, nof_layers, nof_tx_ports, nof_symbols/nof_layers, type);
if (nlhs >= 1) {
mexutils_write_cf(output, &plhs[0], nof_symbols/nof_layers, nof_tx_ports);
switch (type) {
case SRSLTE_MIMO_TYPE_CDD:
mexutils_write_cf(output, &plhs[0], nof_symbols/nof_layers, nof_tx_ports);
break;
case SRSLTE_MIMO_TYPE_TX_DIVERSITY:
case SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX:
case SRSLTE_MIMO_TYPE_SINGLE_ANTENNA:
default:
mexutils_write_cf(output, &plhs[0], (uint32_t) nof_symbols, nof_tx_ports);
break;
}
}
if (nlhs >= 2) {
mexutils_write_cf(x[0], &plhs[1], nof_symbols / nof_layers, 1);
}
if (nlhs >= 3) {
mexutils_write_cf(x[1], &plhs[2], nof_symbols / nof_layers, 1);
}
if (input) {

@ -34,29 +34,41 @@
#include <stdbool.h>
#include "srslte/srslte.h"
#include "srslte/phy/channel/ch_awgn.h"
#define MSE_THRESHOLD 0.00001
#define MSE_THRESHOLD 0.0005
int nof_symbols = 1000;
int nof_layers = 1, nof_ports = 1;
uint32_t codebook_idx = 0;
int nof_layers = 1, nof_tx_ports = 1, nof_rx_ports = 1, nof_re = 1;
char *mimo_type_name = NULL;
char decoder_type_name [16] = "zf";
float snr_db = 100.0f;
void usage(char *prog) {
printf(
"Usage: %s -m [single|diversity|multiplex] -l [nof_layers] -p [nof_ports]\n",
prog);
"Usage: %s -m [single|diversity|multiplex|cdd] -l [nof_layers] -p [nof_tx_ports]\n"
" -r [nof_rx_ports]\n", prog);
printf("\t-n num_symbols [Default %d]\n", nof_symbols);
printf("\t-c codebook_idx [Default %d]\n", codebook_idx);
printf("\t-s SNR in dB [Default %.1fdB]*\n", snr_db);
printf("\t-d decoder type [zf|mmse] [Default %s]\n", decoder_type_name);
printf("\n");
printf("* Performance test example:\n\t for snr in {0..20..1}; do ./precoding_test -m single -s $snr; done; \n\n", decoder_type_name);
}
void parse_args(int argc, char **argv) {
int opt;
while ((opt = getopt(argc, argv, "mpln")) != -1) {
while ((opt = getopt(argc, argv, "mplnrcds")) != -1) {
switch (opt) {
case 'n':
nof_symbols = atoi(argv[optind]);
break;
case 'p':
nof_ports = atoi(argv[optind]);
nof_tx_ports = atoi(argv[optind]);
break;
case 'r':
nof_rx_ports = atoi(argv[optind]);
break;
case 'l':
nof_layers = atoi(argv[optind]);
@ -64,6 +76,15 @@ void parse_args(int argc, char **argv) {
case 'm':
mimo_type_name = argv[optind];
break;
case 'c':
codebook_idx = (uint32_t) atoi(argv[optind]);
break;
case 'd':
strncpy(decoder_type_name, argv[optind], 16);
break;
case 's':
snr_db = (float) atof(argv[optind]);
break;
default:
usage(argv[0]);
exit(-1);
@ -75,129 +96,236 @@ void parse_args(int argc, char **argv) {
}
}
void populate_channel_cdd(cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], uint32_t n) {
int i, j, k;
for (i = 0; i < nof_tx_ports; i++) {
for (j = 0; j < nof_rx_ports; j++) {
for (k = 0; k < n; k++) {
h[i][j][k] = (float) rand() / RAND_MAX + ((float) rand() / RAND_MAX) * _Complex_I;
}
}
}
}
void populate_channel_diversity(cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], uint32_t n) {
int i, j, k, l;
for (i = 0; i < nof_tx_ports; i++) {
for (j = 0; j < nof_rx_ports; j++) {
for (k = 0; k < n / nof_layers; k++) {
cf_t hsymb = (float) rand() / RAND_MAX + ((float) rand() / RAND_MAX) * _Complex_I;
for (l = 0; l < nof_layers; l++) {
// assume the channel is the same for all symbols
h[i][j][k * nof_layers + l] = hsymb;
}
}
}
}
}
void populate_channel_single(cf_t *h) {
int i;
for (i = 0; i < nof_re; i++) {
h[i] = (float) rand() / RAND_MAX + ((float) rand() / RAND_MAX) * _Complex_I;
}
}
void populate_channel(srslte_mimo_type_t type, cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS]) {
switch (type) {
case SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX:
case SRSLTE_MIMO_TYPE_CDD:
populate_channel_cdd(h, (uint32_t) nof_re);
break;
case SRSLTE_MIMO_TYPE_TX_DIVERSITY:
populate_channel_diversity(h, (uint32_t) nof_re);
break;
case SRSLTE_MIMO_TYPE_SINGLE_ANTENNA:
default:
populate_channel_single(h[0][0]);
}
}
static void awgn(cf_t *y[SRSLTE_MAX_PORTS], uint32_t n, float snr) {
int i;
float std_dev = powf(10, - (snr + 3.0f) / 20.0f);
for (i = 0; i < nof_rx_ports; i++) {
srslte_ch_awgn_c(y[i], y[i], std_dev, n);
}
}
int main(int argc, char **argv) {
int i, j;
int i, j, k, nof_errors = 0, ret = SRSLTE_SUCCESS;
float mse;
cf_t *x[SRSLTE_MAX_LAYERS], *r[SRSLTE_MAX_PORTS], *y[SRSLTE_MAX_PORTS], *h[SRSLTE_MAX_PORTS],
cf_t *x[SRSLTE_MAX_LAYERS], *r[SRSLTE_MAX_PORTS], *y[SRSLTE_MAX_PORTS], *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS],
*xr[SRSLTE_MAX_LAYERS];
srslte_mimo_type_t type;
parse_args(argc, argv);
if (nof_ports > SRSLTE_MAX_PORTS || nof_layers > SRSLTE_MAX_LAYERS) {
/* Check input ranges */
if (nof_tx_ports > SRSLTE_MAX_PORTS || nof_rx_ports > SRSLTE_MAX_PORTS || nof_layers > SRSLTE_MAX_LAYERS) {
fprintf(stderr, "Invalid number of layers or ports\n");
exit(-1);
}
/* Parse MIMO Type */
if (srslte_str2mimotype(mimo_type_name, &type)) {
fprintf(stderr, "Invalid MIMO type %s\n", mimo_type_name);
exit(-1);
}
/* Check scenario conditions are OK */
switch (type) {
case SRSLTE_MIMO_TYPE_TX_DIVERSITY:
nof_re = nof_layers*nof_symbols;
break;
case SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX:
nof_re = nof_symbols;
break;
case SRSLTE_MIMO_TYPE_CDD:
nof_re = nof_symbols*nof_tx_ports/nof_layers;
if (nof_rx_ports != 2 || nof_tx_ports != 2) {
fprintf(stderr, "CDD nof_tx_ports=%d nof_rx_ports=%d is not currently supported\n", nof_tx_ports, nof_rx_ports);
exit(-1);
}
break;
default:
nof_re = nof_symbols*nof_layers;
}
/* Allocate x and xr (received symbols) in memory for each layer */
for (i = 0; i < nof_layers; i++) {
/* Source data */
x[i] = srslte_vec_malloc(sizeof(cf_t) * nof_symbols);
if (!x[i]) {
perror("srslte_vec_malloc");
exit(-1);
}
/* Sink data */
xr[i] = srslte_vec_malloc(sizeof(cf_t) * nof_symbols);
if (!xr[i]) {
perror("srslte_vec_malloc");
exit(-1);
}
}
for (i = 0; i < nof_ports; i++) {
y[i] = srslte_vec_malloc(sizeof(cf_t) * nof_symbols * nof_layers);
// TODO: The number of symbols per port is different in spatial multiplexing.
/* Allocate y in memory for tx each port */
for (i = 0; i < nof_tx_ports; i++) {
y[i] = srslte_vec_malloc(sizeof(cf_t) * nof_re);
if (!y[i]) {
perror("srslte_vec_malloc");
exit(-1);
}
h[i] = srslte_vec_malloc(sizeof(cf_t) * nof_symbols * nof_layers);
if (!h[i]) {
perror("srslte_vec_malloc");
exit(-1);
}
/* Allocate h in memory for each cross channel and layer */
for (i = 0; i < nof_tx_ports; i++) {
for (j = 0; j < nof_rx_ports; j++) {
h[i][j] = srslte_vec_malloc(sizeof(cf_t) * nof_re);
if (!h[i][j]) {
perror("srslte_vec_malloc");
exit(-1);
}
}
}
/* only 1 receiver antenna supported now */
r[0] = srslte_vec_malloc(sizeof(cf_t) * nof_symbols * nof_layers);
if (!r[0]) {
perror("srslte_vec_malloc");
exit(-1);
/* Allocate r */
for (i = 0; i < nof_rx_ports; i++) {
r[i] = srslte_vec_malloc(sizeof(cf_t) * nof_re);
if (!r[i]) {
perror("srslte_vec_malloc");
exit(-1);
}
}
/* generate random data */
/* Generate source random data */
for (i = 0; i < nof_layers; i++) {
for (j = 0; j < nof_symbols; j++) {
x[i][j] = (2*(rand()%2)-1+(2*(rand()%2)-1)*_Complex_I)/sqrt(2);
x[i][j] = (2 * (rand() % 2) - 1 + (2 * (rand() % 2) - 1) * _Complex_I) / sqrt(2);
}
}
/* precoding */
if (srslte_precoding_type(x, y, nof_layers, nof_ports, nof_symbols, type) < 0) {
/* Execute Precoding (Tx) */
if (srslte_precoding_type(x, y, nof_layers, nof_tx_ports, codebook_idx, nof_symbols, type) < 0) {
fprintf(stderr, "Error layer mapper encoder\n");
exit(-1);
}
/* generate channel */
for (i = 0; i < nof_ports; i++) {
for (j = 0; j < nof_symbols; j++) {
h[i][nof_layers*j] = (float) rand()/RAND_MAX+((float) rand()/RAND_MAX)*_Complex_I;
// assume the channel is time-invariant in nlayer consecutive symbols
for (int k=0;k<nof_layers;k++) {
h[i][nof_layers*j+k] = h[i][nof_layers*j];
}
}
}
populate_channel(type, h);
/* pass signal through channel
(we are in the frequency domain so it's a multiplication) */
/* there's only one receiver antenna, signals from different transmitter
* ports are simply combined at the receiver
*/
for (j = 0; j < nof_symbols * nof_layers; j++) {
r[0][j] = 0;
for (i = 0; i < nof_ports; i++) {
r[0][j] += y[i][j] * h[i][j];
for (i = 0; i < nof_rx_ports; i++) {
for (k = 0; k < nof_re; k++) {
r[i][k] = (cf_t) (0.0 + 0.0 * _Complex_I);
for (j = 0; j < nof_tx_ports; j++) {
r[i][k] += y[j][k] * h[j][i][k];
}
}
}
awgn(r, (uint32_t) nof_re, snr_db);
/* If CDD or Spatial muliplex choose decoder */
if (strncmp(decoder_type_name, "zf", 16) == 0) {
srslte_predecoding_set_mimo_decoder(SRSLTE_MIMO_DECODER_ZF);
} else if (strncmp(decoder_type_name, "mmse", 16) == 0) {
srslte_predecoding_set_mimo_decoder(SRSLTE_MIMO_DECODER_MMSE);
} else {
ret = SRSLTE_ERROR;
goto quit;
}
/* predecoding / equalization */
struct timeval t[3];
gettimeofday(&t[1], NULL);
if (srslte_predecoding_type(r[0], h, xr, nof_ports, nof_layers,
nof_symbols * nof_layers, type, 0) < 0) {
fprintf(stderr, "Error layer mapper encoder\n");
exit(-1);
}
srslte_predecoding_type_multi(r, h, xr, nof_rx_ports, nof_tx_ports, nof_layers,
codebook_idx, nof_re, type, powf(10, -snr_db/10));
gettimeofday(&t[2], NULL);
get_time_interval(t);
printf("Execution Time: %ld us\n", t[0].tv_usec);
/* check errors */
mse = 0;
for (i = 0; i < nof_layers; i++) {
for (j = 0; j < nof_symbols; j++) {
mse += cabsf(xr[i][j] - x[i][j]);
if ((crealf(xr[i][j]) > 0) != (crealf(x[i][j]) > 0)) {
nof_errors ++;
}
if ((cimagf(xr[i][j]) > 0) != (cimagf(x[i][j]) > 0)) {
nof_errors ++;
}
}
}
printf("MSE: %f\n", mse/ nof_layers / nof_symbols );
printf("SNR: %5.1fdB;\tExecution time: %5ldus;\tMSE: %.6f;\tBER: %.6f\n", snr_db, t[0].tv_usec,
mse / nof_layers / nof_symbols, (float) nof_errors / (4.0f * nof_re));
if (mse / nof_layers / nof_symbols > MSE_THRESHOLD) {
exit(-1);
ret = SRSLTE_ERROR;
}
quit:
/* Free all data */
for (i = 0; i < nof_layers; i++) {
free(x[i]);
free(xr[i]);
}
for (i = 0; i < nof_ports; i++) {
free(y[i]);
free(h[i]);
for (i = 0; i < nof_rx_ports; i++) {
free(r[i]);
}
free(r[0]);
printf("Ok\n");
exit(0);
for (i = 0; i < nof_rx_ports; i++) {
for (j = 0; j < nof_tx_ports; j++) {
free(h[j][i]);
}
}
exit(ret);
}

@ -35,8 +35,10 @@
#define HEST prhs[1]
#define NEST prhs[2]
#define NLAYERS prhs[3]
#define TXSCHEME prhs[4]
#define NOF_INPUTS 5
#define NCW prhs[4]
#define TXSCHEME prhs[5]
#define CODEBOOK prhs[6]
#define NOF_INPUTS 7
void help()
@ -48,118 +50,159 @@ void help()
/* the gateway function */
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
const mwSize *dims = mxGetDimensions(INPUT);
mwSize ndims;
cf_t *input = NULL;
cf_t *hest = NULL;
cf_t *output = NULL;
uint32_t nof_symbols = 0;
uint32_t nof_rx_ants = 1;
uint32_t nof_layers;
uint32_t nof_tx_ports = 1;
uint32_t nof_codewords = 1;
uint32_t codebook_idx = 0;
float noise_estimate = 0;
cf_t *x[SRSLTE_MAX_LAYERS];
cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS];
cf_t *y[SRSLTE_MAX_PORTS];
int symbols_layers[SRSLTE_MAX_LAYERS];
int i, j;
srslte_mimo_type_t type;
/* Print help if number of inputs does not match with expected */
if (nrhs < NOF_INPUTS) {
help();
return;
}
// Read input symbols
/* Read input symbols */
if (mexutils_read_cf(INPUT, &input) < 0) {
mexErrMsgTxt("Error reading input\n");
return;
}
uint32_t nof_layers = mxGetScalar(NLAYERS);
uint32_t nof_tx_ports = 1;
uint32_t nof_codewords = 1;
uint32_t nof_rx_ants = 1;
const mwSize *dims = mxGetDimensions(INPUT);
mwSize ndims = mxGetNumberOfDimensions(INPUT);
nof_symbols = dims[0];
/* Read number of layers */
nof_layers = (uint32_t) mxGetScalar(NLAYERS);
/* Read number of codewords */
nof_codewords = (uint32_t) mxGetScalar(NCW);
if (nof_layers > SRSLTE_MAX_LAYERS) {
mexErrMsgTxt("Too many layers\n");
return;
}
/* Read number of symbols and Rx antennas */
ndims = mxGetNumberOfDimensions(INPUT);
nof_symbols = (uint32_t) dims[0];
if (ndims >= 2) {
nof_rx_ants = dims[1];
nof_rx_ants = (uint32_t) dims[1];
}
// Read channel estimates
/* Read channel estimates */
if (mexutils_read_cf(HEST, &hest) < 0) {
mexErrMsgTxt("Error reading hest\n");
return;
}
/* Get number of tx ports */
dims = mxGetDimensions(HEST);
ndims = mxGetNumberOfDimensions(HEST);
if (ndims == 3) {
nof_tx_ports = dims[2];
nof_tx_ports = (uint32_t) dims[2];
}
mexPrintf("nof_tx_ports=%d, nof_rx_ants=%d, nof_layers=%d, nof_symbols=%d\n", nof_tx_ports, nof_rx_ants, nof_layers, nof_symbols);
// Read noise estimate
float noise_estimate = 0;
/* Print parameters trace */
mexPrintf("nof_tx_ports=%d, nof_rx_ants=%d, nof_layers=%d, nof_codewords=%d, codebook_idx=%d, nof_symbols=%d\n",
nof_tx_ports, nof_rx_ants, nof_layers, nof_codewords, codebook_idx, nof_symbols);
/* Read noise estimate */
if (nrhs >= NOF_INPUTS) {
noise_estimate = mxGetScalar(NEST);
noise_estimate = (float) mxGetScalar(NEST);
}
cf_t *x[SRSLTE_MAX_LAYERS];
cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS];
cf_t *y[SRSLTE_MAX_PORTS];
for (int i=0;i<SRSLTE_MAX_LAYERS;i++) {
/* Initialise x, h & y pointers */
for (i=0;i<SRSLTE_MAX_LAYERS;i++) {
x[i] = NULL;
}
for (int i=0;i<SRSLTE_MAX_PORTS;i++) {
for (int j=0;j<SRSLTE_MAX_PORTS;j++) {
for (i=0;i<SRSLTE_MAX_PORTS;i++) {
for (j=0;j<SRSLTE_MAX_PORTS;j++) {
h[i][j] = NULL;
}
}
/* Allocate memory */
output = srslte_vec_malloc(sizeof(cf_t)*nof_symbols);
for (int i = 0; i < nof_tx_ports; i++) {
x[i] = srslte_vec_malloc(sizeof(cf_t)*nof_symbols);
for (int j=0;j<nof_rx_ants;j++) {
h[i][j] = &hest[i*nof_symbols*nof_rx_ants + j*nof_symbols];
for (i=0;i<SRSLTE_MAX_PORTS;i++) {
y[i] = NULL;
}
/* Allocate memory for ouput */
output = srslte_vec_malloc(sizeof(cf_t)*nof_symbols*nof_layers);
/* Allocate memory for intermediate data */
for (i = 0; i < nof_tx_ports; i++) {
x[i] = srslte_vec_malloc(sizeof(cf_t) * nof_symbols*nof_layers);
}
/* Allocate memory for channel estimate */
for (i = 0; i < nof_tx_ports; i++) {
for (j=0; j<nof_rx_ants; j++) {
h[i][j] = &hest[(i*nof_rx_ants + j)*nof_symbols];
}
}
for (int j=0;j<nof_rx_ants;j++) {
/* Allocate memory for input */
for (j = 0; j < nof_rx_ants; j++) {
y[j] = &input[j*nof_symbols];
}
char *txscheme = "Port0";
/* Parse Tx scheme */
char txscheme[32] = "Port0";
if (nrhs >= NOF_INPUTS) {
txscheme = mxArrayToString(TXSCHEME);
}
srslte_mimo_type_t type = SRSLTE_MIMO_TYPE_SINGLE_ANTENNA;
if (!strcmp(txscheme, "Port0")) {
type = SRSLTE_MIMO_TYPE_SINGLE_ANTENNA;
} else if (!strcmp(txscheme, "TxDiversity")) {
type = SRSLTE_MIMO_TYPE_TX_DIVERSITY;
} else if (!strcmp(txscheme, "CDD")) {
type = SRSLTE_MIMO_TYPE_CDD;
} else if (!strcmp(txscheme, "SpatialMux")) {
type = SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX;
} else {
mxGetString_700(TXSCHEME, txscheme, 32);
}
codebook_idx = (uint32_t) mxGetScalar(CODEBOOK);
if (srslte_str2mimotype(txscheme, &type)) {
mexPrintf("Unsupported TxScheme=%s\n", txscheme);
return;
}
int symbols_layers[SRSLTE_MAX_LAYERS];
for (int i=0;i<nof_layers;i++) {
/* Populate symbols in layers */
for (i = 0; i < nof_layers; i++) {
symbols_layers[i] = nof_symbols;
}
cf_t *d[SRSLTE_MAX_LAYERS];
d[0] = output;
srslte_predecoding_type_multi(y, h, x, nof_rx_ants, nof_tx_ports, nof_layers, nof_symbols/nof_layers, type, noise_estimate);
srslte_layerdemap_type(x, d, nof_layers, nof_codewords, nof_symbols, symbols_layers, type);
if (nlhs >= 1) {
mexutils_write_cf(output, &plhs[0], nof_symbols, 1);
/* Set output pointer */
cf_t *d[SRSLTE_MAX_CODEWORDS];
for (i = 0; i<nof_codewords; i++) {
d[i] = &output[i*nof_symbols*nof_layers/nof_codewords];
}
/* Pre-decode */
srslte_predecoding_type_multi(y, h, x, nof_rx_ants, nof_tx_ports, nof_layers, codebook_idx, nof_symbols, type,
noise_estimate);
/* Layer de-mapper */
srslte_layerdemap_type(x, d, nof_layers, nof_codewords, nof_symbols, symbols_layers, type);
/* Write output */
if (nlhs >= 1) {
mexutils_write_cf(output, &plhs[0], nof_symbols, nof_codewords);
}
/* Free memory */
if (input) {
free(input);
}
if (hest) {
free(hest);
}
if (output) {
free(output);
}
for (int i=0;i<SRSLTE_MAX_LAYERS;i++) {
for (i=0;i<SRSLTE_MAX_LAYERS;i++) {
if (x[i]) {
free(x[i]);
}

@ -159,46 +159,54 @@ int srslte_cqi_size(srslte_cqi_value_t *value) {
return -1;
}
bool srslte_cqi_send(uint32_t I_cqi_pmi, uint32_t tti) {
uint32_t N_p = 0;
uint32_t N_offset = 0;
static bool srslte_cqi_get_N(uint32_t I_cqi_pmi, uint32_t *N_p, uint32_t *N_offset) {
if (I_cqi_pmi <= 1) {
N_p = 2;
N_offset = I_cqi_pmi;
*N_p = 2;
*N_offset = I_cqi_pmi;
} else if (I_cqi_pmi <= 6) {
N_p = 5;
N_offset = I_cqi_pmi - 2;
*N_p = 5;
*N_offset = I_cqi_pmi - 2;
} else if (I_cqi_pmi <= 16) {
N_p = 10;
N_offset = I_cqi_pmi - 7;
*N_p = 10;
*N_offset = I_cqi_pmi - 7;
} else if (I_cqi_pmi <= 36) {
N_p = 20;
N_offset = I_cqi_pmi - 17;
*N_p = 20;
*N_offset = I_cqi_pmi - 17;
} else if (I_cqi_pmi <= 76) {
N_p = 40;
N_offset = I_cqi_pmi - 37;
*N_p = 40;
*N_offset = I_cqi_pmi - 37;
} else if (I_cqi_pmi <= 156) {
N_p = 80;
N_offset = I_cqi_pmi - 77;
*N_p = 80;
*N_offset = I_cqi_pmi - 77;
} else if (I_cqi_pmi <= 316) {
N_p = 160;
N_offset = I_cqi_pmi - 157;
*N_p = 160;
*N_offset = I_cqi_pmi - 157;
} else if (I_cqi_pmi == 317) {
return false;
return false;
} else if (I_cqi_pmi <= 349) {
N_p = 32;
N_offset = I_cqi_pmi - 318;
*N_p = 32;
*N_offset = I_cqi_pmi - 318;
} else if (I_cqi_pmi <= 413) {
N_p = 64;
N_offset = I_cqi_pmi - 350;
*N_p = 64;
*N_offset = I_cqi_pmi - 350;
} else if (I_cqi_pmi <= 541) {
N_p = 128;
N_offset = I_cqi_pmi - 414;
*N_p = 128;
*N_offset = I_cqi_pmi - 414;
} else if (I_cqi_pmi <= 1023) {
return false;
return false;
}
return true;
}
bool srslte_cqi_send(uint32_t I_cqi_pmi, uint32_t tti) {
uint32_t N_p = 0;
uint32_t N_offset = 0;
if (!srslte_cqi_get_N(I_cqi_pmi, &N_p, &N_offset)) {
return false;
}
if (N_p) {
if ((tti-N_offset)%N_p == 0) {
return true;
@ -207,6 +215,47 @@ bool srslte_cqi_send(uint32_t I_cqi_pmi, uint32_t tti) {
return false;
}
bool srslte_ri_send(uint32_t I_cqi_pmi, uint32_t I_ri, uint32_t tti) {
uint32_t M_ri = 0;
uint32_t N_offset_ri = 0;
uint32_t N_p = 0;
uint32_t N_offset_p = 0;
if (!srslte_cqi_get_N(I_cqi_pmi, &N_p, &N_offset_p)) {
return false;
}
if (I_ri <= 160) {
M_ri = 1;
N_offset_ri = I_ri;
} else if (I_ri <= 161) {
M_ri = 2;
N_offset_ri = I_ri - 161;
} else if (I_ri <= 322) {
M_ri = 4;
N_offset_ri = I_ri - 322;
} else if (I_ri <= 483) {
M_ri = 8;
N_offset_ri = I_ri - 483;
} else if (I_ri <= 644) {
M_ri = 16;
N_offset_ri = I_ri - 644;
} else if (I_ri <= 805) {
M_ri = 32;
N_offset_ri = I_ri - 805;
} else if (I_ri <= 966) {
return false;
}
if (M_ri) {
if ((tti - N_offset_p + N_offset_ri) % (N_p * M_ri) == 0) {
return true;
}
}
return false;
}
// CQI-to-Spectral Efficiency: 36.213 Table 7.2.3-1 */
static float cqi_to_coderate[16] = {0, 0.1523, 0.2344, 0.3770, 0.6016, 0.8770, 1.1758, 1.4766, 1.9141, 2.4063, 2.7305, 3.3223, 3.9023, 4.5234, 5.1152, 5.5547};

@ -1051,6 +1051,16 @@ int dci_format2AB_pack(srslte_ra_dl_dci_t *data, srslte_dci_msg_t *msg, uint32_t
} else {
*y++ = data->tb_cw_swap;
}
/* Force MCS_idx and RV_idx in function of block enable according to 7.1.7 of 36.213 */
if (!data->tb_en[0]) {
data->mcs_idx = 0;
data->rv_idx= 1;
}
if (!data->tb_en[1]) {
data->mcs_idx_1 = 0;
data->rv_idx_1 = 1;
}
/* pack TB1 */
srslte_bit_unpack(data->mcs_idx, &y, 5);

@ -57,14 +57,10 @@ bool srslte_pcfich_exists(int nframe, int nslot) {
return true;
}
int srslte_pcfich_init(srslte_pcfich_t *q) {
return srslte_pcfich_init_multi(q, 1);
}
/** Initializes the pcfich channel receiver.
* On error, returns -1 and frees the structrure
*/
int srslte_pcfich_init_multi(srslte_pcfich_t *q, uint32_t nof_rx_antennas) {
int srslte_pcfich_init(srslte_pcfich_t *q, uint32_t nof_rx_antennas) {
int ret = SRSLTE_ERROR_INVALID_INPUTS;
if (q != NULL)

@ -61,11 +61,7 @@ float srslte_pdcch_coderate(uint32_t nof_bits, uint32_t l) {
}
/** Initializes the PDCCH transmitter and receiver */
int srslte_pdcch_init(srslte_pdcch_t *q, uint32_t max_prb) {
return srslte_pdcch_init_multi(q, max_prb, 1);
}
int srslte_pdcch_init_multi(srslte_pdcch_t *q, uint32_t max_prb, uint32_t nof_rx_antennas)
static int pdcch_init(srslte_pdcch_t *q, uint32_t max_prb, uint32_t nof_rx_antennas, bool is_ue)
{
int ret = SRSLTE_ERROR_INVALID_INPUTS;
@ -74,7 +70,7 @@ int srslte_pdcch_init_multi(srslte_pdcch_t *q, uint32_t max_prb, uint32_t nof_rx
ret = SRSLTE_ERROR;
bzero(q, sizeof(srslte_pdcch_t));
q->nof_rx_antennas = nof_rx_antennas;
q->is_ue = is_ue;
/* Allocate memory for the maximum number of PDCCH bits (CFI=3) */
q->max_bits = max_prb*3*12*2;
@ -110,22 +106,22 @@ int srslte_pdcch_init_multi(srslte_pdcch_t *q, uint32_t max_prb, uint32_t nof_rx
}
for (int i = 0; i < SRSLTE_MAX_PORTS; i++) {
for (int j=0;j<q->nof_rx_antennas;j++) {
q->ce[i][j] = srslte_vec_malloc(sizeof(cf_t) * q->max_bits / 2);
if (!q->ce[i][j]) {
goto clean;
}
}
q->x[i] = srslte_vec_malloc(sizeof(cf_t) * q->max_bits / 2);
if (!q->x[i]) {
goto clean;
}
}
for (int j=0;j<q->nof_rx_antennas;j++) {
q->symbols[j] = srslte_vec_malloc(sizeof(cf_t) * q->max_bits / 2);
if (!q->symbols[j]) {
q->symbols[i] = srslte_vec_malloc(sizeof(cf_t) * q->max_bits / 2);
if (!q->symbols[i]) {
goto clean;
}
if (q->is_ue) {
for (int j = 0; j < q->nof_rx_antennas; j++) {
q->ce[i][j] = srslte_vec_malloc(sizeof(cf_t) * q->max_bits / 2);
if (!q->ce[i][j]) {
goto clean;
}
}
}
}
ret = SRSLTE_SUCCESS;
@ -137,6 +133,14 @@ int srslte_pdcch_init_multi(srslte_pdcch_t *q, uint32_t max_prb, uint32_t nof_rx
return ret;
}
int srslte_pdcch_init_enb(srslte_pdcch_t *q, uint32_t max_prb) {
return pdcch_init(q, max_prb, 0, false);
}
int srslte_pdcch_init_ue(srslte_pdcch_t *q, uint32_t max_prb, uint32_t nof_rx_antennas) {
return pdcch_init(q, max_prb, nof_rx_antennas, true);
}
void srslte_pdcch_free(srslte_pdcch_t *q) {
if (q->e) {
@ -149,18 +153,18 @@ void srslte_pdcch_free(srslte_pdcch_t *q) {
free(q->d);
}
for (int i = 0; i < SRSLTE_MAX_PORTS; i++) {
for (int j=0;j<q->nof_rx_antennas;j++) {
if (q->ce[i][j]) {
free(q->ce[i][j]);
}
}
if (q->x[i]) {
free(q->x[i]);
}
}
for (int j=0;j<q->nof_rx_antennas;j++) {
if (q->symbols[j]) {
free(q->symbols[j]);
if (q->symbols[i]) {
free(q->symbols[i]);
}
if (q->is_ue) {
for (int j=0;j<q->nof_rx_antennas;j++) {
if (q->ce[i][j]) {
free(q->ce[i][j]);
}
}
}
}
for (int i = 0; i < SRSLTE_NSUBFRAMES_X_FRAME; i++) {

@ -28,11 +28,16 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
#include <srslte/phy/phch/pdsch_cfg.h>
#include <srslte/phy/common/sequence.h>
#include <srslte/phy/phch/pdsch.h>
#include "srslte/phy/phch/pdsch.h"
#include "prb_dl.h"
#include "srslte/phy/phch/pdsch.h"
#include "srslte/phy/utils/debug.h"
#include "srslte/phy/utils/vector.h"
#include "srslte/phy/utils/bit.h"
#define MAX_PDSCH_RE(cp) (2 * SRSLTE_CP_NSYMB(cp) * 12)
@ -189,50 +194,58 @@ int srslte_pdsch_get(srslte_pdsch_t *q, cf_t *sf_symbols, cf_t *symbols,
return srslte_pdsch_cp(q, sf_symbols, symbols, grant, lstart, subframe, false);
}
/** Initializes the PDCCH transmitter and receiver */
int pdsch_init_multi(srslte_pdsch_t *q, uint32_t max_prb, uint32_t nof_rx_antennas, bool is_ue)
/** Initializes the PDSCH transmitter and receiver */
static int pdsch_init(srslte_pdsch_t *q, uint32_t max_prb, bool is_ue, uint32_t nof_antennas)
{
int ret = SRSLTE_ERROR_INVALID_INPUTS;
int i;
if (q != NULL &&
nof_rx_antennas <= SRSLTE_MAX_PORTS)
{
if (q != NULL)
{
bzero(q, sizeof(srslte_pdsch_t));
ret = SRSLTE_ERROR;
q->max_re = max_prb * MAX_PDSCH_RE(q->cell.cp);
q->nof_rx_antennas = nof_rx_antennas;
q->max_re = max_prb * MAX_PDSCH_RE(q->cell.cp);
q->is_ue = is_ue;
q->nof_rx_antennas = nof_antennas;
INFO("Init PDSCH: %d PRBs, max_symbols: %d\n", max_prb, q->max_re);
for (i = 0; i < 4; i++) {
for (int i = 0; i < 4; i++) {
if (srslte_modem_table_lte(&q->mod[i], modulations[i])) {
goto clean;
}
srslte_modem_table_bytes(&q->mod[i]);
}
srslte_sch_init(&q->dl_sch);
// Allocate int16_t for reception (LLRs)
q->e = srslte_vec_malloc(sizeof(int16_t) * q->max_re * srslte_mod_bits_x_symbol(SRSLTE_MOD_64QAM));
if (!q->e) {
if (srslte_sch_init(&q->dl_sch)) {
ERROR("Initiating DL SCH");
goto clean;
}
q->d = srslte_vec_malloc(sizeof(cf_t) * q->max_re);
if (!q->d) {
goto clean;
for (int i = 0; i < SRSLTE_MAX_CODEWORDS; i++) {
// Allocate int16_t for reception (LLRs)
q->e[i] = srslte_vec_malloc(sizeof(int16_t) * q->max_re * srslte_mod_bits_x_symbol(SRSLTE_MOD_64QAM));
if (!q->e[i]) {
goto clean;
}
q->d[i] = srslte_vec_malloc(sizeof(cf_t) * q->max_re);
if (!q->d[i]) {
goto clean;
}
}
for (i = 0; i < SRSLTE_MAX_PORTS; i++) {
for (int i = 0; i < SRSLTE_MAX_PORTS; i++) {
q->x[i] = srslte_vec_malloc(sizeof(cf_t) * q->max_re);
if (!q->x[i]) {
goto clean;
}
if (is_ue) {
q->symbols[i] = srslte_vec_malloc(sizeof(cf_t) * q->max_re);
if (!q->symbols[i]) {
goto clean;
}
if (q->is_ue) {
for (int j=0;j<q->nof_rx_antennas;j++) {
q->ce[i][j] = srslte_vec_malloc(sizeof(cf_t) * q->max_re);
if (!q->ce[i][j]) {
@ -241,15 +254,8 @@ int pdsch_init_multi(srslte_pdsch_t *q, uint32_t max_prb, uint32_t nof_rx_antenn
}
}
}
for (int j=0;j<SRSLTE_MAX(q->nof_rx_antennas, q->cell.nof_ports);j++) {
q->symbols[j] = srslte_vec_malloc(sizeof(cf_t) * q->max_re);
if (!q->symbols[j]) {
goto clean;
}
}
q->is_ue = is_ue;
q->users = calloc(sizeof(srslte_pdsch_user_t*), is_ue?1:(1+SRSLTE_SIRNTI));
q->users = calloc(sizeof(srslte_pdsch_user_t*), q->is_ue?1:(1+SRSLTE_SIRNTI));
if (!q->users) {
perror("malloc");
goto clean;
@ -261,6 +267,7 @@ int pdsch_init_multi(srslte_pdsch_t *q, uint32_t max_prb, uint32_t nof_rx_antenn
ret = SRSLTE_SUCCESS;
}
clean:
if (ret == SRSLTE_ERROR) {
srslte_pdsch_free(q);
@ -268,51 +275,47 @@ int pdsch_init_multi(srslte_pdsch_t *q, uint32_t max_prb, uint32_t nof_rx_antenn
return ret;
}
int srslte_pdsch_init_ue(srslte_pdsch_t *q, uint32_t max_prb)
int srslte_pdsch_init_ue(srslte_pdsch_t *q, uint32_t max_prb, uint32_t nof_antennas)
{
return pdsch_init_multi(q, max_prb, 1, true);
return pdsch_init(q, max_prb, true, nof_antennas);
}
int srslte_pdsch_init_enb(srslte_pdsch_t *q, uint32_t max_prb)
{
return pdsch_init_multi(q, max_prb, 1, false);
}
int srslte_pdsch_init_multi_ue(srslte_pdsch_t *q, uint32_t max_prb, uint32_t nof_rx_antennas)
{
return pdsch_init_multi(q, max_prb, nof_rx_antennas, true);
return pdsch_init(q, max_prb, false, 0);
}
int srslte_pdsch_init_multi_enb(srslte_pdsch_t *q, uint32_t max_prb, uint32_t nof_rx_antennas)
{
return pdsch_init_multi(q, max_prb, nof_rx_antennas, false);
}
void srslte_pdsch_free(srslte_pdsch_t *q) {
for (int i = 0; i < SRSLTE_MAX_CODEWORDS; i++) {
void srslte_pdsch_free(srslte_pdsch_t *q) {
int i;
if (q->e[i]) {
free(q->e[i]);
}
if (q->e) {
free(q->e);
}
if (q->d) {
free(q->d);
if (q->d[i]) {
free(q->d[i]);
}
}
for (i = 0; i < SRSLTE_MAX_PORTS; i++) {
/* Free sch objects */
srslte_sch_free(&q->dl_sch);
for (int i = 0; i < SRSLTE_MAX_PORTS; i++) {
if (q->x[i]) {
free(q->x[i]);
}
for (int j=0;j<q->nof_rx_antennas;j++) {
if (q->ce[i][j]) {
free(q->ce[i][j]);
if (q->symbols[i]) {
free(q->symbols[i]);
}
if (q->is_ue) {
for (int j=0;j<q->nof_rx_antennas;j++) {
if (q->ce[i][j]) {
free(q->ce[i][j]);
}
}
}
}
for (int j=0;j<q->nof_rx_antennas;j++) {
if (q->symbols[j]) {
free(q->symbols[j]);
}
}
if (q->users) {
if (q->is_ue) {
srslte_pdsch_free_rnti(q, 0);
@ -328,14 +331,11 @@ void srslte_pdsch_free(srslte_pdsch_t *q) {
srslte_sequence_free(&q->tmp_seq);
for (i = 0; i < 4; i++) {
for (int i = 0; i < 4; i++) {
srslte_modem_table_free(&q->mod[i]);
}
srslte_sch_free(&q->dl_sch);
bzero(q, sizeof(srslte_pdsch_t));
}
int srslte_pdsch_set_cell(srslte_pdsch_t *q, srslte_cell_t cell)
@ -356,35 +356,10 @@ int srslte_pdsch_set_cell(srslte_pdsch_t *q, srslte_cell_t cell)
return ret;
}
/* Configures the structure srslte_pdsch_cfg_t from the DL DCI allocation dci_msg.
* If dci_msg is NULL, the grant is assumed to be already stored in cfg->grant
*/
int srslte_pdsch_cfg(srslte_pdsch_cfg_t *cfg, srslte_cell_t cell, srslte_ra_dl_grant_t *grant, uint32_t cfi, uint32_t sf_idx, uint32_t rvidx)
{
if (cfg) {
if (grant) {
memcpy(&cfg->grant, grant, sizeof(srslte_ra_dl_grant_t));
}
if (srslte_cbsegm(&cfg->cb_segm, cfg->grant.mcs.tbs)) {
fprintf(stderr, "Error computing Codeblock segmentation for TBS=%d\n", cfg->grant.mcs.tbs);
return SRSLTE_ERROR;
}
srslte_ra_dl_grant_to_nbits(&cfg->grant, cfi, cell, sf_idx, &cfg->nbits);
cfg->sf_idx = sf_idx;
cfg->rv = rvidx;
return SRSLTE_SUCCESS;
} else {
return SRSLTE_ERROR_INVALID_INPUTS;
}
}
/* Precalculate the PDSCH scramble sequences for a given RNTI. This function takes a while
* to execute, so shall be called once the final C-RNTI has been allocated for the session.
*/
int srslte_pdsch_set_rnti(srslte_pdsch_t *q, uint16_t rnti) {
uint32_t i;
uint32_t rnti_idx = q->is_ue?0:rnti;
if (!q->users[rnti_idx] || q->is_ue) {
@ -395,13 +370,15 @@ int srslte_pdsch_set_rnti(srslte_pdsch_t *q, uint16_t rnti) {
return -1;
}
}
for (i = 0; i < SRSLTE_NSUBFRAMES_X_FRAME; i++) {
if (srslte_sequence_pdsch(&q->users[rnti_idx]->seq[i], rnti, 0, 2 * i, q->cell.id,
q->max_re * srslte_mod_bits_x_symbol(SRSLTE_MOD_64QAM)))
{
fprintf(stderr, "Error initializing PDSCH scrambling sequence\n");
srslte_pdsch_free_rnti(q, rnti);
return SRSLTE_ERROR;
for (int i = 0; i < SRSLTE_NSUBFRAMES_X_FRAME; i++) {
for (int j = 0; j < SRSLTE_MAX_CODEWORDS; j++) {
if (srslte_sequence_pdsch(&q->users[rnti_idx]->seq[j][i], rnti, j, 2 * i, q->cell.id,
q->max_re * srslte_mod_bits_x_symbol(SRSLTE_MOD_64QAM)))
{
fprintf(stderr, "Error initializing PDSCH scrambling sequence\n");
srslte_pdsch_free_rnti(q, rnti);
return SRSLTE_ERROR;
}
}
}
q->users[rnti_idx]->cell_id = q->cell.id;
@ -417,29 +394,134 @@ void srslte_pdsch_free_rnti(srslte_pdsch_t* q, uint16_t rnti)
uint32_t rnti_idx = q->is_ue?0:rnti;
if (q->users[rnti_idx]) {
for (int i = 0; i < SRSLTE_NSUBFRAMES_X_FRAME; i++) {
srslte_sequence_free(&q->users[rnti_idx]->seq[i]);
for (int j = 0; j < SRSLTE_MAX_CODEWORDS; j++) {
srslte_sequence_free(&q->users[rnti_idx]->seq[j][i]);
}
}
free(q->users[rnti_idx]);
q->users[rnti_idx] = NULL;
}
}
int srslte_pdsch_decode(srslte_pdsch_t *q,
srslte_pdsch_cfg_t *cfg, srslte_softbuffer_rx_t *softbuffer,
cf_t *sf_symbols, cf_t *ce[SRSLTE_MAX_PORTS], float noise_estimate,
uint16_t rnti, uint8_t *data)
static void pdsch_decode_debug(srslte_pdsch_t *q, srslte_pdsch_cfg_t *cfg,
cf_t *sf_symbols[SRSLTE_MAX_PORTS], cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS])
{
cf_t *_sf_symbols[SRSLTE_MAX_PORTS];
cf_t *_ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS];
_sf_symbols[0] = sf_symbols;
for (int i=0;i<q->cell.nof_ports;i++) {
_ce[i][0] = ce[i];
if (SRSLTE_VERBOSE_ISDEBUG()) {
char filename[FILENAME_MAX];
for (int j = 0; j < q->nof_rx_antennas; j++) {
if (snprintf(filename, FILENAME_MAX, "subframe_p%d.dat", j) < 0) {
ERROR("Generating file name");
break;
}
DEBUG("SAVED FILE %s: received subframe symbols\n", filename);
srslte_vec_save_file(filename, sf_symbols[j], SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp)*sizeof(cf_t));
for (int i = 0; i < q->cell.nof_ports; i++) {
if (snprintf(filename, FILENAME_MAX, "hest_%d%d.dat", i, j) < 0) {
ERROR("Generating file name");
break;
}
DEBUG("SAVED FILE %s: channel estimates for Tx %d and Rx %d\n", filename, j, i);
srslte_vec_save_file(filename, ce[i][j], SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp)*sizeof(cf_t));
}
}
for (int i=0;i<cfg->nof_layers;i++) {
if (snprintf(filename, FILENAME_MAX, "pdsch_symbols_%d.dat", i) < 0) {
ERROR("Generating file name");
break;
}
DEBUG("SAVED FILE %s: symbols after equalization\n", filename);
srslte_vec_save_file(filename, q->d[i], cfg->nbits[0].nof_re*sizeof(cf_t));
if (snprintf(filename, FILENAME_MAX, "llr_%d.dat", i) < 0) {
ERROR("Generating file name");
break;
}
DEBUG("SAVED FILE %s: LLR estimates after demodulation and descrambling\n", filename);
srslte_vec_save_file(filename, q->e[i], cfg->nbits[0].nof_bits*sizeof(int16_t));
}
}
return srslte_pdsch_decode_multi(q, cfg, softbuffer, _sf_symbols, _ce, noise_estimate, rnti, data);
}
static srslte_sequence_t *get_user_sequence(srslte_pdsch_t *q, uint16_t rnti, uint32_t sf_idx, uint32_t len)
/* Configures the structure srslte_pdsch_cfg_t from the DL DCI allocation dci_msg.
* If dci_msg is NULL, the grant is assumed to be already stored in cfg->grant
*/
int srslte_pdsch_cfg(srslte_pdsch_cfg_t *cfg, srslte_cell_t cell, srslte_ra_dl_grant_t *grant, uint32_t cfi,
uint32_t sf_idx, int rvidx) {
int _rvids[SRSLTE_MAX_CODEWORDS] = {1};
_rvids[0] = rvidx;
return srslte_pdsch_cfg_mimo(cfg, cell, grant, cfi, sf_idx, _rvids, SRSLTE_MIMO_TYPE_SINGLE_ANTENNA, 0);
}
/* Configures the structure srslte_pdsch_cfg_t from the DL DCI allocation dci_msg.
* If dci_msg is NULL, the grant is assumed to be already stored in cfg->grant
*/
int srslte_pdsch_cfg_mimo(srslte_pdsch_cfg_t *cfg, srslte_cell_t cell, srslte_ra_dl_grant_t *grant, uint32_t cfi,
uint32_t sf_idx, int rvidx[SRSLTE_MAX_CODEWORDS], srslte_mimo_type_t mimo_type,
uint32_t pmi) {
if (cfg) {
if (grant) {
memcpy(&cfg->grant, grant, sizeof(srslte_ra_dl_grant_t));
}
for (int i = 0; i < grant->nof_tb; i++) {
if (srslte_cbsegm(&cfg->cb_segm[i], (uint32_t) cfg->grant.mcs[i].tbs)) {
fprintf(stderr, "Error computing Codeblock (1) segmentation for TBS=%d\n", cfg->grant.mcs[i].tbs);
return SRSLTE_ERROR;
}
}
srslte_ra_dl_grant_to_nbits(&cfg->grant, cfi, cell, sf_idx, cfg->nbits);
cfg->sf_idx = sf_idx;
memcpy(cfg->rv, rvidx, sizeof(uint32_t) * SRSLTE_MAX_CODEWORDS);
cfg->mimo_type = mimo_type;
/* Check and configure PDSCH transmission modes */
switch(mimo_type) {
case SRSLTE_MIMO_TYPE_SINGLE_ANTENNA:
if (grant->nof_tb != 1) {
ERROR("Number of transport blocks is not supported for single transmission mode.");
return SRSLTE_ERROR;
}
cfg->nof_layers = 1;
break;
case SRSLTE_MIMO_TYPE_TX_DIVERSITY:
if (grant->nof_tb != 1) {
ERROR("Number of transport blocks is not supported for transmit diversity mode.");
return SRSLTE_ERROR;
}
cfg->nof_layers = 2;
break;
case SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX:
if (grant->nof_tb == 1) {
cfg->codebook_idx = pmi;
cfg->nof_layers = 1;
} else {
cfg->codebook_idx = pmi + 1;
cfg->nof_layers = 2;
}
INFO("PDSCH configured for Spatial Multiplex; nof_codewords=%d; nof_layers=%d; codebook_idx=%d;\n",
grant->nof_tb, cfg->nof_layers, cfg->codebook_idx);
break;
case SRSLTE_MIMO_TYPE_CDD:
if (grant->nof_tb != 2) {
ERROR("Number of transport blocks (%d) is not supported for CDD transmission mode.", grant->nof_tb);
return SRSLTE_ERROR;
}
cfg->nof_layers = 2;
break;
}
return SRSLTE_SUCCESS;
} else {
return SRSLTE_ERROR_INVALID_INPUTS;
}
}
static srslte_sequence_t *get_user_sequence(srslte_pdsch_t *q, uint16_t rnti,
uint32_t codeword_idx, uint32_t sf_idx, uint32_t len)
{
uint32_t rnti_idx = q->is_ue?0:rnti;
@ -448,178 +530,264 @@ static srslte_sequence_t *get_user_sequence(srslte_pdsch_t *q, uint16_t rnti, ui
q->users[rnti_idx]->cell_id == q->cell.id &&
((rnti >= SRSLTE_CRNTI_START && rnti < SRSLTE_CRNTI_END) || !q->is_ue))
{
return &q->users[rnti_idx]->seq[sf_idx];
return &q->users[rnti_idx]->seq[codeword_idx][sf_idx];
} else {
srslte_sequence_pdsch(&q->tmp_seq, rnti, 0, 2 * sf_idx, q->cell.id, len);
srslte_sequence_pdsch(&q->tmp_seq, rnti, codeword_idx, 2 * sf_idx, q->cell.id, len);
return &q->tmp_seq;
}
}
static int srslte_pdsch_codeword_encode(srslte_pdsch_t *q, srslte_pdsch_cfg_t *cfg,
srslte_softbuffer_tx_t *softbuffer, uint16_t rnti, uint8_t *data,
uint32_t codeword_idx) {
srslte_ra_nbits_t *nbits = &cfg->nbits[codeword_idx];
srslte_ra_mcs_t *mcs = &cfg->grant.mcs[codeword_idx];
uint32_t rv = cfg->rv[codeword_idx];
if (nbits->nof_bits) {
INFO("Encoding PDSCH SF: %d (TB %d), Mod %s, NofBits: %d, NofSymbols: %d, NofBitsE: %d, rv_idx: %d\n",
cfg->sf_idx, codeword_idx, srslte_mod_string(mcs->mod), mcs->tbs,
nbits->nof_re, nbits->nof_bits, rv);
/* Channel coding */
if (srslte_dlsch_encode2(&q->dl_sch, cfg, softbuffer, data, q->e[codeword_idx], codeword_idx)) {
ERROR("Error encoding TB %d", codeword_idx);
return SRSLTE_ERROR;
}
/* Select scrambling sequence */
srslte_sequence_t *seq = get_user_sequence(q, rnti, codeword_idx, cfg->sf_idx, nbits->nof_bits);
/* Bit scrambling */
srslte_scrambling_bytes(seq, (uint8_t *) q->e[codeword_idx], nbits->nof_bits);
/* Bit mapping */
srslte_mod_modulate_bytes(&q->mod[mcs->mod],
(uint8_t *) q->e[codeword_idx],
q->d[codeword_idx], nbits->nof_bits);
}
return SRSLTE_SUCCESS;
}
static int srslte_pdsch_codeword_decode(srslte_pdsch_t *q, srslte_pdsch_cfg_t *cfg,
srslte_softbuffer_rx_t *softbuffer, uint16_t rnti, uint8_t *data,
uint32_t codeword_idx) {
srslte_ra_nbits_t *nbits = &cfg->nbits[codeword_idx];
srslte_ra_mcs_t *mcs = &cfg->grant.mcs[codeword_idx];
uint32_t rv = cfg->rv[codeword_idx];
if (nbits->nof_bits) {
INFO("Decoding PDSCH SF: %d (TB %d), Mod %s, NofBits: %d, NofSymbols: %d, NofBitsE: %d, rv_idx: %d\n",
cfg->sf_idx, codeword_idx, srslte_mod_string(mcs->mod), mcs->tbs,
nbits->nof_re, nbits->nof_bits, rv);
/* demodulate symbols
* The MAX-log-MAP algorithm used in turbo decoding is unsensitive to SNR estimation,
* thus we don't need tot set it in the LLRs normalization
*/
srslte_demod_soft_demodulate_s(mcs->mod, q->d[codeword_idx], q->e[codeword_idx], nbits->nof_re);
/* Select scrambling sequence */
srslte_sequence_t *seq = get_user_sequence(q, rnti, codeword_idx, cfg->sf_idx, nbits->nof_bits);
/* Bit scrambling */
srslte_scrambling_s_offset(seq, q->e[codeword_idx], 0, nbits->nof_bits);
return srslte_dlsch_decode2(&q->dl_sch, cfg, softbuffer, q->e[codeword_idx], data, codeword_idx);
}
return SRSLTE_SUCCESS;
}
/** Decodes the PDSCH from the received symbols
*/
int srslte_pdsch_decode_multi(srslte_pdsch_t *q,
srslte_pdsch_cfg_t *cfg, srslte_softbuffer_rx_t *softbuffer,
cf_t *sf_symbols[SRSLTE_MAX_PORTS], cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], float noise_estimate,
uint16_t rnti, uint8_t *data)
int srslte_pdsch_decode(srslte_pdsch_t *q,
srslte_pdsch_cfg_t *cfg, srslte_softbuffer_rx_t *softbuffers[SRSLTE_MAX_CODEWORDS],
cf_t *sf_symbols[SRSLTE_MAX_PORTS], cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS],
float noise_estimate, uint16_t rnti, uint8_t *data[SRSLTE_MAX_CODEWORDS],
bool acks[SRSLTE_MAX_CODEWORDS])
{
/* Set pointers for layermapping & precoding */
uint32_t i, n;
uint32_t i;
cf_t *x[SRSLTE_MAX_LAYERS];
if (q != NULL &&
sf_symbols != NULL &&
data != NULL &&
data != NULL &&
cfg != NULL)
{
INFO("Decoding PDSCH SF: %d, RNTI: 0x%x, Mod %s, TBS: %d, NofSymbols: %d, NofBitsE: %d, rv_idx: %d, C_prb=%d\n",
cfg->sf_idx, rnti, srslte_mod_string(cfg->grant.mcs.mod), cfg->grant.mcs.tbs, cfg->nbits.nof_re,
cfg->nbits.nof_bits, cfg->rv, cfg->grant.nof_prb);
INFO("Decoding PDSCH SF: %d, RNTI: 0x%x, NofSymbols: %d, C_prb=%d, nof_layers=%d, nof_tb=%d\n",
cfg->sf_idx, rnti, cfg->nbits[0].nof_re, cfg->grant.nof_prb, cfg->nof_layers, cfg->grant.nof_tb);
/* number of layers equals number of ports */
for (i = 0; i < q->cell.nof_ports; i++) {
x[i] = q->x[i];
}
memset(&x[q->cell.nof_ports], 0, sizeof(cf_t*) * (SRSLTE_MAX_LAYERS - q->cell.nof_ports));
// Extract Symbols and Channel Estimates
for (int j=0;j<q->nof_rx_antennas;j++) {
/* extract symbols */
n = srslte_pdsch_get(q, sf_symbols[j], q->symbols[j], &cfg->grant, cfg->nbits.lstart, cfg->sf_idx);
if (n != cfg->nbits.nof_re) {
fprintf(stderr, "Error expecting %d symbols but got %d\n", cfg->nbits.nof_re, n);
int n = srslte_pdsch_get(q, sf_symbols[j], q->symbols[j], &cfg->grant, cfg->nbits[0].lstart, cfg->sf_idx);
if (n != cfg->nbits[0].nof_re) {
fprintf(stderr, "Error expecting %d symbols but got %d\n", cfg->nbits[0].nof_re, n);
return SRSLTE_ERROR;
}
/* extract channel estimates */
for (i = 0; i < q->cell.nof_ports; i++) {
n = srslte_pdsch_get(q, ce[i][j], q->ce[i][j], &cfg->grant, cfg->nbits.lstart, cfg->sf_idx);
if (n != cfg->nbits.nof_re) {
fprintf(stderr, "Error expecting %d symbols but got %d\n", cfg->nbits.nof_re, n);
n = srslte_pdsch_get(q, ce[i][j], q->ce[i][j], &cfg->grant, cfg->nbits[0].lstart, cfg->sf_idx);
if (n != cfg->nbits[0].nof_re) {
fprintf(stderr, "Error expecting %d symbols but got %d\n", cfg->nbits[0].nof_re, n);
return SRSLTE_ERROR;
}
}
}
}
/* TODO: only diversity is supported */
if (q->cell.nof_ports == 1) {
/* no need for layer demapping */
srslte_predecoding_single_multi(q->symbols, q->ce[0], q->d, q->nof_rx_antennas, cfg->nbits.nof_re, noise_estimate);
// Prepare layers
int nof_symbols [SRSLTE_MAX_CODEWORDS];
nof_symbols[0] = cfg->nbits[0].nof_re * cfg->grant.nof_tb / cfg->nof_layers;
nof_symbols[1] = cfg->nbits[1].nof_re * cfg->grant.nof_tb / cfg->nof_layers;
if (cfg->nof_layers == cfg->grant.nof_tb) {
/* Skip layer demap */
for (i = 0; i < cfg->nof_layers; i++) {
x[i] = q->d[i];
}
} else {
srslte_predecoding_diversity_multi(q->symbols, q->ce, x, q->nof_rx_antennas, q->cell.nof_ports, cfg->nbits.nof_re);
srslte_layerdemap_diversity(x, q->d, q->cell.nof_ports, cfg->nbits.nof_re / q->cell.nof_ports);
}
if (SRSLTE_VERBOSE_ISDEBUG()) {
DEBUG("SAVED FILE subframe.dat: received subframe symbols\n",0);
srslte_vec_save_file("subframe.dat", sf_symbols[0], SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp)*sizeof(cf_t));
DEBUG("SAVED FILE hest0.dat and hest1.dat: channel estimates for port 0 and port 1\n",0);
srslte_vec_save_file("hest0.dat", ce[0][0], SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp)*sizeof(cf_t));
if (q->cell.nof_ports > 1) {
srslte_vec_save_file("hest1.dat", ce[1][0], SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp)*sizeof(cf_t));
/* number of layers equals number of ports */
for (i = 0; i < cfg->nof_layers; i++) {
x[i] = q->x[i];
}
DEBUG("SAVED FILE pdsch_symbols.dat: symbols after equalization\n",0);
srslte_vec_save_file("pdsch_symbols.dat", q->d, cfg->nbits.nof_re*sizeof(cf_t));
memset(&x[cfg->nof_layers], 0, sizeof(cf_t*) * (SRSLTE_MAX_LAYERS - cfg->nof_layers));
}
/* demodulate symbols
* The MAX-log-MAP algorithm used in turbo decoding is unsensitive to SNR estimation,
* thus we don't need tot set it in the LLRs normalization
*/
srslte_demod_soft_demodulate_s(cfg->grant.mcs.mod, q->d, q->e, cfg->nbits.nof_re);
// Generate scrambling sequence if not pre-generated
srslte_sequence_t *seq = get_user_sequence(q, rnti, cfg->sf_idx, cfg->nbits.nof_bits);
// Pre-decoder
srslte_predecoding_type_multi(q->symbols, q->ce, x, q->nof_rx_antennas, q->cell.nof_ports, cfg->nof_layers,
cfg->codebook_idx, cfg->nbits[0].nof_re, cfg->mimo_type, noise_estimate);
// Run scrambling
srslte_scrambling_s_offset(seq, q->e, 0, cfg->nbits.nof_bits);
// Layer demapping only if necessary
if (cfg->nof_layers != cfg->grant.nof_tb) {
srslte_layerdemap_type(x, q->d, cfg->nof_layers, cfg->grant.nof_tb,
nof_symbols[0], nof_symbols, cfg->mimo_type);
}
if (SRSLTE_VERBOSE_ISDEBUG()) {
DEBUG("SAVED FILE llr.dat: LLR estimates after demodulation and descrambling\n",0);
srslte_vec_save_file("llr.dat", q->e, cfg->nbits.nof_bits*sizeof(int16_t));
// Codeword decoding
for (uint32_t tb = 0; tb < cfg->grant.nof_tb; tb ++) {
int ret = srslte_pdsch_codeword_decode(q, cfg, softbuffers[tb], rnti, data[tb], tb);
acks[tb] = (ret == SRSLTE_SUCCESS);
}
return srslte_dlsch_decode(&q->dl_sch, cfg, softbuffer, q->e, data);
pdsch_decode_debug(q, cfg, sf_symbols, ce);
return SRSLTE_SUCCESS;
} else {
return SRSLTE_ERROR_INVALID_INPUTS;
}
}
int srslte_pdsch_pmi_select(srslte_pdsch_t *q,
srslte_pdsch_cfg_t *cfg,
cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], float noise_estimate, uint32_t nof_ce,
uint32_t pmi[SRSLTE_MAX_LAYERS], float sinr[SRSLTE_MAX_LAYERS][SRSLTE_MAX_CODEBOOKS]) {
if (q->cell.nof_ports == 2 && q->nof_rx_antennas == 2) {
for (int nof_layers = 1; nof_layers <= 2; nof_layers++ ) {
if (sinr[nof_layers - 1] && pmi) {
if (srslte_precoding_pmi_select(ce, nof_ce, noise_estimate, nof_layers, &pmi[nof_layers - 1],
sinr[nof_layers - 1]) < 0) {
ERROR("PMI Select for %d layers", nof_layers);
return SRSLTE_ERROR;
}
}
}
} else {
ERROR("Not implemented configuration");
return SRSLTE_ERROR_INVALID_INPUTS;
}
return SRSLTE_SUCCESS;
}
int srslte_pdsch_cn_compute(srslte_pdsch_t *q,
cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], uint32_t nof_ce, float *cn) {
return srslte_precoding_cn(ce, q->cell.nof_ports, q->nof_rx_antennas, nof_ce, cn);
}
int srslte_pdsch_encode(srslte_pdsch_t *q,
srslte_pdsch_cfg_t *cfg, srslte_softbuffer_tx_t *softbuffer,
uint8_t *data, uint16_t rnti, cf_t *sf_symbols[SRSLTE_MAX_PORTS])
int srslte_pdsch_encode(srslte_pdsch_t *q,
srslte_pdsch_cfg_t *cfg, srslte_softbuffer_tx_t *softbuffers[SRSLTE_MAX_CODEWORDS],
uint8_t *data[SRSLTE_MAX_CODEWORDS], uint16_t rnti, cf_t *sf_symbols[SRSLTE_MAX_PORTS])
{
int i;
/* Set pointers for layermapping & precoding */
cf_t *x[SRSLTE_MAX_LAYERS];
int ret = SRSLTE_ERROR_INVALID_INPUTS;
if (q != NULL &&
cfg != NULL)
{
int ret = SRSLTE_ERROR_INVALID_INPUTS;
if (q != NULL &&
cfg != NULL) {
for (i=0;i<q->cell.nof_ports;i++) {
for (i = 0; i < q->cell.nof_ports; i++) {
if (sf_symbols[i] == NULL) {
return SRSLTE_ERROR_INVALID_INPUTS;
}
}
if (cfg->grant.mcs.tbs == 0) {
return SRSLTE_ERROR_INVALID_INPUTS;
}
if (cfg->nbits.nof_re > q->max_re) {
fprintf(stderr,
"Error too many RE per subframe (%d). PDSCH configured for %d RE (%d PRB)\n",
cfg->nbits.nof_re, q->max_re, q->cell.nof_prb);
/* If both transport block size is zero return error */
if (cfg->grant.mcs[0].tbs == 0) {
return SRSLTE_ERROR_INVALID_INPUTS;
}
INFO("Encoding PDSCH SF: %d, Mod %s, NofBits: %d, NofSymbols: %d, NofBitsE: %d, rv_idx: %d\n",
cfg->sf_idx, srslte_mod_string(cfg->grant.mcs.mod), cfg->grant.mcs.tbs,
cfg->nbits.nof_re, cfg->nbits.nof_bits, cfg->rv);
/* number of layers equals number of ports */
for (i = 0; i < q->cell.nof_ports; i++) {
x[i] = q->x[i];
if (cfg->nbits[0].nof_re > q->max_re) {
fprintf(stderr,
"Error too many RE per subframe (%d). PDSCH configured for %d RE (%d PRB)\n",
cfg->nbits[0].nof_re, q->max_re, q->cell.nof_prb);
return SRSLTE_ERROR_INVALID_INPUTS;
}
memset(&x[q->cell.nof_ports], 0, sizeof(cf_t*) * (SRSLTE_MAX_LAYERS - q->cell.nof_ports));
if (srslte_dlsch_encode(&q->dl_sch, cfg, softbuffer, data, q->e)) {
fprintf(stderr, "Error encoding TB\n");
return SRSLTE_ERROR;
for (uint32_t tb = 0; tb < cfg->grant.nof_tb; tb ++) {
ret |= srslte_pdsch_codeword_encode(q, cfg, softbuffers[tb], rnti, data[tb], tb);
}
// Generate scrambling sequence if not pre-generated
srslte_sequence_t *seq = get_user_sequence(q, rnti, cfg->sf_idx, cfg->nbits.nof_bits);
// Layer mapping & precode if necessary
if (q->cell.nof_ports > 1) {
int nof_symbols;
/* If number of layers is equal to transport blocks (codewords) skip layer mapping */
if (cfg->nof_layers == cfg->grant.nof_tb) {
for (i = 0; i < cfg->nof_layers; i++) {
x[i] = q->d[i];
}
nof_symbols = cfg->nbits[0].nof_re;
} else {
/* Initialise layer map pointers */
for (i = 0; i < cfg->nof_layers; i++) {
x[i] = q->x[i];
}
memset(&x[cfg->nof_layers], 0, sizeof(cf_t *) * (SRSLTE_MAX_LAYERS - cfg->nof_layers));
srslte_scrambling_bytes(seq, (uint8_t*) q->e, cfg->nbits.nof_bits);
nof_symbols = srslte_layermap_type(q->d, x, cfg->grant.nof_tb, cfg->nof_layers,
(int[SRSLTE_MAX_CODEWORDS]) {cfg->nbits[0].nof_re, cfg->nbits[1].nof_re},
cfg->mimo_type);
}
srslte_mod_modulate_bytes(&q->mod[cfg->grant.mcs.mod], (uint8_t*) q->e, q->d, cfg->nbits.nof_bits);
/* TODO: only diversity supported */
if (q->cell.nof_ports > 1) {
srslte_layermap_diversity(q->d, x, q->cell.nof_ports, cfg->nbits.nof_re);
srslte_precoding_diversity(x, q->symbols, q->cell.nof_ports,
cfg->nbits.nof_re / q->cell.nof_ports);
/* Precode */
srslte_precoding_type(x, q->symbols, cfg->nof_layers, q->cell.nof_ports, cfg->codebook_idx,
nof_symbols, cfg->mimo_type);
} else {
memcpy(q->symbols[0], q->d, cfg->nbits.nof_re * sizeof(cf_t));
memcpy(q->symbols[0], q->d[0], cfg->nbits[0].nof_re * sizeof(cf_t));
}
/* mapping to resource elements */
for (i = 0; i < q->cell.nof_ports; i++) {
srslte_pdsch_put(q, q->symbols[i], sf_symbols[i], &cfg->grant, cfg->nbits.lstart, cfg->sf_idx);
srslte_pdsch_put(q, q->symbols[i], sf_symbols[i], &cfg->grant, cfg->nbits[0].lstart, cfg->sf_idx);
}
ret = SRSLTE_SUCCESS;
}
return ret;
}
return ret;
}
float srslte_pdsch_average_noi(srslte_pdsch_t *q)
{
void srslte_pdsch_set_max_noi(srslte_pdsch_t *q, uint32_t max_iter) {
srslte_sch_set_max_noi(&q->dl_sch, max_iter);
}
float srslte_pdsch_average_noi(srslte_pdsch_t *q) {
return q->dl_sch.average_nof_iterations;
}

@ -68,13 +68,8 @@ void srslte_phich_reset(srslte_phich_t *q, cf_t *slot_symbols[SRSLTE_MAX_PORTS])
}
}
int srslte_phich_init(srslte_phich_t *q)
{
return srslte_phich_init_multi(q, 1);
}
/** Initializes the phich channel receiver */
int srslte_phich_init_multi(srslte_phich_t *q, uint32_t nof_rx_antennas)
int srslte_phich_init(srslte_phich_t *q, uint32_t nof_rx_antennas)
{
int ret = SRSLTE_ERROR_INVALID_INPUTS;

@ -434,6 +434,10 @@ int srslte_pucch_init(srslte_pucch_t *q) {
srslte_uci_cqi_pucch_init(&q->cqi);
q->z = srslte_vec_malloc(sizeof(cf_t)*SRSLTE_PUCCH_MAX_SYMBOLS);
q->z_tmp = srslte_vec_malloc(sizeof(cf_t)*SRSLTE_PUCCH_MAX_SYMBOLS);
q->ce = srslte_vec_malloc(sizeof(cf_t)*SRSLTE_PUCCH_MAX_SYMBOLS);
q->threshold_format1 = 0.8;
ret = SRSLTE_SUCCESS;
@ -851,4 +855,4 @@ int srslte_pucch_decode(srslte_pucch_t* q, srslte_pucch_format_t format,
}

@ -492,44 +492,44 @@ static int dl_dci_to_grant_mcs(srslte_ra_dl_dci_t *dci, srslte_ra_dl_grant_t *gr
fprintf(stderr, "Error decoding DCI: P/SI/RA-RNTI supports Format1A/1C only\n");
return SRSLTE_ERROR;
}
grant->mcs.mod = SRSLTE_MOD_QPSK;
grant->mcs.tbs = (uint32_t) tbs;
grant->mcs[0].mod = SRSLTE_MOD_QPSK;
grant->mcs[0].tbs = (uint32_t) tbs;
} else {
n_prb = grant->nof_prb;
grant->nof_tb = 0;
if (dci->tb_en[0]) {
grant->mcs.idx = dci->mcs_idx;
tbs = dl_fill_ra_mcs(&grant->mcs, n_prb);
grant->mcs[0].idx = dci->mcs_idx;
tbs = dl_fill_ra_mcs(&grant->mcs[0], n_prb);
if (tbs) {
last_dl_tbs[dci->harq_process%8] = tbs;
} else {
// For mcs>=29, set last TBS received for this PID
grant->mcs.tbs = last_dl_tbs[dci->harq_process%8];
grant->mcs[0].tbs = last_dl_tbs[dci->harq_process%8];
}
grant->nof_tb++;
} else {
grant->mcs.tbs = 0;
grant->mcs[0].tbs = 0;
}
if (dci->tb_en[1]) {
grant->mcs2.idx = dci->mcs_idx_1;
tbs = dl_fill_ra_mcs(&grant->mcs2, n_prb);
grant->mcs[1].idx = dci->mcs_idx_1;
tbs = dl_fill_ra_mcs(&grant->mcs[1], n_prb);
if (tbs) {
last_dl_tbs2[dci->harq_process%8] = tbs;
} else {
// For mcs>=29, set last TBS received for this PID
grant->mcs2.tbs = last_dl_tbs2[dci->harq_process%8];
grant->mcs[1].tbs = last_dl_tbs2[dci->harq_process%8];
}
grant->nof_tb++;
} else {
grant->mcs2.tbs = 0;
grant->mcs[1].tbs = 0;
}
}
if (dci->tb_en[0]) {
grant->Qm = srslte_mod_bits_x_symbol(grant->mcs.mod);
}
if (dci->tb_en[1]) {
grant->Qm2 = srslte_mod_bits_x_symbol(grant->mcs2.mod);
grant->nof_tb = 0;
for (int tb = 0; tb < SRSLTE_MAX_CODEWORDS; tb++) {
if (dci->tb_en[tb]) {
grant->Qm[tb] = srslte_mod_bits_x_symbol(grant->mcs[tb].mod);
grant->nof_tb++;
}
}
grant->pinfo = dci->pinfo;
if (tbs < 0) {
return SRSLTE_ERROR;
} else {
@ -537,13 +537,17 @@ static int dl_dci_to_grant_mcs(srslte_ra_dl_dci_t *dci, srslte_ra_dl_grant_t *gr
}
}
void srslte_ra_dl_grant_to_nbits(srslte_ra_dl_grant_t *grant, uint32_t cfi, srslte_cell_t cell, uint32_t sf_idx, srslte_ra_nbits_t *nbits)
void srslte_ra_dl_grant_to_nbits(srslte_ra_dl_grant_t *grant, uint32_t cfi, srslte_cell_t cell, uint32_t sf_idx,
srslte_ra_nbits_t nbits [SRSLTE_MAX_CODEWORDS])
{
// Compute number of RE
nbits->nof_re = srslte_ra_dl_grant_nof_re(grant, cell, sf_idx, cell.nof_prb<10?(cfi+1):cfi);
nbits->lstart = cell.nof_prb<10?(cfi+1):cfi;
nbits->nof_symb = 2*SRSLTE_CP_NSYMB(cell.cp)-nbits->lstart;
nbits->nof_bits = nbits->nof_re * grant->Qm;
for (int i = 0; i < grant->nof_tb; i++) {
/* Compute number of RE for first transport block */
nbits[i].nof_re = srslte_ra_dl_grant_nof_re(grant, cell, sf_idx, cell.nof_prb < 10 ? (cfi + 1) : cfi);
nbits[i].lstart = cell.nof_prb < 10 ? (cfi + 1) : cfi;
nbits[i].nof_symb = 2 * SRSLTE_CP_NSYMB(cell.cp) - nbits[0].lstart;
nbits[i].nof_bits = nbits[i].nof_re * grant->Qm[i];
}
}
/** Obtains a DL grant from a DCI grant for PDSCH */
@ -796,18 +800,32 @@ void srslte_ra_pdsch_fprint(FILE *f, srslte_ra_dl_dci_t *dci, uint32_t nof_prb)
}
break;
}
fprintf(f, " - Modulation and coding scheme index:\t%d\n", dci->mcs_idx);
fprintf(f, " - HARQ process:\t\t\t%d\n", dci->harq_process);
fprintf(f, " - New data indicator:\t\t\t%s\n", dci->ndi ? "Yes" : "No");
fprintf(f, " - Redundancy version:\t\t\t%d\n", dci->rv_idx);
fprintf(f, " - TPC command for PUCCH:\t\t--\n");
fprintf(f, " - Transport blocks swapped:\t\t%s\n", (dci->tb_cw_swap)?"true":"false");
fprintf(f, " - Transport block 1 enabled:\t\t%s\n", (dci->tb_en[0])?"true":"false");
if (dci->tb_en[0]) {
fprintf(f, " + Modulation and coding scheme index:\t%d\n", dci->mcs_idx);
fprintf(f, " + New data indicator:\t\t\t%s\n", dci->ndi ? "Yes" : "No");
fprintf(f, " + Redundancy version:\t\t\t%d\n", dci->rv_idx);
}
fprintf(f, " - Transport block 2 enabled:\t\t%s\n", (dci->tb_en[1])?"true":"false");
if (dci->tb_en[1]) {
fprintf(f, " + Modulation and coding scheme index:\t%d\n", dci->mcs_idx_1);
fprintf(f, " + New data indicator:\t\t\t%s\n", dci->ndi_1 ? "Yes" : "No");
fprintf(f, " + Redundancy version:\t\t\t%d\n", dci->rv_idx_1);
}
}
void srslte_ra_dl_grant_fprint(FILE *f, srslte_ra_dl_grant_t *grant) {
srslte_ra_prb_fprint(f, grant);
fprintf(f, " - Number of PRBs:\t\t\t%d\n", grant->nof_prb);
fprintf(f, " - Modulation type:\t\t\t%s\n", srslte_mod_string(grant->mcs.mod));
fprintf(f, " - Transport block size:\t\t%d\n", grant->mcs.tbs);
fprintf(f, " - Number of TBs:\t\t\t%d\n", grant->nof_tb);
for (int i = 0; i < grant->nof_tb; i++) {
fprintf(f, " - Transport block:\t\t\t%d\n", i);
fprintf(f, " -> Modulation type:\t\t\t%s\n", srslte_mod_string(grant->mcs[i].mod));
fprintf(f, " -> Transport block size:\t\t%d\n", grant->mcs[i].tbs);
}
}
void srslte_ra_prb_fprint(FILE *f, srslte_ra_dl_grant_t *grant) {

@ -455,7 +455,7 @@ static int decode_tb(srslte_sch_t *q,
e_bits != NULL &&
cb_segm != NULL)
{
if (cb_segm->tbs == 0 || cb_segm->C == 0) {
return SRSLTE_SUCCESS;
}
@ -476,8 +476,8 @@ static int decode_tb(srslte_sch_t *q,
data[cb_segm->tbs/8+0] = 0;
data[cb_segm->tbs/8+1] = 0;
data[cb_segm->tbs/8+2] = 0;
data[cb_segm->tbs/8+2] = 0;
// Process Codeblocks in groups of equal CB size to parallelize according to SRSLTE_TDEC_NPAR
for (uint32_t i=0;i<nof_cb_groups && crc_ok;i++) {
crc_ok = decode_tb_cb(q, softbuffer, cb_segm, Qm, rv, nof_e_bits, e_bits, data, i);
@ -514,12 +514,22 @@ static int decode_tb(srslte_sch_t *q,
}
}
int srslte_dlsch_decode(srslte_sch_t *q, srslte_pdsch_cfg_t *cfg, srslte_softbuffer_rx_t *softbuffer,
int16_t *e_bits, uint8_t *data)
{
return decode_tb(q,
softbuffer, &cfg->cb_segm,
cfg->grant.Qm, cfg->rv, cfg->nbits.nof_bits,
int srslte_dlsch_decode(srslte_sch_t *q, srslte_pdsch_cfg_t *cfg, srslte_softbuffer_rx_t *softbuffer,
int16_t *e_bits, uint8_t *data) {
return srslte_dlsch_decode2(q, cfg, softbuffer, e_bits, data, 0);
}
int srslte_dlsch_decode2(srslte_sch_t *q, srslte_pdsch_cfg_t *cfg, srslte_softbuffer_rx_t *softbuffer,
int16_t *e_bits, uint8_t *data, int codeword_idx) {
uint32_t Nl = 1;
if (cfg->nof_layers != cfg->grant.nof_tb) {
Nl = 2;
}
return decode_tb(q, softbuffer, &cfg->cb_segm[codeword_idx],
cfg->grant.Qm[codeword_idx] * Nl, cfg->rv[codeword_idx], cfg->nbits[codeword_idx].nof_bits,
e_bits, data);
}
@ -536,13 +546,22 @@ int srslte_dlsch_decode(srslte_sch_t *q, srslte_pdsch_cfg_t *cfg, srslte_softbuf
int srslte_dlsch_encode(srslte_sch_t *q, srslte_pdsch_cfg_t *cfg, srslte_softbuffer_tx_t *softbuffer,
uint8_t *data, uint8_t *e_bits)
{
return encode_tb(q,
softbuffer, &cfg->cb_segm,
cfg->grant.Qm, cfg->rv, cfg->nbits.nof_bits,
data, e_bits);
return srslte_dlsch_encode2(q, cfg, softbuffer, data, e_bits, 0);
}
int srslte_dlsch_encode2(srslte_sch_t *q, srslte_pdsch_cfg_t *cfg, srslte_softbuffer_tx_t *softbuffer,
uint8_t *data, uint8_t *e_bits, int codeword_idx) {
uint32_t Nl = 1;
if (cfg->nof_layers != cfg->grant.nof_tb) {
Nl = 2;
}
return encode_tb(q, softbuffer, &cfg->cb_segm[codeword_idx], cfg->grant.Qm[codeword_idx]*Nl, cfg->rv[codeword_idx],
cfg->nbits[codeword_idx].nof_bits, data, e_bits);
}
/* Compute the interleaving function on-the-fly, because it depends on number of RI bits
/* Compute the interleaving function on-the-fly, because it depends on number of RI bits
* Profiling show that the computation of this matrix is neglegible.
*/
static void ulsch_interleave_gen(uint32_t H_prime_total, uint32_t N_pusch_symbs, uint32_t Qm,

@ -85,7 +85,79 @@ target_link_libraries(pdsch_test srslte_phy)
add_test(pdsch_test_qpsk pdsch_test -m 10 -n 50 -r 1)
add_test(pdsch_test_qam16 pdsch_test -m 20 -n 100)
add_test(pdsch_test_qam16 pdsch_test -m 20 -n 100 -r 2)
add_test(pdsch_test_qam64 pdsch_test -m 28 -n 100)
add_test(pdsch_test_qam64 pdsch_test -n 100)
# PDSCH test for single transmision mode and 2 Rx antennas
add_test(pdsch_test_sin_6 pdsch_test -x single -a 2 -n 6)
add_test(pdsch_test_sin_12 pdsch_test -x single -a 2 -n 12)
add_test(pdsch_test_sin_25 pdsch_test -x single -a 2 -n 25)
add_test(pdsch_test_sin_50 pdsch_test -x single -a 2 -n 50)
add_test(pdsch_test_sin_75 pdsch_test -x single -a 2 -n 75)
add_test(pdsch_test_sin_100 pdsch_test -x single -a 2 -n 100)
# PDSCH test for transmit diversity transmision mode (1 codeword)
add_test(pdsch_test_div_6 pdsch_test -x diversity -a 2 -n 6)
add_test(pdsch_test_div_12 pdsch_test -x diversity -a 2 -n 12)
add_test(pdsch_test_div_25 pdsch_test -x diversity -a 2 -n 25)
add_test(pdsch_test_div_50 pdsch_test -x diversity -a 2 -n 50)
add_test(pdsch_test_div_75 pdsch_test -x diversity -a 2 -n 75)
add_test(pdsch_test_div_100 pdsch_test -x diversity -a 2 -n 100)
# PDSCH test for CDD transmision mode (2 codeword)
add_test(pdsch_test_cdd_6 pdsch_test -x cdd -a 2 -t 0 -n 6)
add_test(pdsch_test_cdd_12 pdsch_test -x cdd -a 2 -t 0 -n 12)
add_test(pdsch_test_cdd_25 pdsch_test -x cdd -a 2 -t 0 -n 25)
add_test(pdsch_test_cdd_50 pdsch_test -x cdd -a 2 -t 0 -n 50)
add_test(pdsch_test_cdd_75 pdsch_test -x cdd -a 2 -t 0 -n 75)
add_test(pdsch_test_cdd_100 pdsch_test -x cdd -a 2 -t 0 -n 100)
# PDSCH test for Spatial Multiplex transmision mode with PMI = 0 (1 codeword)
add_test(pdsch_test_multiplex1cw_p0_6 pdsch_test -x multiplex -a 2 -p 0 -n 6)
add_test(pdsch_test_multiplex1cw_p0_12 pdsch_test -x multiplex -a 2 -p 0 -n 12)
add_test(pdsch_test_multiplex1cw_p0_25 pdsch_test -x multiplex -a 2 -p 0 -n 25)
add_test(pdsch_test_multiplex1cw_p0_50 pdsch_test -x multiplex -a 2 -p 0 -n 50)
add_test(pdsch_test_multiplex1cw_p0_75 pdsch_test -x multiplex -a 2 -p 0 -n 75)
add_test(pdsch_test_multiplex1cw_p0_100 pdsch_test -x multiplex -a 2 -p 0 -n 100)
# PDSCH test for Spatial Multiplex transmision mode with PMI = 1 (1 codeword)
add_test(pdsch_test_multiplex1cw_p1_6 pdsch_test -x multiplex -a 2 -p 1 -n 6)
add_test(pdsch_test_multiplex1cw_p1_12 pdsch_test -x multiplex -a 2 -p 1 -n 12)
add_test(pdsch_test_multiplex1cw_p1_25 pdsch_test -x multiplex -a 2 -p 1 -n 25)
add_test(pdsch_test_multiplex1cw_p1_50 pdsch_test -x multiplex -a 2 -p 1 -n 50)
add_test(pdsch_test_multiplex1cw_p1_75 pdsch_test -x multiplex -a 2 -p 1 -n 75)
add_test(pdsch_test_multiplex1cw_p1_100 pdsch_test -x multiplex -a 2 -p 1 -n 100)
# PDSCH test for Spatial Multiplex transmision mode with PMI = 2 (1 codeword)
add_test(pdsch_test_multiplex1cw_p2_6 pdsch_test -x multiplex -a 2 -p 2 -n 6)
add_test(pdsch_test_multiplex1cw_p2_12 pdsch_test -x multiplex -a 2 -p 2 -n 12)
add_test(pdsch_test_multiplex1cw_p2_25 pdsch_test -x multiplex -a 2 -p 2 -n 25)
add_test(pdsch_test_multiplex1cw_p2_50 pdsch_test -x multiplex -a 2 -p 2 -n 50)
add_test(pdsch_test_multiplex1cw_p2_75 pdsch_test -x multiplex -a 2 -p 2 -n 75)
add_test(pdsch_test_multiplex1cw_p2_100 pdsch_test -x multiplex -a 2 -p 2 -n 100)
# PDSCH test for Spatial Multiplex transmision mode with PMI = 3 (1 codeword)
add_test(pdsch_test_multiplex1cw_p3_6 pdsch_test -x multiplex -a 2 -p 3 -n 6)
add_test(pdsch_test_multiplex1cw_p3_12 pdsch_test -x multiplex -a 2 -p 3 -n 12)
add_test(pdsch_test_multiplex1cw_p3_25 pdsch_test -x multiplex -a 2 -p 3 -n 25)
add_test(pdsch_test_multiplex1cw_p3_50 pdsch_test -x multiplex -a 2 -p 3 -n 50)
add_test(pdsch_test_multiplex1cw_p3_75 pdsch_test -x multiplex -a 2 -p 3 -n 75)
add_test(pdsch_test_multiplex1cw_p3_100 pdsch_test -x multiplex -a 2 -p 3 -n 100)
# PDSCH test for Spatial Multiplex transmision mode with PMI = 0 (2 codeword)
add_test(pdsch_test_multiplex2cw_p0_6 pdsch_test -x multiplex -a 2 -t 0 -p 0 -n 6)
add_test(pdsch_test_multiplex2cw_p0_12 pdsch_test -x multiplex -a 2 -t 0 -p 0 -n 12)
add_test(pdsch_test_multiplex2cw_p0_25 pdsch_test -x multiplex -a 2 -t 0 -p 0 -n 25)
add_test(pdsch_test_multiplex2cw_p0_50 pdsch_test -x multiplex -a 2 -t 0 -p 0 -n 50)
add_test(pdsch_test_multiplex2cw_p0_75 pdsch_test -x multiplex -a 2 -t 0 -p 0 -n 75)
add_test(pdsch_test_multiplex2cw_p0_100 pdsch_test -x multiplex -a 2 -t 0 -p 0 -n 100)
# PDSCH test for Spatial Multiplex transmision mode with PMI = 1 (2 codeword)
add_test(pdsch_test_multiplex2cw_p1_6 pdsch_test -x multiplex -a 2 -t 0 -p 1 -n 6)
add_test(pdsch_test_multiplex2cw_p1_12 pdsch_test -x multiplex -a 2 -t 0 -p 1 -n 12)
add_test(pdsch_test_multiplex2cw_p1_25 pdsch_test -x multiplex -a 2 -t 0 -p 1 -n 25)
add_test(pdsch_test_multiplex2cw_p1_50 pdsch_test -x multiplex -a 2 -t 0 -p 1 -n 50)
add_test(pdsch_test_multiplex2cw_p1_75 pdsch_test -x multiplex -a 2 -t 0 -p 1 -n 75)
add_test(pdsch_test_multiplex2cw_p1_100 pdsch_test -x multiplex -a 2 -t 0 -p 1 -n 100)
########################################################################
# FILE TEST

@ -43,9 +43,14 @@ void help()
/* the gateway function */
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
int i;
srslte_sch_t dlsch;
srslte_pdsch_cfg_t cfg;
srslte_softbuffer_tx_t softbuffer;
srslte_softbuffer_tx_t softbuffers[SRSLTE_MAX_CODEWORDS];
uint32_t nof_codewords = 1;
memset(&dlsch, 0, sizeof(srslte_sch_t));
memset(&cfg, 0, sizeof(srslte_pdsch_cfg_t));
if (nrhs < NOF_INPUTS) {
help();
@ -62,6 +67,7 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
srslte_verbose = SRSLTE_VERBOSE_NONE;
uint8_t *trblkin_bits = NULL;
cfg.grant.nof_tb = 1;
cfg.grant.mcs.tbs = mexutils_read_uint8(TRBLKIN, &trblkin_bits);
if (cfg.grant.mcs.tbs == 0) {
mexErrMsgTxt("Error trblklen is zero\n");
@ -76,6 +82,11 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
return;
}
if (mexutils_read_uint32_struct(PUSCHCFG, "NLayers", &cfg.nof_layers)) {
mexErrMsgTxt("Field NLayers not found in dlsch config\n");
return;
}
char *mod_str = mexutils_get_char_struct(PUSCHCFG, "Modulation");
if (!strcmp(mod_str, "QPSK")) {
@ -94,9 +105,12 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
mxFree(mod_str);
if (srslte_softbuffer_tx_init(&softbuffer, cell.nof_prb)) {
mexErrMsgTxt("Error initiating DL-SCH soft buffer\n");
return;
/* Initialise buffers */
for (i = 0; i < nof_codewords; i++) {
if (srslte_softbuffer_tx_init(&softbuffers[i], cell.nof_prb)) {
mexErrMsgTxt("Error initiating DL-SCH soft buffer\n");
return;
}
}
cfg.nbits.nof_bits = mxGetScalar(OUTLEN);
@ -111,13 +125,13 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
uint32_t tmp_rv=cfg.rv;
if (tmp_rv) {
cfg.rv = 0;
if (srslte_dlsch_encode(&dlsch, &cfg, &softbuffer, trblkin, e_bits)) {
if (srslte_dlsch_encode_multi(&dlsch, &cfg, softbuffers, &trblkin, &e_bits)) {
mexErrMsgTxt("Error encoding TB\n");
return;
}
cfg.rv = tmp_rv;
}
if (srslte_dlsch_encode(&dlsch, &cfg, &softbuffer, trblkin, e_bits)) {
if (srslte_dlsch_encode_multi(&dlsch, &cfg, softbuffers, &trblkin, &e_bits)) {
mexErrMsgTxt("Error encoding TB\n");
return;
}
@ -135,7 +149,9 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
free(trblkin);
free(e_bits);
free(e_bits_unpacked);
for (i = 0; i < nof_codewords; i++) {
srslte_softbuffer_tx_free(&softbuffers[i]);
}
return;
}

@ -161,7 +161,7 @@ int base_init() {
return -1;
}
if (srslte_pcfich_init(&pcfich)) {
if (srslte_pcfich_init(&pcfich, 1)) {
fprintf(stderr, "Error creating PBCH object\n");
return -1;
}

@ -124,7 +124,7 @@ int main(int argc, char **argv) {
exit(-1);
}
if (srslte_pcfich_init(&pcfich)) {
if (srslte_pcfich_init(&pcfich, 1)) {
fprintf(stderr, "Error creating PBCH object\n");
exit(-1);
}

@ -171,7 +171,7 @@ int base_init() {
fprintf(stderr, "Error setting CFI %d\n", cfi);
return -1;
}
if (srslte_pdcch_init(&pdcch, cell.nof_prb)) {
if (srslte_pdcch_init_ue(&pdcch, cell.nof_prb, 1)) {
fprintf(stderr, "Error creating PDCCH object\n");
exit(-1);
}

@ -27,22 +27,26 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <unistd.h>
#include <srslte/phy/common/phy_common.h>
#include <srslte/phy/phch/ra.h>
#include <srslte/phy/phch/dci.h>
#include <srslte/phy/phch/pdcch.h>
#include "srslte/srslte.h"
srslte_cell_t cell = {
6, // nof_prb
1, // nof_ports
1, // cell_id
SRSLTE_CP_NORM, // cyclic prefix
SRSLTE_PHICH_R_1, // PHICH resources
SRSLTE_PHICH_NORM // PHICH length
.nof_prb = 6,
.nof_ports = 1,
.id = 1,
.cp = SRSLTE_CP_NORM,
.phich_resources = SRSLTE_PHICH_R_1,
.phich_length = SRSLTE_PHICH_NORM
};
uint32_t cfi = 1;
bool print_dci_table;
uint32_t nof_rx_ant = 1;
bool print_dci_table;
void usage(char *prog) {
printf("Usage: %s [cfpndv]\n", prog);
@ -50,25 +54,29 @@ void usage(char *prog) {
printf("\t-f cfi [Default %d]\n", cfi);
printf("\t-p cell.nof_ports [Default %d]\n", cell.nof_ports);
printf("\t-n cell.nof_prb [Default %d]\n", cell.nof_prb);
printf("\t-A nof_rx_ant [Default %d]\n", nof_rx_ant);
printf("\t-d Print DCI table [Default %s]\n", print_dci_table?"yes":"no");
printf("\t-v [set srslte_verbose to debug, default none]\n");
}
void parse_args(int argc, char **argv) {
int opt;
while ((opt = getopt(argc, argv, "cfpndv")) != -1) {
while ((opt = getopt(argc, argv, "cfpndvA")) != -1) {
switch (opt) {
case 'p':
cell.nof_ports = atoi(argv[optind]);
cell.nof_ports = (uint32_t) atoi(argv[optind]);
break;
case 'f':
cfi = atoi(argv[optind]);
cfi = (uint32_t) atoi(argv[optind]);
break;
case 'n':
cell.nof_prb = atoi(argv[optind]);
cell.nof_prb = (uint32_t) atoi(argv[optind]);
break;
case 'c':
cell.id = atoi(argv[optind]);
cell.id = (uint32_t) atoi(argv[optind]);
break;
case 'A':
nof_rx_ant = (uint32_t) atoi(argv[optind]);
break;
case 'd':
print_dci_table = true;
@ -85,25 +93,26 @@ void parse_args(int argc, char **argv) {
int test_dci_payload_size() {
int i, j;
int x[4];
const srslte_dci_format_t formats[4] = { SRSLTE_DCI_FORMAT0, SRSLTE_DCI_FORMAT1, SRSLTE_DCI_FORMAT1A, SRSLTE_DCI_FORMAT1C };
int x[5];
const srslte_dci_format_t formats[] = { SRSLTE_DCI_FORMAT0, SRSLTE_DCI_FORMAT1, SRSLTE_DCI_FORMAT1A, SRSLTE_DCI_FORMAT1C, SRSLTE_DCI_FORMAT2A };
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 } };
const int dci_sz[6][5] = { { 21, 19, 21, 8, 28 }, { 22, 23, 22, 10 , 31}, { 25, 27,
25, 12 , 36}, { 27, 31, 27, 13 , 41}, { 27, 33, 27, 14 , 42}, { 28, 39, 28, 15, 48 }};
printf("Testing DCI payload sizes...\n");
printf(" PRB\t0\t1\t1A\t1C\n");
printf(" PRB\t0\t1\t1A\t1C\t2A\n");
for (i = 0; i < 6; i++) {
int n = prb[i];
for (j = 0; j < 4; j++) {
x[j] = srslte_dci_format_sizeof(formats[j], n, 1);
for (j = 0; j < 5; j++) {
x[j] = srslte_dci_format_sizeof(formats[j], (uint32_t) n, 1);
if (x[j] != dci_sz[i][j]) {
fprintf(stderr, "Invalid DCI payload size for %s\n",
srslte_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(" %2d:\t%2d\t%2d\t%2d\t%2d\t%2d\n", n, x[0], x[1], x[2], x[3], x[4]);
}
printf("Ok\n");
@ -111,8 +120,8 @@ int test_dci_payload_size() {
printf("dci_sz_table[101][4] = {\n");
for (i=0;i<=100;i++) {
printf(" {");
for (int j=0;j<4;j++) {
printf("%d",srslte_dci_format_sizeof(formats[j], i, 1));
for (j=0;j<4;j++) {
printf("%d",srslte_dci_format_sizeof(formats[j], (uint32_t) i, 1));
if (j<3) {
printf(", ");
}
@ -128,16 +137,23 @@ int test_dci_payload_size() {
return 0;
}
typedef struct {
srslte_dci_msg_t dci_tx, dci_rx;
srslte_dci_location_t dci_location;
srslte_dci_format_t dci_format;
srslte_ra_dl_dci_t ra_dl_tx;
srslte_ra_dl_dci_t ra_dl_rx;
} testcase_dci_t;
int main(int argc, char **argv) {
srslte_pdcch_t pdcch;
srslte_dci_msg_t dci_tx[2], dci_rx[2], dci_tmp;
srslte_dci_location_t dci_locations[2];
srslte_pdcch_t pdcch_tx, pdcch_rx;
testcase_dci_t testcases[10] = {0};
srslte_ra_dl_dci_t ra_dl;
srslte_regs_t regs;
int i, j;
cf_t *ce[SRSLTE_MAX_PORTS];
int i, j, k;
cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS];
int nof_re;
cf_t *slot_symbols[SRSLTE_MAX_PORTS];
cf_t *tx_slot_symbols[SRSLTE_MAX_PORTS], *rx_slot_symbols[SRSLTE_MAX_PORTS];
int nof_dcis;
int ret = -1;
@ -152,19 +168,30 @@ int main(int argc, char **argv) {
/* init memory */
for (i = 0; i < SRSLTE_MAX_PORTS; i++) {
ce[i] = malloc(sizeof(cf_t) * nof_re);
if (!ce[i]) {
for (j = 0; j < SRSLTE_MAX_PORTS; j++) {
ce[i][j] = malloc(sizeof(cf_t) * nof_re);
if (!ce[i][j]) {
perror("malloc");
exit(-1);
}
for (k = 0; k < nof_re; k++) {
//ce[i][j][k] = (i == j) ? 1 : 0;
ce[i][j][k] = ((float)rand()/(float)RAND_MAX) + _Complex_I*((float)rand()/(float)RAND_MAX);
}
}
tx_slot_symbols[i] = malloc(sizeof(cf_t) * nof_re);
if (!tx_slot_symbols[i]) {
perror("malloc");
exit(-1);
}
for (j = 0; j < nof_re; j++) {
ce[i][j] = 1;
}
slot_symbols[i] = malloc(sizeof(cf_t) * nof_re);
if (!slot_symbols[i]) {
bzero(tx_slot_symbols[i], sizeof(cf_t) * nof_re);
rx_slot_symbols[i] = malloc(sizeof(cf_t) * nof_re);
if (!rx_slot_symbols[i]) {
perror("malloc");
exit(-1);
}
bzero(rx_slot_symbols[i], sizeof(cf_t) * nof_re);
}
if (srslte_regs_init(&regs, cell)) {
@ -177,16 +204,26 @@ int main(int argc, char **argv) {
exit(-1);
}
if (srslte_pdcch_init(&pdcch, cell.nof_prb)) {
if (srslte_pdcch_init_enb(&pdcch_tx, cell.nof_prb)) {
fprintf(stderr, "Error creating PDCCH object\n");
exit(-1);
}
if (srslte_pdcch_set_cell(&pdcch, &regs, cell)) {
if (srslte_pdcch_set_cell(&pdcch_tx, &regs, cell)) {
fprintf(stderr, "Error setting cell in PDCCH object\n");
exit(-1);
}
if (srslte_pdcch_init_ue(&pdcch_rx, cell.nof_prb, nof_rx_ant)) {
fprintf(stderr, "Error creating PDCCH object\n");
exit(-1);
}
if (srslte_pdcch_set_cell(&pdcch_rx, &regs, cell)) {
fprintf(stderr, "Error setting cell in PDCCH object\n");
exit(-1);
}
nof_dcis = 2;
/* Resource allocate init */
nof_dcis = 0;
bzero(&ra_dl, sizeof(srslte_ra_dl_dci_t));
ra_dl.harq_process = 0;
ra_dl.mcs_idx = 5;
@ -194,62 +231,131 @@ int main(int argc, char **argv) {
ra_dl.rv_idx = 0;
ra_dl.alloc_type = SRSLTE_RA_ALLOC_TYPE0;
ra_dl.type0_alloc.rbg_bitmask = 0x5;
ra_dl.tb_en[0] = true;
srslte_dci_msg_pack_pdsch(&ra_dl, SRSLTE_DCI_FORMAT1, &dci_tx[0], cell.nof_prb, cell.nof_ports, false);
srslte_dci_location_set(&dci_locations[0], 0, 0);
/* Format 1 Test case */
testcases[nof_dcis].dci_format = SRSLTE_DCI_FORMAT1;
testcases[nof_dcis].ra_dl_tx = ra_dl;
nof_dcis++;
/* Format 1 Test case */
ra_dl.mcs_idx = 15;
srslte_dci_msg_pack_pdsch(&ra_dl, SRSLTE_DCI_FORMAT1, &dci_tx[1], cell.nof_prb, cell.nof_ports, false);
srslte_dci_location_set(&dci_locations[1], 0, 1);
testcases[nof_dcis].dci_format = SRSLTE_DCI_FORMAT1;
testcases[nof_dcis].ra_dl_tx = ra_dl;
nof_dcis++;
/* Tx Diversity Test case */
if (cell.nof_ports > 1) {
ra_dl.mcs_idx_1 = 0;
ra_dl.rv_idx_1 = 0;
ra_dl.ndi_1 = false;
ra_dl.tb_en[1] = false;
testcases[nof_dcis].dci_format = SRSLTE_DCI_FORMAT2A;
testcases[nof_dcis].ra_dl_tx = ra_dl;
nof_dcis++;
}
/* CDD Spatial Multiplexing Test case */
if (cell.nof_ports > 1) {
ra_dl.mcs_idx_1 = 28;
ra_dl.rv_idx_1 = 1;
ra_dl.ndi_1 = false;
ra_dl.tb_en[1] = true;
testcases[nof_dcis].dci_format = SRSLTE_DCI_FORMAT2A;
testcases[nof_dcis].ra_dl_tx = ra_dl;
nof_dcis++;
}
/* Execute Rx */
for (i=0;i<nof_dcis;i++) {
if (srslte_pdcch_encode(&pdcch, &dci_tx[i], dci_locations[i], 1234+i, slot_symbols, 0, cfi)) {
srslte_dci_msg_pack_pdsch(&testcases[i].ra_dl_tx, testcases[i].dci_format, &testcases[i].dci_tx,
cell.nof_prb, cell.nof_ports, false);
srslte_dci_location_set(&testcases[i].dci_location, 0, (uint32_t) i);
if (srslte_pdcch_encode(&pdcch_tx, &testcases[i].dci_tx, testcases[i].dci_location, (uint16_t) (1234 + i),
tx_slot_symbols, 0, cfi)) {
fprintf(stderr, "Error encoding DCI message\n");
goto quit;
}
}
srslte_vec_fprint_b(stdout, dci_tx[0].data, dci_tx[0].nof_bits);
/* combine outputs */
for (i = 1; i < cell.nof_ports; i++) {
for (j = 0; j < nof_re; j++) {
slot_symbols[0][j] += slot_symbols[i][j];
/* Apply channel */
for (j = 0; j < nof_rx_ant; j++) {
for (k = 0; k < nof_re; k++) {
for (i = 0; i < cell.nof_ports; i++) {
rx_slot_symbols[j][k] += tx_slot_symbols[i][k]*ce[i][j][k];
}
}
}
for (i=0;i<2;i++) {
if (srslte_pdcch_extract_llr(&pdcch, slot_symbols[0], ce, 0, 0, cfi)) {
fprintf(stderr, "Error extracting LLRs\n");
/* Execute 'Rx' */
if (srslte_pdcch_extract_llr_multi(&pdcch_rx, rx_slot_symbols, ce, 0, 0, cfi)) {
fprintf(stderr, "Error extracting LLRs\n");
goto quit;
}
/* Decode DCIs */
for (i=0;i<nof_dcis;i++) {
uint16_t crc_rem;
if (srslte_pdcch_decode_msg(&pdcch_rx, &testcases[i].dci_rx, &testcases[i].dci_location, testcases[i].dci_format, &crc_rem)) {
fprintf(stderr, "Error decoding DCI message\n");
goto quit;
}
uint16_t crc_rem;
if (srslte_pdcch_decode_msg(&pdcch, &dci_tmp, &dci_locations[i], SRSLTE_DCI_FORMAT1, &crc_rem)) {
fprintf(stderr, "Error decoding DCI message\n");
if (srslte_dci_msg_unpack_pdsch(&testcases[i].dci_rx, &testcases[i].ra_dl_rx, cell.nof_prb, cell.nof_ports, false)) {
fprintf(stderr, "Error unpacking DCI message\n");
goto quit;
}
}
if (crc_rem >= 1234 && crc_rem < 1234 + nof_dcis) {
crc_rem -= 1234;
memcpy(&dci_rx[crc_rem], &dci_tmp, sizeof(srslte_dci_msg_t));
} else {
printf("Received invalid DCI CRC 0x%x\n", crc_rem);
goto quit;
}
}
/* Compare Tx and Rx */
for (i = 0; i < nof_dcis; i++) {
if (memcmp(dci_tx[i].data, dci_rx[i].data, dci_tx[i].nof_bits)) {
if (memcmp(testcases[i].dci_tx.data, testcases[i].dci_rx.data, testcases[i].dci_tx.nof_bits)) {
printf("Error in DCI %d: Received data does not match\n", i);
goto quit;
}
if (memcmp(&testcases[i].ra_dl_tx, &testcases[i].ra_dl_rx, sizeof(srslte_ra_dl_dci_t))) {
printf("Error in RA %d: Received data does not match\n", i);
printf(" Field | Tx | Rx \n");
printf("--------------+----------+----------\n");
printf(" harq_process | %8d | %8d\n", testcases[i].ra_dl_tx.harq_process, testcases[i].ra_dl_rx.harq_process);
printf(" mcs_idx | %8d | %8d\n", testcases[i].ra_dl_tx.mcs_idx, testcases[i].ra_dl_rx.mcs_idx);
printf(" rv_idx | %8d | %8d\n", testcases[i].ra_dl_tx.rv_idx, testcases[i].ra_dl_rx.rv_idx);
printf(" ndi | %8d | %8d\n", testcases[i].ra_dl_tx.ndi, testcases[i].ra_dl_rx.ndi);
printf(" mcs_idx_1 | %8d | %8d\n", testcases[i].ra_dl_tx.mcs_idx_1, testcases[i].ra_dl_rx.mcs_idx_1);
printf(" rv_idx_1 | %8d | %8d\n", testcases[i].ra_dl_tx.rv_idx_1, testcases[i].ra_dl_rx.rv_idx_1);
printf(" ndi_1 | %8d | %8d\n", testcases[i].ra_dl_tx.ndi_1, testcases[i].ra_dl_rx.ndi_1);
printf(" tb_cw_swap | %8d | %8d\n", testcases[i].ra_dl_tx.tb_cw_swap, testcases[i].ra_dl_rx.tb_cw_swap);
printf(" sram_id | %8d | %8d\n", testcases[i].ra_dl_tx.sram_id, testcases[i].ra_dl_rx.sram_id);
printf(" pinfo | %8d | %8d\n", testcases[i].ra_dl_tx.pinfo, testcases[i].ra_dl_rx.pinfo);
printf(" pconf | %8d | %8d\n", testcases[i].ra_dl_tx.pconf, testcases[i].ra_dl_rx.pconf);
printf(" power_offset | %8d | %8d\n", testcases[i].ra_dl_tx.power_offset, testcases[i].ra_dl_rx.power_offset);
printf(" tpc_pucch | %8d | %8d\n", testcases[i].ra_dl_tx.tpc_pucch, testcases[i].ra_dl_rx.tpc_pucch);
printf(" tb_en[0] | %8d | %8d\n", testcases[i].ra_dl_tx.tb_en[0], testcases[i].ra_dl_rx.tb_en[0]);
printf(" tb_en[1] | %8d | %8d\n", testcases[i].ra_dl_tx.tb_en[1], testcases[i].ra_dl_rx.tb_en[1]);
printf(" dci_is_1a | %8d | %8d\n", testcases[i].ra_dl_tx.dci_is_1a, testcases[i].ra_dl_rx.dci_is_1a);
printf(" dci_is_1c | %8d | %8d\n", testcases[i].ra_dl_tx.dci_is_1c, testcases[i].ra_dl_rx.dci_is_1c);
goto quit;
}
}
ret = 0;
quit:
srslte_pdcch_free(&pdcch);
srslte_pdcch_free(&pdcch_tx);
srslte_pdcch_free(&pdcch_rx);
srslte_regs_free(&regs);
for (i = 0; i < SRSLTE_MAX_PORTS; i++) {
free(ce[i]);
free(slot_symbols[i]);
for (j = 0; j < SRSLTE_MAX_PORTS; j++) {
free(ce[i][j]);
}
free(tx_slot_symbols[i]);
free(rx_slot_symbols[i]);
}
if (ret) {
printf("Error\n");

@ -33,13 +33,14 @@
#define ENBCFG prhs[0]
#define RNTI prhs[1]
#define INPUT prhs[2]
#define NOF_INPUTS 3
#define AMP prhs[2]
#define INPUT prhs[3]
#define NOF_INPUTS 4
srslte_dci_format_t ue_formats[] = {SRSLTE_DCI_FORMAT1A,SRSLTE_DCI_FORMAT1}; // SRSLTE_DCI_FORMAT1B should go here also
const uint32_t nof_ue_formats = 2;
srslte_dci_format_t ue_formats[] = {SRSLTE_DCI_FORMAT1A,SRSLTE_DCI_FORMAT1,SRSLTE_DCI_FORMAT2B}; // SRSLTE_DCI_FORMAT1B should go here also
const uint32_t nof_ue_formats = 3;
srslte_dci_format_t common_formats[] = {SRSLTE_DCI_FORMAT1A,SRSLTE_DCI_FORMAT1C};
const uint32_t nof_common_formats = 2;
@ -162,7 +163,10 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
} else {
noise_power = srslte_chest_dl_get_noise_estimate(&chest);
}
mexPrintf("noise power=%f, RNTI=0x%x, cfi=%d\n", noise_power, rnti, cfi);
float amplitude = mxGetScalar(AMP);
srslte_viterbi_set_gain_quant(&pdcch.decoder, amplitude);
srslte_pdcch_extract_llr(&pdcch, input_fft, ce, noise_power, sf_idx, cfi);

@ -54,7 +54,7 @@ uint32_t sf_idx = 0;
srslte_dci_format_t dci_format = SRSLTE_DCI_FORMAT1A;
srslte_filesource_t fsrc;
srslte_ue_dl_t ue_dl;
cf_t *input_buffer;
cf_t *input_buffer[SRSLTE_MAX_PORTS];
void usage(char *prog) {
printf("Usage: %s [rovfcenmps] -i input_file\n", prog);
@ -131,13 +131,13 @@ int base_init() {
flen = 2 * (SRSLTE_SLOT_LEN(srslte_symbol_sz(cell.nof_prb)));
input_buffer = malloc(flen * sizeof(cf_t));
if (!input_buffer) {
input_buffer[0] = malloc(flen * sizeof(cf_t));
if (!input_buffer[0]) {
perror("malloc");
exit(-1);
}
if (srslte_ue_dl_init_multi(&ue_dl, cell.nof_prb, 1)) {
if (srslte_ue_dl_init(&ue_dl, cell.nof_prb, 1)) {
fprintf(stderr, "Error initializing UE DL\n");
return -1;
}
@ -155,12 +155,13 @@ int base_init() {
void base_free() {
srslte_filesource_free(&fsrc);
srslte_ue_dl_free(&ue_dl);
free(input_buffer);
free(input_buffer[0]);
}
int main(int argc, char **argv) {
int nof_frames;
int ret;
bool acks[SRSLTE_MAX_TB];
if (argc < 3) {
usage(argv[0]);
@ -173,15 +174,15 @@ int main(int argc, char **argv) {
exit(-1);
}
uint8_t *data = malloc(100000);
uint8_t *data[] = {malloc(100000)};
ret = -1;
nof_frames = 0;
do {
srslte_filesource_read(&fsrc, input_buffer, flen);
srslte_filesource_read(&fsrc, input_buffer[0], flen);
INFO("Reading %d samples sub-frame %d\n", flen, sf_idx);
ret = srslte_ue_dl_decode(&ue_dl, input_buffer, data, sf_idx);
ret = srslte_ue_dl_decode(&ue_dl, input_buffer, data, 0, sf_idx, acks);
if(ret > 0) {
printf("PDSCH Decoded OK!\n");
} else if (ret == 0) {
@ -194,7 +195,8 @@ int main(int argc, char **argv) {
} while (nof_frames <= max_frames && ret == 0);
base_free();
if (ret > 0) {
free(data[0]);
if (ret > 0) {
exit(0);
} else {
exit(-1);

@ -27,60 +27,80 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <unistd.h>
#include <sys/time.h>
#include <srslte/phy/phch/ra.h>
#include "srslte/srslte.h"
// Enable to measure execution time
//#define DO_OFDM
#ifdef DO_OFDM
#define NOF_CE_SYMBOLS SRSLTE_SF_LEN_PRB(cell.nof_prb)
#else
#define NOF_CE_SYMBOLS SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp)
#endif
srslte_cell_t cell = {
6, // nof_prb
1, // nof_ports
0, // cell_id
SRSLTE_CP_NORM, // cyclic prefix
SRSLTE_PHICH_R_1_6, // PHICH resources
SRSLTE_PHICH_NORM // PHICH length
SRSLTE_PHICH_NORM, // PHICH length
SRSLTE_PHICH_R_1_6 // PHICH resources
};
char mimo_type_str [32] = "single";
srslte_mimo_type_t mimo_type = SRSLTE_MIMO_TYPE_SINGLE_ANTENNA;
uint32_t cfi = 2;
uint32_t mcs = 0;
uint32_t mcs[SRSLTE_MAX_CODEWORDS] = {0, 0};
uint32_t subframe = 1;
uint32_t rv_idx = 0;
uint16_t rnti = 1234;
int rv_idx[SRSLTE_MAX_CODEWORDS] = {0, 1};
uint16_t rnti = 1234;
uint32_t nof_rx_antennas = 1;
uint32_t pmi = 0;
char *input_file = NULL;
void usage(char *prog) {
printf("Usage: %s [fmcsrRFpnv] \n", prog);
printf("Usage: %s [fmMcsrtRFpnwav] \n", prog);
printf("\t-f read signal from file [Default generate it with pdsch_encode()]\n");
printf("\t-m MCS [Default %d]\n", mcs);
printf("\t-m MCS [Default %d]\n", mcs[0]);
printf("\t-M MCS2 [Default %d]\n", mcs[1]);
printf("\t-c cell id [Default %d]\n", cell.id);
printf("\t-s subframe [Default %d]\n", subframe);
printf("\t-r rv_idx [Default %d]\n", rv_idx);
printf("\t-r rv_idx [Default %d]\n", rv_idx[0]);
printf("\t-t rv_idx2 [Default %d]\n", rv_idx[1]);
printf("\t-R rnti [Default %d]\n", rnti);
printf("\t-F cfi [Default %d]\n", cfi);
printf("\t-p cell.nof_ports [Default %d]\n", cell.nof_ports);
printf("\t-x Transmission mode [single|diversity|cdd|multiplex] [Default %s]\n", mimo_type_str);
printf("\t-n cell.nof_prb [Default %d]\n", cell.nof_prb);
printf("\t-a nof_rx_antennas [Default %d]\n", nof_rx_antennas);
printf("\t-p pmi (multiplex only) [Default %d]\n", pmi);
printf("\t-v [set srslte_verbose to debug, default none]\n");
}
void parse_args(int argc, char **argv) {
int opt;
while ((opt = getopt(argc, argv, "fmcsrRFpnv")) != -1) {
while ((opt = getopt(argc, argv, "fmMcsrtRFpnavx")) != -1) {
switch(opt) {
case 'f':
input_file = argv[optind];
break;
case 'm':
mcs = atoi(argv[optind]);
mcs[0] = (uint32_t) atoi(argv[optind]);
break;
case 'M':
mcs[1] = (uint32_t) atoi(argv[optind]);
break;
case 's':
subframe = atoi(argv[optind]);
break;
case 'r':
rv_idx = atoi(argv[optind]);
rv_idx[0] = (uint32_t) atoi(argv[optind]);
break;
case 't':
rv_idx[1] = (uint32_t) atoi(argv[optind]);
break;
case 'R':
rnti = atoi(argv[optind]);
@ -88,8 +108,11 @@ void parse_args(int argc, char **argv) {
case 'F':
cfi = atoi(argv[optind]);
break;
case 'x':
strncpy(mimo_type_str, argv[optind], 32);
break;
case 'p':
cell.nof_ports = atoi(argv[optind]);
pmi = (uint32_t) atoi(argv[optind]);
break;
case 'n':
cell.nof_prb = atoi(argv[optind]);
@ -97,6 +120,9 @@ void parse_args(int argc, char **argv) {
case 'c':
cell.id = atoi(argv[optind]);
break;
case 'a':
nof_rx_antennas = (uint32_t) atoi(argv[optind]);
break;
case 'v':
srslte_verbose++;
break;
@ -107,199 +133,399 @@ void parse_args(int argc, char **argv) {
}
}
uint8_t *data = NULL;
cf_t *ce[SRSLTE_MAX_PORTS];
srslte_softbuffer_rx_t softbuffer_rx;
static uint8_t *data_tx[SRSLTE_MAX_CODEWORDS] = {NULL};
static uint8_t *data_rx[SRSLTE_MAX_CODEWORDS] = {NULL};
cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS];
srslte_softbuffer_rx_t *softbuffers_rx[SRSLTE_MAX_CODEWORDS];
srslte_ra_dl_grant_t grant;
srslte_pdsch_cfg_t pdsch_cfg;
cf_t *sf_symbols;
cf_t *slot_symbols[SRSLTE_MAX_PORTS];
srslte_pdsch_t pdsch;
#ifdef DO_OFDM
cf_t *tx_sf_symbols[SRSLTE_MAX_PORTS];
cf_t *rx_sf_symbols[SRSLTE_MAX_PORTS];
#endif /* DO_OFDM */
cf_t *tx_slot_symbols[SRSLTE_MAX_PORTS];
cf_t *rx_slot_symbols[SRSLTE_MAX_PORTS];
srslte_pdsch_t pdsch_tx, pdsch_rx;
srslte_ofdm_t ofdm_tx, ofdm_rx;
int main(int argc, char **argv) {
uint32_t i, j;
uint32_t i, j, k;
int ret = -1;
struct timeval t[3];
srslte_softbuffer_tx_t softbuffer_tx;
srslte_softbuffer_tx_t *softbuffers_tx[SRSLTE_MAX_CODEWORDS];
int M=1;
bool acks[SRSLTE_MAX_CODEWORDS] = {false};
parse_args(argc,argv);
bzero(&pdsch, sizeof(srslte_pdsch_t));
/* Initialise to zeros */
bzero(&pdsch_tx, sizeof(srslte_pdsch_t));
bzero(&pdsch_rx, sizeof(srslte_pdsch_t));
bzero(&pdsch_cfg, sizeof(srslte_pdsch_cfg_t));
bzero(ce, sizeof(cf_t*)*SRSLTE_MAX_PORTS);
bzero(slot_symbols, sizeof(cf_t*)*SRSLTE_MAX_PORTS);
bzero(&softbuffer_rx, sizeof(srslte_softbuffer_rx_t));
bzero(&softbuffer_tx, sizeof(srslte_softbuffer_tx_t));
bzero(tx_slot_symbols, sizeof(cf_t*)*SRSLTE_MAX_PORTS);
bzero(rx_slot_symbols, sizeof(cf_t*)*SRSLTE_MAX_PORTS);
/* Parse transmission mode */
if (srslte_str2mimotype(mimo_type_str, &mimo_type)) {
ERROR("Wrong transmission mode.");
goto quit;
}
switch(mimo_type) {
case SRSLTE_MIMO_TYPE_SINGLE_ANTENNA:
cell.nof_ports = 1;
break;
case SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX:
case SRSLTE_MIMO_TYPE_CDD:
if (nof_rx_antennas < 2) {
ERROR("At least two receiving antennas are required");
goto quit;
}
case SRSLTE_MIMO_TYPE_TX_DIVERSITY:
default:
cell.nof_ports = 2;
break;
}
srslte_ra_dl_dci_t dci;
bzero(&dci, sizeof(srslte_ra_dl_dci_t));
dci.mcs_idx = mcs;
dci.rv_idx = rv_idx;
dci.type0_alloc.rbg_bitmask = 0xffffffff;
dci.tb_en[0] = true;
/* If transport block 0 is enabled */
if (mcs[0] != 0 || rv_idx[0] != 1) {
dci.mcs_idx = mcs[0];
dci.rv_idx = rv_idx[0];
dci.tb_en[0] = true;
}
/* If transport block 0 is disabled */
if (mcs[1] != 0 || rv_idx[1] != 1) {
dci.mcs_idx_1 = mcs[1];
dci.rv_idx_1 = rv_idx[1];
dci.tb_en[1] = true;
}
/* Generate grant from DCI */
if (srslte_ra_dl_dci_to_grant(&dci, cell.nof_prb, rnti, &grant)) {
fprintf(stderr, "Error computing resource allocation\n");
return ret;
}
#ifdef DO_OFDM
srslte_ofdm_tx_init(&ofdm_tx, cell.cp, cell.nof_prb);
srslte_ofdm_rx_init(&ofdm_rx, cell.cp, cell.nof_prb);
sf_symbols=srslte_vec_malloc(sizeof(cf_t)*SRSLTE_SF_LEN_PRB(cell.nof_prb));
srslte_ofdm_set_normalize(&ofdm_tx, true);
srslte_ofdm_set_normalize(&ofdm_rx, true);
for (i = 0; i < cell.nof_ports; i++) {
tx_sf_symbols[i] = srslte_vec_malloc(sizeof(cf_t) * SRSLTE_SF_LEN_PRB(cell.nof_prb));
}
for (i = 0; i < nof_rx_antennas; i++) {
rx_sf_symbols[i] = srslte_vec_malloc(sizeof(cf_t) * SRSLTE_SF_LEN_PRB(cell.nof_prb));
}
#endif /* DO_OFDM */
/* Configure PDSCH */
if (srslte_pdsch_cfg(&pdsch_cfg, cell, &grant, cfi, subframe, rv_idx)) {
if (srslte_pdsch_cfg_mimo(&pdsch_cfg, cell, &grant, cfi, subframe, rv_idx, mimo_type, pmi)) {
fprintf(stderr, "Error configuring PDSCH\n");
exit(-1);
goto quit;
}
/* init memory */
for (i=0;i<SRSLTE_MAX_PORTS;i++) {
ce[i] = srslte_vec_malloc(sizeof(cf_t) * SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp));
if (!ce[i]) {
perror("srslte_vec_malloc");
goto quit;
}
for (j=0;j<SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp);j++) {
ce[i][j] = 1;
for (j = 0; j < SRSLTE_MAX_PORTS; j++) {
ce[i][j] = srslte_vec_malloc(sizeof(cf_t) * NOF_CE_SYMBOLS);
if (!ce[i]) {
perror("srslte_vec_malloc");
goto quit;
}
for (k = 0; k < NOF_CE_SYMBOLS; k++) {
ce[i][j][k] = (i == j) ? 1.0f : 0.0f;
}
}
slot_symbols[i] = srslte_vec_malloc(sizeof(cf_t)*SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp));
if (!slot_symbols[i]) {
rx_slot_symbols[i] = srslte_vec_malloc(sizeof(cf_t) * SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp));
if (!rx_slot_symbols[i]) {
perror("srslte_vec_malloc");
goto quit;
}
}
data = srslte_vec_malloc(sizeof(uint8_t) * (grant.mcs.tbs/8)+24);
if (!data) {
perror("srslte_vec_malloc");
goto quit;
for (int i = 0; i < grant.nof_tb; i++) {
if (grant.mcs[i].tbs) {
data_tx[i] = srslte_vec_malloc(sizeof(uint8_t) * grant.mcs[i].tbs);
if (!data_tx[i]) {
perror("srslte_vec_malloc");
goto quit;
}
bzero(data_tx[i], sizeof(uint8_t) * grant.mcs[i].tbs);
data_rx[i] = srslte_vec_malloc(sizeof(uint8_t) * grant.mcs[i].tbs);
if (!data_rx[i]) {
perror("srslte_vec_malloc");
goto quit;
}
bzero(data_rx[i], sizeof(uint8_t) * grant.mcs[i].tbs);
}
}
if (srslte_pdsch_init_ue(&pdsch, cell.nof_prb)) {
if (srslte_pdsch_init_ue(&pdsch_rx, cell.nof_prb, nof_rx_antennas)) {
fprintf(stderr, "Error creating PDSCH object\n");
goto quit;
}
if (srslte_pdsch_set_cell(&pdsch, cell)) {
if (srslte_pdsch_set_cell(&pdsch_rx, cell)) {
fprintf(stderr, "Error creating PDSCH object\n");
goto quit;
}
srslte_pdsch_set_rnti(&pdsch, rnti);
if (srslte_softbuffer_rx_init(&softbuffer_rx, cell.nof_prb)) {
fprintf(stderr, "Error initiating RX soft buffer\n");
goto quit;
srslte_pdsch_set_rnti(&pdsch_rx, rnti);
for (i = 0; i < SRSLTE_MAX_CODEWORDS; i++) {
softbuffers_rx[i] = calloc(sizeof(srslte_softbuffer_rx_t), 1);
if (!softbuffers_rx[i]) {
fprintf(stderr, "Error allocating RX soft buffer\n");
goto quit;
}
if (srslte_softbuffer_rx_init(softbuffers_rx[i], cell.nof_prb)) {
fprintf(stderr, "Error initiating RX soft buffer\n");
goto quit;
}
}
INFO(" Global:\n");
INFO(" nof_prb=%d\n", cell.nof_prb);
INFO(" nof_ports=%d\n", cell.nof_ports);
INFO(" id=%d\n", cell.id);
INFO(" cp=%s\n", srslte_cp_string(cell.cp));
INFO(" phich_length=%d\n", (int) cell.phich_length);
INFO(" phich_resources=%d\n", (int) cell.phich_resources);
INFO(" nof_tb=%d\n", pdsch_cfg.grant.nof_tb);
INFO(" nof_prb=%d\n", pdsch_cfg.grant.nof_prb);
INFO(" sf_idx=%d\n", pdsch_cfg.sf_idx);
INFO(" mimo_type=%s\n", srslte_mimotype2str(pdsch_cfg.mimo_type));
INFO(" nof_layers=%d\n", pdsch_cfg.nof_layers);
INFO(" nof_tb=%d\n", pdsch_cfg.grant.nof_tb);
for (i = 0; i < SRSLTE_MAX_CODEWORDS; i++) {
INFO(" Tranport block index %d:\n", i);
INFO(" Qm=%d\n", pdsch_cfg.grant.Qm[i]);
INFO(" mcs.idx=0x%X\n", pdsch_cfg.grant.mcs[i].idx);
INFO(" mcs.tbs=%d\n", pdsch_cfg.grant.mcs[i].tbs);
INFO(" mcs.mod=%s\n", srslte_mod_string(pdsch_cfg.grant.mcs[i].mod));
INFO(" rv=%d\n", pdsch_cfg.rv[i]);
INFO(" lstart=%d\n", pdsch_cfg.nbits[i].lstart);
INFO(" nof_bits=%d\n", pdsch_cfg.nbits[i].nof_bits);
INFO(" nof_re=%d\n", pdsch_cfg.nbits[i].nof_re);
INFO(" nof_symb=%d\n", pdsch_cfg.nbits[i].nof_symb);
}
if (input_file) {
srslte_filesource_t fsrc;
if (srslte_filesource_init(&fsrc, input_file, SRSLTE_COMPLEX_FLOAT_BIN)) {
fprintf(stderr, "Error opening file %s\n", input_file);
exit(-1);
goto quit;
}
#ifdef DO_OFDM
srslte_filesource_read(&fsrc, sf_symbols, SRSLTE_SF_LEN_PRB(cell.nof_prb));
srslte_filesource_read(&fsrc, rx_slot_symbols, SRSLTE_SF_LEN_PRB(cell.nof_prb));
#else
srslte_filesource_read(&fsrc, slot_symbols[0], SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp));
srslte_filesource_read(&fsrc, rx_slot_symbols[0], SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp));
#endif
srslte_chest_dl_t chest;
srslte_chest_dl_t chest;
if (srslte_chest_dl_init(&chest, cell.nof_prb)) {
printf("Error initializing equalizer\n");
fprintf(stderr, "Error initializing equalizer\n");
exit(-1);
}
if (srslte_chest_dl_set_cell(&chest, cell)) {
printf("Error initializing equalizer\n");
exit(-1);
}
srslte_chest_dl_estimate(&chest, slot_symbols[0], ce, subframe);
srslte_chest_dl_estimate(&chest, rx_slot_symbols[0], ce[0], subframe);
srslte_chest_dl_free(&chest);
srslte_filesource_free(&fsrc);
} else {
if (srslte_softbuffer_tx_init(&softbuffer_tx, cell.nof_prb)) {
fprintf(stderr, "Error initiating TX soft buffer\n");
} else {
if (srslte_pdsch_init_enb(&pdsch_tx, cell.nof_prb)) {
fprintf(stderr, "Error creating PDSCH object\n");
goto quit;
}
if (srslte_pdsch_set_cell(&pdsch_tx, cell)) {
fprintf(stderr, "Error creating PDSCH object\n");
goto quit;
}
srslte_pdsch_set_rnti(&pdsch_tx, rnti);
for (i = 0; i < SRSLTE_MAX_CODEWORDS; i++) {
softbuffers_tx[i] = calloc(sizeof(srslte_softbuffer_tx_t), 1);
if (!softbuffers_tx[i]) {
fprintf(stderr, "Error allocating TX soft buffer\n");
}
for (i=0;i<grant.mcs.tbs/8;i++) {
data[i] = rand()%256;
if (srslte_softbuffer_tx_init(softbuffers_tx[i], cell.nof_prb)) {
fprintf(stderr, "Error initiating TX soft buffer\n");
goto quit;
}
}
uint8_t databit[100000];
for (i = 0; i < cell.nof_ports; i++) {
tx_slot_symbols[i] = calloc(SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp), sizeof(cf_t));
if (!tx_slot_symbols[i]) {
perror("srslte_vec_malloc");
goto quit;
}
}
for (int tb = 0; tb < grant.nof_tb; tb++) {
for (int byte = 0; byte < grant.mcs[tb].tbs / 8; byte++) {
data_tx[tb][byte] = (uint8_t)(rand() % 256);
}
}
/*uint8_t databit[100000];
srslte_bit_unpack_vector(data, databit, grant.mcs.tbs);
srslte_vec_save_file("data_in", databit, grant.mcs.tbs);
srslte_vec_save_file("data_in", databit, grant.mcs.tbs);*/
if (!input_file) {
if (rv_idx) {
/* Do 1st transmission for rv_idx!=0 */
pdsch_cfg.rv = 0;
if (srslte_pdsch_encode(&pdsch, &pdsch_cfg, &softbuffer_tx, data, rnti, slot_symbols)) {
fprintf(stderr, "Error encoding PDSCH\n");
goto quit;
}
}
pdsch_cfg.rv = rv_idx;
if (srslte_pdsch_encode(&pdsch, &pdsch_cfg, &softbuffer_tx, data, rnti, slot_symbols)) {
if (rv_idx[0] != 0 || rv_idx[1] != 0) {
/* Do 1st transmission for rv_idx!=0 */
bzero(pdsch_cfg.rv, sizeof(uint32_t)*SRSLTE_MAX_CODEWORDS);
if (srslte_pdsch_encode(&pdsch_tx, &pdsch_cfg, softbuffers_tx, data_tx, rnti, tx_slot_symbols)) {
fprintf(stderr, "Error encoding PDSCH\n");
goto quit;
}
}
memcpy(pdsch_cfg.rv, rv_idx, sizeof(uint32_t)*SRSLTE_MAX_CODEWORDS);
gettimeofday(&t[1], NULL);
for (k = 0; k < M; k++) {
if (srslte_pdsch_encode(&pdsch_tx, &pdsch_cfg, softbuffers_tx, data_tx, rnti, tx_slot_symbols)) {
ERROR("Error encoding PDSCH");
goto quit;
}
}
gettimeofday(&t[2], NULL);
get_time_interval(t);
printf("ENCODED in %.2f (PHY bitrate=%.2f Mbps. Processing bitrate=%.2f Mbps)\n",
(float) t[0].tv_usec/M, (float) (grant.mcs[0].tbs + grant.mcs[1].tbs)/1000.0f,
(float) (grant.mcs[0].tbs + grant.mcs[1].tbs)*M/t[0].tv_usec);
#ifdef DO_OFDM
for (i = 0; i < cell.nof_ports; i++) {
/* For each Tx antenna modulate OFDM */
srslte_ofdm_tx_sf(&ofdm_tx, tx_slot_symbols[i], tx_sf_symbols[i]);
}
/* combine outputs */
for (i=0;i<cell.nof_ports;i++) {
for (j=0;j<SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp);j++) {
if (i > 0) {
slot_symbols[0][j] += slot_symbols[i][j];
for (j = 0; j < nof_rx_antennas; j++) {
for (k = 0; k < NOF_CE_SYMBOLS; k++) {
rx_sf_symbols[j][k] = 0.0f;
for (i = 0; i < cell.nof_ports; i++) {
rx_sf_symbols[j][k] += tx_sf_symbols[i][k] * ce[i][j][k];
}
}
}
#else
/* combine outputs */
for (j = 0; j < nof_rx_antennas; j++) {
for (k = 0; k < SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp); k++) {
rx_slot_symbols[j][k] = 0.0f;
for (i = 0; i < cell.nof_ports; i++) {
rx_slot_symbols[j][k] += tx_slot_symbols[i][k] * ce[i][j][k];
}
ce[i][j] = 1;
}
}
#ifdef DO_OFDM
srslte_ofdm_tx_sf(&ofdm_tx, slot_symbols[0], sf_symbols);
#endif
}
int M=1;
int r=0;
srslte_sch_set_max_noi(&pdsch.dl_sch, 10);
}
int r=0;
srslte_pdsch_set_max_noi(&pdsch_rx, 10);
gettimeofday(&t[1], NULL);
for (i=0;i<M;i++) {
#ifdef DO_OFDM
srslte_ofdm_rx_sf(&ofdm_rx, sf_symbols, slot_symbols[1]);
#endif
srslte_softbuffer_rx_reset_tbs(&softbuffer_rx, grant.mcs.tbs);
r = srslte_pdsch_decode(&pdsch, &pdsch_cfg, &softbuffer_rx, slot_symbols[0], ce, 0, rnti, data);
for (k = 0; k < M; k++) {
#ifdef DO_OFDM
/* For each Rx antenna demodulate OFDM */
for (i = 0; i < nof_rx_antennas; i++) {
srslte_ofdm_rx_sf(&ofdm_rx, tx_sf_symbols[i], rx_slot_symbols[i]);
}
#endif
for (i = 0; i < grant.nof_tb; i++) {
if (grant.mcs[i].tbs) {
srslte_softbuffer_rx_reset_tbs(softbuffers_rx[i], (uint32_t) grant.mcs[i].tbs);
}
}
r = srslte_pdsch_decode(&pdsch_rx, &pdsch_cfg, softbuffers_rx, rx_slot_symbols, ce, 0, rnti, data_rx, acks);
}
gettimeofday(&t[2], NULL);
get_time_interval(t);
printf("DECODED %s in %.2f (PHY bitrate=%.2f Mbps. Processing bitrate=%.2f Mbps)\n", r?"Error":"OK",
(float) t[0].tv_usec/M, (float) grant.mcs.tbs/1000, (float) grant.mcs.tbs*M/t[0].tv_usec);
(float) t[0].tv_usec/M, (float) (grant.mcs[0].tbs + grant.mcs[1].tbs)/1000.0f,
(float) (grant.mcs[0].tbs + grant.mcs[1].tbs)*M/t[0].tv_usec);
/* If there is an error in PDSCH decode */
if (r) {
ret = -1;
goto quit;
}
}
/* Check Tx and Rx bytes */
for (int tb = 0; tb < grant.nof_tb; tb++) {
for (int byte = 0; byte < grant.mcs[tb].tbs / 8; byte++) {
if (data_tx[tb][byte] != data_rx[tb][byte]) {
ERROR("Found BYTE error in TB %d (%02X != %02X), quiting...", tb, data_tx[tb][byte], data_rx[tb][byte]);
ret = SRSLTE_ERROR;
goto quit;
}
}
}
/* Check all transport blocks have been decoded OK */
for (int tb = 0; tb < grant.nof_tb; tb++) {
ret |= (acks[tb]) ? SRSLTE_SUCCESS : SRSLTE_ERROR;
}
ret = SRSLTE_SUCCESS;
ret = 0;
quit:
srslte_pdsch_free(&pdsch);
srslte_softbuffer_tx_free(&softbuffer_tx);
srslte_softbuffer_rx_free(&softbuffer_rx);
for (i=0;i<cell.nof_ports;i++) {
if (ce[i]) {
free(ce[i]);
srslte_pdsch_free(&pdsch_tx);
srslte_pdsch_free(&pdsch_rx);
for (i = 0; i < SRSLTE_MAX_CODEWORDS; i++) {
srslte_softbuffer_tx_free(softbuffers_tx[i]);
if (softbuffers_tx[i]) {
free(softbuffers_tx[i]);
}
srslte_softbuffer_rx_free(softbuffers_rx[i]);
if (softbuffers_rx[i]) {
free(softbuffers_rx[i]);
}
if (data_tx[i]) {
free(data_tx[i]);
}
if (slot_symbols[i]) {
free(slot_symbols[i]);
if (data_rx[i]) {
free(data_rx[i]);
}
}
if (data) {
free(data);
for (i=0;i<SRSLTE_MAX_PORTS;i++) {
for (j = 0; j < SRSLTE_MAX_PORTS; j++) {
if (ce[i][j]) {
free(ce[i][j]);
}
}
if (tx_slot_symbols[i]) {
free(tx_slot_symbols[i]);
}
if (rx_slot_symbols[i]) {
free(rx_slot_symbols[i]);
}
}
if (ret) {
printf("Error\n");

@ -101,7 +101,7 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
nof_antennas = dims[2];
}
if (srslte_pdsch_init_multi(&pdsch, cell, nof_antennas)) {
if (srslte_pdsch_init_rx_multi(&pdsch, cell, nof_antennas)) {
mexErrMsgTxt("Error initiating PDSCH\n");
return;
}
@ -202,11 +202,18 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
ce[i][j] = srslte_vec_malloc(SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp) * sizeof(cf_t));
}
}
uint8_t *data_bytes = srslte_vec_malloc(sizeof(uint8_t) * grant.mcs.tbs/8);
if (!data_bytes) {
uint8_t *data_bytes[SRSLTE_MAX_CODEWORDS];
data_bytes[0] = srslte_vec_malloc(sizeof(uint8_t) * grant.mcs.tbs/8);
if (!data_bytes[0]) {
return;
}
srslte_sch_set_max_noi(&pdsch.dl_sch, max_iterations);
data_bytes[1] = srslte_vec_malloc(sizeof(uint8_t) * grant.mcs2.tbs/8);
if (!data_bytes[1]) {
return;
}
srslte_pdsch_set_max_noi(&pdsch, max_iterations);
bool input_fft_allocated = false;
int r=-1;
@ -272,7 +279,7 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
}
uint8_t *data = malloc(grant.mcs.tbs);
srslte_bit_unpack_vector(data_bytes, data, grant.mcs.tbs);
srslte_bit_unpack_vector(data_bytes[0], data, grant.mcs.tbs);
if (nlhs >= 1) {
plhs[0] = mxCreateLogicalScalar(r == 0);
@ -284,10 +291,10 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
mexutils_write_cf(pdsch.symbols[0], &plhs[2], cfg.nbits.nof_re, 1);
}
if (nlhs >= 4) {
mexutils_write_cf(pdsch.d, &plhs[3], cfg.nbits.nof_re, 1);
mexutils_write_cf(pdsch.d[0], &plhs[3], cfg.nbits.nof_re, 1);
}
if (nlhs >= 5) {
mexutils_write_s(pdsch.e, &plhs[4], cfg.nbits.nof_bits, 1);
mexutils_write_s(pdsch.e[0], &plhs[4], cfg.nbits.nof_bits, 1);
}
if (nlhs >= 6) {
uint32_t len = nof_antennas*cell.nof_ports*SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp);
@ -323,7 +330,11 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
}
}
}
free(data_bytes);
for (i = 0; i < SRSLTE_MAX_CODEWORDS; i++) {
if (data_bytes[i]) {
free(data_bytes[i]);
}
}
free(data);
return;

@ -185,7 +185,7 @@ int base_init() {
return -1;
}
if (srslte_phich_init(&phich)) {
if (srslte_phich_init(&phich, 1)) {
fprintf(stderr, "Error creating PBCH object\n");
return -1;
}

@ -142,7 +142,7 @@ int main(int argc, char **argv) {
cid = cell.id;
max_cid = cell.id;
}
if (srslte_phich_init(&phich)) {
if (srslte_phich_init(&phich, 1)) {
fprintf(stderr, "Error creating PBCH object\n");
exit(-1);
}

@ -104,6 +104,8 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
srslte_prach_set_detect_factor(&prach, factor);
}
mexPrintf("format=%d config=%d, N_cp=%d, ifft=%d\n", prach.f, prach.config_idx, prach.N_cp, prach.N_ifft_ul);
if (srslte_prach_detect_offset(&prach, frequency_offset, &input_signal[prach.N_cp], nof_samples, preambles, offsets, NULL, &nof_detected)) {
mexErrMsgTxt("Error detecting PRACH\n");
return;

@ -172,7 +172,7 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
srslte_pucch_set_cfg(&pucch, &pucch_cfg, group_hopping_en);
if (srslte_pucch_encode(&pucch, format, n_pucch, sf_idx, bits, sf_symbols)) {
if (srslte_pucch_encode(&pucch, format, n_pucch, sf_idx, (uint16_t) rnti, bits, sf_symbols)) {
mexErrMsgTxt("Error encoding PUCCH\n");
return;
}

@ -187,12 +187,14 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
srslte_pucch_set_cfg(&pucch, &pucch_cfg, group_hopping_en);
if (srslte_chest_ul_estimate_pucch(&chest_ul, sf_symbols, ce, format, n_pucch, sf_idx)) {
uint8_t pucch2_ack_bits[2] = {0};
if (srslte_chest_ul_estimate_pucch(&chest_ul, sf_symbols, ce, format, n_pucch, sf_idx, &pucch2_ack_bits)) {
mexErrMsgTxt("Error estimating PUCCH DMRS\n");
return;
}
if (srslte_pucch_decode(&pucch, format, n_pucch, sf_idx, sf_symbols, ce, 0, bits)<0) {
if (srslte_pucch_decode(&pucch, format, n_pucch, sf_idx, (uint16_t) rnti, sf_symbols, ce, 0, bits)<0) {
mexErrMsgTxt("Error decoding PUCCH\n");
return;
}

@ -178,7 +178,7 @@ float rf_blade_get_rssi(void *h)
return 0;
}
int rf_blade_open_multi(char *args, void **h, uint32_t nof_rx_antennas)
int rf_blade_open_multi(char *args, void **h, uint32_t nof_channels)
{
return rf_blade_open(args, h);
}
@ -469,6 +469,20 @@ int rf_blade_recv_with_time(void *h,
return nsamples;
}
int rf_blade_send_timed_multi(void *h,
void *data[4],
int nsamples,
time_t secs,
double frac_secs,
bool has_time_spec,
bool blocking,
bool is_start_of_burst,
bool is_end_of_burst)
{
return rf_blade_send_timed(h, data[0], nsamples, secs, frac_secs, has_time_spec, blocking, is_start_of_burst,
is_end_of_burst);
}
int rf_blade_send_timed(void *h,
void *data,
int nsamples,

@ -34,7 +34,7 @@ SRSLTE_API int rf_blade_open(char *args,
void **handler);
SRSLTE_API int rf_blade_open_multi(char *args,
void **handler, uint32_t nof_rx_antennas);
void **handler, uint32_t nof_channels);
SRSLTE_API char* rf_blade_devname(void *h);
@ -111,6 +111,16 @@ SRSLTE_API void rf_blade_get_time(void *h,
time_t *secs,
double *frac_secs);
SRSLTE_API int rf_blade_send_timed_multi(void *h,
void *data[4],
int nsamples,
time_t secs,
double frac_secs,
bool has_time_spec,
bool blocking,
bool is_start_of_burst,
bool is_end_of_burst);
SRSLTE_API int rf_blade_send_timed(void *h,
void *data,
int nsamples,

@ -38,7 +38,7 @@ typedef struct {
void (*srslte_rf_suppress_stdout)(void *h);
void (*srslte_rf_register_error_handler)(void *h, srslte_rf_error_handler_t error_handler);
int (*srslte_rf_open)(char *args, void **h);
int (*srslte_rf_open_multi)(char *args, void **h, uint32_t nof_rx_antennas);
int (*srslte_rf_open_multi)(char *args, void **h, uint32_t nof_channels);
int (*srslte_rf_close)(void *h);
void (*srslte_rf_set_master_clock_rate)(void *h, double rate);
bool (*srslte_rf_is_master_clock_dynamic)(void *h);
@ -58,6 +58,9 @@ typedef struct {
int (*srslte_rf_send_timed)(void *h, void *data, int nsamples,
time_t secs, double frac_secs, bool has_time_spec,
bool blocking, bool is_start_of_burst, bool is_end_of_burst);
int (*srslte_rf_send_timed_multi)(void *h, void *data[4], int nsamples,
time_t secs, double frac_secs, bool has_time_spec,
bool blocking, bool is_start_of_burst, bool is_end_of_burst);
void (*srslte_rf_set_tx_cal)(void *h, srslte_rf_cal_t *cal);
void (*srslte_rf_set_rx_cal)(void *h, srslte_rf_cal_t *cal);
@ -81,7 +84,7 @@ static rf_dev_t dev_uhd = {
rf_uhd_suppress_stdout,
rf_uhd_register_error_handler,
rf_uhd_open,
rf_uhd_open_multi,
.srslte_rf_open_multi = rf_uhd_open_multi,
rf_uhd_close,
rf_uhd_set_master_clock_rate,
rf_uhd_is_master_clock_dynamic,
@ -97,6 +100,7 @@ static rf_dev_t dev_uhd = {
rf_uhd_recv_with_time,
rf_uhd_recv_with_time_multi,
rf_uhd_send_timed,
.srslte_rf_send_timed_multi = rf_uhd_send_timed_multi,
rf_uhd_set_tx_cal,
rf_uhd_set_rx_cal
};
@ -119,7 +123,7 @@ static rf_dev_t dev_blade = {
rf_blade_suppress_stdout,
rf_blade_register_error_handler,
rf_blade_open,
rf_blade_open_multi,
.srslte_rf_open_multi = rf_blade_open_multi,
rf_blade_close,
rf_blade_set_master_clock_rate,
rf_blade_is_master_clock_dynamic,
@ -135,6 +139,7 @@ static rf_dev_t dev_blade = {
rf_blade_recv_with_time,
rf_blade_recv_with_time_multi,
rf_blade_send_timed,
.srslte_rf_send_timed_multi = rf_blade_send_timed_multi,
rf_blade_set_tx_cal,
rf_blade_set_rx_cal
};
@ -172,6 +177,7 @@ static rf_dev_t dev_soapy = {
rf_soapy_recv_with_time,
rf_soapy_recv_with_time_multi,
rf_soapy_send_timed,
.srslte_rf_send_timed_multi = /* FIXME: Implement srslte_rf_send_timed_multi for Soapy SDR */ NULL,
rf_soapy_set_tx_cal,
rf_soapy_set_rx_cal
};

@ -102,7 +102,7 @@ int srslte_rf_open_devname(srslte_rf_t *rf, char *devname, char *args) {
return srslte_rf_open_devname_multi(rf, devname, args, 1);
}
int srslte_rf_open_devname_multi(srslte_rf_t *rf, char *devname, char *args, uint32_t nof_rx_antennas) {
int srslte_rf_open_devname_multi(srslte_rf_t *rf, char *devname, char *args, uint32_t nof_channels) {
/* Try to open the device if name is provided */
if (devname) {
if (devname[0] != '\0') {
@ -110,7 +110,7 @@ int srslte_rf_open_devname_multi(srslte_rf_t *rf, char *devname, char *args, uin
while(available_devices[i] != NULL) {
if (!strcmp(available_devices[i]->name, devname)) {
rf->dev = available_devices[i];
return available_devices[i]->srslte_rf_open_multi(args, &rf->handler, nof_rx_antennas);
return available_devices[i]->srslte_rf_open_multi(args, &rf->handler, nof_channels);
}
i++;
}
@ -121,7 +121,7 @@ int srslte_rf_open_devname_multi(srslte_rf_t *rf, char *devname, char *args, uin
/* If in auto mode or provided device not found, try to open in order of apperance in available_devices[] array */
int i=0;
while(available_devices[i] != NULL) {
if (!available_devices[i]->srslte_rf_open_multi(args, &rf->handler, nof_rx_antennas)) {
if (!available_devices[i]->srslte_rf_open_multi(args, &rf->handler, nof_channels)) {
rf->dev = available_devices[i];
return 0;
}
@ -301,6 +301,32 @@ int srslte_rf_send_timed3(srslte_rf_t *rf,
has_time_spec, blocking, is_start_of_burst, is_end_of_burst);
}
int srslte_rf_send_timed_multi(srslte_rf_t *rf,
void *data[4],
int nsamples,
time_t secs,
double frac_secs,
bool blocking,
bool is_start_of_burst,
bool is_end_of_burst)
{
return ((rf_dev_t*) rf->dev)->srslte_rf_send_timed_multi(rf->handler, data, nsamples, secs, frac_secs,
true, blocking, is_start_of_burst, is_end_of_burst);
}
int srslte_rf_send_multi(srslte_rf_t *rf,
void *data[4],
int nsamples,
bool blocking,
bool is_start_of_burst,
bool is_end_of_burst)
{
return ((rf_dev_t*) rf->dev)->srslte_rf_send_timed_multi(rf->handler, data, nsamples, 0, 0,
false, blocking, is_start_of_burst, is_end_of_burst);
}
int srslte_rf_send(srslte_rf_t *rf, void *data, uint32_t nsamples, bool blocking)
{
return srslte_rf_send2(rf, data, nsamples, blocking, true, true);

@ -289,7 +289,7 @@ int rf_uhd_open(char *args, void **h)
return rf_uhd_open_multi(args, h, 1);
}
int rf_uhd_open_multi(char *args, void **h, uint32_t nof_rx_antennas)
int rf_uhd_open_multi(char *args, void **h, uint32_t nof_channels)
{
if (h) {
*h = NULL;
@ -397,11 +397,11 @@ int rf_uhd_open_multi(char *args, void **h, uint32_t nof_rx_antennas)
.otw_format = "sc16",
.args = "",
.channel_list = channel,
.n_channels = 1
.n_channels = nof_channels,
};
handler->nof_rx_channels = nof_rx_antennas;
handler->nof_tx_channels = 1;
handler->nof_rx_channels = nof_channels;
handler->nof_tx_channels = nof_channels;
/* Set default rate to avoid decimation warnings */
uhd_usrp_set_rx_rate(handler->usrp, 1.92e6, 0);
@ -656,8 +656,28 @@ int rf_uhd_send_timed(void *h,
bool is_start_of_burst,
bool is_end_of_burst)
{
void *_data[SRSLTE_MAX_PORTS]= {data, zero_mem, zero_mem, zero_mem};
return rf_uhd_send_timed_multi(h, _data, nsamples, secs, frac_secs, has_time_spec, blocking, is_start_of_burst, is_end_of_burst);
}
int rf_uhd_send_timed_multi(void *h,
void *data[4],
int nsamples,
time_t secs,
double frac_secs,
bool has_time_spec,
bool blocking,
bool is_start_of_burst,
bool is_end_of_burst) {
rf_uhd_handler_t* handler = (rf_uhd_handler_t*) h;
/* Resets the USRP time FIXME: this might cause problems for burst transmissions */
if (!has_time_spec && is_start_of_burst && handler->nof_tx_channels > 1) {
uhd_usrp_set_time_now(handler->usrp, 0, 0, 0);
uhd_tx_metadata_set_time_spec(&handler->tx_md, 0, 0.1);
}
size_t txd_samples;
if (has_time_spec) {
uhd_tx_metadata_set_time_spec(&handler->tx_md, secs, frac_secs);
@ -665,7 +685,10 @@ int rf_uhd_send_timed(void *h,
int trials = 0;
if (blocking) {
int n = 0;
cf_t *data_c = (cf_t*) data;
cf_t *data_c[4];
for (int i = 0; i < 4; i++) {
data_c[i] = data[i];
}
do {
size_t tx_samples = handler->tx_nof_samples;
@ -683,9 +706,12 @@ int rf_uhd_send_timed(void *h,
tx_samples = nsamples - n;
uhd_tx_metadata_set_end(&handler->tx_md, is_end_of_burst);
}
void *buff = (void*) &data_c[n];
const void *buffs_ptr[4] = {buff, zero_mem, zero_mem, zero_mem};
const void *buffs_ptr[4];
for (int i = 0; i < 4; i++) {
void *buff = (void*) &data_c[i][n];
buffs_ptr[i] = buff;
}
uhd_error error = uhd_tx_streamer_send(handler->tx_stream, buffs_ptr,
tx_samples, &handler->tx_md, 3.0, &txd_samples);
if (error) {
@ -699,7 +725,10 @@ int rf_uhd_send_timed(void *h,
} while (n < nsamples && trials < 100);
return nsamples;
} else {
const void *buffs_ptr[4] = {data, zero_mem, zero_mem, zero_mem};
const void *buffs_ptr[4];
for (int i = 0; i < 4; i++) {
buffs_ptr[i] = data[i];
}
uhd_tx_metadata_set_start(&handler->tx_md, is_start_of_burst);
uhd_tx_metadata_set_end(&handler->tx_md, is_end_of_burst);
return uhd_tx_streamer_send(handler->tx_stream, buffs_ptr, nsamples, &handler->tx_md, 0.0, &txd_samples);

@ -39,7 +39,7 @@ SRSLTE_API int rf_uhd_open(char *args,
SRSLTE_API int rf_uhd_open_multi(char *args,
void **handler,
uint32_t nof_rx_antennas);
uint32_t nof_channels);
SRSLTE_API char* rf_uhd_devname(void *h);
@ -123,3 +123,13 @@ SRSLTE_API int rf_uhd_send_timed(void *h,
bool is_start_of_burst,
bool is_end_of_burst);
SRSLTE_API int rf_uhd_send_timed_multi(void *h,
void *data[SRSLTE_MAX_PORTS],
int nsamples,
time_t secs,
double frac_secs,
bool has_time_spec,
bool blocking,
bool is_start_of_burst,
bool is_end_of_burst);

@ -26,8 +26,6 @@
#include "srslte/phy/ue/ue_dl.h"
#include <complex.h>
#include <math.h>
#include <string.h>
@ -39,21 +37,23 @@
#define MAX_SFLEN_RE SRSLTE_SF_LEN_RE(max_prb, q->cell.cp)
static srslte_dci_format_t ue_formats[] = {SRSLTE_DCI_FORMAT1A, SRSLTE_DCI_FORMAT1}; // Only TM1 and TM2 are currently supported
const uint32_t nof_ue_formats = 2;
const static srslte_dci_format_t ue_dci_formats[8][2] = {
/* Mode 1 */ {SRSLTE_DCI_FORMAT1A, SRSLTE_DCI_FORMAT1},
/* Mode 2 */ {SRSLTE_DCI_FORMAT1A, SRSLTE_DCI_FORMAT1},
/* Mode 3 */ {SRSLTE_DCI_FORMAT1A, SRSLTE_DCI_FORMAT2A},
/* Mode 4 */ {SRSLTE_DCI_FORMAT1A, SRSLTE_DCI_FORMAT2},
/* Mode 5 */ {SRSLTE_DCI_FORMAT1A, SRSLTE_DCI_FORMAT1D},
/* Mode 6 */ {SRSLTE_DCI_FORMAT1A, SRSLTE_DCI_FORMAT1B},
/* Mode 7 */ {SRSLTE_DCI_FORMAT1A, SRSLTE_DCI_FORMAT1},
/* Mode 8 */ {SRSLTE_DCI_FORMAT1A, SRSLTE_DCI_FORMAT2B}
};
static srslte_dci_format_t common_formats[] = {SRSLTE_DCI_FORMAT1A,SRSLTE_DCI_FORMAT1C};
const uint32_t nof_common_formats = 2;
int srslte_ue_dl_init(srslte_ue_dl_t *q,
uint32_t max_prb)
{
return srslte_ue_dl_init_multi(q, max_prb, 1);
}
int srslte_ue_dl_init_multi(srslte_ue_dl_t *q,
uint32_t max_prb,
uint32_t nof_rx_antennas)
int srslte_ue_dl_init(srslte_ue_dl_t *q,
uint32_t max_prb,
uint32_t nof_rx_antennas)
{
int ret = SRSLTE_ERROR_INVALID_INPUTS;
@ -78,33 +78,41 @@ int srslte_ue_dl_init_multi(srslte_ue_dl_t *q,
fprintf(stderr, "Error initiating channel estimator\n");
goto clean_exit;
}
if (srslte_pcfich_init_multi(&q->pcfich, nof_rx_antennas)) {
if (srslte_pcfich_init(&q->pcfich, nof_rx_antennas)) {
fprintf(stderr, "Error creating PCFICH object\n");
goto clean_exit;
}
if (srslte_phich_init(&q->phich)) {
if (srslte_phich_init(&q->phich, nof_rx_antennas)) {
fprintf(stderr, "Error creating PHICH object\n");
goto clean_exit;
}
if (srslte_pdcch_init_multi(&q->pdcch, max_prb, nof_rx_antennas)) {
if (srslte_pdcch_init_ue(&q->pdcch, max_prb, nof_rx_antennas)) {
fprintf(stderr, "Error creating PDCCH object\n");
goto clean_exit;
}
if (srslte_pdsch_init_multi_ue(&q->pdsch, max_prb, nof_rx_antennas)) {
if (srslte_pdsch_init_ue(&q->pdsch, max_prb, nof_rx_antennas)) {
fprintf(stderr, "Error creating PDSCH object\n");
goto clean_exit;
}
if (srslte_softbuffer_rx_init(&q->softbuffer, max_prb)) {
fprintf(stderr, "Error initiating soft buffer\n");
goto clean_exit;
for (int i = 0; i < SRSLTE_MAX_TB; i++) {
q->softbuffers[i] = srslte_vec_malloc(sizeof(srslte_softbuffer_rx_t));
if (!q->softbuffers[i]) {
fprintf(stderr, "Error allocating soft buffer\n");
goto clean_exit;
}
if (srslte_softbuffer_rx_init(q->softbuffers[i], max_prb)) {
fprintf(stderr, "Error initiating soft buffer\n");
goto clean_exit;
}
}
if (srslte_cfo_init(&q->sfo_correct, max_prb*SRSLTE_NRE)) {
fprintf(stderr, "Error initiating SFO correct\n");
goto clean_exit;
}
srslte_cfo_set_tol(&q->sfo_correct, 1e-5/q->fft.symbol_sz);
srslte_cfo_set_tol(&q->sfo_correct, 1e-5f/q->fft.symbol_sz);
for (int j=0;j<nof_rx_antennas;j++) {
q->sf_symbols_m[j] = srslte_vec_malloc(MAX_SFLEN_RE * sizeof(cf_t));
@ -148,7 +156,12 @@ void srslte_ue_dl_free(srslte_ue_dl_t *q) {
srslte_pdcch_free(&q->pdcch);
srslte_pdsch_free(&q->pdsch);
srslte_cfo_free(&q->sfo_correct);
srslte_softbuffer_rx_free(&q->softbuffer);
for (int i = 0; i < SRSLTE_MAX_TB; i++) {
srslte_softbuffer_rx_free(q->softbuffers[i]);
if (q->softbuffers[i]) {
free(q->softbuffers[i]);
}
}
for (int j=0;j<q->nof_rx_antennas;j++) {
if (q->sf_symbols_m[j]) {
free(q->sf_symbols_m[j]);
@ -243,7 +256,9 @@ void srslte_ue_dl_set_rnti(srslte_ue_dl_t *q, uint16_t rnti) {
}
void srslte_ue_dl_reset(srslte_ue_dl_t *q) {
srslte_softbuffer_rx_reset(&q->softbuffer);
for(int i = 0; i < SRSLTE_MAX_CODEWORDS; i++){
srslte_softbuffer_rx_reset(q->softbuffers[i]);
}
bzero(&q->pdsch_cfg, sizeof(srslte_pdsch_cfg_t));
}
@ -258,24 +273,12 @@ void srslte_ue_dl_set_sample_offset(srslte_ue_dl_t * q, float sample_offset) {
* - PDCCH decoding: Find DCI for RNTI given by previous call to srslte_ue_dl_set_rnti()
* - PDSCH decoding: Decode TB scrambling with RNTI given by srslte_ue_dl_set_rnti()
*/
int srslte_ue_dl_decode(srslte_ue_dl_t *q, cf_t *input, uint8_t *data, uint32_t tti) {
cf_t *_input[SRSLTE_MAX_PORTS];
_input[0] = input;
return srslte_ue_dl_decode_rnti_multi(q, _input, data, tti, q->current_rnti);
}
int srslte_ue_dl_decode_multi(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS], uint8_t *data, uint32_t tti) {
return srslte_ue_dl_decode_rnti_multi(q, input, data, tti, q->current_rnti);
int srslte_ue_dl_decode(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS], uint8_t *data[SRSLTE_MAX_CODEWORDS],
uint32_t tm, uint32_t tti, bool acks[SRSLTE_MAX_CODEWORDS]) {
return srslte_ue_dl_decode_rnti(q, input, data, tm, tti, q->current_rnti, acks);
}
int srslte_ue_dl_decode_fft_estimate(srslte_ue_dl_t *q, cf_t *input, uint32_t sf_idx, uint32_t *cfi)
{
cf_t *_input[SRSLTE_MAX_PORTS];
_input[0] = input;
return srslte_ue_dl_decode_fft_estimate_multi(q, _input, sf_idx, cfi);
}
int srslte_ue_dl_decode_fft_estimate_multi(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS], uint32_t sf_idx, uint32_t *cfi)
int srslte_ue_dl_decode_fft_estimate(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS], uint32_t sf_idx, uint32_t *cfi)
{
if (input && q && cfi && sf_idx < SRSLTE_NSUBFRAMES_X_FRAME) {
@ -328,29 +331,43 @@ int srslte_ue_dl_decode_estimate(srslte_ue_dl_t *q, uint32_t sf_idx, uint32_t *c
}
int srslte_ue_dl_cfg_grant(srslte_ue_dl_t *q, srslte_ra_dl_grant_t *grant, uint32_t cfi, uint32_t sf_idx, uint32_t rvidx)
{
return srslte_pdsch_cfg(&q->pdsch_cfg, q->cell, grant, cfi, sf_idx, rvidx);
}
int srslte_ue_dl_cfg_grant(srslte_ue_dl_t *q, srslte_ra_dl_grant_t *grant, uint32_t cfi, uint32_t sf_idx,
int rvidx[SRSLTE_MAX_CODEWORDS], srslte_mimo_type_t mimo_type) {
uint32_t pmi = 0;
int srslte_ue_dl_decode_rnti(srslte_ue_dl_t *q, cf_t *input, uint8_t *data, uint32_t tti, uint16_t rnti)
{
cf_t *_input[SRSLTE_MAX_PORTS];
_input[0] = input;
return srslte_ue_dl_decode_rnti_multi(q, _input, data, tti, rnti);
/* Translates Precoding Information (pinfo) to Precoding matrix Index (pmi) as 3GPP 36.212 Table 5.3.3.1.5-4 */
if (mimo_type == SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX) {
if (grant->nof_tb == 1) {
if (grant->pinfo > 0 && grant->pinfo < 5) {
pmi = grant->pinfo - 1;
} else {
ERROR("Not Implemented (nof_tb=%d, pinfo=%d)", q->pdsch_cfg.grant.nof_tb, grant->pinfo);
return SRSLTE_ERROR;
}
} else {
if (grant->pinfo < 2) {
pmi = grant->pinfo;
} else {
ERROR("Not Implemented (nof_tb=%d, pinfo=%d)", q->pdsch_cfg.grant.nof_tb, grant->pinfo);
return SRSLTE_ERROR;
}
}
}
return srslte_pdsch_cfg_mimo(&q->pdsch_cfg, q->cell, grant, cfi, sf_idx, rvidx, mimo_type, pmi);
}
int srslte_ue_dl_decode_rnti_multi(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS], uint8_t *data, uint32_t tti, uint16_t rnti)
{
int srslte_ue_dl_decode_rnti(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS],
uint8_t *data[SRSLTE_MAX_CODEWORDS], uint32_t tm, uint32_t tti, uint16_t rnti,
bool acks[SRSLTE_MAX_CODEWORDS]) {
srslte_mimo_type_t mimo_type;
srslte_dci_msg_t dci_msg;
srslte_ra_dl_dci_t dci_unpacked;
srslte_ra_dl_grant_t grant;
int ret = SRSLTE_ERROR;
uint32_t cfi;
uint32_t sf_idx = tti%10;
uint32_t sf_idx = tti%10;
if ((ret = srslte_ue_dl_decode_fft_estimate_multi(q, input, sf_idx, &cfi)) < 0) {
if ((ret = srslte_ue_dl_decode_fft_estimate(q, input, sf_idx, &cfi)) < 0) {
return ret;
}
@ -363,7 +380,7 @@ int srslte_ue_dl_decode_rnti_multi(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_POR
return SRSLTE_ERROR;
}
int found_dci = srslte_ue_dl_find_dl_dci(q, cfi, sf_idx, rnti, &dci_msg);
int found_dci = srslte_ue_dl_find_dl_dci(q, tm, cfi, sf_idx, rnti, &dci_msg);
if (found_dci == 1) {
if (srslte_dci_msg_to_dl_grant(&dci_msg, rnti, q->cell.nof_prb, q->cell.nof_ports, &dci_unpacked, &grant)) {
@ -374,18 +391,68 @@ int srslte_ue_dl_decode_rnti_multi(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_POR
/* ===== These lines of code are supposed to be MAC functionality === */
uint32_t rvidx = 0;
int rvidx[SRSLTE_MAX_CODEWORDS] = {1};
if (dci_unpacked.rv_idx < 0) {
uint32_t sfn = tti/10;
uint32_t k = (sfn/2)%4;
rvidx = ((uint32_t) ceilf((float)1.5*k))%4;
srslte_softbuffer_rx_reset_tbs(&q->softbuffer, grant.mcs.tbs);
uint32_t k = (sfn/2)%4;
for (int i = 0; i < grant.nof_tb; i++) {
rvidx[i] = ((uint32_t) ceilf((float) 1.5 * k)) % 4;
srslte_softbuffer_rx_reset_tbs(q->softbuffers[i], (uint32_t) grant.mcs[i].tbs);
}
} else {
rvidx = dci_unpacked.rv_idx;
srslte_softbuffer_rx_reset_tbs(&q->softbuffer, grant.mcs.tbs);
for (int i = 0; i < grant.nof_tb; i++) {
switch(i) {
case 0:
rvidx[i] = (uint32_t) dci_unpacked.rv_idx;
break;
case 1:
rvidx[i] = (uint32_t) dci_unpacked.rv_idx_1;
break;
default:
ERROR("Wrong number of transport blocks");
return SRSLTE_ERROR;
}
srslte_softbuffer_rx_reset_tbs(q->softbuffers[i], (uint32_t) grant.mcs[i].tbs);
}
}
switch(dci_msg.format) {
case SRSLTE_DCI_FORMAT1:
case SRSLTE_DCI_FORMAT1A:
if (q->cell.nof_ports == 1) {
mimo_type = SRSLTE_MIMO_TYPE_SINGLE_ANTENNA;
} else {
mimo_type = SRSLTE_MIMO_TYPE_TX_DIVERSITY;
}
break;
case SRSLTE_DCI_FORMAT2:
if (grant.nof_tb == 1 && dci_unpacked.pinfo == 0) {
mimo_type = SRSLTE_MIMO_TYPE_TX_DIVERSITY;
} else {
mimo_type = SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX;
}
break;
case SRSLTE_DCI_FORMAT2A:
if (grant.nof_tb == 1 && dci_unpacked.pinfo == 0) {
mimo_type = SRSLTE_MIMO_TYPE_TX_DIVERSITY;
} else {
mimo_type = SRSLTE_MIMO_TYPE_CDD;
}
break;
/* Not implemented formats */
case SRSLTE_DCI_FORMAT0:
case SRSLTE_DCI_FORMAT1C:
case SRSLTE_DCI_FORMAT1B:
case SRSLTE_DCI_FORMAT1D:
case SRSLTE_DCI_FORMAT2B:
default:
ERROR("Transmission mode not supported.");
return SRSLTE_ERROR;
}
if (srslte_ue_dl_cfg_grant(q, &grant, cfi, sf_idx, rvidx)) {
if (srslte_ue_dl_cfg_grant(q, &grant, cfi, sf_idx, rvidx, mimo_type)) {
ERROR("Configuing PDSCH");
return SRSLTE_ERROR;
}
@ -394,17 +461,26 @@ int srslte_ue_dl_decode_rnti_multi(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_POR
q->nof_detected++;
if (q->pdsch_cfg.grant.mcs.mod > 0 && q->pdsch_cfg.grant.mcs.tbs >= 0) {
ret = srslte_pdsch_decode_multi(&q->pdsch, &q->pdsch_cfg, &q->softbuffer,
q->sf_symbols_m, q->ce_m,
noise_estimate,
rnti, data);
if (q->pdsch_cfg.grant.mcs[0].mod > 0 && q->pdsch_cfg.grant.mcs[0].tbs >= 0) {
ret = srslte_pdsch_decode(&q->pdsch, &q->pdsch_cfg, q->softbuffers,
q->sf_symbols_m, q->ce_m,
noise_estimate,
rnti, data, acks);
for (int tb = 0; tb < q->pdsch_cfg.grant.nof_tb; tb++) {
if (!acks[tb]) {
q->pkt_errors++;
}
q->pkts_total++;
}
if (ret == SRSLTE_ERROR) {
q->pkt_errors++;
} else if (ret == SRSLTE_ERROR_INVALID_INPUTS) {
fprintf(stderr, "Error calling srslte_pdsch_decode()\n");
}
}
/* If we are in TM4 (Closed-Loop MIMO), compute condition number */
}
/*
@ -416,15 +492,95 @@ int srslte_ue_dl_decode_rnti_multi(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_POR
}
q->pkts_total++;
if (found_dci == 1 && ret == SRSLTE_SUCCESS) {
return q->pdsch_cfg.grant.mcs.tbs;
return q->pdsch_cfg.grant.mcs[0].tbs;
} else {
return 0;
}
}
/* Compute the Rank Indicator (RI) and Precoder Matrix Indicator (PMI) by computing the Signal to Interference plus
* Noise Ratio (SINR), valid for TM4 */
int srslte_ue_dl_ri_pmi_select(srslte_ue_dl_t *q, uint32_t *ri, uint32_t *pmi, float *current_sinr) {
float noise_estimate = srslte_chest_dl_get_noise_estimate(&q->chest);
float best_sinr = -INFINITY;
uint32_t best_pmi = 0, best_ri = 0;
if (q->cell.nof_ports < 2 || q->nof_rx_antennas < 2) {
/* Do nothing */
return SRSLTE_SUCCESS;
} else if (q->cell.nof_ports == 2 && q->nof_rx_antennas == 2) {
if (srslte_pdsch_pmi_select(&q->pdsch, &q->pdsch_cfg, q->ce_m, noise_estimate,
SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp), q->pmi, q->sinr)) {
ERROR("SINR calculation error");
return SRSLTE_ERROR;
}
/* Select the best Rank indicator (RI) and Precoding Matrix Indicator (PMI) */
for (uint32_t nof_layers = 1; nof_layers <= 2; nof_layers++) {
float _sinr = q->sinr[nof_layers - 1][q->pmi[nof_layers - 1]] * nof_layers;
if (_sinr > best_sinr + 0.1) {
best_sinr = _sinr;
best_pmi = q->pmi[nof_layers - 1];
best_ri = nof_layers;
}
}
/* Set RI */
if (ri != NULL) {
*ri = best_ri;
}
/* Set PMI */
if (pmi != NULL) {
*pmi = best_pmi;
}
/* Set current SINR */
if (current_sinr != NULL && q->pdsch_cfg.mimo_type == SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX) {
if (q->pdsch_cfg.nof_layers == 1) {
*current_sinr = q->sinr[0][q->pdsch_cfg.codebook_idx];
} else if (q->pdsch_cfg.nof_layers == 2) {
*current_sinr = q->sinr[1][q->pdsch_cfg.codebook_idx - 1];
} else {
ERROR("Not implemented number of layers (%d)", q->pdsch_cfg.nof_layers);
return SRSLTE_ERROR;
}
}
/* Print Trace */
if (ri != NULL && pmi != NULL && current_sinr != NULL) {
INFO("PDSCH Select RI=%d; PMI=%d; Current SINR=%.1fdB (nof_layers=%d, codebook_idx=%d)\n", *ri, *pmi,
10*log10(*current_sinr), q->pdsch_cfg.nof_layers, q->pdsch_cfg.codebook_idx);
}
} else {
ERROR("Not implemented configuration");
return SRSLTE_ERROR_INVALID_INPUTS;
}
return SRSLTE_SUCCESS;
}
/* Compute the Rank Indicator (RI) by computing the condition number, valid for TM3 */
int srslte_ue_dl_ri_select(srslte_ue_dl_t *q, uint32_t *ri, float *cn) {
float _cn;
int ret = srslte_pdsch_cn_compute(&q->pdsch, q->ce_m, SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp), &_cn);
/* Set Condition number */
if (cn) {
*cn = _cn;
}
/* Set rank indicator */
if (!ret && ri) {
*ri = (_cn > 3.0f)? 1:0;
}
return ret;
}
uint32_t srslte_ue_dl_get_ncce(srslte_ue_dl_t *q) {
return q->last_location.ncce;
}
@ -502,7 +658,7 @@ int srslte_ue_dl_find_ul_dci(srslte_ue_dl_t *q, uint32_t cfi, uint32_t sf_idx, u
}
}
int srslte_ue_dl_find_dl_dci(srslte_ue_dl_t *q, uint32_t cfi, uint32_t sf_idx, uint16_t rnti, srslte_dci_msg_t *dci_msg)
int srslte_ue_dl_find_dl_dci(srslte_ue_dl_t *q, uint32_t tm, uint32_t cfi, uint32_t sf_idx, uint16_t rnti, srslte_dci_msg_t *dci_msg)
{
srslte_rnti_type_t rnti_type;
if (rnti == SRSLTE_SIRNTI) {
@ -514,7 +670,7 @@ int srslte_ue_dl_find_dl_dci(srslte_ue_dl_t *q, uint32_t cfi, uint32_t sf_idx, u
} else {
rnti_type = SRSLTE_RNTI_USER;
}
return srslte_ue_dl_find_dl_dci_type(q, cfi, sf_idx, rnti, rnti_type, dci_msg);
return srslte_ue_dl_find_dl_dci_type(q, tm, cfi, sf_idx, rnti, rnti_type, dci_msg);
}
// Blind search for SI/P/RA-RNTI
@ -538,12 +694,17 @@ static int find_dl_dci_type_siprarnti(srslte_ue_dl_t *q, uint32_t cfi, uint16_t
}
// Blind search for C-RNTI
static int find_dl_dci_type_crnti(srslte_ue_dl_t *q, uint32_t cfi, uint32_t sf_idx, uint16_t rnti, srslte_dci_msg_t *dci_msg)
{
static int find_dl_dci_type_crnti(srslte_ue_dl_t *q, uint32_t tm, uint32_t cfi,
uint32_t sf_idx, uint16_t rnti, srslte_dci_msg_t *dci_msg) {
int ret = SRSLTE_SUCCESS;
dci_blind_search_t search_space;
dci_blind_search_t *current_ss = &search_space;
if (cfi < 1 || cfi > 3) {
ERROR("CFI must be 1 ≤ cfi ≤ 3", cfi);
return SRSLTE_ERROR;
}
// Search UE-specific search space
if (q->current_rnti == rnti) {
current_ss = &q->current_ss_ue[cfi-1][sf_idx];
@ -553,15 +714,19 @@ static int find_dl_dci_type_crnti(srslte_ue_dl_t *q, uint32_t cfi, uint32_t sf_i
}
srslte_pdcch_set_cfi(&q->pdcch, cfi);
INFO("Searching DL C-RNTI in %d ue locations, %d formats\n", current_ss->nof_locations, nof_ue_formats);
for (int f=0;f<nof_ue_formats;f++) {
current_ss->format = ue_formats[f];
for (int f = 0; f < 2; f++) {
srslte_dci_format_t format = ue_dci_formats[tm][f];
INFO("Searching DL C-RNTI %s in %d ue locations\n", srslte_dci_format_string(format),
current_ss->nof_locations);
current_ss->format = format;
if ((ret = dci_blind_search(q, current_ss, rnti, dci_msg))) {
return ret;
}
}
// Search Format 1A in the Common SS also
if (q->current_rnti == rnti) {
current_ss = &q->current_ss_common[cfi-1];
@ -581,13 +746,13 @@ static int find_dl_dci_type_crnti(srslte_ue_dl_t *q, uint32_t cfi, uint32_t sf_i
return SRSLTE_SUCCESS;
}
int srslte_ue_dl_find_dl_dci_type(srslte_ue_dl_t *q, uint32_t cfi, uint32_t sf_idx,
int srslte_ue_dl_find_dl_dci_type(srslte_ue_dl_t *q, uint32_t tm, uint32_t cfi, uint32_t sf_idx,
uint16_t rnti, srslte_rnti_type_t rnti_type, srslte_dci_msg_t *dci_msg)
{
if (rnti_type == SRSLTE_RNTI_SI || rnti_type == SRSLTE_RNTI_PCH || rnti_type == SRSLTE_RNTI_RAR) {
return find_dl_dci_type_siprarnti(q, cfi, rnti, dci_msg);
} else {
return find_dl_dci_type_crnti(q, cfi, sf_idx, rnti, dci_msg);
return find_dl_dci_type_crnti(q, tm, cfi, sf_idx, rnti, dci_msg);
}
}
@ -639,18 +804,17 @@ void srslte_ue_dl_save_signal(srslte_ue_dl_t *q, srslte_softbuffer_rx_t *softbuf
srslte_vec_save_file("pdcch_eq_symbols", q->pdcch.d, q->pdcch.nof_cce*36*sizeof(cf_t));
srslte_vec_save_file("pdcch_llr", q->pdcch.llr, q->pdcch.nof_cce*72*sizeof(float));
srslte_vec_save_file("pdsch_symbols", q->pdsch.symbols[0], q->pdsch_cfg.nbits.nof_re*sizeof(cf_t));
srslte_vec_save_file("pdsch_eq_symbols", q->pdsch.d, q->pdsch_cfg.nbits.nof_re*sizeof(cf_t));
srslte_vec_save_file("pdsch_llr", q->pdsch.e, q->pdsch_cfg.nbits.nof_bits*sizeof(cf_t));
int cb_len = q->pdsch_cfg.cb_segm.K1;
for (int i=0;i<q->pdsch_cfg.cb_segm.C;i++) {
char tmpstr[64];
srslte_vec_save_file("pdsch_symbols", q->pdsch.d, q->pdsch_cfg.nbits[0].nof_re*sizeof(cf_t));
srslte_vec_save_file("llr", q->pdsch.e, q->pdsch_cfg.nbits[0].nof_bits*sizeof(cf_t));
int cb_len = q->pdsch_cfg.cb_segm[0].K1;
for (int i=0;i<q->pdsch_cfg.cb_segm[0].C;i++) {
char tmpstr[64];
snprintf(tmpstr,64,"rmout_%d.dat",i);
srslte_vec_save_file(tmpstr, softbuffer->buffer_f[i], (3*cb_len+12)*sizeof(int16_t));
}
printf("Saved files for tti=%d, sf=%d, cfi=%d, mcs=%d, rv=%d, rnti=0x%x\n", tti, tti%10, cfi,
q->pdsch_cfg.grant.mcs.idx, rv_idx, rnti);
q->pdsch_cfg.grant.mcs[0].idx, rv_idx, rnti);
}

@ -54,6 +54,11 @@ cf_t dummy_buffer1[15*2048/2];
cf_t *dummy_offset_buffer[SRSLTE_MAX_PORTS] = {dummy_buffer0, dummy_buffer1};
int srslte_ue_sync_init_file(srslte_ue_sync_t *q, uint32_t nof_prb, char *file_name, int offset_time, float offset_freq) {
return srslte_ue_sync_init_file_multi(q, nof_prb, file_name, offset_time, offset_freq, 1);
}
int srslte_ue_sync_init_file_multi(srslte_ue_sync_t *q, uint32_t nof_prb, char *file_name, int offset_time,
float offset_freq, uint32_t nof_rx_ant) {
int ret = SRSLTE_ERROR_INVALID_INPUTS;
if (q != NULL &&
@ -67,6 +72,7 @@ int srslte_ue_sync_init_file(srslte_ue_sync_t *q, uint32_t nof_prb, char *file_n
q->file_cfo = -offset_freq;
q->correct_cfo = true;
q->fft_size = srslte_symbol_sz(nof_prb);
q->nof_rx_antennas = nof_rx_ant;
if (srslte_cfo_init(&q->file_cfo_correct, 2*q->sf_len)) {
fprintf(stderr, "Error initiating CFO\n");
@ -81,12 +87,12 @@ int srslte_ue_sync_init_file(srslte_ue_sync_t *q, uint32_t nof_prb, char *file_n
INFO("Offseting input file by %d samples and %.1f kHz\n", offset_time, offset_freq/1000);
if (offset_time) {
cf_t *file_offset_buffer = srslte_vec_malloc(offset_time * sizeof(cf_t));
cf_t *file_offset_buffer = srslte_vec_malloc(offset_time * nof_rx_ant * sizeof(cf_t));
if (!file_offset_buffer) {
perror("malloc");
goto clean_exit;
}
srslte_filesource_read(&q->file_source, file_offset_buffer, offset_time);
srslte_filesource_read(&q->file_source, file_offset_buffer, offset_time * nof_rx_ant);
free(file_offset_buffer);
}
@ -581,26 +587,27 @@ int srslte_ue_sync_zerocopy_multi(srslte_ue_sync_t *q, cf_t *input_buffer[SRSLTE
{
if (q->file_mode) {
int n = srslte_filesource_read(&q->file_source, input_buffer[0], q->sf_len);
int n = srslte_filesource_read_multi(&q->file_source, (void **) input_buffer, q->sf_len, q->nof_rx_antennas);
if (n < 0) {
fprintf(stderr, "Error reading input file\n");
return SRSLTE_ERROR;
return SRSLTE_ERROR;
}
if (n == 0) {
srslte_filesource_seek(&q->file_source, 0);
q->sf_idx = 9;
int n = srslte_filesource_read(&q->file_source, input_buffer[0], q->sf_len);
q->sf_idx = 9;
n = srslte_filesource_read_multi(&q->file_source, (void **) input_buffer, q->sf_len, q->nof_rx_antennas);
if (n < 0) {
fprintf(stderr, "Error reading input file\n");
return SRSLTE_ERROR;
return SRSLTE_ERROR;
}
}
if (q->correct_cfo) {
srslte_cfo_correct(&q->file_cfo_correct,
input_buffer[0],
input_buffer[0],
q->file_cfo / 15000 / q->fft_size);
for (int i = 0; i < q->nof_rx_antennas; i++) {
srslte_cfo_correct(&q->file_cfo_correct,
input_buffer[i],
input_buffer[i],
q->file_cfo / 15000 / q->fft_size);
}
}
q->sf_idx++;
if (q->sf_idx == 10) {

@ -0,0 +1,284 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 Software Radio Systems Limited
*
* \section LICENSE
*
* This file is part of the srsLTE library.
*
* srsLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsLTE 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 Affero General Public License for more details.
*
* A copy of the GNU Affero 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 <complex.h>
#include <math.h>
#include "srslte/phy/utils/mat.h"
/* Generic implementation for complex reciprocal */
inline cf_t srslte_mat_cf_recip_gen(cf_t a) {
return conjf(a) / (crealf(a) * crealf(a) + cimagf(a) * cimagf(a));
}
/* Generic implementation for 2x2 determinant */
inline cf_t srslte_mat_2x2_det_gen(cf_t a00, cf_t a01, cf_t a10, cf_t a11) {
return a00 * a11 - a01 * a10;
}
/* 2x2 Matrix inversion, generic implementation */
inline void srslte_mat_2x2_inv_gen(cf_t a00, cf_t a01, cf_t a10, cf_t a11,
cf_t *r00, cf_t *r01, cf_t *r10, cf_t *r11) {
cf_t div = srslte_mat_cf_recip_gen(srslte_mat_2x2_det_gen(a00, a01, a10, a11));
*r00 = a11 * div;
*r01 = -a01 * div;
*r10 = -a10 * div;
*r11 = a00 * div;
}
/* Generic implementation for Zero Forcing (ZF) solver */
inline void srslte_mat_2x2_zf_gen(cf_t y0, cf_t y1, cf_t h00, cf_t h01, cf_t h10, cf_t h11,
cf_t *x0, cf_t *x1, float norm) {
cf_t _norm = srslte_mat_cf_recip_gen(srslte_mat_2x2_det_gen(h00, h01, h10, h11)) * norm;
*x0 = (y0 * h11 - h01 * y1) * _norm;
*x1 = (y1 * h00 - h10 * y0) * _norm;
}
/* Generic implementation for Minimum Mean Squared Error (MMSE) solver */
inline void srslte_mat_2x2_mmse_gen(cf_t y0, cf_t y1, cf_t h00, cf_t h01, cf_t h10, cf_t h11,
cf_t *x0, cf_t *x1, float noise_estimate, float norm) {
/* Create conjugated matrix */
cf_t _h00 = conjf(h00);
cf_t _h01 = conjf(h01);
cf_t _h10 = conjf(h10);
cf_t _h11 = conjf(h11);
/* 1. A = H' x H + No*/
cf_t a00 = _h00 * h00 + _h10 * h10 + noise_estimate;
cf_t a01 = _h00 * h01 + _h10 * h11;
cf_t a10 = _h01 * h00 + _h11 * h10;
cf_t a11 = _h01 * h01 + _h11 * h11 + noise_estimate;
/* 2. B = inv(H' x H + No) = inv(A) */
cf_t b00 = a11;
cf_t b01 = -a01;
cf_t b10 = -a10;
cf_t b11 = a00;
cf_t _norm = norm * srslte_mat_cf_recip_gen(srslte_mat_2x2_det_gen(a00, a01, a10, a11));
/* 3. W = inv(H' x H + No) x H' = B x H' */
cf_t w00 = b00 * _h00 + b01 * _h01;
cf_t w01 = b00 * _h10 + b01 * _h11;
cf_t w10 = b10 * _h00 + b11 * _h01;
cf_t w11 = b10 * _h10 + b11 * _h11;
/* 4. X = W x Y */
*x0 = (y0 * w00 + y1 * w01) * _norm;
*x1 = (y0 * w10 + y1 * w11) * _norm;
}
inline float srslte_mat_2x2_cn(cf_t h00, cf_t h01, cf_t h10, cf_t h11) {
/* 1. A = H * H' (A = A') */
float a00 =
crealf(h00) * crealf(h00) + crealf(h01) * crealf(h01) + cimagf(h00) * cimagf(h00) + cimagf(h01) * cimagf(h01);
cf_t a01 = h00 * conjf(h10) + h01 * conjf(h11);
//cf_t a10 = h10*conjf(h00) + h11*conjf(h01) = conjf(a01);
float a11 =
crealf(h10) * crealf(h10) + crealf(h11) * crealf(h11) + cimagf(h10) * cimagf(h10) + cimagf(h11) * cimagf(h11);
/* 2. |H * H' - {λ0, λ1}| = 0 -> aλ² + bλ + c = 0 */
float b = a00 + a11;
float c = a00 * a11 - (crealf(a01) * crealf(a01) + cimagf(a01) * cimagf(a01));
/* 3. λ = (-b ± sqrt(b² - 4 * c))/2 */
float sqr = sqrtf(b * b - 4.0f * c);
float xmax = b + sqr;
float xmin = b - sqr;
/* 4. κ = sqrt(λ_max / λ_min) */
return 10 * log10f(xmax / xmin);
}
#ifdef LV_HAVE_SSE
#include <smmintrin.h>
/* SSE implementation for complex reciprocal */
inline __m128 srslte_mat_cf_recip_sse(__m128 a) {
__m128 conj = _MM_CONJ_PS(a);
__m128 sqabs = _mm_mul_ps(a, a);
sqabs = _mm_add_ps(_mm_movehdup_ps(sqabs), _mm_moveldup_ps(sqabs));
__m128 recp = _mm_rcp_ps(sqabs);
return _mm_mul_ps(recp, conj);
}
/* SSE implementation for 2x2 determinant */
inline __m128 srslte_mat_2x2_det_sse(__m128 a00, __m128 a01, __m128 a10, __m128 a11) {
return _mm_sub_ps(_MM_PROD_PS(a00, a11), _MM_PROD_PS(a01, a10));
}
/* SSE implementation for Zero Forcing (ZF) solver */
inline void srslte_mat_2x2_zf_sse(__m128 y0, __m128 y1, __m128 h00, __m128 h01, __m128 h10, __m128 h11,
__m128 *x0, __m128 *x1, float norm) {
__m128 detmult1 = _MM_PROD_PS(h00, h11);
__m128 detmult2 = _MM_PROD_PS(h01, h10);
__m128 det = _mm_sub_ps(detmult1, detmult2);
__m128 detrec = _mm_mul_ps(srslte_mat_cf_recip_sse(det), _mm_set1_ps(norm));
*x0 = _MM_PROD_PS(_mm_sub_ps(_MM_PROD_PS(h11, y0), _MM_PROD_PS(h01, y1)), detrec);
*x1 = _MM_PROD_PS(_mm_sub_ps(_MM_PROD_PS(h00, y1), _MM_PROD_PS(h10, y0)), detrec);
}
/* SSE implementation for Minimum Mean Squared Error (MMSE) solver */
inline void srslte_mat_2x2_mmse_sse(__m128 y0, __m128 y1, __m128 h00, __m128 h01, __m128 h10, __m128 h11,
__m128 *x0, __m128 *x1, float noise_estimate, float norm) {
__m128 _noise_estimate = _mm_set_ps(0.0f, noise_estimate, 0.0f, noise_estimate);
__m128 _norm = _mm_set1_ps(norm);
/* Create conjugated matrix */
__m128 _h00 = _MM_CONJ_PS(h00);
__m128 _h01 = _MM_CONJ_PS(h01);
__m128 _h10 = _MM_CONJ_PS(h10);
__m128 _h11 = _MM_CONJ_PS(h11);
/* 1. A = H' x H + No*/
__m128 a00 = _mm_add_ps(_mm_add_ps(_MM_SQMOD_PS(h00), _MM_SQMOD_PS(h10)), _noise_estimate);
__m128 a01 = _mm_add_ps(_MM_PROD_PS(_h00, h01), _MM_PROD_PS(_h10, h11));
__m128 a10 = _mm_add_ps(_MM_PROD_PS(_h01, h00), _MM_PROD_PS(_h11, h10));
__m128 a11 = _mm_add_ps(_mm_add_ps(_MM_SQMOD_PS(h01), _MM_SQMOD_PS(h11)), _noise_estimate);
/* 2. B = inv(H' x H + No) = inv(A) */
__m128 b00 = a11;
__m128 b01 = _mm_xor_ps(a01, _mm_set1_ps(-0.0f));
__m128 b10 = _mm_xor_ps(a10, _mm_set1_ps(-0.0f));
__m128 b11 = a00;
_norm = _mm_mul_ps(_norm, srslte_mat_cf_recip_sse(srslte_mat_2x2_det_sse(a00, a01, a10, a11)));
/* 3. W = inv(H' x H + No) x H' = B x H' */
__m128 w00 = _mm_add_ps(_MM_PROD_PS(b00, _h00), _MM_PROD_PS(b01, _h01));
__m128 w01 = _mm_add_ps(_MM_PROD_PS(b00, _h10), _MM_PROD_PS(b01, _h11));
__m128 w10 = _mm_add_ps(_MM_PROD_PS(b10, _h00), _MM_PROD_PS(b11, _h01));
__m128 w11 = _mm_add_ps(_MM_PROD_PS(b10, _h10), _MM_PROD_PS(b11, _h11));
/* 4. X = W x Y */
*x0 = _MM_PROD_PS(_mm_add_ps(_MM_PROD_PS(y0, w00), _MM_PROD_PS(y1, w01)), _norm);
*x1 = _MM_PROD_PS(_mm_add_ps(_MM_PROD_PS(y0, w10), _MM_PROD_PS(y1, w11)), _norm);
}
#endif /* LV_HAVE_SSE */
#ifdef LV_HAVE_AVX
#include <immintrin.h>
/* AVX implementation for complex reciprocal */
inline __m256 srslte_mat_cf_recip_avx(__m256 a) {
__m256 conj = _MM256_CONJ_PS(a);
__m256 sqabs = _mm256_mul_ps(a, a);
sqabs = _mm256_add_ps(_mm256_movehdup_ps(sqabs), _mm256_moveldup_ps(sqabs));
__m256 recp = _mm256_rcp_ps(sqabs);
return _mm256_mul_ps(recp, conj);
}
/* AVX implementation for 2x2 determinant */
inline __m256 srslte_mat_2x2_det_avx(__m256 a00, __m256 a01, __m256 a10, __m256 a11) {
#ifdef LV_HAVE_FMA
return _MM256_PROD_SUB_PS(a00, a11, _MM256_PROD_PS(a01, a10));
#else
return _mm256_sub_ps(_MM256_PROD_PS(a00, a11), _MM256_PROD_PS(a01, a10));
#endif /* LV_HAVE_FMA */
}
/* AVX implementation for Zero Forcing (ZF) solver */
inline void srslte_mat_2x2_zf_avx(__m256 y0, __m256 y1, __m256 h00, __m256 h01, __m256 h10, __m256 h11,
__m256 *x0, __m256 *x1, float norm) {
__m256 det = srslte_mat_2x2_det_avx(h00, h01, h10, h11);
__m256 detrec = _mm256_mul_ps(srslte_mat_cf_recip_avx(det), _mm256_set1_ps(norm));
#ifdef LV_HAVE_FMA
*x0 = _MM256_PROD_PS(_MM256_PROD_SUB_PS(h11, y0, _MM256_PROD_PS(h01, y1)), detrec);
*x1 = _MM256_PROD_PS(_MM256_PROD_SUB_PS(h00, y1, _MM256_PROD_PS(h10, y0)), detrec);
#else
*x0 = _MM256_PROD_PS(_mm256_sub_ps(_MM256_PROD_PS(h11, y0), _MM256_PROD_PS(h01, y1)), detrec);
*x1 = _MM256_PROD_PS(_mm256_sub_ps(_MM256_PROD_PS(h00, y1), _MM256_PROD_PS(h10, y0)), detrec);
#endif /* LV_HAVE_FMA */
}
/* AVX implementation for Minimum Mean Squared Error (MMSE) solver */
inline void srslte_mat_2x2_mmse_avx(__m256 y0, __m256 y1, __m256 h00, __m256 h01, __m256 h10, __m256 h11,
__m256 *x0, __m256 *x1, float noise_estimate, float norm) {
__m256 _noise_estimate = _mm256_set_ps(0.0f, noise_estimate, 0.0f, noise_estimate,
0.0f, noise_estimate, 0.0f, noise_estimate);
__m256 _norm = _mm256_set1_ps(norm);
/* Create conjugated matrix */
__m256 _h00 = _MM256_CONJ_PS(h00);
__m256 _h01 = _MM256_CONJ_PS(h01);
__m256 _h10 = _MM256_CONJ_PS(h10);
__m256 _h11 = _MM256_CONJ_PS(h11);
/* 1. A = H' x H + No*/
#ifdef LV_HAVE_FMA
__m256 a00 = _MM256_SQMOD_ADD_PS(h00, h10, _noise_estimate);
__m256 a01 = _MM256_PROD_ADD_PS(_h00, h01, _MM256_PROD_PS(_h10, h11));
__m256 a10 = _MM256_PROD_ADD_PS(_h01, h00, _MM256_PROD_PS(_h11, h10));
__m256 a11 = _MM256_SQMOD_ADD_PS(h01, h11, _noise_estimate);
#else
__m256 a00 = _mm256_add_ps(_MM256_SQMOD_PS(h00, h10), _noise_estimate);
__m256 a01 = _mm256_add_ps(_MM256_PROD_PS(_h00, h01), _MM256_PROD_PS(_h10, h11));
__m256 a10 = _mm256_add_ps(_MM256_PROD_PS(_h01, h00), _MM256_PROD_PS(_h11, h10));
__m256 a11 = _mm256_add_ps(_MM256_SQMOD_PS(h01, h11), _noise_estimate);
#endif /* LV_HAVE_FMA */
/* 2. B = inv(H' x H + No) = inv(A) */
__m256 b00 = a11;
__m256 b01 = _mm256_xor_ps(a01, _mm256_set1_ps(-0.0f));
__m256 b10 = _mm256_xor_ps(a10, _mm256_set1_ps(-0.0f));
__m256 b11 = a00;
_norm = _mm256_mul_ps(_norm, srslte_mat_cf_recip_avx(srslte_mat_2x2_det_avx(a00, a01, a10, a11)));
/* 3. W = inv(H' x H + No) x H' = B x H' */
#ifdef LV_HAVE_FMA
__m256 w00 = _MM256_PROD_ADD_PS(b00, _h00, _MM256_PROD_PS(b01, _h01));
__m256 w01 = _MM256_PROD_ADD_PS(b00, _h10, _MM256_PROD_PS(b01, _h11));
__m256 w10 = _MM256_PROD_ADD_PS(b10, _h00, _MM256_PROD_PS(b11, _h01));
__m256 w11 = _MM256_PROD_ADD_PS(b10, _h10, _MM256_PROD_PS(b11, _h11));
#else
__m256 w00 = _mm256_add_ps(_MM256_PROD_PS(b00, _h00), _MM256_PROD_PS(b01, _h01));
__m256 w01 = _mm256_add_ps(_MM256_PROD_PS(b00, _h10), _MM256_PROD_PS(b01, _h11));
__m256 w10 = _mm256_add_ps(_MM256_PROD_PS(b10, _h00), _MM256_PROD_PS(b11, _h01));
__m256 w11 = _mm256_add_ps(_MM256_PROD_PS(b10, _h10), _MM256_PROD_PS(b11, _h11));
#endif /* LV_HAVE_FMA */
/* 4. X = W x Y */
#ifdef LV_HAVE_FMA
*x0 = _MM256_PROD_PS(_MM256_PROD_ADD_PS(y0, w00, _MM256_PROD_PS(y1, w01)), _norm);
*x1 = _MM256_PROD_PS(_MM256_PROD_ADD_PS(y0, w10, _MM256_PROD_PS(y1, w11)), _norm);
#else
*x0 = _MM256_PROD_PS(_mm256_add_ps(_MM256_PROD_PS(y0, w00), _MM256_PROD_PS(y1, w01)), _norm);
*x1 = _MM256_PROD_PS(_mm256_add_ps(_MM256_PROD_PS(y0, w10), _MM256_PROD_PS(y1, w11)), _norm);
#endif /* LV_HAVE_FMA */
}
#endif /* LV_HAVE_AVX */

@ -33,3 +33,12 @@ add_test(dft_dc dft_test -b -d) # Backwards first & handle dc internally
add_test(dft_odd dft_test -N 255) # Odd-length
add_test(dft_odd_dc dft_test -N 255 -b -d) # Odd-length, backwards first, handle dc
########################################################################
# Algebra TEST
########################################################################
add_executable(algebra_test mat_test.c)
target_link_libraries(algebra_test srslte_phy)
add_test(algebra_2x2_zf_solver_test algebra_test -z)
add_test(algebra_2x2_mmse_solver_test algebra_test -m)

@ -0,0 +1,415 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2015 Software Radio Systems Limited
*
* \section LICENSE
*
* This file is part of the srsLTE library.
*
* srsLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsLTE 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 Affero General Public License for more details.
*
* A copy of the GNU Affero 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 <unistd.h>
#include <complex.h>
#include <stdbool.h>
#include <immintrin.h>
#include <sys/time.h>
#include "srslte/phy/utils/mat.h"
bool zf_solver = false;
bool mmse_solver = false;
bool verbose = false;
double elapsed_us(struct timeval *ts_start, struct timeval *ts_end) {
if (ts_end->tv_usec > ts_start->tv_usec) {
return ((double) ts_end->tv_sec - (double) ts_start->tv_sec) * 1000000 +
(double) ts_end->tv_usec - (double) ts_start->tv_usec;
} else {
return ((double) ts_end->tv_sec - (double) ts_start->tv_sec - 1) * 1000000 +
((double) ts_end->tv_usec + 1000000) - (double) ts_start->tv_usec;
}
}
#define NOF_REPETITIONS 1000
#define RUN_TEST(FUNCTION) /*TYPE NAME (void)*/ { \
int i;\
struct timeval start, end;\
gettimeofday(&start, NULL); \
bool ret = true; \
for (i = 0; i < NOF_REPETITIONS; i++) {ret &= FUNCTION ();}\
gettimeofday(&end, NULL);\
if (verbose) printf("%32s: %s ... %6.2f us/call\n", #FUNCTION, (ret)?"Pass":"Fail", \
elapsed_us(&start, &end)/NOF_REPETITIONS);\
passed &= ret;\
}
void usage(char *prog) {
printf("Usage: %s [mzvh]\n", prog);
printf("\t-m Test Minimum Mean Squared Error (MMSE) solver\n");
printf("\t-z Test Zero Forcing (ZF) solver\n");
printf("\t-v Verbose\n");
printf("\t-h Show this message\n");
}
void parse_args(int argc, char **argv) {
int opt;
while ((opt = getopt(argc, argv, "mzvh")) != -1) {
switch (opt) {
case 'm':
mmse_solver = true;
break;
case 'z':
zf_solver = true;
break;
case 'v':
verbose = true;
break;
case 'h':
default:
usage(argv[0]);
exit(-1);
}
}
}
bool test_zf_solver_gen(void) {
cf_t x0, x1, cf_error0, cf_error1;
float error;
cf_t x0_gold = RANDOM_CF();
cf_t x1_gold = RANDOM_CF();
cf_t h00 = RANDOM_CF();
cf_t h01 = RANDOM_CF();
cf_t h10 = RANDOM_CF();
cf_t h11 = (1 - h01 * h10) / h00;
cf_t y0 = x0_gold * h00 + x1_gold * h01;
cf_t y1 = x0_gold * h10 + x1_gold * h11;
srslte_mat_2x2_zf_gen(y0, y1, h00, h01, h10, h11, &x0, &x1, 1.0f);
cf_error0 = x0 - x0_gold;
cf_error1 = x1 - x1_gold;
error = crealf(cf_error0) * crealf(cf_error0) + cimagf(cf_error0) * cimagf(cf_error0) +
crealf(cf_error1) * crealf(cf_error1) + cimagf(cf_error1) * cimagf(cf_error1);
return (error < 1e-6);
}
bool test_mmse_solver_gen(void) {
cf_t x0, x1, cf_error0, cf_error1;
float error;
cf_t x0_gold = RANDOM_CF();
cf_t x1_gold = RANDOM_CF();
cf_t h00 = RANDOM_CF();
cf_t h01 = RANDOM_CF();
cf_t h10 = RANDOM_CF();
cf_t h11 = (1 - h01 * h10) / h00;
cf_t y0 = x0_gold * h00 + x1_gold * h01;
cf_t y1 = x0_gold * h10 + x1_gold * h11;
srslte_mat_2x2_mmse_gen(y0, y1, h00, h01, h10, h11, &x0, &x1, 0.0f, 1.0f);
cf_error0 = x0 - x0_gold;
cf_error1 = x1 - x1_gold;
error = crealf(cf_error0) * crealf(cf_error0) + cimagf(cf_error0) * cimagf(cf_error0) +
crealf(cf_error1) * crealf(cf_error1) + cimagf(cf_error1) * cimagf(cf_error1);
return (error < 1e-6);
}
#ifdef LV_HAVE_SSE
bool test_zf_solver_sse(void) {
cf_t cf_error0, cf_error1;
float error = 0.0f;
cf_t x0_gold_1 = RANDOM_CF();
cf_t x1_gold_1 = RANDOM_CF();
cf_t h00_1 = RANDOM_CF();
cf_t h01_1 = RANDOM_CF();
cf_t h10_1 = RANDOM_CF();
cf_t h11_1 = (1 - h01_1 * h10_1) / h00_1;
cf_t y0_1 = x0_gold_1 * h00_1 + x1_gold_1 * h01_1;
cf_t y1_1 = x0_gold_1 * h10_1 + x1_gold_1 * h11_1;
cf_t x0_gold_2 = RANDOM_CF();
cf_t x1_gold_2 = RANDOM_CF();
cf_t h00_2 = RANDOM_CF();
cf_t h01_2 = RANDOM_CF();
cf_t h10_2 = RANDOM_CF();
cf_t h11_2 = (1 - h01_2 * h10_2) / h00_2;
cf_t y0_2 = x0_gold_2 * h00_2 + x1_gold_2 * h01_2;
cf_t y1_2 = x0_gold_2 * h10_2 + x1_gold_2 * h11_2;
__m128 _y0 = _mm_set_ps(cimagf(y0_1), crealf(y0_1), cimagf(y0_2), crealf(y0_2));
__m128 _y1 = _mm_set_ps(cimagf(y1_1), crealf(y1_1), cimagf(y1_2), crealf(y1_2));
__m128 _h00 = _mm_set_ps(cimagf(h00_1), crealf(h00_1), cimagf(h00_2), crealf(h00_2));
__m128 _h01 = _mm_set_ps(cimagf(h01_1), crealf(h01_1), cimagf(h01_2), crealf(h01_2));
__m128 _h10 = _mm_set_ps(cimagf(h10_1), crealf(h10_1), cimagf(h10_2), crealf(h10_2));
__m128 _h11 = _mm_set_ps(cimagf(h11_1), crealf(h11_1), cimagf(h11_2), crealf(h11_2));
__m128 _x0, _x1;
srslte_mat_2x2_zf_sse(_y0, _y1, _h00, _h01, _h10, _h11, &_x0, &_x1, 1.0f);
__attribute__((aligned(128))) cf_t x0[2];
__attribute__((aligned(128))) cf_t x1[2];
_mm_store_ps((float *) x0, _x0);
_mm_store_ps((float *) x1, _x1);
cf_error0 = x0[1] - x0_gold_1;
cf_error1 = x1[1] - x1_gold_1;
error += crealf(cf_error0) * crealf(cf_error0) + cimagf(cf_error0) * cimagf(cf_error0) +
crealf(cf_error1) * crealf(cf_error1) + cimagf(cf_error1) * cimagf(cf_error1);
cf_error0 = x0[0] - x0_gold_2;
cf_error1 = x1[0] - x1_gold_2;
error += crealf(cf_error0) * crealf(cf_error0) + cimagf(cf_error0) * cimagf(cf_error0) +
crealf(cf_error1) * crealf(cf_error1) + cimagf(cf_error1) * cimagf(cf_error1);
return (error < 1e-3);
}
bool test_mmse_solver_sse(void) {
cf_t cf_error0, cf_error1;
float error = 0.0f;
cf_t x0_gold_1 = RANDOM_CF();
cf_t x1_gold_1 = RANDOM_CF();
cf_t h00_1 = RANDOM_CF();
cf_t h01_1 = RANDOM_CF();
cf_t h10_1 = RANDOM_CF();
cf_t h11_1 = (1 - h01_1 * h10_1) / h00_1;
cf_t y0_1 = x0_gold_1 * h00_1 + x1_gold_1 * h01_1;
cf_t y1_1 = x0_gold_1 * h10_1 + x1_gold_1 * h11_1;
cf_t x0_gold_2 = RANDOM_CF();
cf_t x1_gold_2 = RANDOM_CF();
cf_t h00_2 = RANDOM_CF();
cf_t h01_2 = RANDOM_CF();
cf_t h10_2 = RANDOM_CF();
cf_t h11_2 = (1 - h01_2 * h10_2) / h00_2;
cf_t y0_2 = x0_gold_2 * h00_2 + x1_gold_2 * h01_2;
cf_t y1_2 = x0_gold_2 * h10_2 + x1_gold_2 * h11_2;
__m128 _y0 = _mm_set_ps(cimagf(y0_1), crealf(y0_1), cimagf(y0_2), crealf(y0_2));
__m128 _y1 = _mm_set_ps(cimagf(y1_1), crealf(y1_1), cimagf(y1_2), crealf(y1_2));
__m128 _h00 = _mm_set_ps(cimagf(h00_1), crealf(h00_1), cimagf(h00_2), crealf(h00_2));
__m128 _h01 = _mm_set_ps(cimagf(h01_1), crealf(h01_1), cimagf(h01_2), crealf(h01_2));
__m128 _h10 = _mm_set_ps(cimagf(h10_1), crealf(h10_1), cimagf(h10_2), crealf(h10_2));
__m128 _h11 = _mm_set_ps(cimagf(h11_1), crealf(h11_1), cimagf(h11_2), crealf(h11_2));
__m128 _x0, _x1;
srslte_mat_2x2_mmse_sse(_y0, _y1, _h00, _h01, _h10, _h11, &_x0, &_x1, 0.0f, 1.0f);
__attribute__((aligned(128))) cf_t x0[2];
__attribute__((aligned(128))) cf_t x1[2];
_mm_store_ps((float *) x0, _x0);
_mm_store_ps((float *) x1, _x1);
cf_error0 = x0[1] - x0_gold_1;
cf_error1 = x1[1] - x1_gold_1;
error += crealf(cf_error0) * crealf(cf_error0) + cimagf(cf_error0) * cimagf(cf_error0) +
crealf(cf_error1) * crealf(cf_error1) + cimagf(cf_error1) * cimagf(cf_error1);
cf_error0 = x0[0] - x0_gold_2;
cf_error1 = x1[0] - x1_gold_2;
error += crealf(cf_error0) * crealf(cf_error0) + cimagf(cf_error0) * cimagf(cf_error0) +
crealf(cf_error1) * crealf(cf_error1) + cimagf(cf_error1) * cimagf(cf_error1);
return (error < 1e-3);
}
#endif /* LV_HAVE_SSE */
#ifdef LV_HAVE_AVX
bool test_zf_solver_avx(void) {
cf_t cf_error0, cf_error1;
float error = 0.0f;
cf_t x0_gold_1 = RANDOM_CF();
cf_t x1_gold_1 = RANDOM_CF();
cf_t h00_1 = RANDOM_CF();
cf_t h01_1 = RANDOM_CF();
cf_t h10_1 = RANDOM_CF();
cf_t h11_1 = (1 - h01_1 * h10_1) / h00_1;
cf_t y0_1 = x0_gold_1 * h00_1 + x1_gold_1 * h01_1;
cf_t y1_1 = x0_gold_1 * h10_1 + x1_gold_1 * h11_1;
cf_t x0_gold_2 = RANDOM_CF();
cf_t x1_gold_2 = RANDOM_CF();
cf_t h00_2 = RANDOM_CF();
cf_t h01_2 = RANDOM_CF();
cf_t h10_2 = RANDOM_CF();
cf_t h11_2 = (1 - h01_2 * h10_2) / h00_2;
cf_t y0_2 = x0_gold_2 * h00_2 + x1_gold_2 * h01_2;
cf_t y1_2 = x0_gold_2 * h10_2 + x1_gold_2 * h11_2;
__m256 _y0 = _mm256_set_ps(cimagf(y0_1), crealf(y0_1), cimagf(y0_2), crealf(y0_2),
cimagf(y0_1), crealf(y0_1), cimagf(y0_2), crealf(y0_2));
__m256 _y1 = _mm256_set_ps(cimagf(y1_1), crealf(y1_1), cimagf(y1_2), crealf(y1_2),
cimagf(y1_1), crealf(y1_1), cimagf(y1_2), crealf(y1_2));
__m256 _h00 = _mm256_set_ps(cimagf(h00_1), crealf(h00_1), cimagf(h00_2), crealf(h00_2),
cimagf(h00_1), crealf(h00_1), cimagf(h00_2), crealf(h00_2));
__m256 _h01 = _mm256_set_ps(cimagf(h01_1), crealf(h01_1), cimagf(h01_2), crealf(h01_2),
cimagf(h01_1), crealf(h01_1), cimagf(h01_2), crealf(h01_2));
__m256 _h10 = _mm256_set_ps(cimagf(h10_1), crealf(h10_1), cimagf(h10_2), crealf(h10_2),
cimagf(h10_1), crealf(h10_1), cimagf(h10_2), crealf(h10_2));
__m256 _h11 = _mm256_set_ps(cimagf(h11_1), crealf(h11_1), cimagf(h11_2), crealf(h11_2),
cimagf(h11_1), crealf(h11_1), cimagf(h11_2), crealf(h11_2));
__m256 _x0, _x1;
srslte_mat_2x2_zf_avx(_y0, _y1, _h00, _h01, _h10, _h11, &_x0, &_x1, 1.0f);
__attribute__((aligned(256))) cf_t x0[4];
__attribute__((aligned(256))) cf_t x1[4];
_mm256_store_ps((float *) x0, _x0);
_mm256_store_ps((float *) x1, _x1);
cf_error0 = x0[1] - x0_gold_1;
cf_error1 = x1[1] - x1_gold_1;
error += crealf(cf_error0) * crealf(cf_error0) + cimagf(cf_error0) * cimagf(cf_error0) +
crealf(cf_error1) * crealf(cf_error1) + cimagf(cf_error1) * cimagf(cf_error1);
cf_error0 = x0[0] - x0_gold_2;
cf_error1 = x1[0] - x1_gold_2;
error += crealf(cf_error0) * crealf(cf_error0) + cimagf(cf_error0) * cimagf(cf_error0) +
crealf(cf_error1) * crealf(cf_error1) + cimagf(cf_error1) * cimagf(cf_error1);
return (error < 1e-3);
}
bool test_mmse_solver_avx(void) {
cf_t cf_error0, cf_error1;
float error = 0.0f;
cf_t x0_gold_1 = RANDOM_CF();
cf_t x1_gold_1 = RANDOM_CF();
cf_t h00_1 = RANDOM_CF();
cf_t h01_1 = RANDOM_CF();
cf_t h10_1 = RANDOM_CF();
cf_t h11_1 = (1 - h01_1 * h10_1) / h00_1;
cf_t y0_1 = x0_gold_1 * h00_1 + x1_gold_1 * h01_1;
cf_t y1_1 = x0_gold_1 * h10_1 + x1_gold_1 * h11_1;
cf_t x0_gold_2 = RANDOM_CF();
cf_t x1_gold_2 = RANDOM_CF();
cf_t h00_2 = RANDOM_CF();
cf_t h01_2 = RANDOM_CF();
cf_t h10_2 = RANDOM_CF();
cf_t h11_2 = (1 - h01_2 * h10_2) / h00_2;
cf_t y0_2 = x0_gold_2 * h00_2 + x1_gold_2 * h01_2;
cf_t y1_2 = x0_gold_2 * h10_2 + x1_gold_2 * h11_2;
__m256 _y0 = _mm256_set_ps(cimagf(y0_1), crealf(y0_1), cimagf(y0_2), crealf(y0_2),
cimagf(y0_1), crealf(y0_1), cimagf(y0_2), crealf(y0_2));
__m256 _y1 = _mm256_set_ps(cimagf(y1_1), crealf(y1_1), cimagf(y1_2), crealf(y1_2),
cimagf(y1_1), crealf(y1_1), cimagf(y1_2), crealf(y1_2));
__m256 _h00 = _mm256_set_ps(cimagf(h00_1), crealf(h00_1), cimagf(h00_2), crealf(h00_2),
cimagf(h00_1), crealf(h00_1), cimagf(h00_2), crealf(h00_2));
__m256 _h01 = _mm256_set_ps(cimagf(h01_1), crealf(h01_1), cimagf(h01_2), crealf(h01_2),
cimagf(h01_1), crealf(h01_1), cimagf(h01_2), crealf(h01_2));
__m256 _h10 = _mm256_set_ps(cimagf(h10_1), crealf(h10_1), cimagf(h10_2), crealf(h10_2),
cimagf(h10_1), crealf(h10_1), cimagf(h10_2), crealf(h10_2));
__m256 _h11 = _mm256_set_ps(cimagf(h11_1), crealf(h11_1), cimagf(h11_2), crealf(h11_2),
cimagf(h11_1), crealf(h11_1), cimagf(h11_2), crealf(h11_2));
__m256 _x0, _x1;
srslte_mat_2x2_mmse_avx(_y0, _y1, _h00, _h01, _h10, _h11, &_x0, &_x1, 0.0f, 1.0f);
__attribute__((aligned(256))) cf_t x0[4];
__attribute__((aligned(256))) cf_t x1[4];
_mm256_store_ps((float *) x0, _x0);
_mm256_store_ps((float *) x1, _x1);
cf_error0 = x0[1] - x0_gold_1;
cf_error1 = x1[1] - x1_gold_1;
error += crealf(cf_error0) * crealf(cf_error0) + cimagf(cf_error0) * cimagf(cf_error0) +
crealf(cf_error1) * crealf(cf_error1) + cimagf(cf_error1) * cimagf(cf_error1);
cf_error0 = x0[0] - x0_gold_2;
cf_error1 = x1[0] - x1_gold_2;
error += crealf(cf_error0) * crealf(cf_error0) + cimagf(cf_error0) * cimagf(cf_error0) +
crealf(cf_error1) * crealf(cf_error1) + cimagf(cf_error1) * cimagf(cf_error1);
return (error < 1e-3);
}
#endif /* LV_HAVE_AVX */
int main(int argc, char **argv) {
bool passed = true;
int ret = 0;
parse_args(argc, argv);
if (zf_solver) {
RUN_TEST(test_zf_solver_gen);
#ifdef LV_HAVE_SSE
RUN_TEST(test_zf_solver_sse);
#endif /* LV_HAVE_SSE */
#ifdef LV_HAVE_AVX
RUN_TEST(test_zf_solver_avx);
#endif /* LV_HAVE_AVX */
}
if (mmse_solver) {
RUN_TEST(test_mmse_solver_gen);
#ifdef LV_HAVE_SSE
RUN_TEST(test_mmse_solver_sse);
#endif /* LV_HAVE_SSE */
#ifdef LV_HAVE_AVX
RUN_TEST(test_mmse_solver_avx);
#endif /* LV_HAVE_AVX */
}
printf("%s!\n", (passed) ? "Ok" : "Failed");
if (!passed) {
exit(ret);
}
exit(ret);
}

@ -35,6 +35,16 @@
#include "srslte/phy/utils/vector_simd.h"
#include "srslte/phy/utils/bit.h"
#ifdef LV_HAVE_SSE
#include <smmintrin.h>
#endif
#ifdef LV_HAVE_AVX
#include <immintrin.h>
#endif
#ifdef HAVE_VOLK
#include "volk/volk.h"
#endif
@ -852,3 +862,24 @@ void srslte_vec_quant_suc(int16_t *in, uint8_t *out, float gain, int16_t offset,
}
}
void srs_vec_cf_cpy(cf_t *dst, cf_t *src, int len) {
int i = 0;
#ifdef LV_HAVE_AVX
for (; i < len - 3; i += 4) {
_mm256_store_ps((float *) &dst[i], _mm256_load_ps((float *) &src[i]));
}
#endif /* LV_HAVE_AVX */
#ifdef LV_HAVE_SSE
for (; i < len - 1; i += 2) {
_mm_store_ps((float *) &dst[i], _mm_load_ps((float *) &src[i]));
}
for (; i < len; i++) {
((__m64*) dst)[i] = ((__m64*) src)[i];
}
#else
for (; i < len; i++) {
dst[i] = src[i];
}
#endif /* LV_HAVE_SSE */
}

@ -169,6 +169,8 @@ bool radio::has_rssi()
bool radio::tx(void* buffer, uint32_t nof_samples, srslte_timestamp_t tx_time)
{
void *iq_samples[4] = {(void *) zeros, (void *) zeros, (void *) zeros, (void *) zeros};
if (!tx_adv_negative) {
srslte_timestamp_sub(&tx_time, 0, tx_adv_sec);
} else {
@ -177,11 +179,11 @@ bool radio::tx(void* buffer, uint32_t nof_samples, srslte_timestamp_t tx_time)
if (is_start_of_burst) {
if (burst_preamble_samples != 0) {
srslte_timestamp_t tx_time_pad;
srslte_timestamp_t tx_time_pad;
srslte_timestamp_copy(&tx_time_pad, &tx_time);
srslte_timestamp_sub(&tx_time_pad, 0, burst_preamble_time_rounded);
save_trace(1, &tx_time_pad);
srslte_rf_send_timed2(&rf_device, zeros, burst_preamble_samples, tx_time_pad.full_secs, tx_time_pad.frac_secs, true, false);
srslte_rf_send_timed_multi(&rf_device, iq_samples, burst_preamble_samples, tx_time_pad.full_secs, tx_time_pad.frac_secs, true, true, false);
is_start_of_burst = false;
}
}
@ -191,7 +193,8 @@ bool radio::tx(void* buffer, uint32_t nof_samples, srslte_timestamp_t tx_time)
srslte_timestamp_add(&end_of_burst_time, 0, (double) nof_samples/cur_tx_srate);
save_trace(0, &tx_time);
int ret = srslte_rf_send_timed2(&rf_device, buffer, nof_samples+offset, tx_time.full_secs, tx_time.frac_secs, is_start_of_burst, false);
iq_samples[0] = buffer;
int ret = srslte_rf_send_timed_multi(&rf_device, (void**) iq_samples, nof_samples+offset, tx_time.full_secs, tx_time.frac_secs, true, is_start_of_burst, false);
offset = 0;
is_start_of_burst = false;
if (ret > 0) {

@ -43,6 +43,7 @@ struct mac_metrics_t
int rx_brate;
int ul_buffer;
int dl_buffer;
float dl_cqi;
float phr;
};

@ -40,7 +40,10 @@ class sched_ue {
public:
// used by sched_metric
uint32_t ue_idx;
uint32_t ue_idx;
bool has_pusch;
bool has_pucch;
typedef struct {
uint32_t cce_start[4][6];

@ -48,8 +48,9 @@ public:
log_h = NULL;
rnti = 0;
pcap = NULL;
nof_failures = 0;
phr_counter = 0;
nof_failures = 0;
phr_counter = 0;
dl_cqi_counter = 0;
is_phy_added = false;
for (int i=0;i<NOF_HARQ_PROCESSES;i++) {
pending_buffers[i] = NULL;
@ -91,8 +92,10 @@ public:
void metrics_read(srsenb::mac_metrics_t* metrics);
void metrics_rx(bool crc, uint32_t tbs);
void metrics_tx(bool crc, uint32_t tbs);
void metrics_phr(float phr);
void metrics_dl_cqi(uint32_t dl_cqi);
bool is_phy_added;
private:
@ -100,12 +103,11 @@ private:
void allocate_sdu(srslte::sch_pdu *pdu, uint32_t lcid, uint32_t sdu_len);
bool process_ce(srslte::sch_subh *subh);
void allocate_ce(srslte::sch_pdu *pdu, uint32_t lcid);
void metrics_phr(float phr);
uint32_t phr_counter;
std::vector<uint32_t> lc_groups[4];
uint32_t phr_counter;
uint32_t dl_cqi_counter;
mac_metrics_t metrics;
srslte::mac_pcap* pcap;

@ -329,6 +329,7 @@ int mac::cqi_info(uint32_t tti, uint16_t rnti, uint32_t cqi_value)
if (ue_db.count(rnti)) {
scheduler.dl_cqi_info(tti, rnti, cqi_value);
ue_db[rnti]->metrics_dl_cqi(cqi_value);
} else {
Error("User rnti=0x%x not found\n", rnti);
return -1;

@ -691,7 +691,10 @@ int sched::ul_sched(uint32_t tti, srsenb::sched_interface::ul_sched_res_t* sched
for(std::map<uint16_t, sched_ue>::iterator iter=ue_db.begin(); iter!=ue_db.end(); ++iter) {
sched_ue *user = (sched_ue*) &iter->second;
uint16_t rnti = (uint16_t) iter->first;
user->has_pusch = false;
user->has_pucch = false;
ul_harq_proc *h = user->get_ul_harq(current_tti);
/* Indicate PHICH acknowledgment if needed */
@ -717,9 +720,13 @@ int sched::ul_sched(uint32_t tti, srsenb::sched_interface::ul_sched_res_t* sched
uint32_t prb_idx[2] = {0, 0};
uint32_t L = 0;
if (user->get_pucch_sched(current_tti, prb_idx, &L)) {
for (int i=0;i<2;i++) {
ul_harq_proc::ul_alloc_t pucch = {prb_idx[i], L};
ul_metric->update_allocation(pucch);
user->has_pucch = true;
// allocate PUCCH if no PUSCH for user
if (!user->has_pusch) {
for (int i=0;i<2;i++) {
ul_harq_proc::ul_alloc_t pucch = {prb_idx[i], L};
ul_metric->update_allocation(pucch);
}
}
}
}

@ -100,7 +100,7 @@ void harq_proc::set_ack(bool ack_)
ack = ack_;
ack_received = true;
log_h->debug("ACK=%d received pid=%d, n_rtx=%d, max_retx=%d\n", ack_, id, n_rtx, max_retx);
if (n_rtx >= max_retx) {
if (n_rtx + 1 >= max_retx) {
Warning("SCHED: discarting TB pid=%d, tti=%d, maximum number of retx exceeded (%d)\n", id, tti, max_retx);
active = false;
}

@ -214,7 +214,8 @@ void ul_metric_rr::new_tti(std::map<uint16_t,sched_ue> &ue_db, uint32_t nof_rb_,
for(std::map<uint16_t, sched_ue>::iterator iter=ue_db.begin(); iter!=ue_db.end(); ++iter) {
sched_ue *user = (sched_ue*) &iter->second;
if (user->get_pending_ul_new_data(current_tti) || !user->get_ul_harq(current_tti)->is_empty()) {
user->ue_idx = nof_users_with_data;
user->ue_idx = nof_users_with_data;
user->has_pusch = true;
nof_users_with_data++;
}
}

@ -257,7 +257,7 @@ bool sched_ue::get_pucch_sched(uint32_t current_tti, uint32_t prb_idx[2], uint32
if (L) {
*L = 1;
}
Info("SCHED: Reserved Format1A PUCCH for rnti=0x%x, n_prb=%d,%d, n_pucch=%d\n", rnti, prb_idx[0], prb_idx[1], n_pucch);
Debug("SCHED: Reserved Format1A PUCCH for rnti=0x%x, n_prb=%d,%d, n_pucch=%d\n", rnti, prb_idx[0], prb_idx[1], n_pucch);
return true;
}
}
@ -271,7 +271,7 @@ bool sched_ue::get_pucch_sched(uint32_t current_tti, uint32_t prb_idx[2], uint32
if (L) {
*L = 1;
}
Info("SCHED: Reserved Format1 PUCCH for rnti=0x%x, n_prb=%d,%d, n_pucch=%d\n", rnti, prb_idx[0], prb_idx[1], cfg.sr_N_pucch);
Debug("SCHED: Reserved Format1 PUCCH for rnti=0x%x, n_prb=%d,%d, n_pucch=%d\n", rnti, prb_idx[0], prb_idx[1], cfg.sr_N_pucch);
return true;
}
// Finally check Format2 (periodic CQI)
@ -284,7 +284,7 @@ bool sched_ue::get_pucch_sched(uint32_t current_tti, uint32_t prb_idx[2], uint32
if(L) {
*L = 2;
}
Info("SCHED: Reserved Format2 PUCCH for rnti=0x%x, n_prb=%d,%d, n_pucch=%d, pmi_idx=%d\n",
Debug("SCHED: Reserved Format2 PUCCH for rnti=0x%x, n_prb=%d,%d, n_pucch=%d, pmi_idx=%d\n",
rnti, prb_idx[0], prb_idx[1], cfg.cqi_pucch, cfg.cqi_idx);
return true;
}
@ -813,6 +813,11 @@ int sched_ue::alloc_tbs(uint32_t nof_prb,
uint32_t max_mcs = is_ul?max_mcs_ul:max_mcs_dl;
uint32_t max_Qm = is_ul?4:6; // Allow 16-QAM in PUSCH Only
// TODO: Compute real spectral efficiency based on PUSCH-UCI configuration
if (has_pucch) {
cqi-=2;
}
int tbs = cqi_to_tbs(cqi, nof_prb, nof_re, max_mcs, max_Qm, &sel_mcs)/8;
/* If less bytes are requested, lower the MCS */

@ -396,14 +396,20 @@ void ue::metrics_read(mac_metrics_t* metrics_)
metrics.dl_buffer = sched->get_dl_buffer(rnti);
memcpy(metrics_, &metrics, sizeof(mac_metrics_t));
phr_counter = 0;
phr_counter = 0;
dl_cqi_counter = 0;
bzero(&metrics, sizeof(mac_metrics_t));
}
void ue::metrics_phr(float phr) {
metrics.phr = SRSLTE_VEC_CMA(phr, metrics.phr, phr_counter);
phr_counter++;
phr_counter++;
}
void ue::metrics_dl_cqi(uint32_t dl_cqi) {
metrics.dl_cqi = SRSLTE_VEC_CMA((float) dl_cqi, metrics.dl_cqi, dl_cqi_counter);
dl_cqi_counter++;
}
void ue::metrics_rx(bool crc, uint32_t tbs)

@ -373,6 +373,7 @@ int main(int argc, char *argv[])
pthread_cancel(input);
metrics.stop();
enb->stop();
enb->cleanup();
cout << "--- exiting ---" << endl;
exit(0);
}

@ -108,8 +108,8 @@ void metrics_stdout::print_metrics()
{
n_reports = 0;
cout << endl;
cout << "------DL-------------------UL----------------" << endl;
cout << "rnti mcs brate bler snr phr turbo mcs brate bler" << endl;
cout << "------DL-------------------------UL-------------------------------" << endl;
cout << "rnti cqi mcs brate bler snr phr mcs brate bler bsr" << endl;
}
if (metrics.rrc.n_ues > 0) {
@ -122,6 +122,7 @@ void metrics_stdout::print_metrics()
}
cout << std::hex << metrics.mac[i].rnti << " ";
cout << float_to_string(metrics.mac[i].dl_cqi, 2);
cout << float_to_string(metrics.phy[i].dl.mcs, 2);
if (metrics.mac[i].tx_brate > 0 && metrics_report_period) {
cout << float_to_eng_string((float) metrics.mac[i].tx_brate/metrics_report_period, 2);
@ -135,7 +136,6 @@ void metrics_stdout::print_metrics()
}
cout << float_to_string(metrics.phy[i].ul.sinr, 2);
cout << float_to_string(metrics.mac[i].phr, 2);
cout << float_to_string(metrics.phy[i].ul.turbo_iters, 2);
cout << float_to_string(metrics.phy[i].ul.mcs, 2);
if (metrics.mac[i].rx_brate > 0 && metrics_report_period) {
cout << float_to_eng_string((float) metrics.mac[i].rx_brate/metrics_report_period, 2);
@ -147,6 +147,7 @@ void metrics_stdout::print_metrics()
} else {
cout << float_to_string(0, 2) << "%";
}
cout << float_to_eng_string(metrics.mac[i].ul_buffer, 2);
cout << endl;
}
} else {

@ -644,7 +644,7 @@ int phch_worker::encode_pdsch(srslte_enb_dl_pdsch_t *grants, uint32_t nof_grants
if (LOG_THIS(rnti)) {
uint8_t x = 0;
uint8_t *ptr = grants[i].data;
uint32_t len = phy_grant.mcs.tbs/8;
uint32_t len = phy_grant.mcs[0].tbs / (uint32_t) 8;
if (!ptr) {
ptr = &x;
len = 1;
@ -652,17 +652,18 @@ int phch_worker::encode_pdsch(srslte_enb_dl_pdsch_t *grants, uint32_t nof_grants
log_h->info_hex(ptr, len,
"PDSCH: rnti=0x%x, l_crb=%2d, %s, harq=%d, tbs=%d, mcs=%d, rv=%d, tti_tx=%d\n",
rnti, phy_grant.nof_prb, grant_str, grants[i].grant.harq_process,
phy_grant.mcs.tbs/8, phy_grant.mcs.idx, grants[i].grant.rv_idx, tti_tx);
phy_grant.mcs[0].tbs/8, phy_grant.mcs[0].idx, grants[i].grant.rv_idx, tti_tx);
}
if (srslte_enb_dl_put_pdsch(&enb_dl, &phy_grant, grants[i].softbuffer, rnti, grants[i].grant.rv_idx, sf_idx,
grants[i].data))
srslte_softbuffer_tx_t *sb[SRSLTE_MAX_CODEWORDS] = {grants[i].softbuffer, NULL};
uint8_t *d[SRSLTE_MAX_CODEWORDS] = {grants[i].data, NULL};
if (srslte_enb_dl_put_pdsch(&enb_dl, &phy_grant, sb, rnti, grants[i].grant.rv_idx, sf_idx, d))
{
fprintf(stderr, "Error putting PDSCH %d\n",i);
return SRSLTE_ERROR;
}
// Save metrics stats
ue_db[rnti].metrics_dl(phy_grant.mcs.idx);
ue_db[rnti].metrics_dl(phy_grant.mcs[0].idx);
}
}
return SRSLTE_SUCCESS;

@ -84,20 +84,20 @@ public:
harq_pid = grant.pid%N;
}
if (grant.rnti_type == SRSLTE_RNTI_TEMP && last_temporal_crnti != grant.rnti) {
grant.ndi = true;
grant.ndi[0] = true;
Info("Set NDI=1 for Temp-RNTI DL grant\n");
last_temporal_crnti = grant.rnti;
}
if (grant.rnti_type == SRSLTE_RNTI_USER && proc[harq_pid].is_sps()) {
grant.ndi = true;
grant.ndi[0] = true;
Info("Set NDI=1 for C-RNTI DL grant\n");
}
proc[harq_pid].new_grant_dl(grant, action);
} else {
/* This is for SPS scheduling */
uint32_t harq_pid = get_harq_sps_pid(grant.tti)%N;
if (grant.ndi) {
grant.ndi = false;
if (grant.ndi[0]) {
grant.ndi[0] = false;
proc[harq_pid].new_grant_dl(grant, action);
} else {
if (grant.is_sps_release) {
@ -117,12 +117,12 @@ public:
}
void tb_decoded(bool ack, srslte_rnti_type_t rnti_type, uint32_t harq_pid)
void tb_decoded(bool ack, uint32_t tb_idx, srslte_rnti_type_t rnti_type, uint32_t harq_pid)
{
if (rnti_type == SRSLTE_RNTI_SI) {
proc[N].tb_decoded(ack);
proc[N].tb_decoded(ack, 0);
} else {
proc[harq_pid%N].tb_decoded(ack);
proc[harq_pid%N].tb_decoded(ack, tb_idx);
}
}
@ -137,200 +137,238 @@ public:
void start_pcap(srslte::mac_pcap* pcap_) { pcap = pcap_; }
int get_current_tbs(uint32_t harq_pid) { return proc[harq_pid%N].get_current_tbs(); }
int get_current_tbs(uint32_t harq_pid, uint32_t tb_idx) { return proc[harq_pid%N].get_current_tbs(tb_idx); }
void set_si_window_start(int si_window_start_) { si_window_start = si_window_start_; }
float get_average_retx() { return average_retx; }
private:
private:
class dl_harq_process {
public:
dl_harq_process()
{
is_initiated = false;
ack = false;
bzero(&cur_grant, sizeof(Tgrant));
dl_harq_process() : subproc(SRSLTE_MAX_TB) {
}
bool init(uint32_t pid_, dl_harq_entity *parent)
{
if (srslte_softbuffer_rx_init(&softbuffer, 110)) {
Error("Error initiating soft buffer\n");
return false;
} else {
pid = pid_;
is_initiated = true;
harq_entity = parent;
log_h = harq_entity->log_h;
return true;
bool init(uint32_t pid_, dl_harq_entity *parent) {
bool ret = true;
for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) {
ret &= subproc[tb].init(pid_, parent, tb);
}
return ret;
}
void reset()
{
ack = false;
payload_buffer_ptr = NULL;
bzero(&cur_grant, sizeof(Tgrant));
if (is_initiated) {
srslte_softbuffer_rx_reset(&softbuffer);
void reset(void) {
for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) {
subproc[tb].reset();
}
}
void new_grant_dl(Tgrant grant, Taction *action)
{
// Compute RV for BCCH when not specified in PDCCH format
if (pid == HARQ_BCCH_PID && grant.rv == -1) {
uint32_t k;
if ((grant.tti/10)%2 == 0 && grant.tti%10 == 5) { // This is SIB1, k is different
k = (grant.tti/20)%4;
grant.rv = ((uint32_t) ceilf((float)1.5*k))%4;
} else if (grant.rv == -1) {
k = (grant.tti-harq_entity->si_window_start)%4;
grant.rv = ((uint32_t) ceilf((float)1.5*k))%4;
}
}
calc_is_new_transmission(grant);
if (is_new_transmission) {
ack = false;
srslte_softbuffer_rx_reset_tbs(&softbuffer, cur_grant.n_bytes*8);
n_retx = 0;
void new_grant_dl(Tgrant grant, Taction *action) {
for (uint32_t tb = 0; tb < grant.phy_grant.dl.nof_tb; tb++) {
subproc[tb].new_grant_dl(grant, action);
}
// Save grant
grant.last_ndi = cur_grant.ndi;
grant.last_tti = cur_grant.tti;
memcpy(&cur_grant, &grant, sizeof(Tgrant));
// Fill action structure
bzero(action, sizeof(Taction));
action->default_ack = ack;
action->generate_ack = true;
action->decode_enabled = false;
// If data has not yet been successfully decoded
if (ack == false) {
// Instruct the PHY To combine the received data and attempt to decode it
payload_buffer_ptr = harq_entity->demux_unit->request_buffer(pid, cur_grant.n_bytes);
action->payload_ptr = payload_buffer_ptr;
if (!action->payload_ptr) {
action->decode_enabled = false;
Error("Can't get a buffer for TBS=%d\n", cur_grant.n_bytes);
return;
}
action->decode_enabled = true;
action->rv = cur_grant.rv;
action->rnti = cur_grant.rnti;
action->softbuffer = &softbuffer;
memcpy(&action->phy_grant, &cur_grant.phy_grant, sizeof(Tphygrant));
n_retx++;
} else {
Warning("DL PID %d: Received duplicate TB. Discarting and retransmitting ACK\n", pid);
}
int get_current_tbs(uint32_t tb_idx) { return subproc[tb_idx].get_current_tbs(); }
bool is_sps() { return false; }
void tb_decoded(bool ack_, uint32_t tb_idx) {
subproc[tb_idx].tb_decoded(ack_);
}
private:
class dl_tb_process {
public:
dl_tb_process(void) {
is_initiated = false;
ack = false;
bzero(&cur_grant, sizeof(Tgrant));
}
if (pid == HARQ_BCCH_PID || harq_entity->timers_db->get(TIME_ALIGNMENT)->is_expired()) {
// Do not generate ACK
Debug("Not generating ACK\n");
action->generate_ack = false;
} else {
if (cur_grant.rnti_type == SRSLTE_RNTI_TEMP && ack == false) {
// Postpone ACK after contention resolution is resolved
action->generate_ack_callback = harq_entity->generate_ack_callback;
action->generate_ack_callback_arg = harq_entity->demux_unit;
Debug("ACK pending contention resolution\n");
bool init(uint32_t pid_, dl_harq_entity *parent, uint32_t tb_idx) {
tid = tb_idx;
if (srslte_softbuffer_rx_init(&softbuffer, 110)) {
Error("Error initiating soft buffer\n");
return false;
} else {
Debug("Generating ACK\n");
pid = pid_;
is_initiated = true;
harq_entity = parent;
log_h = harq_entity->log_h;
return true;
}
}
}
void tb_decoded(bool ack_)
{
ack = ack_;
if (ack == true) {
if (pid == HARQ_BCCH_PID) {
if (harq_entity->pcap) {
harq_entity->pcap->write_dl_sirnti(payload_buffer_ptr, cur_grant.n_bytes, ack, cur_grant.tti);
void reset(void) {
ack = false;
payload_buffer_ptr = NULL;
bzero(&cur_grant, sizeof(Tgrant));
if (is_initiated) {
srslte_softbuffer_rx_reset(&softbuffer);
}
}
void new_grant_dl(Tgrant grant, Taction *action) {
// Compute RV for BCCH when not specified in PDCCH format
if (pid == HARQ_BCCH_PID && grant.rv[tid] == -1) {
uint32_t k;
if ((grant.tti / 10) % 2 == 0 && grant.tti % 10 == 5) { // This is SIB1, k is different
k = (grant.tti / 20) % 4;
grant.rv[tid] = ((uint32_t) ceilf((float) 1.5 * k)) % 4;
} else if (grant.rv[tid] == -1) {
k = (grant.tti - harq_entity->si_window_start) % 4;
grant.rv[tid] = ((uint32_t) ceilf((float) 1.5 * k)) % 4;
}
Debug("Delivering PDU=%d bytes to Dissassemble and Demux unit (BCCH)\n", cur_grant.n_bytes);
harq_entity->demux_unit->push_pdu(pid, payload_buffer_ptr, cur_grant.n_bytes, cur_grant.tti);
} else {
if (harq_entity->pcap) {
harq_entity->pcap->write_dl_crnti(payload_buffer_ptr, cur_grant.n_bytes, cur_grant.rnti, ack, cur_grant.tti);
}
calc_is_new_transmission(grant);
if (is_new_transmission) {
ack = false;
srslte_softbuffer_rx_reset_tbs(&softbuffer, cur_grant.n_bytes[tid] * 8);
n_retx = 0;
}
// Save grant
grant.last_ndi[tid] = cur_grant.ndi[tid];
grant.last_tti = cur_grant.tti;
memcpy(&cur_grant, &grant, sizeof(Tgrant));
// Fill action structure
bzero(action, sizeof(Taction));
action->default_ack = ack;
action->generate_ack = true;
action->decode_enabled = false;
// If data has not yet been successfully decoded
if (!ack) {
// Instruct the PHY To combine the received data and attempt to decode it
payload_buffer_ptr = harq_entity->demux_unit->request_buffer(pid * SRSLTE_MAX_TB + tid,
cur_grant.n_bytes[tid]);
action->payload_ptr[tid] = payload_buffer_ptr;
if (!action->payload_ptr) {
action->decode_enabled = false;
Error("Can't get a buffer for TBS=%d\n", cur_grant.n_bytes[tid]);
return;
}
if (ack) {
if (cur_grant.rnti_type == SRSLTE_RNTI_TEMP) {
Debug("Delivering PDU=%d bytes to Dissassemble and Demux unit (Temporal C-RNTI)\n", cur_grant.n_bytes);
harq_entity->demux_unit->push_pdu_temp_crnti(payload_buffer_ptr, cur_grant.n_bytes);
} else {
Debug("Delivering PDU=%d bytes to Dissassemble and Demux unit\n", cur_grant.n_bytes);
harq_entity->demux_unit->push_pdu(pid, payload_buffer_ptr, cur_grant.n_bytes, cur_grant.tti);
// Compute average number of retransmissions per packet
harq_entity->average_retx = SRSLTE_VEC_CMA((float) n_retx, harq_entity->average_retx, harq_entity->nof_pkts++);
}
action->decode_enabled = true;
action->rv[tid] = cur_grant.rv[tid];
action->rnti = cur_grant.rnti;
action->softbuffers[tid] = &softbuffer;
memcpy(&action->phy_grant, &cur_grant.phy_grant, sizeof(Tphygrant));
n_retx++;
} else {
Warning("DL PID %d: Received duplicate TB. Discarting and retransmitting ACK\n", pid);
}
if (pid == HARQ_BCCH_PID || harq_entity->timers_db->get(TIME_ALIGNMENT)->is_expired()) {
// Do not generate ACK
Debug("Not generating ACK\n");
action->generate_ack = false;
} else {
if (cur_grant.rnti_type == SRSLTE_RNTI_TEMP && !ack) {
// Postpone ACK after contention resolution is resolved
action->generate_ack_callback = harq_entity->generate_ack_callback;
action->generate_ack_callback_arg = harq_entity->demux_unit;
Debug("ACK pending contention resolution\n");
} else {
Debug("Generating ACK\n");
}
}
} else {
harq_entity->demux_unit->deallocate(payload_buffer_ptr);
}
Info("DL %d: %s tbs=%d, rv=%d, ack=%s, ndi=%d (%d), tti=%d (%d)\n",
pid, is_new_transmission?"newTX":"reTX ",
cur_grant.n_bytes, cur_grant.rv, ack?"OK":"KO",
cur_grant.ndi, cur_grant.last_ndi, cur_grant.tti, cur_grant.last_tti);
if (ack && pid == HARQ_BCCH_PID) {
reset();
}
}
bool is_sps() { return false; }
void tb_decoded(bool ack_) {
ack = ack_;
if (ack) {
if (pid == HARQ_BCCH_PID) {
if (harq_entity->pcap) {
harq_entity->pcap->write_dl_sirnti(payload_buffer_ptr, cur_grant.n_bytes[tid], ack, cur_grant.tti);
}
Debug("Delivering PDU=%d bytes to Dissassemble and Demux unit (BCCH)\n", cur_grant.n_bytes[tid]);
harq_entity->demux_unit->push_pdu(pid * SRSLTE_MAX_TB + tid, payload_buffer_ptr, cur_grant.n_bytes[tid],
cur_grant.tti);
} else {
if (harq_entity->pcap) {
harq_entity->pcap->write_dl_crnti(payload_buffer_ptr, cur_grant.n_bytes[tid], cur_grant.rnti, ack,
cur_grant.tti);
}
if (ack) {
if (cur_grant.rnti_type == SRSLTE_RNTI_TEMP) {
Debug("Delivering PDU=%d bytes to Dissassemble and Demux unit (Temporal C-RNTI)\n",
cur_grant.n_bytes[tid]);
harq_entity->demux_unit->push_pdu_temp_crnti(payload_buffer_ptr, cur_grant.n_bytes[tid]);
} else {
Debug("Delivering PDU=%d bytes to Dissassemble and Demux unit\n", cur_grant.n_bytes[tid]);
harq_entity->demux_unit->push_pdu(pid * SRSLTE_MAX_TB + tid, payload_buffer_ptr, cur_grant.n_bytes[tid],
cur_grant.tti);
int get_current_tbs() { return cur_grant.n_bytes*8; }
private:
bool calc_is_new_transmission(Tgrant grant)
{
bool is_new_tb = true;
if ((srslte_tti_interval(grant.tti, cur_grant.tti) <= 8 && (grant.n_bytes == cur_grant.n_bytes)) ||
pid == HARQ_BCCH_PID)
{
is_new_tb = false;
// Compute average number of retransmissions per packet
harq_entity->average_retx = SRSLTE_VEC_CMA((float) n_retx, harq_entity->average_retx,
harq_entity->nof_pkts++);
}
}
}
} else {
harq_entity->demux_unit->deallocate(payload_buffer_ptr);
}
Info("DL %d (TB %d): %s tbs=%d, rv=%d, ack=%s, ndi=%d (%d), tti=%d (%d)\n",
pid, tid, is_new_transmission ? "newTX" : "reTX ",
cur_grant.n_bytes[tid], cur_grant.rv[tid], ack ? "OK" : "KO",
cur_grant.ndi[tid], cur_grant.last_ndi[tid], cur_grant.tti, cur_grant.last_tti);
if (ack && pid == HARQ_BCCH_PID) {
reset();
}
}
if ((grant.ndi != cur_grant.ndi && !is_new_tb) || // NDI toggled for same TB
is_new_tb || // is new TB
(pid == HARQ_BCCH_PID && grant.rv == 0)) // Broadcast PID and 1st TX (RV=0)
{
is_new_transmission = true;
Debug("Set HARQ for new transmission\n");
} else {
is_new_transmission = false;
Debug("Set HARQ for retransmission\n");
int get_current_tbs(void) { return cur_grant.n_bytes[tid] * 8; }
private:
bool calc_is_new_transmission(Tgrant grant) {
bool is_new_tb = true;
if ((srslte_tti_interval(grant.tti, cur_grant.tti) <= 8 && (grant.n_bytes[tid] == cur_grant.n_bytes[tid])) ||
pid == HARQ_BCCH_PID) {
is_new_tb = false;
}
if ((grant.ndi[tid] != cur_grant.ndi[tid] && !is_new_tb) || // NDI toggled for same TB
is_new_tb || // is new TB
(pid == HARQ_BCCH_PID && grant.rv[tid] == 0)) // Broadcast PID and 1st TX (RV=0)
{
is_new_transmission = true;
Debug("Set HARQ for new transmission\n");
} else {
is_new_transmission = false;
Debug("Set HARQ for retransmission\n");
}
return is_new_transmission;
}
return is_new_transmission;
}
bool is_initiated;
dl_harq_entity *harq_entity;
srslte::log *log_h;
bool is_initiated;
dl_harq_entity *harq_entity;
srslte::log *log_h;
bool is_new_transmission;
uint32_t pid;
uint8_t *payload_buffer_ptr;
bool ack;
uint32_t n_retx;
Tgrant cur_grant;
srslte_softbuffer_rx_t softbuffer;
bool is_new_transmission;
uint32_t pid; /* HARQ Proccess ID */
uint32_t tid; /* Transport block ID */
uint8_t *payload_buffer_ptr;
bool ack;
uint32_t n_retx;
Tgrant cur_grant;
srslte_softbuffer_rx_t softbuffer;
};
/* Transport blocks */
std::vector<dl_tb_process> subproc;
};
// Private members of dl_harq_entity
static bool generate_ack_callback(void *arg)

@ -65,7 +65,7 @@ public:
void new_grant_ul_ack(mac_grant_t grant, bool ack, tb_action_ul_t *action);
void harq_recv(uint32_t tti, bool ack, tb_action_ul_t *action);
void new_grant_dl(mac_grant_t grant, tb_action_dl_t *action);
void tb_decoded(bool ack, srslte_rnti_type_t rnti_type, uint32_t harq_pid);
void tb_decoded(bool ack, uint32_t tb_idx, srslte_rnti_type_t rnti_type, uint32_t harq_pid);
void bch_decoded_ok(uint8_t *payload, uint32_t len);
void pch_decoded_ok(uint32_t len);
void tti_clock(uint32_t tti);

@ -113,12 +113,12 @@ public:
grant.rnti_type == SRSLTE_RNTI_RAR)
{
if (grant.rnti_type == SRSLTE_RNTI_USER && proc[pidof(grant.tti)].is_sps()) {
grant.ndi = true;
grant.ndi[0] = true;
}
run_tti(grant.tti, &grant, action);
} else if (grant.rnti_type == SRSLTE_RNTI_SPS) {
if (grant.ndi) {
grant.ndi = proc[pidof(grant.tti)].get_ndi();
if (grant.ndi[0]) {
grant.ndi[0] = proc[pidof(grant.tti)].get_ndi();
run_tti(grant.tti, &grant, action);
} else {
Info("Not implemented\n");
@ -208,7 +208,7 @@ private:
// Receive and route HARQ feedbacks
if (grant) {
if ((!(grant->rnti_type == SRSLTE_RNTI_TEMP) && grant->ndi != get_ndi()) ||
if ((!(grant->rnti_type == SRSLTE_RNTI_TEMP) && grant->ndi[0] != get_ndi()) ||
(grant->rnti_type == SRSLTE_RNTI_USER && !has_grant()) ||
grant->is_from_rar)
{
@ -216,8 +216,8 @@ private:
// Uplink grant in a RAR
if (grant->is_from_rar) {
Debug("Getting Msg3 buffer payload, grant size=%d bytes\n", grant->n_bytes);
pdu_ptr = harq_entity->mux_unit->msg3_get(payload_buffer, grant->n_bytes);
Debug("Getting Msg3 buffer payload, grant size=%d bytes\n", grant->n_bytes[0]);
pdu_ptr = harq_entity->mux_unit->msg3_get(payload_buffer, grant->n_bytes[0]);
if (pdu_ptr) {
generate_new_tx(tti_tx, true, grant, action);
} else {
@ -227,7 +227,7 @@ private:
// Normal UL grant
} else {
// Request a MAC PDU from the Multiplexing & Assemble Unit
pdu_ptr = harq_entity->mux_unit->pdu_get(payload_buffer, grant->n_bytes, tti_tx, pid);
pdu_ptr = harq_entity->mux_unit->pdu_get(payload_buffer, grant->n_bytes[0], tti_tx, pid);
if (pdu_ptr) {
generate_new_tx(tti_tx, false, grant, action);
} else {
@ -258,7 +258,7 @@ private:
if (grant->is_from_rar) {
grant->rnti = harq_entity->rntis->temp_rnti;
}
harq_entity->pcap->write_ul_crnti(pdu_ptr, grant->n_bytes, grant->rnti, get_nof_retx(), tti_tx);
harq_entity->pcap->write_ul_crnti(pdu_ptr, grant->n_bytes[0], grant->rnti, get_nof_retx(), tti_tx);
}
}
@ -285,7 +285,7 @@ private:
bool is_sps() { return false; }
uint32_t last_tx_tti() { return tti_last_tx; }
uint32_t get_nof_retx() { return current_tx_nb; }
int get_current_tbs() { return cur_grant.n_bytes*8; }
int get_current_tbs() { return cur_grant.n_bytes[0]*8; }
private:
Tgrant cur_grant;
@ -321,16 +321,16 @@ private:
if (grant) {
// HARQ entity requests an adaptive transmission
if (grant->rv) {
current_irv = irv_of_rv[grant->rv%4];
current_irv = irv_of_rv[grant->rv[0]%4];
}
memcpy(&cur_grant, grant, sizeof(Tgrant));
harq_feedback = false;
Info("UL %d: Adaptive retx=%d, RV=%d, TBS=%d\n",
pid, current_tx_nb, get_rv(), grant->n_bytes);
pid, current_tx_nb, get_rv(), grant->n_bytes[0]);
generate_tx(tti_tx, action);
} else {
Info("UL %d: Non-Adaptive retx=%d, RV=%d, TBS=%d\n",
pid, current_tx_nb, get_rv(), cur_grant.n_bytes);
pid, current_tx_nb, get_rv(), cur_grant.n_bytes[0]);
// HARQ entity requests a non-adaptive transmission
if (!harq_feedback) {
generate_tx(tti_tx, action);
@ -358,7 +358,7 @@ private:
current_irv = 0;
is_msg3 = is_msg3_;
Info("UL %d: New TX%s, RV=%d, TBS=%d, RNTI=%d\n",
pid, is_msg3?" for Msg3":"", get_rv(), cur_grant.n_bytes, cur_grant.rnti);
pid, is_msg3?" for Msg3":"", get_rv(), cur_grant.n_bytes[0], cur_grant.rnti);
generate_tx(tti_tx, action);
}
}
@ -370,10 +370,10 @@ private:
current_tx_nb++;
action->expect_ack = true;
action->rnti = is_msg3?harq_entity->rntis->temp_rnti:cur_grant.rnti;
action->rv = cur_grant.rv>0?cur_grant.rv:get_rv();
action->softbuffer = &softbuffer;
action->rv[0] = cur_grant.rv[0]>0?cur_grant.rv[0]:get_rv();
action->softbuffers = &softbuffer;
action->tx_enabled = true;
action->payload_ptr = pdu_ptr;
action->payload_ptr[0] = pdu_ptr;
memcpy(&action->phy_grant, &cur_grant.phy_grant, sizeof(Tphygrant));
current_irv = (current_irv+1)%4;

@ -78,8 +78,15 @@ private:
/* ... for DL */
bool decode_pdcch_ul(mac_interface_phy::mac_grant_t *grant);
bool decode_pdcch_dl(mac_interface_phy::mac_grant_t *grant);
bool decode_phich(bool *ack);
bool decode_pdsch(srslte_ra_dl_grant_t *grant, uint8_t *payload, srslte_softbuffer_rx_t* softbuffer, int rv, uint16_t rnti, uint32_t pid);
bool decode_phich(bool *ack);
int decode_pdsch(srslte_ra_dl_grant_t *grant,
uint8_t *payload[SRSLTE_MAX_CODEWORDS],
srslte_softbuffer_rx_t *softbuffers[SRSLTE_MAX_CODEWORDS],
int rv[SRSLTE_MAX_CODEWORDS],
uint16_t rnti,
uint32_t pid,
bool acks[SRSLTE_MAX_CODEWORDS]);
/* ... for UL */
void encode_pusch(srslte_ra_ul_grant_t *grant, uint8_t *payload, uint32_t current_tx_nb, srslte_softbuffer_tx_t *softbuffer,
@ -90,7 +97,7 @@ private:
void set_uci_sr();
void set_uci_periodic_cqi();
void set_uci_aperiodic_cqi();
void set_uci_ack(bool ack);
void set_uci_ack(bool ack[SRSLTE_MAX_CODEWORDS], uint32_t nof_tb);
bool srs_is_ready_to_send();
float set_power(float tx_power);
void setup_tx_gain();

@ -44,7 +44,7 @@ namespace srsue {
mac::mac() : ttisync(10240),
timers_db((uint32_t) NOF_MAC_TIMERS),
mux_unit(MAC_NOF_HARQ_PROC),
demux_unit(MAC_NOF_HARQ_PROC),
demux_unit(SRSLTE_MAX_TB*MAC_NOF_HARQ_PROC),
pdu_process_thread(&demux_unit)
{
started = false;
@ -240,17 +240,17 @@ void mac::pch_decoded_ok(uint32_t len)
}
}
void mac::tb_decoded(bool ack, srslte_rnti_type_t rnti_type, uint32_t harq_pid)
void mac::tb_decoded(bool ack, uint32_t tb_idx, srslte_rnti_type_t rnti_type, uint32_t harq_pid)
{
if (rnti_type == SRSLTE_RNTI_RAR) {
if (ack) {
ra_procedure.tb_decoded_ok();
}
} else {
dl_harq.tb_decoded(ack, rnti_type, harq_pid);
dl_harq.tb_decoded(ack, tb_idx, rnti_type, harq_pid);
if (ack) {
pdu_process_thread.notify();
metrics.rx_brate += dl_harq.get_current_tbs(harq_pid);
metrics.rx_brate += dl_harq.get_current_tbs(harq_pid, tb_idx);
} else {
metrics.rx_errors++;
}
@ -268,12 +268,12 @@ void mac::new_grant_dl(mac_interface_phy::mac_grant_t grant, mac_interface_phy::
action->generate_ack = false;
action->decode_enabled = true;
srslte_softbuffer_rx_reset_cb(&pch_softbuffer, 1);
action->payload_ptr = pch_payload_buffer;
action->softbuffer = &pch_softbuffer;
action->payload_ptr[0] = pch_payload_buffer;
action->softbuffers[0] = &pch_softbuffer;
action->rnti = grant.rnti;
action->rv = grant.rv;
if (grant.n_bytes > pch_payload_buffer_sz) {
Error("Received grant for PCH (%d bytes) exceeds buffer (%d bytes)\n", grant.n_bytes, pch_payload_buffer_sz);
action->rv[0] = grant.rv[0];
if (grant.n_bytes[0] > pch_payload_buffer_sz) {
Error("Received grant for PCH (%d bytes) exceeds buffer (%d bytes)\n", grant.n_bytes[0], pch_payload_buffer_sz);
action->decode_enabled = false;
}
} else {

@ -269,23 +269,23 @@ void ra_proc::step_pdcch_setup() {
void ra_proc::new_grant_dl(mac_interface_phy::mac_grant_t grant, mac_interface_phy::tb_action_dl_t* action)
{
if (grant.n_bytes < MAX_RAR_PDU_LEN) {
if (grant.n_bytes[0] < MAX_RAR_PDU_LEN) {
rDebug("DL grant found RA-RNTI=%d\n", ra_rnti);
action->decode_enabled = true;
action->default_ack = false;
action->generate_ack = false;
action->payload_ptr = rar_pdu_buffer;
action->payload_ptr[0] = rar_pdu_buffer;
action->rnti = grant.rnti;
memcpy(&action->phy_grant, &grant.phy_grant, sizeof(srslte_phy_grant_t));
action->rv = grant.rv;
action->softbuffer = &softbuffer_rar;
rar_grant_nbytes = grant.n_bytes;
action->rv[0] = grant.rv[0];
action->softbuffers[0] = &softbuffer_rar;
rar_grant_nbytes = grant.n_bytes[0];
rar_grant_tti = grant.tti;
if (action->rv == 0) {
if (action->rv[0] == 0) {
srslte_softbuffer_rx_reset(&softbuffer_rar);
}
} else {
rError("Received RAR grant exceeds buffer length (%d>%d)\n", grant.n_bytes, MAX_RAR_PDU_LEN);
rError("Received RAR grant exceeds buffer length (%d>%d)\n", grant.n_bytes[0], MAX_RAR_PDU_LEN);
action->decode_enabled = false;
state = RESPONSE_ERROR;
}

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save