Merge to next_with_matlab

master
Xavier Arteaga 8 years ago
parent fa741f24e7
commit 6142a5f9e5

@ -118,7 +118,7 @@ int parse_args(prog_args_t *args, int argc, char **argv) {
/**********************************************************************/ /**********************************************************************/
/* TODO: Do something with the output data */ /* TODO: Do something with the output data */
uint8_t data[1000000]; uint8_t *data[SRSLTE_MAX_CODEWORDS];
bool go_exit = false; bool go_exit = false;
void sig_int_handler(int signo) void sig_int_handler(int signo)
@ -183,6 +183,9 @@ int main(int argc, char **argv) {
} }
sf_buffer[0] = srslte_vec_malloc(3*sizeof(cf_t)*SRSLTE_SF_LEN_PRB(100)); 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; sigset_t sigset;
sigemptyset(&sigset); sigemptyset(&sigset);
@ -322,7 +325,7 @@ int main(int argc, char **argv) {
nof_trials++; nof_trials++;
} else { } else {
printf("Decoded SIB1. Payload: "); printf("Decoded SIB1. Payload: ");
srslte_vec_fprint_byte(stdout, data, n/8);; srslte_vec_fprint_byte(stdout, data[0], n/8);;
state = MEASURE; state = MEASURE;
} }
} }
@ -386,6 +389,12 @@ int main(int argc, char **argv) {
sf_cnt++; sf_cnt++;
} // Main loop } // Main loop
for (int i = 0; i < SRSLTE_MAX_CODEWORDS; i++) {
if (data[i]) {
free(data[i]);
}
}
srslte_ue_sync_free(&ue_sync); srslte_ue_sync_free(&ue_sync);
srslte_rf_close(&rf); srslte_rf_close(&rf);
printf("\nBye\n"); printf("\nBye\n");

@ -27,12 +27,12 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <strings.h>
#include <unistd.h> #include <unistd.h>
#include <sys/select.h>
#include <pthread.h> #include <pthread.h>
#include <semaphore.h> #include <semaphore.h>
#include <signal.h> #include <signal.h>
#include <srslte/phy/common/phy_common.h>
#include <srslte/phy/phch/pdsch_cfg.h>
#include "srslte/srslte.h" #include "srslte/srslte.h"
@ -59,8 +59,8 @@ srslte_cell_t cell = {
1, // nof_ports 1, // nof_ports
0, // cell_id 0, // cell_id
SRSLTE_CP_NORM, // cyclic prefix SRSLTE_CP_NORM, // cyclic prefix
SRSLTE_PHICH_R_1, // PHICH resources SRSLTE_PHICH_NORM, // PHICH length
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 int net_port = -1; // -1 generates random dataThat means there is some problem sending samples to the device
@ -68,6 +68,8 @@ int net_port = -1; // -1 generates random dataThat means there is some problem s
uint32_t cfi=3; uint32_t cfi=3;
uint32_t mcs_idx = 1, last_mcs_idx = 1; uint32_t mcs_idx = 1, last_mcs_idx = 1;
int nof_frames = -1; int nof_frames = -1;
char mimo_type_str[32] = "single";
uint32_t nof_tb = 1;
char *rf_args = ""; char *rf_args = "";
float rf_amp = 0.8, rf_gain = 70.0, rf_freq = 2400000000; float rf_amp = 0.8, rf_gain = 70.0, rf_freq = 2400000000;
@ -80,11 +82,11 @@ srslte_pcfich_t pcfich;
srslte_pdcch_t pdcch; srslte_pdcch_t pdcch;
srslte_pdsch_t pdsch; srslte_pdsch_t pdsch;
srslte_pdsch_cfg_t pdsch_cfg; srslte_pdsch_cfg_t pdsch_cfg;
srslte_softbuffer_tx_t softbuffer; srslte_softbuffer_tx_t softbuffers[SRSLTE_MAX_CODEWORDS];
srslte_regs_t regs; srslte_regs_t regs;
srslte_ra_dl_dci_t ra_dl; srslte_ra_dl_dci_t ra_dl;
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; int sf_n_re, sf_n_samples;
pthread_t net_thread; pthread_t net_thread;
@ -99,7 +101,7 @@ int prbset_orig = 0;
void usage(char *prog) { void usage(char *prog) {
printf("Usage: %s [agmfoncvpu]\n", prog); printf("Usage: %s [agmfoncvpuM]\n", prog);
#ifndef DISABLE_RF #ifndef DISABLE_RF
printf("\t-a RF args [Default %s]\n", rf_args); printf("\t-a RF args [Default %s]\n", rf_args);
printf("\t-l RF amplitude [Default %.2f]\n", rf_amp); printf("\t-l RF amplitude [Default %.2f]\n", rf_amp);
@ -113,13 +115,14 @@ void usage(char *prog) {
printf("\t-n number of frames [Default %d]\n", nof_frames); printf("\t-n number of frames [Default %d]\n", nof_frames);
printf("\t-c cell id [Default %d]\n", cell.id); printf("\t-c cell id [Default %d]\n", cell.id);
printf("\t-p nof_prb [Default %d]\n", cell.nof_prb); printf("\t-p nof_prb [Default %d]\n", cell.nof_prb);
printf("\t-M Transmission mode[single|diversity|cdd] [Default %s]\n", mimo_type_str);
printf("\t-u listen TCP port for input data (-1 is random) [Default %d]\n", net_port); 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("\t-v [set srslte_verbose to debug, default none]\n");
} }
void parse_args(int argc, char **argv) { void parse_args(int argc, char **argv) {
int opt; int opt;
while ((opt = getopt(argc, argv, "aglfmoncpvu")) != -1) { while ((opt = getopt(argc, argv, "aglfmoncpvutM")) != -1) {
switch (opt) { switch (opt) {
case 'a': case 'a':
rf_args = argv[optind]; rf_args = argv[optind];
@ -151,6 +154,9 @@ void parse_args(int argc, char **argv) {
case 'c': case 'c':
cell.id = atoi(argv[optind]); cell.id = atoi(argv[optind]);
break; break;
case 'M':
strncpy(mimo_type_str, argv[optind], 32);
break;
case 'v': case 'v':
srslte_verbose++; srslte_verbose++;
break; break;
@ -168,18 +174,54 @@ void parse_args(int argc, char **argv) {
} }
void base_init() { void base_init() {
int i;
/* Select transmission mode */
if (srslte_str2mimotype(mimo_type_str, &pdsch_cfg.mimo_type)) {
ERROR("Wrong transmission mode! Allowed modes: single, diversity, cdd");
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;
pdsch_cfg.nof_layers = 1;
nof_tb = 1;
break;
case SRSLTE_MIMO_TYPE_TX_DIVERSITY:
cell.nof_ports = 2;
pdsch_cfg.nof_layers = 2;
nof_tb = 1;
break;
case SRSLTE_MIMO_TYPE_CDD:
cell.nof_ports = 2;
pdsch_cfg.nof_layers = 2;
nof_tb = 2;
break;
default:
ERROR("Transmission mode not implemented.");
exit(-1);
}
/* init memory */ /* init memory */
sf_buffer = srslte_vec_malloc(sizeof(cf_t) * sf_n_re); for (i = 0; i < cell.nof_ports; i++) {
if (!sf_buffer) { sf_buffer[i] = srslte_vec_malloc(sizeof(cf_t) * sf_n_re);
if (!sf_buffer[i]) {
perror("malloc"); perror("malloc");
exit(-1); exit(-1);
} }
output_buffer = srslte_vec_malloc(sizeof(cf_t) * sf_n_samples); }
if (!output_buffer) {
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"); perror("malloc");
exit(-1); exit(-1);
} }
bzero(output_buffer[i], sizeof(cf_t) * sf_n_samples);
}
/* open file or USRP */ /* open file or USRP */
if (output_file_name) { if (output_file_name) {
if (strcmp(output_file_name, "NULL")) { if (strcmp(output_file_name, "NULL")) {
@ -194,7 +236,7 @@ void base_init() {
} else { } else {
#ifndef DISABLE_RF #ifndef DISABLE_RF
printf("Opening RF device...\n"); printf("Opening RF device...\n");
if (srslte_rf_open(&rf, rf_args)) { if (srslte_rf_open_multi2(&rf, rf_args, cell.nof_ports, 1)) {
fprintf(stderr, "Error opening rf\n"); fprintf(stderr, "Error opening rf\n");
exit(-1); exit(-1);
} }
@ -247,27 +289,32 @@ void base_init() {
exit(-1); exit(-1);
} }
if (srslte_pdcch_init(&pdcch, &regs, cell)) { if (srslte_pdcch_init_tx(&pdcch, &regs, cell)) {
fprintf(stderr, "Error creating PDCCH object\n"); fprintf(stderr, "Error creating PDCCH object\n");
exit(-1); exit(-1);
} }
if (srslte_pdsch_init(&pdsch, cell)) { bzero(&pdsch, sizeof(srslte_pdsch_t));
if (srslte_pdsch_init_tx_multi(&pdsch, cell)) {
fprintf(stderr, "Error creating PDSCH object\n"); fprintf(stderr, "Error creating PDSCH object\n");
exit(-1); exit(-1);
} }
srslte_pdsch_set_rnti(&pdsch, UE_CRNTI); srslte_pdsch_set_rnti(&pdsch, UE_CRNTI);
if (srslte_softbuffer_tx_init(&softbuffer, cell.nof_prb)) { for (i = 0; i < nof_tb; i++) {
if (srslte_softbuffer_tx_init(&softbuffers[i], cell.nof_prb)) {
fprintf(stderr, "Error initiating soft buffer\n"); fprintf(stderr, "Error initiating soft buffer\n");
exit(-1); exit(-1);
} }
}
} }
void base_free() { void base_free() {
int i;
srslte_softbuffer_tx_free(&softbuffer); for (i = 0; i < nof_tb; i++) {
srslte_softbuffer_tx_free(&softbuffers[i]);
}
srslte_pdsch_free(&pdsch); srslte_pdsch_free(&pdsch);
srslte_pdcch_free(&pdcch); srslte_pdcch_free(&pdcch);
srslte_regs_free(&regs); srslte_regs_free(&regs);
@ -275,11 +322,14 @@ void base_free() {
srslte_ofdm_tx_free(&ifft); srslte_ofdm_tx_free(&ifft);
if (sf_buffer) { for (i = 0; i < SRSLTE_MAX_PORTS; i++) {
free(sf_buffer); if (sf_buffer[i]) {
free(sf_buffer[i]);
}
if (output_buffer[i]) {
free(output_buffer[i]);
} }
if (output_buffer) {
free(output_buffer);
} }
if (output_file_name) { if (output_file_name) {
if (!null_file_sink) { if (!null_file_sink) {
@ -342,6 +392,13 @@ int update_radl() {
ra_dl.type0_alloc.rbg_bitmask = prbset_to_bitmask(); 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 = 0;
ra_dl.tb_en[1] = 1;
}
srslte_ra_pdsch_fprint(stdout, &ra_dl, cell.nof_prb); srslte_ra_pdsch_fprint(stdout, &ra_dl, cell.nof_prb);
srslte_ra_dl_grant_t dummy_grant; srslte_ra_dl_grant_t dummy_grant;
srslte_ra_nbits_t dummy_nbits; srslte_ra_nbits_t dummy_nbits;
@ -497,9 +554,9 @@ int main(int argc, char **argv) {
exit(-1); exit(-1);
} }
for (i = 0; i < SRSLTE_MAX_PORTS; i++) { // now there's only 1 port for (i = 0; i < SRSLTE_MAX_PORTS; i++) {
sf_symbols[i] = sf_buffer; sf_symbols[i] = sf_buffer[i%cell.nof_ports];
slot1_symbols[i] = &sf_buffer[SRSLTE_SLOT_LEN_RE(cell.nof_prb, cell.cp)]; slot1_symbols[i] = &sf_buffer[i%cell.nof_ports][SRSLTE_SLOT_LEN_RE(cell.nof_prb, cell.cp)];
} }
#ifndef DISABLE_RF #ifndef DISABLE_RF
@ -556,7 +613,9 @@ int main(int argc, char **argv) {
nf = 0; nf = 0;
bool send_data = false; bool send_data = false;
srslte_softbuffer_tx_reset(&softbuffer); for (i = 0; i < nof_tb; i++) {
srslte_softbuffer_tx_reset(&softbuffers[i]);
}
#ifndef DISABLE_RF #ifndef DISABLE_RF
bool start_of_burst = true; bool start_of_burst = true;
@ -564,15 +623,25 @@ int main(int argc, char **argv) {
while ((nf < nof_frames || nof_frames == -1) && !go_exit) { 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++) { 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) { if (sf_idx == 0 || sf_idx == 5) {
srslte_pss_put_slot(pss_signal, sf_buffer, cell.nof_prb, SRSLTE_CP_NORM); 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_buffer, cell.nof_prb, srslte_sss_put_slot(sf_idx ? sss_signal5 : sss_signal0, sf_symbols[0], cell.nof_prb,
SRSLTE_CP_NORM); 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); srslte_pbch_mib_pack(&cell, sfn, bch_payload);
if (sf_idx == 0) { if (sf_idx == 0) {
@ -606,10 +675,23 @@ int main(int argc, char **argv) {
} }
if (send_data) { if (send_data) {
srslte_dci_format_t dci_format = SRSLTE_DCI_FORMAT1;
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:
default:
fprintf(stderr, "Wrong MIMO configuration\n");
exit(SRSLTE_ERROR);
}
/* Encode PDCCH */ /* Encode PDCCH */
INFO("Putting DCI to location: n=%d, L=%d\n", locations[sf_idx][0].ncce, locations[sf_idx][0].L); 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)) { 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"); fprintf(stderr, "Error encoding DCI message\n");
exit(-1); exit(-1);
@ -618,13 +700,14 @@ int main(int argc, char **argv) {
/* Configure pdsch_cfg parameters */ /* Configure pdsch_cfg parameters */
srslte_ra_dl_grant_t grant; srslte_ra_dl_grant_t grant;
srslte_ra_dl_dci_to_grant(&ra_dl, cell.nof_prb, UE_CRNTI, &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_multi(&pdsch_cfg, cell, &grant, cfi, sf_idx, 0, 0)) {
fprintf(stderr, "Error configuring PDSCH\n"); fprintf(stderr, "Error configuring PDSCH\n");
exit(-1); exit(-1);
} }
/* Encode PDSCH */ /* Encode PDSCH */
if (srslte_pdsch_encode(&pdsch, &pdsch_cfg, &softbuffer, data, UE_CRNTI, sf_symbols)) { if (srslte_pdsch_encode_multi(&pdsch, &pdsch_cfg, softbuffers, (uint8_t*[2]){data, data}, UE_CRNTI,
sf_symbols)) {
fprintf(stderr, "Error encoding PDSCH\n"); fprintf(stderr, "Error encoding PDSCH\n");
exit(-1); exit(-1);
} }
@ -641,20 +724,23 @@ int main(int argc, char **argv) {
} }
/* Transform to OFDM symbols */ /* 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 */ /* send to file or usrp */
if (output_file_name) { if (output_file_name) {
if (!null_file_sink) { 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); usleep(1000);
} else { } else {
#ifndef DISABLE_RF #ifndef DISABLE_RF
// FIXME
float norm_factor = (float) cell.nof_prb/15/sqrtf(pdsch_cfg.grant.nof_prb); 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)); for (i = 0; i < cell.nof_ports; i++) {
srslte_rf_send2(&rf, output_buffer, sf_n_samples, true, start_of_burst, false); 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; start_of_burst=false;
#endif #endif
} }

@ -258,7 +258,7 @@ void parse_args(prog_args_t *args, int argc, char **argv) {
/**********************************************************************/ /**********************************************************************/
/* TODO: Do something with the output data */ /* TODO: Do something with the output data */
uint8_t data[20000]; uint8_t *data[SRSLTE_MAX_CODEWORDS];
bool go_exit = false; bool go_exit = false;
void sig_int_handler(int signo) void sig_int_handler(int signo)
@ -266,10 +266,12 @@ void sig_int_handler(int signo)
printf("SIGINT received. Exiting...\n"); printf("SIGINT received. Exiting...\n");
if (signo == SIGINT) { if (signo == SIGINT) {
go_exit = true; 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 #ifndef DISABLE_RF
int srslte_rf_recv_wrapper(void *h, cf_t *data[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte_timestamp_t *t) { int srslte_rf_recv_wrapper(void *h, cf_t *data[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte_timestamp_t *t) {
@ -315,6 +317,14 @@ int main(int argc, char **argv) {
parse_args(&prog_args, argc, argv); 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) { if(prog_args.cpu_affinity > -1) {
cpu_set_t cpuset; cpu_set_t cpuset;
@ -435,8 +445,8 @@ int main(int argc, char **argv) {
cell.nof_ports = prog_args.file_nof_ports; cell.nof_ports = prog_args.file_nof_ports;
cell.nof_prb = prog_args.file_nof_prb; cell.nof_prb = prog_args.file_nof_prb;
if (srslte_ue_sync_init_file(&ue_sync, prog_args.file_nof_prb, 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.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"); fprintf(stderr, "Error initiating ue_sync\n");
exit(-1); exit(-1);
} }
@ -498,7 +508,7 @@ int main(int argc, char **argv) {
// Variables for measurements // Variables for measurements
uint32_t nframes=0; uint32_t nframes=0;
float rsrp=0.0, rsrq=0.0, noise=0.0; float rsrp0=0.0, rsrp1=0.0, rsrq=0.0, noise=0.0;
bool decode_pdsch = false; bool decode_pdsch = false;
#ifndef DISABLE_RF #ifndef DISABLE_RF
@ -596,7 +606,8 @@ int main(int argc, char **argv) {
nof_trials++; nof_trials++;
rsrq = SRSLTE_VEC_EMA(srslte_chest_dl_get_rsrq(&ue_dl.chest), rsrq, 0.1); 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); rsrp0 = SRSLTE_VEC_EMA(srslte_chest_dl_get_rsrp_port(&ue_dl.chest, 0), rsrp0, 0.05);
rsrp1 = SRSLTE_VEC_EMA(srslte_chest_dl_get_rsrp_port(&ue_dl.chest, 1), rsrp1, 0.05);
noise = SRSLTE_VEC_EMA(srslte_chest_dl_get_noise_estimate(&ue_dl.chest), noise, 0.05); noise = SRSLTE_VEC_EMA(srslte_chest_dl_get_noise_estimate(&ue_dl.chest), noise, 0.05);
nframes++; nframes++;
if (isnan(rsrq)) { if (isnan(rsrq)) {
@ -605,8 +616,11 @@ int main(int argc, char **argv) {
if (isnan(noise)) { if (isnan(noise)) {
noise = 0; noise = 0;
} }
if (isnan(rsrp)) { if (isnan(rsrp0)) {
rsrp = 0; rsrp1 = 0;
}
if (isnan(rsrp0)) {
rsrp1 = 0;
} }
} }
@ -616,14 +630,27 @@ int main(int argc, char **argv) {
if (gain < 0) { if (gain < 0) {
gain = 10*log10(srslte_agc_get_gain(&ue_sync.agc)); gain = 10*log10(srslte_agc_get_gain(&ue_sync.agc));
} }
if (cell.nof_ports == 1) {
printf("CFO: %+6.2f kHz, " printf("CFO: %+6.2f kHz, "
"SNR: %4.1f dB, " "SNR: %4.1f dB, "
"PDCCH-Miss: %5.2f%%, PDSCH-BLER: %5.2f%%\r", "PDCCH-Miss: %5.2f%%, PDSCH-BLER: %5.2f%%\r",
srslte_ue_sync_get_cfo(&ue_sync)/1000, srslte_ue_sync_get_cfo(&ue_sync) / 1000,
10*log10(rsrp/noise), 10 * log10(rsrp0 / noise),
100*(1-(float) ue_dl.nof_detected/nof_trials), 100 * (1 - (float) ue_dl.nof_detected / nof_trials),
(float) 100*ue_dl.pkt_errors/ue_dl.pkts_total); (float) 100 * ue_dl.pkt_errors / ue_dl.pkts_total);
} else {
printf("CFO: %+6.2f kHz, "
"SNR port 0: %4.1f dB, "
"SNR port 1: %4.1f dB, "
"PDCCH-Miss: %5.2f%%, PDSCH-BLER: %5.2f%%\r",
srslte_ue_sync_get_cfo(&ue_sync) / 1000,
10 * log10(rsrp0 / noise),
10 * log10(rsrp1 / noise),
100 * (1 - (float) ue_dl.nof_detected / nof_trials),
(float) 100 * ue_dl.pkt_errors / ue_dl.pkts_total);
}
} }
break; break;
} }
@ -674,6 +701,16 @@ int main(int argc, char **argv) {
#endif #endif
srslte_ue_dl_free(&ue_dl); srslte_ue_dl_free(&ue_dl);
srslte_ue_sync_free(&ue_sync); 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 #ifndef DISABLE_RF
if (!prog_args.input_file_name) { if (!prog_args.input_file_name) {

@ -44,6 +44,7 @@ char *output_file_name;
char *rf_args=""; char *rf_args="";
float rf_gain=40.0, rf_freq=-1.0, rf_rate=0.96e6; float rf_gain=40.0, rf_freq=-1.0, rf_rate=0.96e6;
int nof_samples = -1; int nof_samples = -1;
int nof_rx_antennas = 1;
void int_handler(int dummy) { void int_handler(int dummy) {
keep_running = false; keep_running = false;
@ -55,12 +56,13 @@ void usage(char *prog) {
printf("\t-g RF Gain [Default %.2f dB]\n", rf_gain); printf("\t-g RF Gain [Default %.2f dB]\n", rf_gain);
printf("\t-r RF Rate [Default %.6f Hz]\n", rf_rate); printf("\t-r RF Rate [Default %.6f Hz]\n", rf_rate);
printf("\t-n nof_samples [Default %d]\n", nof_samples); 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"); printf("\t-v srslte_verbose\n");
} }
void parse_args(int argc, char **argv) { void parse_args(int argc, char **argv) {
int opt; int opt;
while ((opt = getopt(argc, argv, "agrnvfo")) != -1) { while ((opt = getopt(argc, argv, "agrnvfoA")) != -1) {
switch (opt) { switch (opt) {
case 'o': case 'o':
output_file_name = argv[optind]; output_file_name = argv[optind];
@ -80,6 +82,9 @@ void parse_args(int argc, char **argv) {
case 'n': case 'n':
nof_samples = atoi(argv[optind]); nof_samples = atoi(argv[optind]);
break; break;
case 'A':
nof_rx_antennas = atoi(argv[optind]);
break;
case 'v': case 'v':
srslte_verbose++; srslte_verbose++;
break; break;
@ -95,11 +100,11 @@ void parse_args(int argc, char **argv) {
} }
int main(int argc, char **argv) { int main(int argc, char **argv) {
cf_t *buffer; cf_t *buffer[SRSLTE_MAX_PORTS];
int sample_count, n; int sample_count, n;
srslte_rf_t rf; srslte_rf_t rf;
srslte_filesink_t sink; srslte_filesink_t sink;
int32_t buflen; uint32_t buflen;
signal(SIGINT, int_handler); signal(SIGINT, int_handler);
@ -108,16 +113,18 @@ int main(int argc, char **argv) {
buflen = 4800; buflen = 4800;
sample_count = 0; sample_count = 0;
buffer = malloc(sizeof(cf_t) * buflen); for (int i = 0; i < nof_rx_antennas; i++) {
if (!buffer) { buffer[i] = malloc(sizeof(cf_t) * buflen);
if (!buffer[i]) {
perror("malloc"); perror("malloc");
exit(-1); exit(-1);
} }
}
srslte_filesink_init(&sink, output_file_name, SRSLTE_COMPLEX_FLOAT_BIN); srslte_filesink_init(&sink, output_file_name, SRSLTE_COMPLEX_FLOAT_BIN);
printf("Opening RF device...\n"); 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"); fprintf(stderr, "Error opening rf\n");
exit(-1); exit(-1);
} }
@ -151,18 +158,23 @@ int main(int argc, char **argv) {
while((sample_count < nof_samples || nof_samples == -1) while((sample_count < nof_samples || nof_samples == -1)
&& keep_running){ && 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) { if (n < 0) {
fprintf(stderr, "Error receiving samples\n"); fprintf(stderr, "Error receiving samples\n");
exit(-1); exit(-1);
} }
srslte_filesink_write(&sink, buffer, buflen); srslte_filesink_write_multi(&sink, (void**) buffer, buflen, nof_rx_antennas);
sample_count += buflen; sample_count += buflen;
} }
for (int i = 0; i < nof_rx_antennas; i++) {
if (buffer[i]) {
free(buffer[i]);
}
}
srslte_filesink_free(&sink); srslte_filesink_free(&sink);
free(buffer);
srslte_rf_close(&rf); srslte_rf_close(&rf);
printf("Ok - wrote %d samples\n", sample_count); 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_prb = 6;
int nof_subframes = -1; int nof_subframes = -1;
int N_id_2 = -1; int N_id_2 = -1;
uint32_t nof_rx_antennas = 1;
void int_handler(int dummy) { void int_handler(int dummy) {
keep_running = false; keep_running = false;
@ -56,12 +57,13 @@ void usage(char *prog) {
printf("\t-g RF Gain [Default %.2f dB]\n", rf_gain); printf("\t-g RF Gain [Default %.2f dB]\n", rf_gain);
printf("\t-p nof_prb [Default %d]\n", nof_prb); printf("\t-p nof_prb [Default %d]\n", nof_prb);
printf("\t-n nof_subframes [Default %d]\n", nof_subframes); 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"); printf("\t-v verbose\n");
} }
void parse_args(int argc, char **argv) { void parse_args(int argc, char **argv) {
int opt; int opt;
while ((opt = getopt(argc, argv, "agpnvfol")) != -1) { while ((opt = getopt(argc, argv, "agpnvfolA")) != -1) {
switch (opt) { switch (opt) {
case 'o': case 'o':
output_file_name = argv[optind]; output_file_name = argv[optind];
@ -84,6 +86,9 @@ void parse_args(int argc, char **argv) {
case 'l': case 'l':
N_id_2 = atoi(argv[optind]); N_id_2 = atoi(argv[optind]);
break; break;
case 'A':
nof_rx_antennas = (uint32_t) atoi(argv[optind]);
break;
case 'v': case 'v':
srslte_verbose++; srslte_verbose++;
break; 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) { 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); 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) { 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); srslte_filesink_init(&sink, output_file_name, SRSLTE_COMPLEX_FLOAT_BIN);
printf("Opening RF device...\n"); 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"); fprintf(stderr, "Error opening rf\n");
exit(-1); exit(-1);
} }
srslte_rf_set_master_clock_rate(&rf, 30.72e6); 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; sigset_t sigset;
sigemptyset(&sigset); sigemptyset(&sigset);
@ -158,7 +165,7 @@ int main(int argc, char **argv) {
cell.nof_prb = nof_prb; cell.nof_prb = nof_prb;
cell.nof_ports = 1; cell.nof_ports = 1;
if (srslte_ue_sync_init_multi(&ue_sync, cell, srslte_rf_recv_wrapper, 1, (void*) &rf)) { if (srslte_ue_sync_init_multi(&ue_sync, cell, srslte_rf_recv_wrapper, nof_rx_antennas, (void*) &rf)) {
fprintf(stderr, "Error initiating ue_sync\n"); fprintf(stderr, "Error initiating ue_sync\n");
exit(-1); exit(-1);
} }
@ -181,7 +188,7 @@ int main(int argc, char **argv) {
} }
} else { } else {
printf("Writing to file %6d subframes...\r", subframe_count); 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++; subframe_count++;
} }
} }
@ -196,6 +203,12 @@ int main(int argc, char **argv) {
srslte_rf_close(&rf); srslte_rf_close(&rf);
srslte_ue_sync_free(&ue_sync); 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); printf("Ok - wrote %d subframes\n", subframe_count);
exit(0); exit(0);
} }

@ -132,6 +132,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_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); SRSLTE_API float srslte_chest_dl_get_rsrp(srslte_chest_dl_t *q);
#endif #endif

@ -244,6 +244,8 @@ SRSLTE_API uint32_t srslte_N_ta_new(uint32_t N_ta_old,
SRSLTE_API char *srslte_cp_string(srslte_cp_t cp); 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 char *srslte_mod_string(srslte_mod_t mod);
SRSLTE_API uint32_t srslte_mod_bits_x_symbol(srslte_mod_t mod); SRSLTE_API uint32_t srslte_mod_bits_x_symbol(srslte_mod_t mod);

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

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

@ -88,11 +88,26 @@ SRSLTE_API int srslte_pdcch_init(srslte_pdcch_t *q,
srslte_regs_t *regs, srslte_regs_t *regs,
srslte_cell_t cell); srslte_cell_t cell);
SRSLTE_API int srslte_pdcch_init_tx(srslte_pdcch_t *q,
srslte_regs_t *regs,
srslte_cell_t cell);
SRSLTE_API int srslte_pdcch_init_rx(srslte_pdcch_t *q,
srslte_regs_t *regs,
srslte_cell_t cell,
uint32_t nof_rx_antennas);
SRSLTE_API int srslte_pdcch_init_multi(srslte_pdcch_t *q, SRSLTE_API int srslte_pdcch_init_multi(srslte_pdcch_t *q,
srslte_regs_t *regs, srslte_regs_t *regs,
srslte_cell_t cell, srslte_cell_t cell,
uint32_t nof_rx_antennas); uint32_t nof_rx_antennas);
SRSLTE_API int srslte_pdcch_init_txrx(srslte_pdcch_t *q,
srslte_regs_t *regs,
srslte_cell_t cell,
uint32_t nof_rx_antennas,
bool isReceiver);
SRSLTE_API void srslte_pdcch_free(srslte_pdcch_t *q); SRSLTE_API void srslte_pdcch_free(srslte_pdcch_t *q);

@ -49,6 +49,7 @@
typedef struct { typedef struct {
srslte_sequence_t seq[SRSLTE_NSUBFRAMES_X_FRAME]; srslte_sequence_t seq[SRSLTE_NSUBFRAMES_X_FRAME];
srslte_sequence_t seq2[SRSLTE_NSUBFRAMES_X_FRAME];
bool sequence_generated; bool sequence_generated;
} srslte_pdsch_user_t; } srslte_pdsch_user_t;
@ -62,11 +63,13 @@ typedef struct SRSLTE_API {
/* buffers */ /* buffers */
// void buffers are shared for tx and rx // void buffers are shared for tx and rx
cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS]; cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS]; /* Channel estimation (Rx only) */
cf_t *symbols[SRSLTE_MAX_PORTS]; cf_t *symbols[SRSLTE_MAX_PORTS]; /* PDSCH Encoded/Decoded Symbols */
cf_t *x[SRSLTE_MAX_PORTS]; cf_t *x[SRSLTE_MAX_LAYERS]; /* Layer mapped */
cf_t *d; cf_t *d; /* Modulated/Demodulated codeword 1 */
cf_t *d2; /* Modulated/Demodulated codeword 2 */
void *e; void *e;
void *e2;
/* tx & rx objects */ /* tx & rx objects */
srslte_modem_table_t mod[4]; srslte_modem_table_t mod[4];
@ -81,9 +84,12 @@ typedef struct SRSLTE_API {
SRSLTE_API int srslte_pdsch_init(srslte_pdsch_t *q, SRSLTE_API int srslte_pdsch_init(srslte_pdsch_t *q,
srslte_cell_t cell); srslte_cell_t cell);
SRSLTE_API int srslte_pdsch_init_multi(srslte_pdsch_t *q, SRSLTE_API int srslte_pdsch_init_tx_multi(srslte_pdsch_t *q,
srslte_cell_t cell);
SRSLTE_API int srslte_pdsch_init_rx_multi(srslte_pdsch_t *q,
srslte_cell_t cell, srslte_cell_t cell,
uint32_t nof_rx_antennas); uint32_t nof_antennas);
SRSLTE_API void srslte_pdsch_free(srslte_pdsch_t *q); SRSLTE_API void srslte_pdsch_free(srslte_pdsch_t *q);
@ -103,6 +109,14 @@ SRSLTE_API int srslte_pdsch_cfg(srslte_pdsch_cfg_t *cfg,
uint32_t sf_idx, uint32_t sf_idx,
uint32_t rvidx); uint32_t rvidx);
SRSLTE_API int srslte_pdsch_cfg_multi(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,
uint32_t rvidx2);
SRSLTE_API int srslte_pdsch_encode(srslte_pdsch_t *q, SRSLTE_API int srslte_pdsch_encode(srslte_pdsch_t *q,
srslte_pdsch_cfg_t *cfg, srslte_pdsch_cfg_t *cfg,
srslte_softbuffer_tx_t *softbuffer, srslte_softbuffer_tx_t *softbuffer,
@ -110,6 +124,13 @@ SRSLTE_API int srslte_pdsch_encode(srslte_pdsch_t *q,
uint16_t rnti, uint16_t rnti,
cf_t *sf_symbols[SRSLTE_MAX_PORTS]); cf_t *sf_symbols[SRSLTE_MAX_PORTS]);
SRSLTE_API int srslte_pdsch_encode_multi(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]);
SRSLTE_API int srslte_pdsch_decode(srslte_pdsch_t *q, SRSLTE_API int srslte_pdsch_decode(srslte_pdsch_t *q,
srslte_pdsch_cfg_t *cfg, srslte_pdsch_cfg_t *cfg,
srslte_softbuffer_rx_t *softbuffer, srslte_softbuffer_rx_t *softbuffer,
@ -121,12 +142,12 @@ SRSLTE_API int srslte_pdsch_decode(srslte_pdsch_t *q,
SRSLTE_API int srslte_pdsch_decode_multi(srslte_pdsch_t *q, SRSLTE_API int srslte_pdsch_decode_multi(srslte_pdsch_t *q,
srslte_pdsch_cfg_t *cfg, srslte_pdsch_cfg_t *cfg,
srslte_softbuffer_rx_t *softbuffer, srslte_softbuffer_rx_t softbuffers[SRSLTE_MAX_CODEWORDS],
cf_t *sf_symbols[SRSLTE_MAX_PORTS], cf_t *sf_symbols[SRSLTE_MAX_PORTS],
cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS],
float noise_estimate, float noise_estimate,
uint16_t rnti, uint16_t rnti,
uint8_t *data); uint8_t *data[SRSLTE_MAX_CODEWORDS]);
SRSLTE_API float srslte_pdsch_average_noi(srslte_pdsch_t *q); SRSLTE_API float srslte_pdsch_average_noi(srslte_pdsch_t *q);

@ -41,10 +41,15 @@
typedef struct SRSLTE_API { typedef struct SRSLTE_API {
srslte_cbsegm_t cb_segm; srslte_cbsegm_t cb_segm;
srslte_cbsegm_t cb_segm2;
srslte_ra_dl_grant_t grant; srslte_ra_dl_grant_t grant;
srslte_ra_nbits_t nbits; srslte_ra_nbits_t nbits;
srslte_ra_nbits_t nbits2;
uint32_t rv; uint32_t rv;
uint32_t rv2;
uint32_t sf_idx; uint32_t sf_idx;
uint32_t nof_layers;
srslte_mimo_type_t mimo_type;
} srslte_pdsch_cfg_t; } srslte_pdsch_cfg_t;
#endif #endif

@ -209,6 +209,13 @@ SRSLTE_API void srslte_ra_dl_grant_to_nbits(srslte_ra_dl_grant_t *grant,
uint32_t sf_idx, uint32_t sf_idx,
srslte_ra_nbits_t *nbits); srslte_ra_nbits_t *nbits);
SRSLTE_API void srslte_ra_dl_grant_to_nbits_multi(srslte_ra_dl_grant_t *grant,
uint32_t cfi,
srslte_cell_t cell,
uint32_t sf_idx,
srslte_ra_nbits_t *nbits,
srslte_ra_nbits_t *nbits2);
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_prb,
uint32_t nof_ctrl_symbols); uint32_t nof_ctrl_symbols);

@ -96,12 +96,24 @@ SRSLTE_API int srslte_dlsch_encode(srslte_sch_t *q,
uint8_t *data, uint8_t *data,
uint8_t *e_bits); uint8_t *e_bits);
SRSLTE_API int srslte_dlsch_encode_multi(srslte_sch_t *q,
srslte_pdsch_cfg_t *cfg,
srslte_softbuffer_tx_t softbuffers[SRSLTE_MAX_CODEWORDS],
uint8_t *data[SRSLTE_MAX_CODEWORDS],
uint8_t *e_bits[SRSLTE_MAX_CODEWORDS]);
SRSLTE_API int srslte_dlsch_decode(srslte_sch_t *q, SRSLTE_API int srslte_dlsch_decode(srslte_sch_t *q,
srslte_pdsch_cfg_t *cfg, srslte_pdsch_cfg_t *cfg,
srslte_softbuffer_rx_t *softbuffer, srslte_softbuffer_rx_t *softbuffer,
int16_t *e_bits, int16_t *e_bits,
uint8_t *data); uint8_t *data);
SRSLTE_API int srslte_dlsch_decode_multi(srslte_sch_t *q,
srslte_pdsch_cfg_t *cfg,
srslte_softbuffer_rx_t softbuffers[SRSLTE_MAX_CODEWORDS],
int16_t *e_bits[SRSLTE_MAX_CODEWORDS],
uint8_t *data[SRSLTE_MAX_CODEWORDS]);
SRSLTE_API int srslte_ulsch_encode(srslte_sch_t *q, SRSLTE_API int srslte_ulsch_encode(srslte_sch_t *q,
srslte_pusch_cfg_t *cfg, srslte_pusch_cfg_t *cfg,
srslte_softbuffer_tx_t *softbuffer, srslte_softbuffer_tx_t *softbuffer,

@ -75,6 +75,11 @@ SRSLTE_API int srslte_rf_open_multi(srslte_rf_t *h,
char *args, char *args,
uint32_t nof_rx_antennas); uint32_t nof_rx_antennas);
SRSLTE_API int srslte_rf_open_multi2(srslte_rf_t *h,
char *args,
uint32_t nof_tx_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 *devname,
char *args); char *args);
@ -84,6 +89,12 @@ SRSLTE_API int srslte_rf_open_devname_multi(srslte_rf_t *h,
char *args, char *args,
uint32_t nof_rx_antennas); uint32_t nof_rx_antennas);
SRSLTE_API int srslte_rf_open_devname_multi2(srslte_rf_t *rf,
char *devname,
char *args,
uint32_t nof_tx_antennas,
uint32_t nof_rx_antennas);
SRSLTE_API const char *srslte_rf_name(srslte_rf_t *h); SRSLTE_API const char *srslte_rf_name(srslte_rf_t *h);
SRSLTE_API int srslte_rf_start_gain_thread(srslte_rf_t *rf, SRSLTE_API int srslte_rf_start_gain_thread(srslte_rf_t *rf,
@ -200,5 +211,12 @@ SRSLTE_API int srslte_rf_send_timed2(srslte_rf_t *h,
bool is_start_of_burst, bool is_start_of_burst,
bool is_end_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 #endif

@ -84,7 +84,7 @@ typedef struct SRSLTE_API {
srslte_cfo_t sfo_correct; srslte_cfo_t sfo_correct;
srslte_pdsch_cfg_t pdsch_cfg; 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_ra_dl_dci_t dl_dci;
srslte_cell_t cell; srslte_cell_t cell;
@ -142,6 +142,13 @@ SRSLTE_API int srslte_ue_dl_cfg_grant(srslte_ue_dl_t *q,
uint32_t sf_idx, uint32_t sf_idx,
uint32_t rvidx); uint32_t rvidx);
SRSLTE_API int srslte_ue_dl_cfg_grant_multi(srslte_ue_dl_t *q,
srslte_ra_dl_grant_t *grant,
uint32_t cfi,
uint32_t sf_idx,
uint32_t rvidx,
uint32_t rvidx2);
SRSLTE_API int srslte_ue_dl_find_ul_dci(srslte_ue_dl_t *q, SRSLTE_API int srslte_ue_dl_find_ul_dci(srslte_ue_dl_t *q,
uint32_t cfi, uint32_t cfi,
uint32_t sf_idx, uint32_t sf_idx,
@ -173,7 +180,7 @@ SRSLTE_API int srslte_ue_dl_decode(srslte_ue_dl_t * q,
SRSLTE_API int srslte_ue_dl_decode_multi(srslte_ue_dl_t * q, SRSLTE_API int srslte_ue_dl_decode_multi(srslte_ue_dl_t * q,
cf_t *input[SRSLTE_MAX_PORTS], cf_t *input[SRSLTE_MAX_PORTS],
uint8_t *data, uint8_t *data[SRSLTE_MAX_CODEWORDS],
uint32_t tti); uint32_t tti);
SRSLTE_API int srslte_ue_dl_decode_rnti(srslte_ue_dl_t * q, SRSLTE_API int srslte_ue_dl_decode_rnti(srslte_ue_dl_t * q,
@ -184,7 +191,7 @@ SRSLTE_API int srslte_ue_dl_decode_rnti(srslte_ue_dl_t * q,
SRSLTE_API int srslte_ue_dl_decode_rnti_multi(srslte_ue_dl_t * q, SRSLTE_API int srslte_ue_dl_decode_rnti_multi(srslte_ue_dl_t * q,
cf_t *input[SRSLTE_MAX_PORTS], cf_t *input[SRSLTE_MAX_PORTS],
uint8_t *data, uint8_t *data[SRSLTE_MAX_CODEWORDS],
uint32_t tti, uint32_t tti,
uint16_t rnti); uint16_t rnti);

@ -148,6 +148,13 @@ SRSLTE_API int srslte_ue_sync_init_file(srslte_ue_sync_t *q,
int offset_time, int offset_time,
float offset_freq); 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 void srslte_ue_sync_free(srslte_ue_sync_t *q);
SRSLTE_API int srslte_ue_sync_start_agc(srslte_ue_sync_t *q, SRSLTE_API int srslte_ue_sync_start_agc(srslte_ue_sync_t *q,

@ -63,5 +63,6 @@ SRSLTE_API extern int srslte_verbose;
#define INFO(_fmt, ...) if (SRSLTE_DEBUG_ENABLED && srslte_verbose >= SRSLTE_VERBOSE_INFO) \ #define INFO(_fmt, ...) if (SRSLTE_DEBUG_ENABLED && srslte_verbose >= SRSLTE_VERBOSE_INFO) \
fprintf(stdout, "[INFO]: " _fmt, __VA_ARGS__) fprintf(stdout, "[INFO]: " _fmt, __VA_ARGS__)
#define ERROR(_fmt) fprintf(stderr, "%s.%d: " _fmt "\n", __FILE__, __LINE__)
#endif // DEBUG_H #endif // DEBUG_H

@ -417,12 +417,15 @@ float srslte_chest_dl_get_rsrq(srslte_chest_dl_t *q) {
} }
float srslte_chest_dl_get_rsrp(srslte_chest_dl_t *q) { float srslte_chest_dl_get_rsrp_port(srslte_chest_dl_t *q, uint32_t port) {
// Note: use only port 0 but average across antennas
float n = 0; float n = 0;
for (int i=0;i<q->last_nof_antennas;i++) { for (int i = 0; i < q->last_nof_antennas; i++) {
n += q->rsrp[i][0]; 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,19 @@ bool srslte_N_id_1_isvalid(uint32_t N_id_1) {
} }
} }
srslte_mod_t srslte_str2mod (char * mod_str) {
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) { char *srslte_mod_string(srslte_mod_t mod) {
switch (mod) { switch (mod) {
case SRSLTE_MOD_BPSK: case SRSLTE_MOD_BPSK:
@ -419,12 +432,14 @@ struct lte_band lte_bands[SRSLTE_NOF_LTE_BANDS] = {
int srslte_str2mimotype(char *mimo_type_str, srslte_mimo_type_t *type) { int srslte_str2mimotype(char *mimo_type_str, srslte_mimo_type_t *type) {
if (!strcmp(mimo_type_str, "single")) { if (!strcmp(mimo_type_str, "single") || !strcmp(mimo_type_str, "Port0")) {
*type = SRSLTE_MIMO_TYPE_SINGLE_ANTENNA; *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; *type = SRSLTE_MIMO_TYPE_TX_DIVERSITY;
} else if (!strcmp(mimo_type_str, "multiplex")) { } else if (!strcmp(mimo_type_str, "multiplex")) {
*type = SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX; *type = SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX;
} else if (!strcmp(mimo_type_str, "cdd") || !strcmp(mimo_type_str, "CDD")) {
*type = SRSLTE_MIMO_TYPE_CDD;
} else { } else {
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }

@ -99,3 +99,60 @@ int srslte_filesink_write(srslte_filesink_t *q, void *buffer, int nsamples) {
return i; 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; 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;
}

@ -530,6 +530,154 @@ int srslte_predecoding_type(cf_t *y_, cf_t *h_[SRSLTE_MAX_PORTS], cf_t *x[SRSLTE
return srslte_predecoding_type_multi(y, h, x, nof_rxant, nof_ports, nof_layers, nof_symbols, type, noise_estimate); return srslte_predecoding_type_multi(y, h, x, nof_rxant, nof_ports, nof_layers, nof_symbols, type, noise_estimate);
} }
int srslte_precoding_mimo_2x2_gen(cf_t W[2][2], cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], cf_t *x[SRSLTE_MAX_LAYERS],
int nof_symbols, float noise_estimate)
{
cf_t G[2][2], Gx[2][2];
for (int i=0; i<nof_symbols; i++) {
// G=H*W
G[0][0] = h[0][0][i]*W[0][0]+h[0][1][i]*W[1][0];
G[0][1] = h[0][0][i]*W[1][0]+h[0][1][i]*W[1][1];
G[1][0] = h[1][0][i]*W[0][0]+h[1][1][i]*W[1][0];
G[1][1] = h[1][0][i]*W[1][0]+h[1][1][i]*W[1][1];
if (noise_estimate == 0) {
// MF equalizer: Gx = G'
Gx[0][0] = conjf(G[0][0]);
Gx[0][1] = conjf(G[1][0]);
Gx[1][0] = conjf(G[0][1]);
Gx[1][1] = conjf(G[1][1]);
} else {
// MMSE equalizer: Gx = (G'G+I)
fprintf(stderr, "MMSE MIMO decoder not implemented\n");
return -1;
}
// x=G*y
x[0][i] = Gx[0][0]*y[0][i] + Gx[0][1]*y[1][i];
x[1][i] = Gx[1][0]*y[0][i] + Gx[1][1]*y[1][i];
}
return SRSLTE_SUCCESS;
}
// SSE implementation of ZF 2x2 CCD equalizer
#ifdef LV_HAVE_SSE
int srslte_predecoding_ccd_2x2_zf_sse(cf_t *y[SRSLTE_MAX_PORTS],
cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS],
cf_t *x[SRSLTE_MAX_LAYERS],
uint32_t nof_symbols) {
uint32_t i = 0;
/* Conjugate mask */
__m128 conj_mask = (__m128) {+0.0f, -0.0f, +0.0f, -0.0f};
for (i = 0; i < nof_symbols; i += 2) {
/* Load channel */
__m128 h00i = _mm_load_ps((float *) &h[0][0][i]);
__m128 h01i = _mm_load_ps((float *) &h[0][1][i]);
__m128 h10i = _mm_load_ps((float *) &h[1][0][i]);
__m128 h11i = _mm_load_ps((float *) &h[1][1][i]);
/* Apply precoding */
__m128 h00 = _mm_add_ps(h00i, _mm_xor_ps(h10i, (__m128) {+0.0f, +0.0f, -0.0f, -0.0f}));
__m128 h10 = _mm_add_ps(h01i, _mm_xor_ps(h11i, (__m128) {+0.0f, +0.0f, -0.0f, -0.0f}));
__m128 h01 = _mm_add_ps(h00i, _mm_xor_ps(h10i, (__m128) {-0.0f, -0.0f, +0.0f, +0.0f}));
__m128 h11 = _mm_add_ps(h01i, _mm_xor_ps(h11i, (__m128) {-0.0f, -0.0f, +0.0f, +0.0f}));
__m128 detmult1 = PROD(h00, h11);
__m128 detmult2 = PROD(h01, h10);
__m128 det = _mm_sub_ps(detmult1, detmult2);
__m128 detconj = _mm_xor_ps(det, conj_mask);
__m128 detabs2 = PROD(det, detconj);
__m128 detabs2rec = _mm_rcp_ps(detabs2);
detabs2rec = _mm_shuffle_ps(detabs2rec, detabs2rec, _MM_SHUFFLE(2, 2, 0, 0));
__m128 detrec = _mm_mul_ps(_mm_mul_ps(detconj, detabs2rec), (__m128) {2.0f, 2.0f, 2.0f, 2.0f});
__m128 y0 = _mm_load_ps((float *) &y[0][i]);
__m128 y1 = _mm_load_ps((float *) &y[1][i]);
__m128 x0 = PROD(_mm_sub_ps(PROD(h11, y0), PROD(h01, y1)), detrec);
__m128 x1 = PROD(_mm_sub_ps(PROD(h00, y1), PROD(h10, y0)), detrec);
_mm_store_ps((float *) &x[0][i], x0);
_mm_store_ps((float *) &x[1][i], x1);
}
return nof_symbols;
}
#endif
// Generic implementation of ZF 2x2 CCD equalizer
int srslte_predecoding_ccd_2x2_zf_gen(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], cf_t *x[SRSLTE_MAX_LAYERS],
int nof_symbols) {
cf_t h00, h01, h10, h11, det;
for (int i = 0; i < nof_symbols; i++) {
// Even precoder
h00 = +h[0][0][i] + h[1][0][i];
h10 = +h[0][1][i] + h[1][1][i];
h01 = +h[0][0][i] - h[1][0][i];
h11 = +h[0][1][i] - h[1][1][i];
det = (h00 * h11 - h01 * h10);
det = conjf(det) * ((float) 2.0 / (crealf(det) * crealf(det) + cimagf(det) * cimagf(det)));
x[0][i] = (+h11 * y[0][i] - h01 * y[1][i]) * det;
x[1][i] = (-h10 * y[0][i] + h00 * y[1][i]) * det;
i++;
// Odd precoder
h00 = h[0][0][i] - h[1][0][i];
h10 = h[0][1][i] - h[1][1][i];
h01 = h[0][0][i] + h[1][0][i];
h11 = h[0][1][i] + h[1][1][i];
det = (h00 * h11 - h01 * h10);
det = conjf(det) * ((float) 2.0 / (crealf(det) * crealf(det) + cimagf(det) * cimagf(det)));
x[0][i] = (+h11 * y[0][i] - h01 * y[1][i]) * det;
x[1][i] = (-h10 * y[0][i] + h00 * y[1][i]) * det;
}
return SRSLTE_SUCCESS;
}
int srslte_predecoding_ccd_zf(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 nof_symbols)
{
if (nof_ports == 2 && nof_rxant == 2) {
if (nof_layers == 2) {
#ifdef LV_HAVE_SSE
return srslte_predecoding_ccd_2x2_zf_sse(y, h, x, nof_symbols);
#else
return srslte_predecoding_ccd_2x2_zf_gen(y, h, x, nof_symbols);
#endif
} else {
fprintf(stderr, "Error predecoding CCD: Invalid number of layers %d\n", nof_layers);
return -1;
}
} else if (nof_ports == 4) {
fprintf(stderr, "Error predecoding CCD: Only 2 ports supported\n");
} else {
fprintf(stderr, "Error predecoding CCD: Invalid combination of ports %d and rx antennax %d\n", nof_ports, nof_rxant);
}
return SRSLTE_ERROR;
}
/* 36.211 v10.3.0 Section 6.3.4 */ /* 36.211 v10.3.0 Section 6.3.4 */
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 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 nof_symbols, srslte_mimo_type_t type, float noise_estimate) { int nof_rxant, int nof_ports, int nof_layers, int nof_symbols, srslte_mimo_type_t type, float noise_estimate) {
@ -547,7 +695,13 @@ int srslte_predecoding_type_multi(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_
switch (type) { switch (type) {
case SRSLTE_MIMO_TYPE_CDD: case SRSLTE_MIMO_TYPE_CDD:
fprintf(stderr, "CCD not supported\n"); if (nof_layers >= 2 && nof_layers <= 4) {
return srslte_predecoding_ccd_zf(y, h, x, nof_rxant, nof_ports, nof_layers, nof_symbols);
} else {
fprintf(stderr,
"Invalid number of layers %d\n", nof_layers);
return -1;
}
return -1; return -1;
case SRSLTE_MIMO_TYPE_SINGLE_ANTENNA: case SRSLTE_MIMO_TYPE_SINGLE_ANTENNA:
if (nof_ports == 1 && nof_layers == 1) { if (nof_ports == 1 && nof_layers == 1) {

@ -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) add_executable(precoding_test precoder_test.c)
@ -52,6 +52,7 @@ 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_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_diversity4 precoding_test -n 1024 -m diversity -l 4 -p 4)
add_test(precoding_cdd_2x2 precoding_test -m cdd -l 2 -p 2 -r 2)

@ -40,7 +40,7 @@ int nof_cw = 1, nof_layers = 1;
char *mimo_type_name = NULL; char *mimo_type_name = NULL;
void usage(char *prog) { 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); printf("\t-n num_symbols [Default %d]\n", nof_symbols);
} }

@ -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); 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++) { 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"; char *txscheme = "Port0";
@ -102,13 +102,30 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
} }
int symbols_layers[SRSLTE_MAX_LAYERS]; int symbols_layers[SRSLTE_MAX_LAYERS];
for (int i=0;i<nof_layers;i++) { 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_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); srslte_precoding_type(x, y, nof_layers, nof_tx_ports, nof_symbols/nof_layers, type);
if (nlhs >= 1) { if (nlhs >= 1) {
switch (type) {
case SRSLTE_MIMO_TYPE_CDD:
mexutils_write_cf(output, &plhs[0], nof_symbols/nof_layers, nof_tx_ports); 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) { if (input) {

@ -35,28 +35,31 @@
#include "srslte/srslte.h" #include "srslte/srslte.h"
#define MSE_THRESHOLD 0.00001 #define MSE_THRESHOLD 0.0005
int nof_symbols = 1000; int nof_symbols = 1000;
int nof_layers = 1, nof_ports = 1; int nof_layers = 1, nof_tx_ports = 1, nof_rx_ports = 1, nof_re = 1;
char *mimo_type_name = NULL; char *mimo_type_name = NULL;
void usage(char *prog) { void usage(char *prog) {
printf( printf(
"Usage: %s -m [single|diversity|multiplex] -l [nof_layers] -p [nof_ports]\n", "Usage: %s -m [single|diversity|multiplex|cdd] -l [nof_layers] -p [nof_tx_ports]\n"
prog); " -r [nof_rx_ports]\n", prog);
printf("\t-n num_symbols [Default %d]\n", nof_symbols); printf("\t-n num_symbols [Default %d]\n", nof_symbols);
} }
void parse_args(int argc, char **argv) { void parse_args(int argc, char **argv) {
int opt; int opt;
while ((opt = getopt(argc, argv, "mpln")) != -1) { while ((opt = getopt(argc, argv, "mplnr")) != -1) {
switch (opt) { switch (opt) {
case 'n': case 'n':
nof_symbols = atoi(argv[optind]); nof_symbols = atoi(argv[optind]);
break; break;
case 'p': case 'p':
nof_ports = atoi(argv[optind]); nof_tx_ports = atoi(argv[optind]);
break;
case 'r':
nof_rx_ports = atoi(argv[optind]);
break; break;
case 'l': case 'l':
nof_layers = atoi(argv[optind]); nof_layers = atoi(argv[optind]);
@ -75,102 +78,175 @@ 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_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_SPATIAL_MULTIPLEX:
fprintf(stderr, "Error: not implemented channel emulator\n");
exit(-1);
//break;
case SRSLTE_MIMO_TYPE_SINGLE_ANTENNA:
default:
populate_channel_single(h[0][0]);
}
}
int main(int argc, char **argv) { int main(int argc, char **argv) {
int i, j; int i, j, k;
float mse; 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]; *xr[SRSLTE_MAX_LAYERS];
srslte_mimo_type_t type; srslte_mimo_type_t type;
parse_args(argc, argv); 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"); fprintf(stderr, "Invalid number of layers or ports\n");
exit(-1); exit(-1);
} }
/* Parse MIMO Type */
if (srslte_str2mimotype(mimo_type_name, &type)) { if (srslte_str2mimotype(mimo_type_name, &type)) {
fprintf(stderr, "Invalid MIMO type %s\n", mimo_type_name); fprintf(stderr, "Invalid MIMO type %s\n", mimo_type_name);
exit(-1); 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_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++) { for (i = 0; i < nof_layers; i++) {
/* Source data */
x[i] = srslte_vec_malloc(sizeof(cf_t) * nof_symbols); x[i] = srslte_vec_malloc(sizeof(cf_t) * nof_symbols);
if (!x[i]) { if (!x[i]) {
perror("srslte_vec_malloc"); perror("srslte_vec_malloc");
exit(-1); exit(-1);
} }
/* Sink data */
xr[i] = srslte_vec_malloc(sizeof(cf_t) * nof_symbols); xr[i] = srslte_vec_malloc(sizeof(cf_t) * nof_symbols);
if (!xr[i]) { if (!xr[i]) {
perror("srslte_vec_malloc"); perror("srslte_vec_malloc");
exit(-1); exit(-1);
} }
} }
for (i = 0; i < nof_ports; i++) {
y[i] = srslte_vec_malloc(sizeof(cf_t) * nof_symbols * nof_layers); /* Allocate y in memory for tx each port */
// TODO: The number of symbols per port is different in spatial multiplexing. for (i = 0; i < nof_tx_ports; i++) {
y[i] = srslte_vec_malloc(sizeof(cf_t) * nof_re);
if (!y[i]) { if (!y[i]) {
perror("srslte_vec_malloc"); perror("srslte_vec_malloc");
exit(-1); exit(-1);
} }
h[i] = srslte_vec_malloc(sizeof(cf_t) * nof_symbols * nof_layers); }
if (!h[i]) {
/* 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"); perror("srslte_vec_malloc");
exit(-1); exit(-1);
} }
} }
}
/* only 1 receiver antenna supported now */ /* Allocate r */
r[0] = srslte_vec_malloc(sizeof(cf_t) * nof_symbols * nof_layers); for (i = 0; i < nof_rx_ports; i++) {
if (!r[0]) { r[i] = srslte_vec_malloc(sizeof(cf_t) * nof_re);
if (!r[i]) {
perror("srslte_vec_malloc"); perror("srslte_vec_malloc");
exit(-1); exit(-1);
} }
}
/* generate random data */ /* Generate source random data */
for (i = 0; i < nof_layers; i++) { for (i = 0; i < nof_layers; i++) {
for (j = 0; j < nof_symbols; j++) { 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 */ /* Execute Precoding (Tx) */
if (srslte_precoding_type(x, y, nof_layers, nof_ports, nof_symbols, type) < 0) { if (srslte_precoding_type(x, y, nof_layers, nof_tx_ports, nof_symbols, type) < 0) {
fprintf(stderr, "Error layer mapper encoder\n"); fprintf(stderr, "Error layer mapper encoder\n");
exit(-1); exit(-1);
} }
/* generate channel */ /* generate channel */
for (i = 0; i < nof_ports; i++) { populate_channel(type, h);
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];
}
}
}
/* pass signal through channel /* pass signal through channel
(we are in the frequency domain so it's a multiplication) */ (we are in the frequency domain so it's a multiplication) */
/* there's only one receiver antenna, signals from different transmitter for (i = 0; i < nof_rx_ports; i++) {
* ports are simply combined at the receiver for (k = 0; k < nof_re; k++) {
*/ r[i][k] = (cf_t) (0.0 + 0.0 * _Complex_I);
for (j = 0; j < nof_symbols * nof_layers; j++) { for (j = 0; j < nof_tx_ports; j++) {
r[0][j] = 0; r[i][k] += y[j][k] * h[j][i][k];
for (i = 0; i < nof_ports; i++) { }
r[0][j] += y[i][j] * h[i][j];
} }
} }
/* predecoding / equalization */ /* predecoding / equalization */
struct timeval t[3]; struct timeval t[3];
gettimeofday(&t[1], NULL); gettimeofday(&t[1], NULL);
if (srslte_predecoding_type(r[0], h, xr, nof_ports, nof_layers, srslte_predecoding_type_multi(r, h, xr, nof_rx_ports, nof_tx_ports, nof_layers,
nof_symbols * nof_layers, type, 0) < 0) { nof_re, type, 0);
fprintf(stderr, "Error layer mapper encoder\n");
exit(-1);
}
gettimeofday(&t[2], NULL); gettimeofday(&t[2], NULL);
get_time_interval(t); get_time_interval(t);
printf("Execution Time: %ld us\n", t[0].tv_usec); printf("Execution Time: %ld us\n", t[0].tv_usec);
@ -187,16 +263,21 @@ int main(int argc, char **argv) {
exit(-1); exit(-1);
} }
/* Free all data */
for (i = 0; i < nof_layers; i++) { for (i = 0; i < nof_layers; i++) {
free(x[i]); free(x[i]);
free(xr[i]); free(xr[i]);
} }
for (i = 0; i < nof_ports; i++) {
free(y[i]); for (i = 0; i < nof_rx_ports; i++) {
free(h[i]); free(r[i]);
} }
free(r[0]); for (i = 0; i < nof_rx_ports; i++) {
for (j = 0; j < nof_tx_ports; j++) {
free(h[j][i]);
}
}
printf("Ok\n"); printf("Ok\n");
exit(0); exit(0);

@ -48,85 +48,113 @@ void help()
/* the gateway function */ /* the gateway function */
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{ {
const mwSize *dims = mxGetDimensions(INPUT);
mwSize ndims;
cf_t *input = NULL; cf_t *input = NULL;
cf_t *hest = NULL; cf_t *hest = NULL;
cf_t *output = NULL; cf_t *output = NULL;
uint32_t nof_symbols = 0; 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;
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) { if (nrhs < NOF_INPUTS) {
help(); help();
return; return;
} }
// Read input symbols /* Read input symbols */
if (mexutils_read_cf(INPUT, &input) < 0) { if (mexutils_read_cf(INPUT, &input) < 0) {
mexErrMsgTxt("Error reading input\n"); mexErrMsgTxt("Error reading input\n");
return; return;
} }
uint32_t nof_layers = mxGetScalar(NLAYERS);
uint32_t nof_tx_ports = 1;
uint32_t nof_codewords = 1;
uint32_t nof_rx_ants = 1; /* Read number of layers */
const mwSize *dims = mxGetDimensions(INPUT); nof_layers = (uint32_t) mxGetScalar(NLAYERS);
mwSize ndims = mxGetNumberOfDimensions(INPUT);
nof_symbols = dims[0]; 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) { 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) { if (mexutils_read_cf(HEST, &hest) < 0) {
mexErrMsgTxt("Error reading hest\n"); mexErrMsgTxt("Error reading hest\n");
return; return;
} }
/* Get number of tx ports */
dims = mxGetDimensions(HEST); dims = mxGetDimensions(HEST);
ndims = mxGetNumberOfDimensions(HEST); ndims = mxGetNumberOfDimensions(HEST);
if (ndims == 3) { if (ndims == 3) {
nof_tx_ports = dims[2]; nof_tx_ports = (uint32_t) dims[2];
} }
/* Print parameters trace */
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); 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 /* Read noise estimate */
float noise_estimate = 0;
if (nrhs >= NOF_INPUTS) { if (nrhs >= NOF_INPUTS) {
noise_estimate = mxGetScalar(NEST); noise_estimate = (float) mxGetScalar(NEST);
} }
cf_t *x[SRSLTE_MAX_LAYERS]; /* Initialise x, h & y pointers */
cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS]; for (i=0;i<SRSLTE_MAX_LAYERS;i++) {
cf_t *y[SRSLTE_MAX_PORTS];
for (int i=0;i<SRSLTE_MAX_LAYERS;i++) {
x[i] = NULL; x[i] = NULL;
} }
for (int i=0;i<SRSLTE_MAX_PORTS;i++) { for (i=0;i<SRSLTE_MAX_PORTS;i++) {
for (int j=0;j<SRSLTE_MAX_PORTS;j++) { for (j=0;j<SRSLTE_MAX_PORTS;j++) {
h[i][j] = NULL; h[i][j] = NULL;
} }
} }
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);
}
/* Allocate memory */ /* Allocate memory for channel estimate */
output = srslte_vec_malloc(sizeof(cf_t)*nof_symbols); for (i = 0; i < nof_tx_ports; i++) {
for (int i = 0; i < nof_tx_ports; i++) { for (j=0; j<nof_rx_ants; j++) {
x[i] = srslte_vec_malloc(sizeof(cf_t)*nof_symbols); h[i][j] = &hest[(i*nof_rx_ants + j)*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 (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]; y[j] = &input[j*nof_symbols];
} }
char *txscheme = "Port0"; /* Parse Tx scheme */
char txscheme[32] = "Port0";
if (nrhs >= NOF_INPUTS) { if (nrhs >= NOF_INPUTS) {
txscheme = mxArrayToString(TXSCHEME); mxGetString_700(TXSCHEME, txscheme, 32);
} }
srslte_mimo_type_t type = SRSLTE_MIMO_TYPE_SINGLE_ANTENNA;
if (!strcmp(txscheme, "Port0")) { if (!strcmp(txscheme, "Port0")) {
type = SRSLTE_MIMO_TYPE_SINGLE_ANTENNA; type = SRSLTE_MIMO_TYPE_SINGLE_ANTENNA;
} else if (!strcmp(txscheme, "TxDiversity")) { } else if (!strcmp(txscheme, "TxDiversity")) {
@ -139,27 +167,40 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
mexPrintf("Unsupported TxScheme=%s\n", txscheme); mexPrintf("Unsupported TxScheme=%s\n", txscheme);
return; 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; 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);
/* Set output pointer */
cf_t *d[SRSLTE_MAX_CODEWORDS];
for (i = 0; i<nof_codewords; i++) {
d[i] = output;
}
/* Pre-decode */
srslte_predecoding_type_multi(y, h, x, nof_rx_ants, nof_tx_ports, nof_layers, 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) { if (nlhs >= 1) {
mexutils_write_cf(output, &plhs[0], nof_symbols, 1); mexutils_write_cf(output, &plhs[0], nof_symbols*nof_layers*nof_rx_ants/nof_tx_ports, 1);
} }
/* Free memory */
if (input) { if (input) {
free(input); free(input);
} }
if (hest) {
free(hest);
}
if (output) { if (output) {
free(output); free(output);
} }
for (int i=0;i<SRSLTE_MAX_LAYERS;i++) { for (i=0;i<SRSLTE_MAX_LAYERS;i++) {
if (x[i]) { if (x[i]) {
free(x[i]); free(x[i]);
} }

@ -1052,6 +1052,16 @@ int dci_format2AB_pack(srslte_ra_dl_dci_t *data, srslte_dci_msg_t *msg, uint32_t
*y++ = data->tb_cw_swap; *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 */ /* pack TB1 */
srslte_bit_unpack(data->mcs_idx, &y, 5); srslte_bit_unpack(data->mcs_idx, &y, 5);
*y++ = data->ndi; *y++ = data->ndi;

@ -65,7 +65,19 @@ int srslte_pdcch_init(srslte_pdcch_t *q, srslte_regs_t *regs, srslte_cell_t cell
return srslte_pdcch_init_multi(q, regs, cell, 1); return srslte_pdcch_init_multi(q, regs, cell, 1);
} }
int srslte_pdcch_init_multi(srslte_pdcch_t *q, srslte_regs_t *regs, srslte_cell_t cell, uint32_t nof_rx_antennas) int srslte_pdcch_init_tx(srslte_pdcch_t *q, srslte_regs_t *regs, srslte_cell_t cell) {
return srslte_pdcch_init_txrx(q, regs, cell, 1, false);
}
int srslte_pdcch_init_rx(srslte_pdcch_t *q, srslte_regs_t *regs, srslte_cell_t cell, uint32_t nof_rx_antennas) {
return srslte_pdcch_init_txrx(q, regs, cell, nof_rx_antennas, true);
}
int srslte_pdcch_init_multi(srslte_pdcch_t *q, srslte_regs_t *regs, srslte_cell_t cell, uint32_t nof_rx_antennas) {
return srslte_pdcch_init_txrx(q, regs, cell, nof_rx_antennas, true);
}
int srslte_pdcch_init_txrx(srslte_pdcch_t *q, srslte_regs_t *regs, srslte_cell_t cell, uint32_t nof_rx_antennas, bool isReceiver)
{ {
int ret = SRSLTE_ERROR_INVALID_INPUTS; int ret = SRSLTE_ERROR_INVALID_INPUTS;
@ -122,19 +134,25 @@ int srslte_pdcch_init_multi(srslte_pdcch_t *q, srslte_regs_t *regs, srslte_cell_
goto clean; goto clean;
} }
if (isReceiver) {
for (int i = 0; i < SRSLTE_MAX_PORTS; i++) { for (int i = 0; i < SRSLTE_MAX_PORTS; i++) {
for (int j=0;j<q->nof_rx_antennas;j++) { for (int j = 0; j < q->nof_rx_antennas; j++) {
q->ce[i][j] = srslte_vec_malloc(sizeof(cf_t) * q->max_bits / 2); q->ce[i][j] = srslte_vec_malloc(sizeof(cf_t) * q->max_bits / 2);
if (!q->ce[i][j]) { if (!q->ce[i][j]) {
goto clean; goto clean;
} }
} }
}
}
for (int i = 0; i < SRSLTE_MAX_PORTS; i++) {
q->x[i] = srslte_vec_malloc(sizeof(cf_t) * q->max_bits / 2); q->x[i] = srslte_vec_malloc(sizeof(cf_t) * q->max_bits / 2);
if (!q->x[i]) { if (!q->x[i]) {
goto clean; goto clean;
} }
} }
for (int j=0;j<q->nof_rx_antennas;j++) {
for (int j = 0; j < ((isReceiver) ? q->nof_rx_antennas : cell.nof_ports); j++) {
q->symbols[j] = srslte_vec_malloc(sizeof(cf_t) * q->max_bits / 2); q->symbols[j] = srslte_vec_malloc(sizeof(cf_t) * q->max_bits / 2);
if (!q->symbols[j]) { if (!q->symbols[j]) {
goto clean; goto clean;

@ -203,20 +203,15 @@ 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); return srslte_pdsch_cp(q, sf_symbols, symbols, grant, lstart, subframe, false);
} }
int srslte_pdsch_init(srslte_pdsch_t *q, srslte_cell_t cell) /** Initializes the PDCCH transmitter or receiver */
{ int srslte_pdsch_init_multi(srslte_pdsch_t *q, srslte_cell_t cell, uint32_t nof_antennas, bool is_receiver)
return srslte_pdsch_init_multi(q, cell, 1);
}
/** Initializes the PDCCH transmitter and receiver */
int srslte_pdsch_init_multi(srslte_pdsch_t *q, srslte_cell_t cell, uint32_t nof_rx_antennas)
{ {
int ret = SRSLTE_ERROR_INVALID_INPUTS; int ret = SRSLTE_ERROR_INVALID_INPUTS;
int i; int i;
if (q != NULL && if (q != NULL &&
srslte_cell_isvalid(&cell) && srslte_cell_isvalid(&cell) &&
nof_rx_antennas <= SRSLTE_MAX_PORTS) nof_antennas <= SRSLTE_MAX_PORTS)
{ {
bzero(q, sizeof(srslte_pdsch_t)); bzero(q, sizeof(srslte_pdsch_t));
@ -224,7 +219,9 @@ int srslte_pdsch_init_multi(srslte_pdsch_t *q, srslte_cell_t cell, uint32_t nof_
q->cell = cell; q->cell = cell;
q->max_re = q->cell.nof_prb * MAX_PDSCH_RE(q->cell.cp); q->max_re = q->cell.nof_prb * MAX_PDSCH_RE(q->cell.cp);
q->nof_rx_antennas = nof_rx_antennas; if (is_receiver) {
q->nof_rx_antennas = nof_antennas;
}
INFO("Init PDSCH: %d ports %d PRBs, max_symbols: %d\n", q->cell.nof_ports, INFO("Init PDSCH: %d ports %d PRBs, max_symbols: %d\n", q->cell.nof_ports,
q->cell.nof_prb, q->max_re); q->cell.nof_prb, q->max_re);
@ -244,23 +241,40 @@ int srslte_pdsch_init_multi(srslte_pdsch_t *q, srslte_cell_t cell, uint32_t nof_
goto clean; goto clean;
} }
q->e2 = srslte_vec_malloc(sizeof(int16_t) * q->max_re * srslte_mod_bits_x_symbol(SRSLTE_MOD_64QAM));
if (!q->e) {
goto clean;
}
q->d = srslte_vec_malloc(sizeof(cf_t) * q->max_re); q->d = srslte_vec_malloc(sizeof(cf_t) * q->max_re);
if (!q->d) { if (!q->d) {
goto clean; goto clean;
} }
q->d2 = srslte_vec_malloc(sizeof(cf_t) * q->max_re);
if (!q->d) {
goto clean;
}
/* Layer mapped symbols memory allocation */
for (i = 0; i < q->cell.nof_ports; i++) { for (i = 0; i < q->cell.nof_ports; i++) {
q->x[i] = srslte_vec_malloc(sizeof(cf_t) * q->max_re); q->x[i] = srslte_vec_malloc(sizeof(cf_t) * q->max_re);
if (!q->x[i]) { if (!q->x[i]) {
goto clean; goto clean;
} }
for (int j=0;j<q->nof_rx_antennas;j++) { }
/* If it is the receiver side, allocate estimated channel */
if (is_receiver) {
for (i = 0; i < q->cell.nof_ports; i++) {
for (int j = 0; j < q->nof_rx_antennas; j++) {
q->ce[i][j] = srslte_vec_malloc(sizeof(cf_t) * q->max_re); q->ce[i][j] = srslte_vec_malloc(sizeof(cf_t) * q->max_re);
if (!q->ce[i][j]) { if (!q->ce[i][j]) {
goto clean; goto clean;
} }
} }
} }
}
for (int j=0;j<SRSLTE_MAX(q->nof_rx_antennas, q->cell.nof_ports);j++) { 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); q->symbols[j] = srslte_vec_malloc(sizeof(cf_t) * q->max_re);
if (!q->symbols[j]) { if (!q->symbols[j]) {
@ -268,6 +282,7 @@ int srslte_pdsch_init_multi(srslte_pdsch_t *q, srslte_cell_t cell, uint32_t nof_
} }
} }
/* Allocate User memory (all zeros) */
q->users = calloc(sizeof(srslte_pdsch_user_t*), 1+SRSLTE_SIRNTI); q->users = calloc(sizeof(srslte_pdsch_user_t*), 1+SRSLTE_SIRNTI);
if (!q->users) { if (!q->users) {
perror("malloc"); perror("malloc");
@ -283,15 +298,33 @@ int srslte_pdsch_init_multi(srslte_pdsch_t *q, srslte_cell_t cell, uint32_t nof_
return ret; return ret;
} }
int srslte_pdsch_init(srslte_pdsch_t *q, srslte_cell_t cell) {
return srslte_pdsch_init_multi(q, cell, 1, true);
}
int srslte_pdsch_init_tx_multi(srslte_pdsch_t *q, srslte_cell_t cell) {
return srslte_pdsch_init_multi(q, cell, 0, false);
}
int srslte_pdsch_init_rx_multi(srslte_pdsch_t *q, srslte_cell_t cell, uint32_t nof_antennas) {
return srslte_pdsch_init_multi(q, cell, nof_antennas, true);
}
void srslte_pdsch_free(srslte_pdsch_t *q) { void srslte_pdsch_free(srslte_pdsch_t *q) {
int i; int i;
if (q->e) { if (q->e) {
free(q->e); free(q->e);
} }
if (q->e2) {
free(q->e2);
}
if (q->d) { if (q->d) {
free(q->d); free(q->d);
} }
if (q->d2) {
free(q->d2);
}
for (i = 0; i < q->cell.nof_ports; i++) { for (i = 0; i < q->cell.nof_ports; i++) {
if (q->x[i]) { if (q->x[i]) {
free(q->x[i]); free(q->x[i]);
@ -302,7 +335,7 @@ void srslte_pdsch_free(srslte_pdsch_t *q) {
} }
} }
} }
for (int j=0;j<q->nof_rx_antennas;j++) { for (int j=0;j<SRSLTE_MAX_PORTS;j++) {
if (q->symbols[j]) { if (q->symbols[j]) {
free(q->symbols[j]); free(q->symbols[j]);
} }
@ -348,6 +381,50 @@ int srslte_pdsch_cfg(srslte_pdsch_cfg_t *cfg, srslte_cell_t cell, srslte_ra_dl_g
} }
} }
/* 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_multi(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, uint32_t rvidx2)
{
if (cfg) {
if (grant) {
memcpy(&cfg->grant, grant, sizeof(srslte_ra_dl_grant_t));
}
if (srslte_cbsegm(&cfg->cb_segm, (uint32_t) cfg->grant.mcs.tbs)) {
fprintf(stderr, "Error computing Codeblock (1) segmentation for TBS=%d\n", cfg->grant.mcs.tbs);
return SRSLTE_ERROR;
}
if (srslte_cbsegm(&cfg->cb_segm2, (uint32_t) cfg->grant.mcs2.tbs)) {
fprintf(stderr, "Error computing Codeblock (2) segmentation for TBS=%d\n", cfg->grant.mcs.tbs);
return SRSLTE_ERROR;
}
srslte_ra_dl_grant_to_nbits_multi(&cfg->grant, cfi, cell, sf_idx, &cfg->nbits, &cfg->nbits2);
cfg->sf_idx = sf_idx;
cfg->rv = rvidx;
cfg->rv2 = rvidx2;
if (cell.nof_ports == 1 && grant->nof_tb == 1) {
cfg->mimo_type = SRSLTE_MIMO_TYPE_SINGLE_ANTENNA;
cfg->nof_layers = 1;
} else if (cell.nof_ports == 2 && grant->nof_tb == 1) {
cfg->mimo_type = SRSLTE_MIMO_TYPE_TX_DIVERSITY;
cfg->nof_layers = 2;
} else if (cell.nof_ports == 2 && grant->nof_tb == 2) {
cfg->mimo_type = SRSLTE_MIMO_TYPE_CDD;
cfg->nof_layers = 2;
} else {
INFO("nof_ports=%d, nof_tb=%d are not consistent\n", cell.nof_ports, grant->nof_tb);
return SRSLTE_ERROR;
}
return SRSLTE_SUCCESS;
} else {
return SRSLTE_ERROR_INVALID_INPUTS;
}
}
/* Precalculate the PDSCH scramble sequences for a given RNTI. This function takes a while /* 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. * to execute, so shall be called once the final C-RNTI has been allocated for the session.
@ -362,6 +439,10 @@ int srslte_pdsch_set_rnti(srslte_pdsch_t *q, uint16_t rnti) {
q->max_re * srslte_mod_bits_x_symbol(SRSLTE_MOD_64QAM))) { q->max_re * srslte_mod_bits_x_symbol(SRSLTE_MOD_64QAM))) {
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
if (srslte_sequence_pdsch(&q->users[rnti]->seq2[i], rnti, 1, 2 * i, q->cell.id,
q->max_re * srslte_mod_bits_x_symbol(SRSLTE_MOD_64QAM))) {
return SRSLTE_ERROR;
}
} }
q->users[rnti]->sequence_generated = true; q->users[rnti]->sequence_generated = true;
} }
@ -374,6 +455,7 @@ void srslte_pdsch_free_rnti(srslte_pdsch_t* q, uint16_t rnti)
if (q->users[rnti]) { if (q->users[rnti]) {
for (int i = 0; i < SRSLTE_NSUBFRAMES_X_FRAME; i++) { for (int i = 0; i < SRSLTE_NSUBFRAMES_X_FRAME; i++) {
srslte_sequence_free(&q->users[rnti]->seq[i]); srslte_sequence_free(&q->users[rnti]->seq[i]);
srslte_sequence_free(&q->users[rnti]->seq2[i]);
} }
free(q->users[rnti]); free(q->users[rnti]);
q->users[rnti] = NULL; q->users[rnti] = NULL;
@ -392,15 +474,15 @@ int srslte_pdsch_decode(srslte_pdsch_t *q,
for (int i=0;i<q->cell.nof_ports;i++) { for (int i=0;i<q->cell.nof_ports;i++) {
_ce[i][0] = ce[i]; _ce[i][0] = ce[i];
} }
return srslte_pdsch_decode_multi(q, cfg, softbuffer, _sf_symbols, _ce, noise_estimate, rnti, data); return srslte_pdsch_decode_multi(q, cfg, softbuffer, _sf_symbols, _ce, noise_estimate, rnti, &data);
} }
/** Decodes the PDSCH from the received symbols /** Decodes the PDSCH from the received symbols
*/ */
int srslte_pdsch_decode_multi(srslte_pdsch_t *q, int srslte_pdsch_decode_multi(srslte_pdsch_t *q,
srslte_pdsch_cfg_t *cfg, srslte_softbuffer_rx_t *softbuffer, 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, 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) uint16_t rnti, uint8_t *data[SRSLTE_MAX_CODEWORDS])
{ {
/* Set pointers for layermapping & precoding */ /* Set pointers for layermapping & precoding */
@ -441,22 +523,38 @@ int srslte_pdsch_decode_multi(srslte_pdsch_t *q,
} }
} }
/* TODO: only diversity is supported */
if (q->cell.nof_ports == 1) { if (q->cell.nof_ports == 1) {
/* no need for layer demapping */ /* 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); srslte_predecoding_single_multi(q->symbols, q->ce[0], q->d, q->nof_rx_antennas, cfg->nbits.nof_re, noise_estimate);
} else { } else {
srslte_predecoding_diversity_multi(q->symbols, q->ce, x, q->nof_rx_antennas, q->cell.nof_ports, cfg->nbits.nof_re); int nof_symbols [SRSLTE_MAX_CODEWORDS];
srslte_layerdemap_diversity(x, q->d, q->cell.nof_ports, cfg->nbits.nof_re / q->cell.nof_ports); nof_symbols[0] = cfg->nbits.nof_re * cfg->grant.nof_tb / q->cell.nof_ports;
nof_symbols[1] = cfg->nbits2.nof_re * cfg->grant.nof_tb / q->cell.nof_ports;
srslte_predecoding_type_multi(q->symbols, q->ce, x, q->nof_rx_antennas, q->cell.nof_ports, cfg->nof_layers,
cfg->nbits.nof_re, cfg->mimo_type, 0.0);
srslte_layerdemap_type(x, (cf_t *[SRSLTE_MAX_CODEWORDS]) {q->d, q->d2}, cfg->nof_layers, cfg->grant.nof_tb,
nof_symbols[0], nof_symbols, cfg->mimo_type);
} }
if (SRSLTE_VERBOSE_ISDEBUG()) { if (SRSLTE_VERBOSE_ISDEBUG()) {
DEBUG("SAVED FILE subframe.dat: received subframe symbols\n",0); char filename[FILENAME_MAX];
srslte_vec_save_file("subframe.dat", sf_symbols[0], SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp)*sizeof(cf_t)); for (int j = 0; j < q->nof_rx_antennas; j++) {
DEBUG("SAVED FILE hest0.dat and hest1.dat: channel estimates for port 0 and port 1\n",0); if (snprintf(filename, FILENAME_MAX, "subframe_p%d.dat", j) < 0) {
srslte_vec_save_file("hest0.dat", ce[0][0], SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp)*sizeof(cf_t)); ERROR("Generating file name");
if (q->cell.nof_ports > 1) { break;
srslte_vec_save_file("hest1.dat", ce[1][0], SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp)*sizeof(cf_t)); }
DEBUG("SAVED FILE %s: received subframe symbols\n", filename);
srslte_vec_save_file(filename, sf_symbols, SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp)*sizeof(cf_t));
for (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));
}
} }
DEBUG("SAVED FILE pdsch_symbols.dat: symbols after equalization\n",0); 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)); srslte_vec_save_file("pdsch_symbols.dat", q->d, cfg->nbits.nof_re*sizeof(cf_t));
@ -466,13 +564,26 @@ int srslte_pdsch_decode_multi(srslte_pdsch_t *q,
* The MAX-log-MAP algorithm used in turbo decoding is unsensitive to SNR estimation, * 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 * thus we don't need tot set it in the LLRs normalization
*/ */
if (cfg->nbits.nof_re) {
srslte_demod_soft_demodulate_s(cfg->grant.mcs.mod, q->d, q->e, cfg->nbits.nof_re); srslte_demod_soft_demodulate_s(cfg->grant.mcs.mod, q->d, q->e, cfg->nbits.nof_re);
}
if (cfg->nbits2.nof_re) {
srslte_demod_soft_demodulate_s(cfg->grant.mcs2.mod, q->d2, q->e2, cfg->nbits2.nof_re);
}
/* descramble */ /* descramble */
if (q->users[rnti] && q->users[rnti]->sequence_generated) { if (q->users[rnti] && q->users[rnti]->sequence_generated) {
if (cfg->nbits.nof_bits) {
srslte_scrambling_s_offset(&q->users[rnti]->seq[cfg->sf_idx], q->e, 0, cfg->nbits.nof_bits); srslte_scrambling_s_offset(&q->users[rnti]->seq[cfg->sf_idx], q->e, 0, cfg->nbits.nof_bits);
}
if (cfg->nbits2.nof_bits) {
srslte_scrambling_s_offset(&q->users[rnti]->seq2[cfg->sf_idx], q->e2, 0, cfg->nbits2.nof_bits);
}
} else { } else {
srslte_sequence_t seq; srslte_sequence_t seq;
if (cfg->nbits.nof_bits) {
if (srslte_sequence_pdsch(&seq, rnti, 0, 2 * cfg->sf_idx, q->cell.id, cfg->nbits.nof_bits)) { if (srslte_sequence_pdsch(&seq, rnti, 0, 2 * cfg->sf_idx, q->cell.id, cfg->nbits.nof_bits)) {
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
@ -480,12 +591,22 @@ int srslte_pdsch_decode_multi(srslte_pdsch_t *q,
srslte_sequence_free(&seq); srslte_sequence_free(&seq);
} }
if (cfg->nbits2.nof_bits) {
if (srslte_sequence_pdsch(&seq, rnti, 1, 2 * cfg->sf_idx, q->cell.id, cfg->nbits2.nof_bits)) {
return SRSLTE_ERROR;
}
srslte_scrambling_s_offset(&seq, q->e2, 0, cfg->nbits2.nof_bits);
srslte_sequence_free(&seq);
}
}
if (SRSLTE_VERBOSE_ISDEBUG()) { if (SRSLTE_VERBOSE_ISDEBUG()) {
DEBUG("SAVED FILE llr.dat: LLR estimates after demodulation and descrambling\n",0); 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)); srslte_vec_save_file("llr.dat", q->e, cfg->nbits.nof_bits*sizeof(int16_t));
} }
return srslte_dlsch_decode(&q->dl_sch, cfg, softbuffer, q->e, data); return srslte_dlsch_decode_multi(&q->dl_sch, cfg, softbuffers, (int16_t *[SRSLTE_MAX_CODEWORDS]) {q->e, q->e2},
data);
} else { } else {
return SRSLTE_ERROR_INVALID_INPUTS; return SRSLTE_ERROR_INVALID_INPUTS;
@ -571,6 +692,112 @@ int srslte_pdsch_encode(srslte_pdsch_t *q,
return ret; return ret;
} }
int srslte_pdsch_encode_multi(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) {
for (i = 0; i < q->cell.nof_ports; i++) {
if (sf_symbols[i] == NULL) {
return SRSLTE_ERROR_INVALID_INPUTS;
}
}
/* If both transport block sizes are zero return error */
if (cfg->grant.mcs.tbs == 0 && cfg->grant.mcs2.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);
return SRSLTE_ERROR_INVALID_INPUTS;
}
INFO("Encoding PDSCH SF: %d (TB 1), 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);
if (cfg->grant.nof_tb > 1) {
INFO("Encoding PDSCH SF: %d (TB 2), Mod %s, NofBits: %d, NofSymbols: %d, NofBitsE: %d, rv_idx: %d\n",
cfg->sf_idx, srslte_mod_string(cfg->grant.mcs2.mod), cfg->grant.mcs2.tbs,
cfg->nbits.nof_re, cfg->nbits.nof_bits, cfg->rv2);
}
/* 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));
if (srslte_dlsch_encode_multi(&q->dl_sch, cfg, softbuffers, data, (uint8_t *[SRSLTE_MAX_CODEWORDS]) {q->e, q->e2})) {
fprintf(stderr, "Error encoding TB\n");
return SRSLTE_ERROR;
}
/* scramble */
if (!q->users[rnti]) {
srslte_sequence_t seq;
if (cfg->nbits.nof_bits) {
if (srslte_sequence_pdsch(&seq, rnti, 0, 2 * cfg->sf_idx, q->cell.id, cfg->nbits.nof_bits)) {
return SRSLTE_ERROR;
}
srslte_scrambling_bytes(&seq, (uint8_t *) q->e, cfg->nbits.nof_bits);
srslte_sequence_free(&seq);
}
if (cfg->nbits2.nof_bits) {
if (srslte_sequence_pdsch(&seq, rnti, 1, 2 * cfg->sf_idx, q->cell.id, cfg->nbits2.nof_bits)) {
return SRSLTE_ERROR;
}
srslte_scrambling_bytes(&seq, (uint8_t *) q->e2, cfg->nbits2.nof_bits);
srslte_sequence_free(&seq);
}
} else {
if (cfg->nbits.nof_bits) {
srslte_scrambling_bytes(&q->users[rnti]->seq[cfg->sf_idx], (uint8_t *) q->e, cfg->nbits.nof_bits);
}
if (cfg->nbits2.nof_bits) {
srslte_scrambling_bytes(&q->users[rnti]->seq2[cfg->sf_idx], (uint8_t *) q->e2, cfg->nbits2.nof_bits);
}
}
if (cfg->nbits.nof_bits) {
srslte_mod_modulate_bytes(&q->mod[cfg->grant.mcs.mod], (uint8_t *) q->e, q->d, cfg->nbits.nof_bits);
}
if (cfg->nbits2.nof_bits) {
srslte_mod_modulate_bytes(&q->mod[cfg->grant.mcs2.mod], (uint8_t *) q->e2, q->d2, cfg->nbits2.nof_bits);
}
if (q->cell.nof_ports > 1) {
int nof_symbols = srslte_layermap_type((cf_t *[SRSLTE_MAX_CODEWORDS]) {q->d, q->d2}, x, cfg->grant.nof_tb, cfg->nof_layers,
(int[SRSLTE_MAX_CODEWORDS]) {cfg->nbits.nof_re, cfg->nbits2.nof_re}, cfg->mimo_type);
srslte_precoding_type(x, q->symbols, q->cell.nof_ports, cfg->nof_layers,
nof_symbols, cfg->mimo_type);
} else {
memcpy(q->symbols[0], q->d, cfg->nbits.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);
}
ret = SRSLTE_SUCCESS;
}
return ret;
}
float srslte_pdsch_average_noi(srslte_pdsch_t *q) float srslte_pdsch_average_noi(srslte_pdsch_t *q)
{ {
return q->dl_sch.average_nof_iterations; return q->dl_sch.average_nof_iterations;

@ -496,7 +496,6 @@ static int dl_dci_to_grant_mcs(srslte_ra_dl_dci_t *dci, srslte_ra_dl_grant_t *gr
grant->mcs.tbs = (uint32_t) tbs; grant->mcs.tbs = (uint32_t) tbs;
} else { } else {
n_prb = grant->nof_prb; n_prb = grant->nof_prb;
grant->nof_tb = 0;
if (dci->tb_en[0]) { if (dci->tb_en[0]) {
grant->mcs.idx = dci->mcs_idx; grant->mcs.idx = dci->mcs_idx;
tbs = dl_fill_ra_mcs(&grant->mcs, n_prb); tbs = dl_fill_ra_mcs(&grant->mcs, n_prb);
@ -506,7 +505,6 @@ static int dl_dci_to_grant_mcs(srslte_ra_dl_dci_t *dci, srslte_ra_dl_grant_t *gr
// For mcs>=29, set last TBS received for this PID // For mcs>=29, set last TBS received for this PID
grant->mcs.tbs = last_dl_tbs[dci->harq_process%8]; grant->mcs.tbs = last_dl_tbs[dci->harq_process%8];
} }
grant->nof_tb++;
} else { } else {
grant->mcs.tbs = 0; grant->mcs.tbs = 0;
} }
@ -519,16 +517,18 @@ static int dl_dci_to_grant_mcs(srslte_ra_dl_dci_t *dci, srslte_ra_dl_grant_t *gr
// For mcs>=29, set last TBS received for this PID // For mcs>=29, set last TBS received for this PID
grant->mcs2.tbs = last_dl_tbs2[dci->harq_process%8]; grant->mcs2.tbs = last_dl_tbs2[dci->harq_process%8];
} }
grant->nof_tb++;
} else { } else {
grant->mcs2.tbs = 0; grant->mcs2.tbs = 0;
} }
} }
grant->nof_tb = 0;
if (dci->tb_en[0]) { if (dci->tb_en[0]) {
grant->Qm = srslte_mod_bits_x_symbol(grant->mcs.mod); grant->Qm = srslte_mod_bits_x_symbol(grant->mcs.mod);
grant->nof_tb++;
} }
if (dci->tb_en[1]) { if (dci->tb_en[1]) {
grant->Qm2 = srslte_mod_bits_x_symbol(grant->mcs2.mod); grant->Qm2 = srslte_mod_bits_x_symbol(grant->mcs2.mod);
grant->nof_tb++;
} }
if (tbs < 0) { if (tbs < 0) {
return SRSLTE_ERROR; return SRSLTE_ERROR;
@ -546,6 +546,23 @@ void srslte_ra_dl_grant_to_nbits(srslte_ra_dl_grant_t *grant, uint32_t cfi, srsl
nbits->nof_bits = nbits->nof_re * grant->Qm; nbits->nof_bits = nbits->nof_re * grant->Qm;
} }
void srslte_ra_dl_grant_to_nbits_multi(srslte_ra_dl_grant_t *grant, uint32_t cfi, srslte_cell_t cell, uint32_t sf_idx,
srslte_ra_nbits_t *nbits, srslte_ra_nbits_t *nbits2) {
/* Compute number of RE for first transport block */
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;
/*/ Compute number of RE for second transport block */
if (grant->nof_tb > 1) {
nbits2->nof_re = nbits->nof_re;
nbits2->lstart = nbits->lstart;
nbits2->nof_symb = 2 * SRSLTE_CP_NSYMB(cell.cp) - nbits2->lstart;
nbits2->nof_bits = nbits2->nof_re * grant->Qm2;
}
}
/** Obtains a DL grant from a DCI grant for PDSCH */ /** Obtains a DL grant from a DCI grant for PDSCH */
int srslte_ra_dl_dci_to_grant(srslte_ra_dl_dci_t *dci, int srslte_ra_dl_dci_to_grant(srslte_ra_dl_dci_t *dci,
uint32_t nof_prb, uint16_t msg_rnti, srslte_ra_dl_grant_t *grant) uint32_t nof_prb, uint16_t msg_rnti, srslte_ra_dl_grant_t *grant)
@ -796,18 +813,31 @@ void srslte_ra_pdsch_fprint(FILE *f, srslte_ra_dl_dci_t *dci, uint32_t nof_prb)
} }
break; 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, " - 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, " - 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) { void srslte_ra_dl_grant_fprint(FILE *f, srslte_ra_dl_grant_t *grant) {
srslte_ra_prb_fprint(f, grant); srslte_ra_prb_fprint(f, grant);
fprintf(f, " - Number of PRBs:\t\t\t%d\n", grant->nof_prb); fprintf(f, " - Number of PRBs:\t\t\t%d\n", grant->nof_prb);
fprintf(f, " - Number of TBs:\t\t\t%d\n", grant->nof_tb);
fprintf(f, " - Modulation type:\t\t\t%s\n", srslte_mod_string(grant->mcs.mod)); 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, " - Transport block size:\t\t%d\n", grant->mcs.tbs);
fprintf(f, " - Modulation type (TB2):\t\t%s\n", srslte_mod_string(grant->mcs2.mod));
fprintf(f, " - Transport block size (TB2):\t\t%d\n", grant->mcs2.tbs);
} }
void srslte_ra_prb_fprint(FILE *f, srslte_ra_dl_grant_t *grant) { void srslte_ra_prb_fprint(FILE *f, srslte_ra_dl_grant_t *grant) {

@ -523,6 +523,32 @@ int srslte_dlsch_decode(srslte_sch_t *q, srslte_pdsch_cfg_t *cfg, srslte_softbuf
e_bits, data); e_bits, data);
} }
int srslte_dlsch_decode_multi(srslte_sch_t *q, srslte_pdsch_cfg_t *cfg, srslte_softbuffer_rx_t softbuffers[SRSLTE_MAX_CODEWORDS],
int16_t *e_bits[SRSLTE_MAX_CODEWORDS], uint8_t *data[SRSLTE_MAX_CODEWORDS])
{
int ret = SRSLTE_SUCCESS;
uint32_t Nl = 1;
if (cfg->nof_layers != cfg->grant.nof_tb) {
Nl = 2;
}
if (cfg->nbits.nof_bits) {
ret |= decode_tb(q, &softbuffers[0], &cfg->cb_segm,
cfg->grant.Qm*Nl, cfg->rv, cfg->nbits.nof_bits,
e_bits[0], data[0]);
}
if (cfg->nbits2.nof_bits) {
ret |= decode_tb(q, &softbuffers[1], &cfg->cb_segm2,
cfg->grant.Qm2*Nl, cfg->rv2, cfg->nbits2.nof_bits,
e_bits[1], data[1]);
}
return ret;
}
/** /**
* Encode transport block. Segments into code blocks, adds channel coding, and does rate matching. * Encode transport block. Segments into code blocks, adds channel coding, and does rate matching.
* *
@ -542,6 +568,35 @@ int srslte_dlsch_encode(srslte_sch_t *q, srslte_pdsch_cfg_t *cfg, srslte_softbuf
data, e_bits); data, e_bits);
} }
int srslte_dlsch_encode_multi(srslte_sch_t *q, srslte_pdsch_cfg_t *cfg, srslte_softbuffer_tx_t softbuffers[SRSLTE_MAX_CODEWORDS],
uint8_t *data[SRSLTE_MAX_CODEWORDS], uint8_t *e_bits[SRSLTE_MAX_CODEWORDS])
{
int ret = 0;
uint32_t Nl = 1;
if (cfg->nof_layers != cfg->grant.nof_tb) {
Nl = 2;
}
/* Check if codeword 1 shall be encoded */
if(cfg->nbits.nof_bits) {
ret |= encode_tb(q,
&softbuffers[0], &cfg->cb_segm,
cfg->grant.Qm*Nl, cfg->rv, cfg->nbits.nof_bits,
data[0], e_bits[0]);
}
/* Check if codeword 2 shall be encoded */
if(cfg->nbits2.nof_bits) {
ret |= encode_tb(q,
&softbuffers[1], &cfg->cb_segm2,
cfg->grant.Qm2*Nl, cfg->rv2, cfg->nbits2.nof_bits,
data[1], e_bits[1]);
}
return ret;
}
/* 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. * Profiling show that the computation of this matrix is neglegible.
*/ */

@ -87,6 +87,27 @@ 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_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 -m 28 -n 100)
add_test(pdsch_test_sin_6 pdsch_test -p 1 -a 2 -w 1 -n 6)
add_test(pdsch_test_sin_12 pdsch_test -p 1 -a 2 -w 1 -n 12)
add_test(pdsch_test_sin_25 pdsch_test -p 1 -a 2 -w 1 -n 25)
add_test(pdsch_test_sin_50 pdsch_test -p 1 -a 2 -w 1 -n 50)
add_test(pdsch_test_sin_75 pdsch_test -p 1 -a 2 -w 1 -n 75)
add_test(pdsch_test_sin_100 pdsch_test -p 1 -a 2 -w 1 -n 100 -m 28)
add_test(pdsch_test_div_6 pdsch_test -p 2 -a 2 -w 1 -n 6)
add_test(pdsch_test_div_12 pdsch_test -p 2 -a 2 -w 1 -n 12)
add_test(pdsch_test_div_25 pdsch_test -p 2 -a 2 -w 1 -n 25)
add_test(pdsch_test_div_50 pdsch_test -p 2 -a 2 -w 1 -n 50)
add_test(pdsch_test_div_75 pdsch_test -p 2 -a 2 -w 1 -n 75)
add_test(pdsch_test_div_100 pdsch_test -p 2 -a 2 -w 1 -n 100 -m 28)
add_test(pdsch_test_cdd_6 pdsch_test -p 2 -a 2 -w 2 -n 6)
add_test(pdsch_test_cdd_12 pdsch_test -p 2 -a 2 -w 2 -n 12)
add_test(pdsch_test_cdd_25 pdsch_test -p 2 -a 2 -w 2 -n 25)
add_test(pdsch_test_cdd_50 pdsch_test -p 2 -a 2 -w 2 -n 50)
add_test(pdsch_test_cdd_75 pdsch_test -p 2 -a 2 -w 2 -n 75)
add_test(pdsch_test_cdd_100 pdsch_test -p 2 -a 2 -w 2 -n 100 -m 28 -M 28)
######################################################################## ########################################################################
# FILE TEST # FILE TEST
######################################################################## ########################################################################

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

@ -27,21 +27,25 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <strings.h>
#include <unistd.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" #include "srslte/srslte.h"
srslte_cell_t cell = { srslte_cell_t cell = {
6, // nof_prb .nof_prb = 6,
1, // nof_ports .nof_ports = 1,
1, // cell_id .id = 1,
SRSLTE_CP_NORM, // cyclic prefix .cp = SRSLTE_CP_NORM,
SRSLTE_PHICH_R_1, // PHICH resources .phich_resources = SRSLTE_PHICH_R_1,
SRSLTE_PHICH_NORM // PHICH length .phich_length = SRSLTE_PHICH_NORM
}; };
uint32_t cfi = 1; uint32_t cfi = 1;
uint32_t nof_rx_ant = 1;
bool print_dci_table; bool print_dci_table;
void usage(char *prog) { void usage(char *prog) {
@ -50,25 +54,29 @@ void usage(char *prog) {
printf("\t-f cfi [Default %d]\n", cfi); printf("\t-f cfi [Default %d]\n", cfi);
printf("\t-p cell.nof_ports [Default %d]\n", cell.nof_ports); 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-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-d Print DCI table [Default %s]\n", print_dci_table?"yes":"no");
printf("\t-v [set srslte_verbose to debug, default none]\n"); printf("\t-v [set srslte_verbose to debug, default none]\n");
} }
void parse_args(int argc, char **argv) { void parse_args(int argc, char **argv) {
int opt; int opt;
while ((opt = getopt(argc, argv, "cfpndv")) != -1) { while ((opt = getopt(argc, argv, "cfpndvA")) != -1) {
switch (opt) { switch (opt) {
case 'p': case 'p':
cell.nof_ports = atoi(argv[optind]); cell.nof_ports = (uint32_t) atoi(argv[optind]);
break; break;
case 'f': case 'f':
cfi = atoi(argv[optind]); cfi = (uint32_t) atoi(argv[optind]);
break; break;
case 'n': case 'n':
cell.nof_prb = atoi(argv[optind]); cell.nof_prb = (uint32_t) atoi(argv[optind]);
break; break;
case 'c': 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; break;
case 'd': case 'd':
print_dci_table = true; print_dci_table = true;
@ -85,25 +93,26 @@ void parse_args(int argc, char **argv) {
int test_dci_payload_size() { int test_dci_payload_size() {
int i, j; int i, j;
int x[4]; int x[5];
const srslte_dci_format_t formats[4] = { SRSLTE_DCI_FORMAT0, SRSLTE_DCI_FORMAT1, SRSLTE_DCI_FORMAT1A, SRSLTE_DCI_FORMAT1C }; 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 prb[6] = { 6, 15, 25, 50, 75, 100 };
const int dci_sz[6][5] = { { 21, 19, 21, 8 }, { 22, 23, 22, 10 }, { 25, 27, const int dci_sz[6][5] = { { 21, 19, 21, 8, 28 }, { 22, 23, 22, 10 , 31}, { 25, 27,
25, 12 }, { 27, 31, 27, 13 }, { 27, 33, 27, 14 }, { 28, 39, 28, 15 } }; 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("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++) { for (i = 0; i < 6; i++) {
int n = prb[i]; int n = prb[i];
for (j = 0; j < 4; j++) { for (j = 0; j < 5; j++) {
x[j] = srslte_dci_format_sizeof(formats[j], n, 1); x[j] = srslte_dci_format_sizeof(formats[j], (uint32_t) n, 1);
if (x[j] != dci_sz[i][j]) { if (x[j] != dci_sz[i][j]) {
fprintf(stderr, "Invalid DCI payload size for %s\n", fprintf(stderr, "Invalid DCI payload size for %s\n",
srslte_dci_format_string(formats[j])); srslte_dci_format_string(formats[j]));
return -1; 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"); printf("Ok\n");
@ -111,8 +120,8 @@ int test_dci_payload_size() {
printf("dci_sz_table[101][4] = {\n"); printf("dci_sz_table[101][4] = {\n");
for (i=0;i<=100;i++) { for (i=0;i<=100;i++) {
printf(" {"); printf(" {");
for (int j=0;j<4;j++) { for (j=0;j<4;j++) {
printf("%d",srslte_dci_format_sizeof(formats[j], i, 1)); printf("%d",srslte_dci_format_sizeof(formats[j], (uint32_t) i, 1));
if (j<3) { if (j<3) {
printf(", "); printf(", ");
} }
@ -128,16 +137,23 @@ int test_dci_payload_size() {
return 0; 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) { int main(int argc, char **argv) {
srslte_pdcch_t pdcch; srslte_pdcch_t pdcch_tx, pdcch_rx;
srslte_dci_msg_t dci_tx[2], dci_rx[2], dci_tmp; testcase_dci_t testcases[10] = {0};
srslte_dci_location_t dci_locations[2];
srslte_ra_dl_dci_t ra_dl; srslte_ra_dl_dci_t ra_dl;
srslte_regs_t regs; srslte_regs_t regs;
int i, j; int i, j, k;
cf_t *ce[SRSLTE_MAX_PORTS]; cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS];
int nof_re; 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 nof_dcis;
int ret = -1; int ret = -1;
@ -152,19 +168,30 @@ int main(int argc, char **argv) {
/* init memory */ /* init memory */
for (i = 0; i < SRSLTE_MAX_PORTS; i++) { for (i = 0; i < SRSLTE_MAX_PORTS; i++) {
ce[i] = malloc(sizeof(cf_t) * nof_re); for (j = 0; j < SRSLTE_MAX_PORTS; j++) {
if (!ce[i]) { ce[i][j] = malloc(sizeof(cf_t) * nof_re);
if (!ce[i][j]) {
perror("malloc"); perror("malloc");
exit(-1); exit(-1);
} }
for (j = 0; j < nof_re; j++) { for (k = 0; k < nof_re; k++) {
ce[i][j] = 1; //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);
} }
slot_symbols[i] = malloc(sizeof(cf_t) * nof_re); bzero(tx_slot_symbols[i], sizeof(cf_t) * nof_re);
if (!slot_symbols[i]) {
rx_slot_symbols[i] = malloc(sizeof(cf_t) * nof_re);
if (!rx_slot_symbols[i]) {
perror("malloc"); perror("malloc");
exit(-1); exit(-1);
} }
bzero(rx_slot_symbols[i], sizeof(cf_t) * nof_re);
} }
if (srslte_regs_init(&regs, cell)) { if (srslte_regs_init(&regs, cell)) {
@ -177,12 +204,18 @@ int main(int argc, char **argv) {
exit(-1); exit(-1);
} }
if (srslte_pdcch_init(&pdcch, &regs, cell)) { if (srslte_pdcch_init_tx(&pdcch_tx, &regs, cell)) {
fprintf(stderr, "Error creating PDCCH object\n"); fprintf(stderr, "Error creating PDCCH object\n");
exit(-1); exit(-1);
} }
nof_dcis = 2; if (srslte_pdcch_init_rx(&pdcch_rx, &regs, cell, nof_rx_ant)) {
fprintf(stderr, "Error creating PDCCH object\n");
exit(-1);
}
/* Resource allocate init */
nof_dcis = 0;
bzero(&ra_dl, sizeof(srslte_ra_dl_dci_t)); bzero(&ra_dl, sizeof(srslte_ra_dl_dci_t));
ra_dl.harq_process = 0; ra_dl.harq_process = 0;
ra_dl.mcs_idx = 5; ra_dl.mcs_idx = 5;
@ -190,62 +223,131 @@ int main(int argc, char **argv) {
ra_dl.rv_idx = 0; ra_dl.rv_idx = 0;
ra_dl.alloc_type = SRSLTE_RA_ALLOC_TYPE0; ra_dl.alloc_type = SRSLTE_RA_ALLOC_TYPE0;
ra_dl.type0_alloc.rbg_bitmask = 0x5; 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); /* Format 1 Test case */
srslte_dci_location_set(&dci_locations[0], 0, 0); 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; 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); testcases[nof_dcis].dci_format = SRSLTE_DCI_FORMAT1;
srslte_dci_location_set(&dci_locations[1], 0, 1); 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++) { 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"); fprintf(stderr, "Error encoding DCI message\n");
goto quit; goto quit;
} }
} }
srslte_vec_fprint_b(stdout, dci_tx[0].data, dci_tx[0].nof_bits); /* Apply channel */
/* combine outputs */ for (j = 0; j < nof_rx_ant; j++) {
for (i = 1; i < cell.nof_ports; i++) { for (k = 0; k < nof_re; k++) {
for (j = 0; j < nof_re; j++) { for (i = 0; i < cell.nof_ports; i++) {
slot_symbols[0][j] += slot_symbols[i][j]; rx_slot_symbols[j][k] += tx_slot_symbols[i][k]*ce[i][j][k];
}
} }
} }
for (i=0;i<2;i++) { /* Execute 'Rx' */
if (srslte_pdcch_extract_llr(&pdcch, slot_symbols[0], ce, 0, 0, cfi)) { if (srslte_pdcch_extract_llr_multi(&pdcch_rx, rx_slot_symbols, ce, 0, 0, cfi)) {
fprintf(stderr, "Error extracting LLRs\n"); fprintf(stderr, "Error extracting LLRs\n");
goto quit; goto quit;
} }
/* Decode DCIs */
for (i=0;i<nof_dcis;i++) {
uint16_t crc_rem; uint16_t crc_rem;
if (srslte_pdcch_decode_msg(&pdcch, &dci_tmp, &dci_locations[i], SRSLTE_DCI_FORMAT1, &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"); fprintf(stderr, "Error decoding DCI message\n");
goto quit; goto quit;
} }
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) { if (crc_rem >= 1234 && crc_rem < 1234 + nof_dcis) {
crc_rem -= 1234; crc_rem -= 1234;
memcpy(&dci_rx[crc_rem], &dci_tmp, sizeof(srslte_dci_msg_t));
} else { } else {
printf("Received invalid DCI CRC 0x%x\n", crc_rem); printf("Received invalid DCI CRC 0x%x\n", crc_rem);
goto quit; goto quit;
} }
} }
/* Compare Tx and Rx */
for (i = 0; i < nof_dcis; i++) { 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); printf("Error in DCI %d: Received data does not match\n", i);
goto quit; 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; ret = 0;
quit: quit:
srslte_pdcch_free(&pdcch); srslte_pdcch_free(&pdcch_tx);
srslte_pdcch_free(&pdcch_rx);
srslte_regs_free(&regs); srslte_regs_free(&regs);
for (i = 0; i < SRSLTE_MAX_PORTS; i++) { for (i = 0; i < SRSLTE_MAX_PORTS; i++) {
free(ce[i]); for (j = 0; j < SRSLTE_MAX_PORTS; j++) {
free(slot_symbols[i]); free(ce[i][j]);
}
free(tx_slot_symbols[i]);
free(rx_slot_symbols[i]);
} }
if (ret) { if (ret) {
printf("Error\n"); printf("Error\n");

@ -33,13 +33,14 @@
#define ENBCFG prhs[0] #define ENBCFG prhs[0]
#define RNTI prhs[1] #define RNTI prhs[1]
#define INPUT prhs[2] #define AMP prhs[2]
#define NOF_INPUTS 3 #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 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 = 2; const uint32_t nof_ue_formats = 3;
srslte_dci_format_t common_formats[] = {SRSLTE_DCI_FORMAT1A,SRSLTE_DCI_FORMAT1C}; srslte_dci_format_t common_formats[] = {SRSLTE_DCI_FORMAT1A,SRSLTE_DCI_FORMAT1C};
const uint32_t nof_common_formats = 2; const uint32_t nof_common_formats = 2;
@ -162,7 +163,10 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
} else { } else {
noise_power = srslte_chest_dl_get_noise_estimate(&chest); 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); srslte_pdcch_extract_llr(&pdcch, input_fft, ce, noise_power, sf_idx, cfi);

@ -30,45 +30,60 @@
#include <strings.h> #include <strings.h>
#include <unistd.h> #include <unistd.h>
#include <sys/time.h> #include <sys/time.h>
#include <srslte/phy/phch/ra.h>
#include "srslte/srslte.h" #include "srslte/srslte.h"
// Enable to measure execution time // Enable to measure execution time
//#define DO_OFDM //#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 = { srslte_cell_t cell = {
6, // nof_prb 6, // nof_prb
1, // nof_ports 1, // nof_ports
0, // cell_id 0, // cell_id
SRSLTE_CP_NORM, // cyclic prefix 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
}; };
uint32_t cfi = 2; uint32_t cfi = 2;
uint32_t mcs = 0; uint32_t mcs = 0;
uint32_t mcs2 = 0;
uint32_t subframe = 1; uint32_t subframe = 1;
uint32_t rv_idx = 0; uint32_t rv_idx = 0;
uint32_t rv_idx2 = 0;
uint16_t rnti = 1234; uint16_t rnti = 1234;
uint32_t nof_tb = 1;
uint32_t nof_rx_antennas = 1;
char *input_file = NULL; char *input_file = NULL;
void usage(char *prog) { 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-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);
printf("\t-M MCS2 [Default %d]\n", mcs2);
printf("\t-c cell id [Default %d]\n", cell.id); printf("\t-c cell id [Default %d]\n", cell.id);
printf("\t-s subframe [Default %d]\n", subframe); 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);
printf("\t-t rv_idx2 [Default %d]\n", rv_idx2);
printf("\t-R rnti [Default %d]\n", rnti); printf("\t-R rnti [Default %d]\n", rnti);
printf("\t-F cfi [Default %d]\n", cfi); printf("\t-F cfi [Default %d]\n", cfi);
printf("\t-p cell.nof_ports [Default %d]\n", cell.nof_ports); 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-n cell.nof_prb [Default %d]\n", cell.nof_prb);
printf("\t-w nof_tb [Default %d]\n", nof_tb);
printf("\t-a nof_rx_antennas [Default %d]\n", nof_rx_antennas);
printf("\t-v [set srslte_verbose to debug, default none]\n"); printf("\t-v [set srslte_verbose to debug, default none]\n");
} }
void parse_args(int argc, char **argv) { void parse_args(int argc, char **argv) {
int opt; int opt;
while ((opt = getopt(argc, argv, "fmcsrRFpnv")) != -1) { while ((opt = getopt(argc, argv, "fmMcsrtRFpnwav")) != -1) {
switch(opt) { switch(opt) {
case 'f': case 'f':
input_file = argv[optind]; input_file = argv[optind];
@ -76,12 +91,18 @@ void parse_args(int argc, char **argv) {
case 'm': case 'm':
mcs = atoi(argv[optind]); mcs = atoi(argv[optind]);
break; break;
case 'M':
mcs2 = (uint32_t) atoi(argv[optind]);
break;
case 's': case 's':
subframe = atoi(argv[optind]); subframe = atoi(argv[optind]);
break; break;
case 'r': case 'r':
rv_idx = atoi(argv[optind]); rv_idx = atoi(argv[optind]);
break; break;
case 't':
rv_idx2 = (uint32_t) atoi(argv[optind]);
break;
case 'R': case 'R':
rnti = atoi(argv[optind]); rnti = atoi(argv[optind]);
break; break;
@ -97,6 +118,12 @@ void parse_args(int argc, char **argv) {
case 'c': case 'c':
cell.id = atoi(argv[optind]); cell.id = atoi(argv[optind]);
break; break;
case 'w':
nof_tb = (uint32_t) atoi(argv[optind]);
break;
case 'a':
nof_rx_antennas = (uint32_t) atoi(argv[optind]);
break;
case 'v': case 'v':
srslte_verbose++; srslte_verbose++;
break; break;
@ -107,30 +134,37 @@ void parse_args(int argc, char **argv) {
} }
} }
uint8_t *data = NULL; uint8_t *data[SRSLTE_MAX_CODEWORDS] = {NULL};
cf_t *ce[SRSLTE_MAX_PORTS]; cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS];
srslte_softbuffer_rx_t softbuffer_rx; srslte_softbuffer_rx_t softbuffers_rx[SRSLTE_MAX_CODEWORDS];
srslte_ra_dl_grant_t grant; srslte_ra_dl_grant_t grant;
srslte_pdsch_cfg_t pdsch_cfg; srslte_pdsch_cfg_t pdsch_cfg;
cf_t *sf_symbols; #ifdef DO_OFDM
cf_t *slot_symbols[SRSLTE_MAX_PORTS]; cf_t *tx_sf_symbols[SRSLTE_MAX_PORTS];
srslte_pdsch_t pdsch; 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; srslte_ofdm_t ofdm_tx, ofdm_rx;
int main(int argc, char **argv) { int main(int argc, char **argv) {
uint32_t i, j; uint32_t i, j, k;
int ret = -1; int ret = -1;
struct timeval t[3]; struct timeval t[3];
srslte_softbuffer_tx_t softbuffer_tx; srslte_softbuffer_tx_t softbuffers_tx[SRSLTE_MAX_CODEWORDS];
parse_args(argc,argv); 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(&pdsch_cfg, sizeof(srslte_pdsch_cfg_t));
bzero(ce, sizeof(cf_t*)*SRSLTE_MAX_PORTS); bzero(ce, sizeof(cf_t*)*SRSLTE_MAX_PORTS);
bzero(slot_symbols, sizeof(cf_t*)*SRSLTE_MAX_PORTS); bzero(tx_slot_symbols, sizeof(cf_t*)*SRSLTE_MAX_PORTS);
bzero(&softbuffer_rx, sizeof(srslte_softbuffer_rx_t)); bzero(rx_slot_symbols, sizeof(cf_t*)*SRSLTE_MAX_PORTS);
bzero(&softbuffer_tx, sizeof(srslte_softbuffer_tx_t)); bzero(softbuffers_tx, sizeof(srslte_softbuffer_tx_t)*SRSLTE_MAX_CODEWORDS);
bzero(softbuffers_rx, sizeof(srslte_softbuffer_rx_t)*SRSLTE_MAX_CODEWORDS);
srslte_ra_dl_dci_t dci; srslte_ra_dl_dci_t dci;
bzero(&dci, sizeof(srslte_ra_dl_dci_t)); bzero(&dci, sizeof(srslte_ra_dl_dci_t));
@ -138,56 +172,135 @@ int main(int argc, char **argv) {
dci.rv_idx = rv_idx; dci.rv_idx = rv_idx;
dci.type0_alloc.rbg_bitmask = 0xffffffff; dci.type0_alloc.rbg_bitmask = 0xffffffff;
dci.tb_en[0] = true; dci.tb_en[0] = true;
if (nof_tb > 1) {
dci.mcs_idx_1 = mcs2;
dci.rv_idx_1 = rv_idx2;
dci.tb_en[1] = true;
}
/* Generate grant from DCI */
if (srslte_ra_dl_dci_to_grant(&dci, cell.nof_prb, rnti, &grant)) { if (srslte_ra_dl_dci_to_grant(&dci, cell.nof_prb, rnti, &grant)) {
fprintf(stderr, "Error computing resource allocation\n"); fprintf(stderr, "Error computing resource allocation\n");
return ret; return ret;
} }
#ifdef DO_OFDM
srslte_ofdm_tx_init(&ofdm_tx, cell.cp, cell.nof_prb); srslte_ofdm_tx_init(&ofdm_tx, cell.cp, cell.nof_prb);
srslte_ofdm_rx_init(&ofdm_rx, 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 */ /* Configure PDSCH */
if (srslte_pdsch_cfg(&pdsch_cfg, cell, &grant, cfi, subframe, rv_idx)) { if (srslte_pdsch_cfg_multi(&pdsch_cfg, cell, &grant, cfi, subframe, rv_idx, rv_idx2)) {
fprintf(stderr, "Error configuring PDSCH\n"); fprintf(stderr, "Error configuring PDSCH\n");
exit(-1); exit(-1);
} }
/* Select MIMO mode */
if (cell.nof_ports == 1 && nof_tb == 1) {
pdsch_cfg.mimo_type = SRSLTE_MIMO_TYPE_SINGLE_ANTENNA;
pdsch_cfg.nof_layers = 1;
} else if (cell.nof_ports == 2 && nof_tb == 1) {
pdsch_cfg.mimo_type = SRSLTE_MIMO_TYPE_TX_DIVERSITY;
pdsch_cfg.nof_layers = 2;
} else if (cell.nof_ports == 2 && nof_tb == 2) {
pdsch_cfg.mimo_type = SRSLTE_MIMO_TYPE_CDD;
pdsch_cfg.nof_layers = 2;
} else {
fprintf(stderr, "nof_ports=%d, nof_tb=%d are not consistent\n", cell.nof_ports, nof_tb);
exit(-1);
}
/* init memory */ /* init memory */
for (i=0;i<SRSLTE_MAX_PORTS;i++) { 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)); for (j = 0; j < SRSLTE_MAX_PORTS; j++) {
ce[i][j] = srslte_vec_malloc(sizeof(cf_t) * NOF_CE_SYMBOLS);
if (!ce[i]) { if (!ce[i]) {
perror("srslte_vec_malloc"); perror("srslte_vec_malloc");
goto quit; goto quit;
} }
for (j=0;j<SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp);j++) { for (k = 0; k < NOF_CE_SYMBOLS; k++) {
ce[i][j] = 1; 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"); perror("srslte_vec_malloc");
goto quit; goto quit;
} }
} }
data = srslte_vec_malloc(sizeof(uint8_t) * (grant.mcs.tbs/8)+24);
if (!data) { if (grant.mcs.tbs) {
data[0] = srslte_vec_malloc(sizeof(uint8_t) * grant.mcs.tbs);
if (!data[0]) {
perror("srslte_vec_malloc"); perror("srslte_vec_malloc");
goto quit; goto quit;
} }
}
if (srslte_pdsch_init(&pdsch, cell)) { if (grant.mcs2.tbs) {
data[1] = srslte_vec_malloc(sizeof(uint8_t) * grant.mcs.tbs);
if (!data[1]) {
perror("srslte_vec_malloc");
goto quit;
}
}
if (srslte_pdsch_init_rx_multi(&pdsch_rx, cell, nof_rx_antennas)) {
fprintf(stderr, "Error creating PDSCH object\n"); fprintf(stderr, "Error creating PDSCH object\n");
goto quit; goto quit;
} }
srslte_pdsch_set_rnti(&pdsch, rnti); srslte_pdsch_set_rnti(&pdsch_rx, rnti);
if (srslte_softbuffer_rx_init(&softbuffer_rx, cell.nof_prb)) { for (i = 0; i < nof_tb; i++) {
if (srslte_softbuffer_rx_init(&softbuffers_rx[i], cell.nof_prb)) {
fprintf(stderr, "Error initiating RX soft buffer\n"); fprintf(stderr, "Error initiating RX soft buffer\n");
goto quit; goto quit;
} }
}
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(" Qm=%d\n", pdsch_cfg.grant.Qm);
INFO(" Qm2=%d\n", pdsch_cfg.grant.Qm2);
INFO(" mcs.idx=0x%X\n", pdsch_cfg.grant.mcs.idx);
INFO(" mcs.tbs=%d\n", pdsch_cfg.grant.mcs.tbs);
INFO(" mcs.mod=%s\n", srslte_mod_string(pdsch_cfg.grant.mcs.mod));
INFO(" mcs2.idx=0x%X\n", pdsch_cfg.grant.mcs2.idx);
INFO(" mcs2.tbs=%d\n", pdsch_cfg.grant.mcs2.tbs);
INFO(" mcs2.mod=%s\n", srslte_mod_string(pdsch_cfg.grant.mcs2.mod));
INFO(" nof_layers=%d\n", pdsch_cfg.nof_layers);
INFO(" rv=%d\n", pdsch_cfg.rv);
INFO(" rv2=%d\n", pdsch_cfg.rv2);
INFO(" sf_idx=%d\n", pdsch_cfg.sf_idx);
INFO(" mimo_type=%d\n", (int) pdsch_cfg.mimo_type);
INFO(" nof_tb=%d\n", pdsch_cfg.grant.nof_tb);
INFO(" lstart=%d\n", pdsch_cfg.nbits.lstart);
INFO(" nof_bits=%d\n", pdsch_cfg.nbits.nof_bits);
INFO(" nof_re=%d\n", pdsch_cfg.nbits.nof_re);
INFO(" nof_symb=%d\n", pdsch_cfg.nbits.nof_symb);
INFO(" lstart=%d\n", pdsch_cfg.nbits2.lstart);
INFO(" nof_bits=%d\n", pdsch_cfg.nbits2.nof_bits);
INFO(" nof_re=%d\n", pdsch_cfg.nbits2.nof_re);
INFO(" nof_symb=%d\n", pdsch_cfg.nbits2.nof_symb);
if (input_file) { if (input_file) {
srslte_filesource_t fsrc; srslte_filesource_t fsrc;
@ -196,102 +309,156 @@ int main(int argc, char **argv) {
exit(-1); exit(-1);
} }
#ifdef DO_OFDM #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 #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 #endif
srslte_chest_dl_t chest; srslte_chest_dl_t chest;
if (srslte_chest_dl_init(&chest, cell)) { if (srslte_chest_dl_init(&chest, cell)) {
printf("Error initializing equalizer\n"); fprintf(stderr, "Error initializing equalizer\n");
exit(-1); 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_chest_dl_free(&chest);
srslte_filesource_free(&fsrc); srslte_filesource_free(&fsrc);
} else { } else {
if (srslte_softbuffer_tx_init(&softbuffer_tx, cell.nof_prb)) {
if (srslte_pdsch_init_tx_multi(&pdsch_tx, cell)) {
fprintf(stderr, "Error creating PDSCH object\n");
goto quit;
}
srslte_pdsch_set_rnti(&pdsch_tx, rnti);
for (i = 0; i < nof_tb; i++) {
if (srslte_softbuffer_tx_init(&softbuffers_tx[i], cell.nof_prb)) {
fprintf(stderr, "Error initiating TX soft buffer\n"); fprintf(stderr, "Error initiating TX soft buffer\n");
goto quit; goto quit;
} }
}
for (i=0;i<grant.mcs.tbs/8;i++) { for (i = 0; i < cell.nof_ports; i++) {
data[i] = rand()%256; 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;
}
} }
uint8_t databit[100000]; for (i = 0; i < grant.mcs.tbs / 8; i++) {
srslte_bit_unpack_vector(data, databit, grant.mcs.tbs); data[0][i] = (uint8_t) (rand() % 256);
srslte_vec_save_file("data_in", databit, grant.mcs.tbs); }
if (!input_file) { for (i = 0; i < grant.mcs2.tbs / 8; i++) {
data[1][i] = (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);*/
if (rv_idx) { if (rv_idx) {
/* Do 1st transmission for rv_idx!=0 */ /* Do 1st transmission for rv_idx!=0 */
pdsch_cfg.rv = 0; pdsch_cfg.rv = 0;
if (srslte_pdsch_encode(&pdsch, &pdsch_cfg, &softbuffer_tx, data, rnti, slot_symbols)) { pdsch_cfg.rv2 = 0;
if (srslte_pdsch_encode_multi(&pdsch_tx, &pdsch_cfg, softbuffers_tx, data, rnti, tx_slot_symbols)) {
fprintf(stderr, "Error encoding PDSCH\n"); fprintf(stderr, "Error encoding PDSCH\n");
goto quit; goto quit;
} }
} }
pdsch_cfg.rv = rv_idx; pdsch_cfg.rv = rv_idx;
pdsch_cfg.rv2 = rv_idx2;
if (srslte_pdsch_encode(&pdsch, &pdsch_cfg, &softbuffer_tx, data, rnti, slot_symbols)) { if (srslte_pdsch_encode_multi(&pdsch_tx, &pdsch_cfg, softbuffers_tx, data, rnti, tx_slot_symbols)) {
fprintf(stderr, "Error encoding PDSCH\n"); fprintf(stderr, "Error encoding PDSCH\n");
goto quit; goto quit;
} }
#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 */ /* combine outputs */
for (i=0;i<cell.nof_ports;i++) { for (j = 0; j < nof_rx_antennas; j++) {
for (j=0;j<SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp);j++) { for (k = 0; k < NOF_CE_SYMBOLS; k++) {
if (i > 0) { rx_sf_symbols[j][k] = 0.0f;
slot_symbols[0][j] += slot_symbols[i][j]; 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 #endif
} }
int M=1; int M=10;
int r=0; int r=0;
srslte_sch_set_max_noi(&pdsch.dl_sch, 10); srslte_sch_set_max_noi(&pdsch_rx.dl_sch, 10);
gettimeofday(&t[1], NULL); gettimeofday(&t[1], NULL);
for (i=0;i<M;i++) { for (k = 0; k < M; k++) {
#ifdef DO_OFDM #ifdef DO_OFDM
srslte_ofdm_rx_sf(&ofdm_rx, sf_symbols, slot_symbols[1]); /* For each Rx antenna demodulate OFDM */
#endif for (i = 0; i < nof_rx_antennas; i++) {
srslte_softbuffer_rx_reset_tbs(&softbuffer_rx, grant.mcs.tbs); srslte_ofdm_rx_sf(&ofdm_rx, tx_sf_symbols[i], rx_slot_symbols[i]);
r = srslte_pdsch_decode(&pdsch, &pdsch_cfg, &softbuffer_rx, slot_symbols[0], ce, 0, rnti, data); }
#endif
if (grant.mcs.tbs) {
srslte_softbuffer_rx_reset_tbs(&softbuffers_rx[0], (uint32_t) grant.mcs.tbs);
}
if (grant.mcs2.tbs) {
srslte_softbuffer_rx_reset_tbs(&softbuffers_rx[1], (uint32_t) grant.mcs2.tbs);
}
r = srslte_pdsch_decode_multi(&pdsch_rx, &pdsch_cfg, softbuffers_rx, rx_slot_symbols, ce, 0, rnti, data);
} }
gettimeofday(&t[2], NULL); gettimeofday(&t[2], NULL);
get_time_interval(t); get_time_interval(t);
printf("DECODED %s in %.2f (PHY bitrate=%.2f Mbps. Processing bitrate=%.2f Mbps)\n", r?"Error":"OK", INFO("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.tbs + grant.mcs2.tbs)/1000.0f,
(float) (grant.mcs.tbs + grant.mcs2.tbs)*M/t[0].tv_usec);
if (r) { if (r) {
ret = -1; ret = -1;
goto quit; goto quit;
} }
ret = 0; ret = 0;
quit: quit:
srslte_pdsch_free(&pdsch); srslte_pdsch_free(&pdsch_tx);
srslte_softbuffer_tx_free(&softbuffer_tx); srslte_pdsch_free(&pdsch_rx);
srslte_softbuffer_rx_free(&softbuffer_rx); for (i = 0; i < nof_tb; i++) {
srslte_softbuffer_tx_free(&softbuffers_tx[i]);
srslte_softbuffer_rx_free(&softbuffers_rx[i]);
if (data[i]) {
free(data[i]);
}
}
for (i=0;i<cell.nof_ports;i++) { for (i=0;i<SRSLTE_MAX_PORTS;i++) {
if (ce[i]) { for (j = 0; j < SRSLTE_MAX_PORTS; j++) {
free(ce[i]); if (ce[i][j]) {
free(ce[i][j]);
}
} }
if (slot_symbols[i]) { if (tx_slot_symbols[i]) {
free(slot_symbols[i]); free(tx_slot_symbols[i]);
} }
if (rx_slot_symbols[i]) {
free(rx_slot_symbols[i]);
} }
if (data) {
free(data);
} }
if (ret) { if (ret) {
printf("Error\n"); printf("Error\n");

@ -101,7 +101,7 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
nof_antennas = dims[2]; 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"); mexErrMsgTxt("Error initiating PDSCH\n");
return; return;
} }

@ -104,6 +104,8 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
srslte_prach_set_detect_factor(&prach, factor); 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)) { 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"); mexErrMsgTxt("Error detecting PRACH\n");
return; 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); 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"); mexErrMsgTxt("Error encoding PUCCH\n");
return; 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); 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"); mexErrMsgTxt("Error estimating PUCCH DMRS\n");
return; 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"); mexErrMsgTxt("Error decoding PUCCH\n");
return; return;
} }

@ -178,7 +178,7 @@ float rf_blade_get_rssi(void *h)
return 0; 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_tx_antennas, uint32_t nof_rx_antennas)
{ {
return rf_blade_open(args, h); return rf_blade_open(args, h);
} }
@ -469,6 +469,20 @@ int rf_blade_recv_with_time(void *h,
return nsamples; 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, int rf_blade_send_timed(void *h,
void *data, void *data,
int nsamples, int nsamples,

@ -34,7 +34,7 @@ SRSLTE_API int rf_blade_open(char *args,
void **handler); void **handler);
SRSLTE_API int rf_blade_open_multi(char *args, SRSLTE_API int rf_blade_open_multi(char *args,
void **handler, uint32_t nof_rx_antennas); void **handler, uint32_t nof_tx_antennas, uint32_t nof_rx_antennas);
SRSLTE_API char* rf_blade_devname(void *h); SRSLTE_API char* rf_blade_devname(void *h);
@ -111,6 +111,16 @@ SRSLTE_API void rf_blade_get_time(void *h,
time_t *secs, time_t *secs,
double *frac_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, SRSLTE_API int rf_blade_send_timed(void *h,
void *data, void *data,
int nsamples, int nsamples,

@ -38,7 +38,7 @@ typedef struct {
void (*srslte_rf_suppress_stdout)(void *h); void (*srslte_rf_suppress_stdout)(void *h);
void (*srslte_rf_register_error_handler)(void *h, srslte_rf_error_handler_t error_handler); 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)(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_tx_antennas, uint32_t nof_rx_antennas);
int (*srslte_rf_close)(void *h); int (*srslte_rf_close)(void *h);
void (*srslte_rf_set_master_clock_rate)(void *h, double rate); void (*srslte_rf_set_master_clock_rate)(void *h, double rate);
bool (*srslte_rf_is_master_clock_dynamic)(void *h); 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, int (*srslte_rf_send_timed)(void *h, void *data, int nsamples,
time_t secs, double frac_secs, bool has_time_spec, time_t secs, double frac_secs, bool has_time_spec,
bool blocking, bool is_start_of_burst, bool is_end_of_burst); 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_tx_cal)(void *h, srslte_rf_cal_t *cal);
void (*srslte_rf_set_rx_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_suppress_stdout,
rf_uhd_register_error_handler, rf_uhd_register_error_handler,
rf_uhd_open, rf_uhd_open,
rf_uhd_open_multi, .srslte_rf_open_multi = rf_uhd_open_multi,
rf_uhd_close, rf_uhd_close,
rf_uhd_set_master_clock_rate, rf_uhd_set_master_clock_rate,
rf_uhd_is_master_clock_dynamic, 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,
rf_uhd_recv_with_time_multi, rf_uhd_recv_with_time_multi,
rf_uhd_send_timed, rf_uhd_send_timed,
.srslte_rf_send_timed_multi = rf_uhd_send_timed_multi,
rf_uhd_set_tx_cal, rf_uhd_set_tx_cal,
rf_uhd_set_rx_cal rf_uhd_set_rx_cal
}; };
@ -119,7 +123,7 @@ static rf_dev_t dev_blade = {
rf_blade_suppress_stdout, rf_blade_suppress_stdout,
rf_blade_register_error_handler, rf_blade_register_error_handler,
rf_blade_open, rf_blade_open,
rf_blade_open_multi, .srslte_rf_open_multi = rf_blade_open_multi,
rf_blade_close, rf_blade_close,
rf_blade_set_master_clock_rate, rf_blade_set_master_clock_rate,
rf_blade_is_master_clock_dynamic, 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,
rf_blade_recv_with_time_multi, rf_blade_recv_with_time_multi,
rf_blade_send_timed, rf_blade_send_timed,
.srslte_rf_send_timed_multi = rf_blade_send_timed_multi,
rf_blade_set_tx_cal, rf_blade_set_tx_cal,
rf_blade_set_rx_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,
rf_soapy_recv_with_time_multi, rf_soapy_recv_with_time_multi,
rf_soapy_send_timed, 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_tx_cal,
rf_soapy_set_rx_cal rf_soapy_set_rx_cal
}; };

@ -103,6 +103,10 @@ int srslte_rf_open_devname(srslte_rf_t *rf, char *devname, char *args) {
} }
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_rx_antennas) {
return srslte_rf_open_devname_multi2(rf, devname, args, 1, nof_rx_antennas);
}
int srslte_rf_open_devname_multi2(srslte_rf_t *rf, char *devname, char *args, uint32_t nof_tx_antennas, uint32_t nof_rx_antennas) {
/* Try to open the device if name is provided */ /* Try to open the device if name is provided */
if (devname) { if (devname) {
if (devname[0] != '\0') { if (devname[0] != '\0') {
@ -110,7 +114,7 @@ int srslte_rf_open_devname_multi(srslte_rf_t *rf, char *devname, char *args, uin
while(available_devices[i] != NULL) { while(available_devices[i] != NULL) {
if (!strcmp(available_devices[i]->name, devname)) { if (!strcmp(available_devices[i]->name, devname)) {
rf->dev = available_devices[i]; 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_tx_antennas, nof_rx_antennas);
} }
i++; i++;
} }
@ -121,7 +125,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 */ /* If in auto mode or provided device not found, try to open in order of apperance in available_devices[] array */
int i=0; int i=0;
while(available_devices[i] != NULL) { 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_tx_antennas, nof_rx_antennas)) {
rf->dev = available_devices[i]; rf->dev = available_devices[i];
return 0; return 0;
} }
@ -194,6 +198,11 @@ int srslte_rf_open_multi(srslte_rf_t *h, char *args, uint32_t nof_rx_antennas)
return srslte_rf_open_devname_multi(h, NULL, args, nof_rx_antennas); return srslte_rf_open_devname_multi(h, NULL, args, nof_rx_antennas);
} }
int srslte_rf_open_multi2(srslte_rf_t *h, char *args, uint32_t nof_tx_antennas, uint32_t nof_rx_antennas)
{
return srslte_rf_open_devname_multi2(h, NULL, args, nof_tx_antennas, nof_rx_antennas);
}
int srslte_rf_close(srslte_rf_t *rf) int srslte_rf_close(srslte_rf_t *rf)
{ {
return ((rf_dev_t*) rf->dev)->srslte_rf_close(rf->handler); return ((rf_dev_t*) rf->dev)->srslte_rf_close(rf->handler);
@ -301,6 +310,18 @@ int srslte_rf_send_timed3(srslte_rf_t *rf,
has_time_spec, blocking, is_start_of_burst, is_end_of_burst); has_time_spec, 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) 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); return srslte_rf_send2(rf, data, nsamples, blocking, true, true);

@ -286,10 +286,10 @@ float rf_uhd_get_rssi(void *h) {
int rf_uhd_open(char *args, void **h) int rf_uhd_open(char *args, void **h)
{ {
return rf_uhd_open_multi(args, h, 1); return rf_uhd_open_multi(args, h, 1, 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_tx_antennas, uint32_t nof_rx_antennas)
{ {
if (h) { if (h) {
*h = NULL; *h = NULL;
@ -395,12 +395,11 @@ int rf_uhd_open_multi(char *args, void **h, uint32_t nof_rx_antennas)
.otw_format = "sc16", .otw_format = "sc16",
.args = "", .args = "",
.channel_list = channel, .channel_list = channel,
.n_channels = 1 .n_channels = (nof_tx_antennas > nof_rx_antennas)?nof_tx_antennas:nof_rx_antennas,
}; };
handler->nof_rx_channels = nof_rx_antennas; handler->nof_rx_channels = nof_rx_antennas;
handler->nof_tx_channels = 1; handler->nof_tx_channels = nof_tx_antennas;
/* Initialize rx and tx stremers */ /* Initialize rx and tx stremers */
uhd_rx_streamer_make(&handler->rx_stream); uhd_rx_streamer_make(&handler->rx_stream);
error = uhd_usrp_get_rx_stream(handler->usrp, &stream_args, handler->rx_stream); error = uhd_usrp_get_rx_stream(handler->usrp, &stream_args, handler->rx_stream);
@ -648,8 +647,28 @@ int rf_uhd_send_timed(void *h,
bool is_start_of_burst, bool is_start_of_burst,
bool is_end_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; rf_uhd_handler_t* handler = (rf_uhd_handler_t*) h;
/* Resets the USRP time FIXME: this might cause problems for burst transmissions */
if (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; size_t txd_samples;
if (has_time_spec) { if (has_time_spec) {
uhd_tx_metadata_set_time_spec(&handler->tx_md, secs, frac_secs); uhd_tx_metadata_set_time_spec(&handler->tx_md, secs, frac_secs);
@ -657,7 +676,10 @@ int rf_uhd_send_timed(void *h,
int trials = 0; int trials = 0;
if (blocking) { if (blocking) {
int n = 0; 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 { do {
size_t tx_samples = handler->tx_nof_samples; size_t tx_samples = handler->tx_nof_samples;
@ -676,8 +698,11 @@ int rf_uhd_send_timed(void *h,
uhd_tx_metadata_set_end(&handler->tx_md, is_end_of_burst); uhd_tx_metadata_set_end(&handler->tx_md, is_end_of_burst);
} }
void *buff = (void*) &data_c[n]; const void *buffs_ptr[4];
const void *buffs_ptr[4] = {buff, zero_mem, zero_mem, zero_mem}; 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, uhd_error error = uhd_tx_streamer_send(handler->tx_stream, buffs_ptr,
tx_samples, &handler->tx_md, 3.0, &txd_samples); tx_samples, &handler->tx_md, 3.0, &txd_samples);
if (error) { if (error) {
@ -691,7 +716,10 @@ int rf_uhd_send_timed(void *h,
} while (n < nsamples && trials < 100); } while (n < nsamples && trials < 100);
return nsamples; return nsamples;
} else { } 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_start(&handler->tx_md, is_start_of_burst);
uhd_tx_metadata_set_end(&handler->tx_md, is_end_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); return uhd_tx_streamer_send(handler->tx_stream, buffs_ptr, nsamples, &handler->tx_md, 0.0, &txd_samples);

@ -39,6 +39,7 @@ SRSLTE_API int rf_uhd_open(char *args,
SRSLTE_API int rf_uhd_open_multi(char *args, SRSLTE_API int rf_uhd_open_multi(char *args,
void **handler, void **handler,
uint32_t nof_tx_antennas,
uint32_t nof_rx_antennas); uint32_t nof_rx_antennas);
SRSLTE_API char* rf_uhd_devname(void *h); SRSLTE_API char* rf_uhd_devname(void *h);
@ -123,3 +124,13 @@ SRSLTE_API int rf_uhd_send_timed(void *h,
bool is_start_of_burst, bool is_start_of_burst,
bool is_end_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);

@ -38,8 +38,8 @@
#define CURRENT_SFLEN_RE SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp) #define CURRENT_SFLEN_RE SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp)
static srslte_dci_format_t ue_formats[] = {SRSLTE_DCI_FORMAT1A, SRSLTE_DCI_FORMAT1}; // Only TM1 and TM2 are currently supported static srslte_dci_format_t ue_formats[] = {SRSLTE_DCI_FORMAT1A, SRSLTE_DCI_FORMAT1, SRSLTE_DCI_FORMAT2A}; // Only TM1 and TM2 are currently supported
const uint32_t nof_ue_formats = 2; const uint32_t nof_ue_formats = 3;
static srslte_dci_format_t common_formats[] = {SRSLTE_DCI_FORMAT1A,SRSLTE_DCI_FORMAT1C}; static srslte_dci_format_t common_formats[] = {SRSLTE_DCI_FORMAT1A,SRSLTE_DCI_FORMAT1C};
const uint32_t nof_common_formats = 2; const uint32_t nof_common_formats = 2;
@ -97,14 +97,17 @@ int srslte_ue_dl_init_multi(srslte_ue_dl_t *q,
goto clean_exit; goto clean_exit;
} }
if (srslte_pdsch_init_multi(&q->pdsch, q->cell, nof_rx_antennas)) { if (srslte_pdsch_init_rx_multi(&q->pdsch, q->cell, nof_rx_antennas)) {
fprintf(stderr, "Error creating PDSCH object\n"); fprintf(stderr, "Error creating PDSCH object\n");
goto clean_exit; goto clean_exit;
} }
if (srslte_softbuffer_rx_init(&q->softbuffer, q->cell.nof_prb)) {
for (int i = 0; i < SRSLTE_MAX_CODEWORDS; i++) {
if (srslte_softbuffer_rx_init(&q->softbuffers[i], q->cell.nof_prb)) {
fprintf(stderr, "Error initiating soft buffer\n"); fprintf(stderr, "Error initiating soft buffer\n");
goto clean_exit; goto clean_exit;
} }
}
if (srslte_cfo_init(&q->sfo_correct, q->cell.nof_prb*SRSLTE_NRE)) { if (srslte_cfo_init(&q->sfo_correct, q->cell.nof_prb*SRSLTE_NRE)) {
fprintf(stderr, "Error initiating SFO correct\n"); fprintf(stderr, "Error initiating SFO correct\n");
goto clean_exit; goto clean_exit;
@ -154,7 +157,9 @@ void srslte_ue_dl_free(srslte_ue_dl_t *q) {
srslte_pdcch_free(&q->pdcch); srslte_pdcch_free(&q->pdcch);
srslte_pdsch_free(&q->pdsch); srslte_pdsch_free(&q->pdsch);
srslte_cfo_free(&q->sfo_correct); srslte_cfo_free(&q->sfo_correct);
srslte_softbuffer_rx_free(&q->softbuffer); for (int i = 0; i < SRSLTE_MAX_CODEWORDS; i++) {
srslte_softbuffer_rx_free(&q->softbuffers[i]);
}
for (int j=0;j<q->nof_rx_antennas;j++) { for (int j=0;j<q->nof_rx_antennas;j++) {
if (q->sf_symbols_m[j]) { if (q->sf_symbols_m[j]) {
free(q->sf_symbols_m[j]); free(q->sf_symbols_m[j]);
@ -188,7 +193,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) { 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)); bzero(&q->pdsch_cfg, sizeof(srslte_pdsch_cfg_t));
} }
@ -204,12 +211,14 @@ void srslte_ue_dl_set_sample_offset(srslte_ue_dl_t * q, float sample_offset) {
* - PDSCH decoding: Decode TB scrambling with RNTI given by 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) { int srslte_ue_dl_decode(srslte_ue_dl_t *q, cf_t *input, uint8_t *data, uint32_t tti) {
uint8_t *_data[SRSLTE_MAX_CODEWORDS];
cf_t *_input[SRSLTE_MAX_PORTS]; cf_t *_input[SRSLTE_MAX_PORTS];
_data[0] = data;
_input[0] = input; _input[0] = input;
return srslte_ue_dl_decode_rnti_multi(q, _input, data, tti, q->current_rnti); 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) { int srslte_ue_dl_decode_multi(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS], uint8_t *data[SRSLTE_MAX_CODEWORDS], uint32_t tti) {
return srslte_ue_dl_decode_rnti_multi(q, input, data, tti, q->current_rnti); return srslte_ue_dl_decode_rnti_multi(q, input, data, tti, q->current_rnti);
} }
@ -275,17 +284,24 @@ 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) 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); return srslte_pdsch_cfg_multi(&q->pdsch_cfg, q->cell, grant, cfi, sf_idx, rvidx, 0);
}
int srslte_ue_dl_cfg_grant_multi(srslte_ue_dl_t *q, srslte_ra_dl_grant_t *grant, uint32_t cfi, uint32_t sf_idx, uint32_t rvidx, uint32_t rvidx2)
{
return srslte_pdsch_cfg_multi(&q->pdsch_cfg, q->cell, grant, cfi, sf_idx, rvidx, rvidx2);
} }
int srslte_ue_dl_decode_rnti(srslte_ue_dl_t *q, cf_t *input, uint8_t *data, uint32_t tti, uint16_t rnti) int srslte_ue_dl_decode_rnti(srslte_ue_dl_t *q, cf_t *input, uint8_t *data, uint32_t tti, uint16_t rnti)
{ {
uint8_t *_data[SRSLTE_MAX_CODEWORDS];
cf_t *_input[SRSLTE_MAX_PORTS]; cf_t *_input[SRSLTE_MAX_PORTS];
_input[0] = input; _input[0] = input;
return srslte_ue_dl_decode_rnti_multi(q, _input, data, tti, rnti); _data[0] = data;
return srslte_ue_dl_decode_rnti_multi(q, _input, _data, tti, rnti);
} }
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_multi(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS], uint8_t *data[SRSLTE_MAX_CODEWORDS], uint32_t tti, uint16_t rnti)
{ {
srslte_dci_msg_t dci_msg; srslte_dci_msg_t dci_msg;
srslte_ra_dl_dci_t dci_unpacked; srslte_ra_dl_dci_t dci_unpacked;
@ -320,17 +336,26 @@ int srslte_ue_dl_decode_rnti_multi(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_POR
uint32_t rvidx = 0; uint32_t rvidx = 0;
uint32_t rvidx2 = 0;
if (dci_unpacked.rv_idx < 0) { if (dci_unpacked.rv_idx < 0) {
uint32_t sfn = tti/10; uint32_t sfn = tti/10;
uint32_t k = (sfn/2)%4; uint32_t k = (sfn/2)%4;
rvidx = ((uint32_t) ceilf((float)1.5*k))%4; rvidx = ((uint32_t) ceilf((float)1.5*k))%4;
srslte_softbuffer_rx_reset_tbs(&q->softbuffer, grant.mcs.tbs); srslte_softbuffer_rx_reset_tbs(&q->softbuffers[0], (uint32_t) grant.mcs.tbs);
if (grant.nof_tb > 1) {
rvidx2 = ((uint32_t) ceilf((float)1.5*k))%4;
srslte_softbuffer_rx_reset_tbs(&q->softbuffers[1], (uint32_t) grant.mcs2.tbs);
}
} else { } else {
rvidx = dci_unpacked.rv_idx; rvidx = (uint32_t) dci_unpacked.rv_idx;
srslte_softbuffer_rx_reset_tbs(&q->softbuffer, grant.mcs.tbs); srslte_softbuffer_rx_reset_tbs(&q->softbuffers[0], (uint32_t) grant.mcs.tbs);
if (grant.nof_tb > 1) {
rvidx2 = (uint32_t) dci_unpacked.rv_idx_1;
srslte_softbuffer_rx_reset_tbs(&q->softbuffers[1], (uint32_t) grant.mcs2.tbs);
}
} }
if (srslte_ue_dl_cfg_grant(q, &grant, cfi, sf_idx, rvidx)) { if (srslte_ue_dl_cfg_grant_multi(q, &grant, cfi, sf_idx, rvidx, rvidx2)) {
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
@ -340,7 +365,7 @@ int srslte_ue_dl_decode_rnti_multi(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_POR
if (q->pdsch_cfg.grant.mcs.mod > 0 && q->pdsch_cfg.grant.mcs.tbs >= 0) { 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, ret = srslte_pdsch_decode_multi(&q->pdsch, &q->pdsch_cfg, q->softbuffers,
q->sf_symbols_m, q->ce_m, q->sf_symbols_m, q->ce_m,
noise_estimate, noise_estimate,
rnti, data); rnti, data);

@ -53,6 +53,11 @@ cf_t dummy_buffer1[15*2048/2];
cf_t *dummy_offset_buffer[SRSLTE_MAX_PORTS] = {dummy_buffer0, dummy_buffer1}; 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) { 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; int ret = SRSLTE_ERROR_INVALID_INPUTS;
if (q != NULL && if (q != NULL &&
@ -66,6 +71,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->file_cfo = -offset_freq;
q->correct_cfo = true; q->correct_cfo = true;
q->fft_size = srslte_symbol_sz(nof_prb); 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)) { if (srslte_cfo_init(&q->file_cfo_correct, 2*q->sf_len)) {
fprintf(stderr, "Error initiating CFO\n"); fprintf(stderr, "Error initiating CFO\n");
@ -80,12 +86,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); INFO("Offseting input file by %d samples and %.1f kHz\n", offset_time, offset_freq/1000);
if (offset_time) { 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) { if (!file_offset_buffer) {
perror("malloc"); perror("malloc");
goto clean_exit; 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); free(file_offset_buffer);
} }
@ -518,7 +524,7 @@ int srslte_ue_sync_zerocopy_multi(srslte_ue_sync_t *q, cf_t *input_buffer[SRSLTE
{ {
if (q->file_mode) { 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) { if (n < 0) {
fprintf(stderr, "Error reading input file\n"); fprintf(stderr, "Error reading input file\n");
return SRSLTE_ERROR; return SRSLTE_ERROR;
@ -526,18 +532,19 @@ int srslte_ue_sync_zerocopy_multi(srslte_ue_sync_t *q, cf_t *input_buffer[SRSLTE
if (n == 0) { if (n == 0) {
srslte_filesource_seek(&q->file_source, 0); srslte_filesource_seek(&q->file_source, 0);
q->sf_idx = 9; q->sf_idx = 9;
int n = srslte_filesource_read(&q->file_source, input_buffer[0], q->sf_len); n = srslte_filesource_read_multi(&q->file_source, (void **) input_buffer, q->sf_len, q->nof_rx_antennas);
if (n < 0) { if (n < 0) {
fprintf(stderr, "Error reading input file\n"); fprintf(stderr, "Error reading input file\n");
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
} }
if (q->correct_cfo) { if (q->correct_cfo) {
for (int i = 0; i < q->nof_rx_antennas; i++) {
srslte_cfo_correct(&q->file_cfo_correct, srslte_cfo_correct(&q->file_cfo_correct,
input_buffer[0], input_buffer[i],
input_buffer[0], input_buffer[i],
q->file_cfo / 15000 / q->fft_size); q->file_cfo / 15000 / q->fft_size);
}
} }
q->sf_idx++; q->sf_idx++;
if (q->sf_idx == 10) { if (q->sf_idx == 10) {

@ -78,6 +78,7 @@ private:
bool decode_pdcch_dl(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_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_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_pdsch_multi(srslte_ra_dl_grant_t *grant, uint8_t *payload[SRSLTE_MAX_CODEWORDS], srslte_softbuffer_rx_t softbuffers[SRSLTE_MAX_CODEWORDS], int rv, uint16_t rnti, uint32_t pid);
/* ... for UL */ /* ... for UL */
void encode_pusch(srslte_ra_ul_grant_t *grant, uint8_t *payload, uint32_t current_tx_nb, srslte_softbuffer_tx_t *softbuffer, void encode_pusch(srslte_ra_ul_grant_t *grant, uint8_t *payload, uint32_t current_tx_nb, srslte_softbuffer_tx_t *softbuffer,

@ -407,6 +407,12 @@ bool phch_worker::decode_pdcch_dl(srsue::mac_interface_phy::mac_grant_t* grant)
bool phch_worker::decode_pdsch(srslte_ra_dl_grant_t *grant, uint8_t *payload, bool phch_worker::decode_pdsch(srslte_ra_dl_grant_t *grant, uint8_t *payload,
srslte_softbuffer_rx_t* softbuffer, int rv, uint16_t rnti, uint32_t harq_pid) srslte_softbuffer_rx_t* softbuffer, int rv, uint16_t rnti, uint32_t harq_pid)
{
return decode_pdsch_multi(grant, &payload, softbuffer, rv, rnti, harq_pid);
}
bool phch_worker::decode_pdsch_multi(srslte_ra_dl_grant_t *grant, uint8_t *payload[SRSLTE_MAX_CODEWORDS],
srslte_softbuffer_rx_t softbuffers[SRSLTE_MAX_CODEWORDS], int rv, uint16_t rnti, uint32_t harq_pid)
{ {
char timestr[64]; char timestr[64];
timestr[0]='\0'; timestr[0]='\0';
@ -435,7 +441,7 @@ bool phch_worker::decode_pdsch(srslte_ra_dl_grant_t *grant, uint8_t *payload,
gettimeofday(&t[1], NULL); gettimeofday(&t[1], NULL);
#endif #endif
bool ack = srslte_pdsch_decode_multi(&ue_dl.pdsch, &ue_dl.pdsch_cfg, softbuffer, ue_dl.sf_symbols_m, bool ack = srslte_pdsch_decode_multi(&ue_dl.pdsch, &ue_dl.pdsch_cfg, softbuffers, ue_dl.sf_symbols_m,
ue_dl.ce_m, noise_estimate, rnti, payload) == 0; ue_dl.ce_m, noise_estimate, rnti, payload) == 0;
#ifdef LOG_EXECTIME #ifdef LOG_EXECTIME
gettimeofday(&t[2], NULL); gettimeofday(&t[2], NULL);

Loading…
Cancel
Save