diff --git a/lib/examples/cell_measurement.c b/lib/examples/cell_measurement.c index bc8262b29..9c7856daa 100644 --- a/lib/examples/cell_measurement.c +++ b/lib/examples/cell_measurement.c @@ -118,7 +118,7 @@ int parse_args(prog_args_t *args, int argc, char **argv) { /**********************************************************************/ /* TODO: Do something with the output data */ -uint8_t data[1000000]; +uint8_t *data[SRSLTE_MAX_CODEWORDS]; bool go_exit = false; void sig_int_handler(int signo) @@ -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)); + for (int i = 0; i < SRSLTE_MAX_CODEWORDS; i++) { + data[i] = srslte_vec_malloc(sizeof(uint8_t) * 1500*8); + } sigset_t sigset; sigemptyset(&sigset); @@ -322,7 +325,7 @@ int main(int argc, char **argv) { nof_trials++; } else { printf("Decoded SIB1. Payload: "); - srslte_vec_fprint_byte(stdout, data, n/8);; + srslte_vec_fprint_byte(stdout, data[0], n/8);; state = MEASURE; } } @@ -386,6 +389,12 @@ int main(int argc, char **argv) { sf_cnt++; } // Main loop + for (int i = 0; i < SRSLTE_MAX_CODEWORDS; i++) { + if (data[i]) { + free(data[i]); + } + } + srslte_ue_sync_free(&ue_sync); srslte_rf_close(&rf); printf("\nBye\n"); diff --git a/lib/examples/pdsch_enodeb.c b/lib/examples/pdsch_enodeb.c index 800e04de9..01e06c4c3 100644 --- a/lib/examples/pdsch_enodeb.c +++ b/lib/examples/pdsch_enodeb.c @@ -27,12 +27,12 @@ #include #include #include -#include #include -#include #include #include #include +#include +#include #include "srslte/srslte.h" @@ -55,19 +55,21 @@ char *output_file_name = NULL; #define DOWN_KEY 66 srslte_cell_t cell = { - 25, // nof_prb - 1, // nof_ports - 0, // cell_id - SRSLTE_CP_NORM, // cyclic prefix - SRSLTE_PHICH_R_1, // PHICH resources - SRSLTE_PHICH_NORM // PHICH length + 25, // nof_prb + 1, // nof_ports + 0, // cell_id + SRSLTE_CP_NORM, // cyclic prefix + SRSLTE_PHICH_NORM, // PHICH length + SRSLTE_PHICH_R_1 // PHICH resources }; - + int net_port = -1; // -1 generates random dataThat means there is some problem sending samples to the device uint32_t cfi=3; uint32_t mcs_idx = 1, last_mcs_idx = 1; int nof_frames = -1; +char mimo_type_str[32] = "single"; +uint32_t nof_tb = 1; char *rf_args = ""; float rf_amp = 0.8, rf_gain = 70.0, rf_freq = 2400000000; @@ -80,14 +82,14 @@ srslte_pcfich_t pcfich; srslte_pdcch_t pdcch; srslte_pdsch_t pdsch; srslte_pdsch_cfg_t pdsch_cfg; -srslte_softbuffer_tx_t softbuffer; +srslte_softbuffer_tx_t softbuffers[SRSLTE_MAX_CODEWORDS]; srslte_regs_t regs; srslte_ra_dl_dci_t ra_dl; -cf_t *sf_buffer = NULL, *output_buffer = NULL; +cf_t *sf_buffer[SRSLTE_MAX_PORTS] = {NULL}, *output_buffer [SRSLTE_MAX_PORTS] = {NULL}; int sf_n_re, sf_n_samples; -pthread_t net_thread; +pthread_t net_thread; void *net_thread_fnc(void *arg); sem_t net_sem; bool net_packet_ready = false; @@ -99,7 +101,7 @@ int prbset_orig = 0; void usage(char *prog) { - printf("Usage: %s [agmfoncvpu]\n", prog); + printf("Usage: %s [agmfoncvpuM]\n", prog); #ifndef DISABLE_RF printf("\t-a RF args [Default %s]\n", rf_args); printf("\t-l RF amplitude [Default %.2f]\n", rf_amp); @@ -113,13 +115,14 @@ void usage(char *prog) { printf("\t-n number of frames [Default %d]\n", nof_frames); printf("\t-c cell id [Default %d]\n", cell.id); printf("\t-p nof_prb [Default %d]\n", cell.nof_prb); + printf("\t-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-v [set srslte_verbose to debug, default none]\n"); } void parse_args(int argc, char **argv) { int opt; - while ((opt = getopt(argc, argv, "aglfmoncpvu")) != -1) { + while ((opt = getopt(argc, argv, "aglfmoncpvutM")) != -1) { switch (opt) { case 'a': rf_args = argv[optind]; @@ -151,6 +154,9 @@ void parse_args(int argc, char **argv) { case 'c': cell.id = atoi(argv[optind]); break; + case 'M': + strncpy(mimo_type_str, argv[optind], 32); + break; case 'v': srslte_verbose++; break; @@ -168,18 +174,54 @@ void parse_args(int argc, char **argv) { } void base_init() { - - /* init memory */ - sf_buffer = srslte_vec_malloc(sizeof(cf_t) * sf_n_re); - if (!sf_buffer) { - perror("malloc"); + int i; + + /* Select transmission mode */ + if (srslte_str2mimotype(mimo_type_str, &pdsch_cfg.mimo_type)) { + ERROR("Wrong transmission mode! Allowed modes: single, diversity, cdd"); exit(-1); } - output_buffer = srslte_vec_malloc(sizeof(cf_t) * sf_n_samples); - if (!output_buffer) { - perror("malloc"); - exit(-1); + + /* Configure cell and PDSCH in function of the transmission mode */ + switch(pdsch_cfg.mimo_type) { + case SRSLTE_MIMO_TYPE_SINGLE_ANTENNA: + cell.nof_ports = 1; + 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 */ + for (i = 0; i < cell.nof_ports; i++) { + sf_buffer[i] = srslte_vec_malloc(sizeof(cf_t) * sf_n_re); + if (!sf_buffer[i]) { + perror("malloc"); + exit(-1); + } + } + + for (i = 0; i < SRSLTE_MAX_PORTS; i++) { + output_buffer[i] = srslte_vec_malloc(sizeof(cf_t) * sf_n_samples); + if (!output_buffer[i]) { + perror("malloc"); + exit(-1); + } + bzero(output_buffer[i], sizeof(cf_t) * sf_n_samples); + } + /* open file or USRP */ if (output_file_name) { if (strcmp(output_file_name, "NULL")) { @@ -194,7 +236,7 @@ void base_init() { } else { #ifndef DISABLE_RF 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"); exit(-1); } @@ -247,27 +289,32 @@ void base_init() { exit(-1); } - if (srslte_pdcch_init(&pdcch, ®s, cell)) { + if (srslte_pdcch_init_tx(&pdcch, ®s, cell)) { fprintf(stderr, "Error creating PDCCH object\n"); 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"); exit(-1); } - + srslte_pdsch_set_rnti(&pdsch, UE_CRNTI); - - if (srslte_softbuffer_tx_init(&softbuffer, cell.nof_prb)) { - fprintf(stderr, "Error initiating soft buffer\n"); - exit(-1); + + for (i = 0; i < nof_tb; i++) { + if (srslte_softbuffer_tx_init(&softbuffers[i], cell.nof_prb)) { + fprintf(stderr, "Error initiating soft buffer\n"); + exit(-1); + } } } void base_free() { - - srslte_softbuffer_tx_free(&softbuffer); + int i; + for (i = 0; i < nof_tb; i++) { + srslte_softbuffer_tx_free(&softbuffers[i]); + } srslte_pdsch_free(&pdsch); srslte_pdcch_free(&pdcch); srslte_regs_free(®s); @@ -275,11 +322,14 @@ void base_free() { srslte_ofdm_tx_free(&ifft); - if (sf_buffer) { - free(sf_buffer); - } - if (output_buffer) { - free(output_buffer); + for (i = 0; i < SRSLTE_MAX_PORTS; i++) { + if (sf_buffer[i]) { + free(sf_buffer[i]); + } + + if (output_buffer[i]) { + free(output_buffer[i]); + } } if (output_file_name) { if (!null_file_sink) { @@ -340,7 +390,14 @@ int update_radl() { ra_dl.rv_idx = 0; ra_dl.alloc_type = SRSLTE_RA_ALLOC_TYPE0; ra_dl.type0_alloc.rbg_bitmask = prbset_to_bitmask(); - ra_dl.tb_en[0] = 1; + ra_dl.tb_en[0] = 1; + + if (nof_tb > 1) { + ra_dl.mcs_idx_1 = mcs_idx; + ra_dl.ndi_1 = 0; + ra_dl.rv_idx_1 = 0; + ra_dl.tb_en[1] = 1; + } srslte_ra_pdsch_fprint(stdout, &ra_dl, cell.nof_prb); srslte_ra_dl_grant_t dummy_grant; @@ -497,9 +554,9 @@ int main(int argc, char **argv) { exit(-1); } - for (i = 0; i < SRSLTE_MAX_PORTS; i++) { // now there's only 1 port - sf_symbols[i] = sf_buffer; - slot1_symbols[i] = &sf_buffer[SRSLTE_SLOT_LEN_RE(cell.nof_prb, cell.cp)]; + for (i = 0; i < SRSLTE_MAX_PORTS; i++) { + sf_symbols[i] = sf_buffer[i%cell.nof_ports]; + slot1_symbols[i] = &sf_buffer[i%cell.nof_ports][SRSLTE_SLOT_LEN_RE(cell.nof_prb, cell.cp)]; } #ifndef DISABLE_RF @@ -556,7 +613,9 @@ int main(int argc, char **argv) { nf = 0; 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 bool start_of_burst = true; @@ -564,15 +623,25 @@ int main(int argc, char **argv) { while ((nf < nof_frames || nof_frames == -1) && !go_exit) { for (sf_idx = 0; sf_idx < SRSLTE_NSUBFRAMES_X_FRAME && (nf < nof_frames || nof_frames == -1); sf_idx++) { - bzero(sf_buffer, sizeof(cf_t) * sf_n_re); + /* Set Antenna port resource elements to zero */ + bzero(sf_symbols[0], sizeof(cf_t) * sf_n_re); + /* Populate Synchronization signals if required */ if (sf_idx == 0 || sf_idx == 5) { - srslte_pss_put_slot(pss_signal, sf_buffer, cell.nof_prb, SRSLTE_CP_NORM); - srslte_sss_put_slot(sf_idx ? sss_signal5 : sss_signal0, sf_buffer, cell.nof_prb, + srslte_pss_put_slot(pss_signal, sf_symbols[0], cell.nof_prb, SRSLTE_CP_NORM); + srslte_sss_put_slot(sf_idx ? sss_signal5 : sss_signal0, sf_symbols[0], cell.nof_prb, SRSLTE_CP_NORM); } - srslte_refsignal_cs_put_sf(cell, 0, est.csr_signal.pilots[0][sf_idx], sf_buffer); + /* Copy zeros, SSS, PSS into the rest of antenna ports */ + for (i = 1; i < cell.nof_ports; i++) { + memcpy(sf_symbols[i], sf_symbols[0], sizeof(cf_t) * sf_n_re); + } + + /* Put reference signals */ + for (i = 0; i < cell.nof_ports; i++) { + srslte_refsignal_cs_put_sf(cell, (uint32_t) i, est.csr_signal.pilots[i / 2][sf_idx], sf_symbols[i]); + } srslte_pbch_mib_pack(&cell, sfn, bch_payload); if (sf_idx == 0) { @@ -606,10 +675,23 @@ int main(int argc, char **argv) { } 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 */ INFO("Putting DCI to location: n=%d, L=%d\n", locations[sf_idx][0].ncce, locations[sf_idx][0].L); - srslte_dci_msg_pack_pdsch(&ra_dl, SRSLTE_DCI_FORMAT1, &dci_msg, cell.nof_prb, cell.nof_ports, false); + srslte_dci_msg_pack_pdsch(&ra_dl, dci_format, &dci_msg, cell.nof_prb, cell.nof_ports, false); if (srslte_pdcch_encode(&pdcch, &dci_msg, locations[sf_idx][0], UE_CRNTI, sf_symbols, sf_idx, cfi)) { fprintf(stderr, "Error encoding DCI message\n"); exit(-1); @@ -618,13 +700,14 @@ int main(int argc, char **argv) { /* Configure pdsch_cfg parameters */ srslte_ra_dl_grant_t grant; srslte_ra_dl_dci_to_grant(&ra_dl, cell.nof_prb, UE_CRNTI, &grant); - if (srslte_pdsch_cfg(&pdsch_cfg, cell, &grant, cfi, sf_idx, 0)) { + if (srslte_pdsch_cfg_multi(&pdsch_cfg, cell, &grant, cfi, sf_idx, 0, 0)) { fprintf(stderr, "Error configuring PDSCH\n"); exit(-1); } /* Encode PDSCH */ - if (srslte_pdsch_encode(&pdsch, &pdsch_cfg, &softbuffer, data, UE_CRNTI, sf_symbols)) { + if (srslte_pdsch_encode_multi(&pdsch, &pdsch_cfg, softbuffers, (uint8_t*[2]){data, data}, UE_CRNTI, + sf_symbols)) { fprintf(stderr, "Error encoding PDSCH\n"); exit(-1); } @@ -641,21 +724,24 @@ int main(int argc, char **argv) { } /* Transform to OFDM symbols */ - srslte_ofdm_tx_sf(&ifft, sf_buffer, output_buffer); - + for (i = 0; i < cell.nof_ports; i++) { + srslte_ofdm_tx_sf(&ifft, sf_buffer[i], output_buffer[i]); + } + /* send to file or usrp */ if (output_file_name) { if (!null_file_sink) { - srslte_filesink_write(&fsink, output_buffer, sf_n_samples); + srslte_filesink_write_multi(&fsink, (void**) output_buffer, sf_n_samples, cell.nof_ports); } usleep(1000); } else { #ifndef DISABLE_RF - // FIXME float norm_factor = (float) cell.nof_prb/15/sqrtf(pdsch_cfg.grant.nof_prb); - srslte_vec_sc_prod_cfc(output_buffer, rf_amp*norm_factor, output_buffer, SRSLTE_SF_LEN_PRB(cell.nof_prb)); - srslte_rf_send2(&rf, output_buffer, sf_n_samples, true, start_of_burst, false); - start_of_burst=false; + for (i = 0; i < cell.nof_ports; i++) { + srslte_vec_sc_prod_cfc(output_buffer[i], rf_amp * norm_factor, output_buffer[i], SRSLTE_SF_LEN_PRB(cell.nof_prb)); + } + srslte_rf_send_multi(&rf, (void**) output_buffer, sf_n_samples, true, start_of_burst, false); + start_of_burst=false; #endif } } diff --git a/lib/examples/pdsch_ue.c b/lib/examples/pdsch_ue.c index 72dc36731..bab9d7219 100644 --- a/lib/examples/pdsch_ue.c +++ b/lib/examples/pdsch_ue.c @@ -258,7 +258,7 @@ void parse_args(prog_args_t *args, int argc, char **argv) { /**********************************************************************/ /* TODO: Do something with the output data */ -uint8_t data[20000]; +uint8_t *data[SRSLTE_MAX_CODEWORDS]; bool go_exit = false; void sig_int_handler(int signo) @@ -266,10 +266,12 @@ void sig_int_handler(int signo) printf("SIGINT received. Exiting...\n"); if (signo == SIGINT) { go_exit = true; + } else if (signo == SIGSEGV) { + exit(1); } } -cf_t *sf_buffer[2] = {NULL, NULL}; +cf_t *sf_buffer[SRSLTE_MAX_PORTS] = {NULL}; #ifndef DISABLE_RF int srslte_rf_recv_wrapper(void *h, cf_t *data[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte_timestamp_t *t) { @@ -315,6 +317,14 @@ int main(int argc, char **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) { cpu_set_t cpuset; @@ -435,8 +445,8 @@ int main(int argc, char **argv) { cell.nof_ports = prog_args.file_nof_ports; cell.nof_prb = prog_args.file_nof_prb; - if (srslte_ue_sync_init_file(&ue_sync, prog_args.file_nof_prb, - prog_args.input_file_name, prog_args.file_offset_time, prog_args.file_offset_freq)) { + if (srslte_ue_sync_init_file_multi(&ue_sync, prog_args.file_nof_prb, + prog_args.input_file_name, prog_args.file_offset_time, prog_args.file_offset_freq, prog_args.rf_nof_rx_ant)) { fprintf(stderr, "Error initiating ue_sync\n"); exit(-1); } @@ -498,7 +508,7 @@ int main(int argc, char **argv) { // Variables for measurements 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; #ifndef DISABLE_RF @@ -596,8 +606,9 @@ int main(int argc, char **argv) { nof_trials++; rsrq = SRSLTE_VEC_EMA(srslte_chest_dl_get_rsrq(&ue_dl.chest), rsrq, 0.1); - rsrp = SRSLTE_VEC_EMA(srslte_chest_dl_get_rsrp(&ue_dl.chest), rsrp, 0.05); - noise = SRSLTE_VEC_EMA(srslte_chest_dl_get_noise_estimate(&ue_dl.chest), noise, 0.05); + 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); nframes++; if (isnan(rsrq)) { rsrq = 0; @@ -605,9 +616,12 @@ int main(int argc, char **argv) { if (isnan(noise)) { noise = 0; } - if (isnan(rsrp)) { - rsrp = 0; - } + if (isnan(rsrp0)) { + rsrp1 = 0; + } + if (isnan(rsrp0)) { + rsrp1 = 0; + } } // Plot and Printf @@ -616,14 +630,27 @@ int main(int argc, char **argv) { if (gain < 0) { gain = 10*log10(srslte_agc_get_gain(&ue_sync.agc)); } - printf("CFO: %+6.2f kHz, " - "SNR: %4.1f dB, " - "PDCCH-Miss: %5.2f%%, PDSCH-BLER: %5.2f%%\r", - - srslte_ue_sync_get_cfo(&ue_sync)/1000, - 10*log10(rsrp/noise), - 100*(1-(float) ue_dl.nof_detected/nof_trials), - (float) 100*ue_dl.pkt_errors/ue_dl.pkts_total); + if (cell.nof_ports == 1) { + printf("CFO: %+6.2f kHz, " + "SNR: %4.1f dB, " + "PDCCH-Miss: %5.2f%%, PDSCH-BLER: %5.2f%%\r", + + srslte_ue_sync_get_cfo(&ue_sync) / 1000, + 10 * log10(rsrp0 / noise), + 100 * (1 - (float) ue_dl.nof_detected / nof_trials), + (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; } @@ -674,6 +701,16 @@ int main(int argc, char **argv) { #endif srslte_ue_dl_free(&ue_dl); srslte_ue_sync_free(&ue_sync); + for (int i = 0; i < SRSLTE_MAX_CODEWORDS; i++) { + if (data[i]) { + free(data[i]); + } + } + for (int i = 0; i < prog_args.rf_nof_rx_ant; i++) { + if (sf_buffer[i]) { + free(sf_buffer[i]); + } + } #ifndef DISABLE_RF if (!prog_args.input_file_name) { diff --git a/lib/examples/usrp_capture.c b/lib/examples/usrp_capture.c index 2692deb0d..02b543c0e 100644 --- a/lib/examples/usrp_capture.c +++ b/lib/examples/usrp_capture.c @@ -44,6 +44,7 @@ char *output_file_name; char *rf_args=""; float rf_gain=40.0, rf_freq=-1.0, rf_rate=0.96e6; int nof_samples = -1; +int nof_rx_antennas = 1; void int_handler(int dummy) { keep_running = false; @@ -55,12 +56,13 @@ void usage(char *prog) { printf("\t-g RF Gain [Default %.2f dB]\n", rf_gain); printf("\t-r RF Rate [Default %.6f Hz]\n", rf_rate); printf("\t-n nof_samples [Default %d]\n", nof_samples); + printf("\t-A nof_rx_antennas [Default %d]\n", nof_rx_antennas); printf("\t-v srslte_verbose\n"); } void parse_args(int argc, char **argv) { int opt; - while ((opt = getopt(argc, argv, "agrnvfo")) != -1) { + while ((opt = getopt(argc, argv, "agrnvfoA")) != -1) { switch (opt) { case 'o': output_file_name = argv[optind]; @@ -80,6 +82,9 @@ void parse_args(int argc, char **argv) { case 'n': nof_samples = atoi(argv[optind]); break; + case 'A': + nof_rx_antennas = atoi(argv[optind]); + break; case 'v': srslte_verbose++; break; @@ -95,11 +100,11 @@ void parse_args(int argc, char **argv) { } int main(int argc, char **argv) { - cf_t *buffer; + cf_t *buffer[SRSLTE_MAX_PORTS]; int sample_count, n; srslte_rf_t rf; srslte_filesink_t sink; - int32_t buflen; + uint32_t buflen; signal(SIGINT, int_handler); @@ -107,17 +112,19 @@ int main(int argc, char **argv) { buflen = 4800; sample_count = 0; - - buffer = malloc(sizeof(cf_t) * buflen); - if (!buffer) { - perror("malloc"); - exit(-1); + + for (int i = 0; i < nof_rx_antennas; i++) { + buffer[i] = malloc(sizeof(cf_t) * buflen); + if (!buffer[i]) { + perror("malloc"); + exit(-1); + } } srslte_filesink_init(&sink, output_file_name, SRSLTE_COMPLEX_FLOAT_BIN); printf("Opening RF device...\n"); - if (srslte_rf_open(&rf, rf_args)) { + if (srslte_rf_open_multi(&rf, rf_args, nof_rx_antennas)) { fprintf(stderr, "Error opening rf\n"); exit(-1); } @@ -151,18 +158,23 @@ int main(int argc, char **argv) { while((sample_count < nof_samples || nof_samples == -1) && keep_running){ - n = srslte_rf_recv(&rf, buffer, buflen, 1); + n = srslte_rf_recv_with_time_multi(&rf, (void**) buffer, buflen, true, NULL, NULL); if (n < 0) { fprintf(stderr, "Error receiving samples\n"); exit(-1); } - srslte_filesink_write(&sink, buffer, buflen); + srslte_filesink_write_multi(&sink, (void**) buffer, buflen, nof_rx_antennas); sample_count += buflen; } + for (int i = 0; i < nof_rx_antennas; i++) { + if (buffer[i]) { + free(buffer[i]); + } + } + srslte_filesink_free(&sink); - free(buffer); srslte_rf_close(&rf); printf("Ok - wrote %d samples\n", sample_count); diff --git a/lib/examples/usrp_capture_sync.c b/lib/examples/usrp_capture_sync.c index 6d2ec18dc..41c233be7 100644 --- a/lib/examples/usrp_capture_sync.c +++ b/lib/examples/usrp_capture_sync.c @@ -45,6 +45,7 @@ float rf_gain=60.0, rf_freq=-1.0; int nof_prb = 6; int nof_subframes = -1; int N_id_2 = -1; +uint32_t nof_rx_antennas = 1; void int_handler(int dummy) { keep_running = false; @@ -56,12 +57,13 @@ void usage(char *prog) { printf("\t-g RF Gain [Default %.2f dB]\n", rf_gain); printf("\t-p nof_prb [Default %d]\n", nof_prb); printf("\t-n nof_subframes [Default %d]\n", nof_subframes); + printf("\t-A nof_rx_antennas [Default %d]\n", nof_rx_antennas); printf("\t-v verbose\n"); } void parse_args(int argc, char **argv) { int opt; - while ((opt = getopt(argc, argv, "agpnvfol")) != -1) { + while ((opt = getopt(argc, argv, "agpnvfolA")) != -1) { switch (opt) { case 'o': output_file_name = argv[optind]; @@ -84,6 +86,9 @@ void parse_args(int argc, char **argv) { case 'l': N_id_2 = atoi(argv[optind]); break; + case 'A': + nof_rx_antennas = (uint32_t) atoi(argv[optind]); + break; case 'v': srslte_verbose++; break; @@ -100,7 +105,7 @@ void parse_args(int argc, char **argv) { int srslte_rf_recv_wrapper(void *h, cf_t *data[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte_timestamp_t *t) { DEBUG(" ---- Receive %d samples ---- \n", nsamples); - return srslte_rf_recv(h, data[0], nsamples, 1); + return srslte_rf_recv_with_time_multi(h, (void**) data, nsamples, true, NULL, NULL); } int main(int argc, char **argv) { @@ -118,13 +123,15 @@ int main(int argc, char **argv) { srslte_filesink_init(&sink, output_file_name, SRSLTE_COMPLEX_FLOAT_BIN); printf("Opening RF device...\n"); - if (srslte_rf_open(&rf, rf_args)) { + if (srslte_rf_open_multi(&rf, rf_args, nof_rx_antennas)) { fprintf(stderr, "Error opening rf\n"); exit(-1); } srslte_rf_set_master_clock_rate(&rf, 30.72e6); - buffer[0] = srslte_vec_malloc(3*sizeof(cf_t)*SRSLTE_SF_LEN_PRB(100)); + for (int i = 0; i< SRSLTE_MAX_PORTS; i++) { + buffer[i] = srslte_vec_malloc(3 * sizeof(cf_t) * SRSLTE_SF_LEN_PRB(100)); + } sigset_t sigset; sigemptyset(&sigset); @@ -158,7 +165,7 @@ int main(int argc, char **argv) { cell.nof_prb = nof_prb; cell.nof_ports = 1; - if (srslte_ue_sync_init_multi(&ue_sync, cell, 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"); exit(-1); } @@ -181,7 +188,7 @@ int main(int argc, char **argv) { } } else { printf("Writing to file %6d subframes...\r", subframe_count); - srslte_filesink_write(&sink, buffer[0], SRSLTE_SF_LEN_PRB(nof_prb)); + srslte_filesink_write_multi(&sink, (void**) buffer, SRSLTE_SF_LEN_PRB(nof_prb),nof_rx_antennas); subframe_count++; } } @@ -196,6 +203,12 @@ int main(int argc, char **argv) { srslte_rf_close(&rf); srslte_ue_sync_free(&ue_sync); + for (int i = 0; i < SRSLTE_MAX_PORTS; i++) { + if (buffer[i]) { + free(buffer[i]); + } + } + printf("Ok - wrote %d subframes\n", subframe_count); exit(0); } diff --git a/lib/include/srslte/phy/ch_estimation/chest_dl.h b/lib/include/srslte/phy/ch_estimation/chest_dl.h index a454f939c..5d0820aa4 100644 --- a/lib/include/srslte/phy/ch_estimation/chest_dl.h +++ b/lib/include/srslte/phy/ch_estimation/chest_dl.h @@ -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_rsrp_port(srslte_chest_dl_t *q, + uint32_t port); + SRSLTE_API float srslte_chest_dl_get_rsrp(srslte_chest_dl_t *q); #endif diff --git a/lib/include/srslte/phy/common/phy_common.h b/lib/include/srslte/phy/common/phy_common.h index efd498c86..b891b7330 100644 --- a/lib/include/srslte/phy/common/phy_common.h +++ b/lib/include/srslte/phy/common/phy_common.h @@ -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 srslte_mod_t srslte_str2mod (char * mod_str); + SRSLTE_API char *srslte_mod_string(srslte_mod_t mod); SRSLTE_API uint32_t srslte_mod_bits_x_symbol(srslte_mod_t mod); diff --git a/lib/include/srslte/phy/io/filesink.h b/lib/include/srslte/phy/io/filesink.h index b8ca8db51..921f1e440 100644 --- a/lib/include/srslte/phy/io/filesink.h +++ b/lib/include/srslte/phy/io/filesink.h @@ -59,4 +59,9 @@ SRSLTE_API int srslte_filesink_write(srslte_filesink_t *q, void *buffer, int nsamples); +SRSLTE_API int srslte_filesink_write_multi(srslte_filesink_t *q, + void **buffer, + int nsamples, + int nchannels); + #endif // FILESINK_ diff --git a/lib/include/srslte/phy/io/filesource.h b/lib/include/srslte/phy/io/filesource.h index ee8bc080d..f515d7034 100644 --- a/lib/include/srslte/phy/io/filesource.h +++ b/lib/include/srslte/phy/io/filesource.h @@ -62,4 +62,9 @@ SRSLTE_API int srslte_filesource_read(srslte_filesource_t *q, void *buffer, int nsamples); +SRSLTE_API int srslte_filesource_read_multi(srslte_filesource_t *q, + void **buffer, + int nsamples, + int nof_channels); + #endif // FILESOURCE_ diff --git a/lib/include/srslte/phy/phch/pdcch.h b/lib/include/srslte/phy/phch/pdcch.h index 8d4aba790..f67d29dcb 100644 --- a/lib/include/srslte/phy/phch/pdcch.h +++ b/lib/include/srslte/phy/phch/pdcch.h @@ -88,11 +88,26 @@ SRSLTE_API int srslte_pdcch_init(srslte_pdcch_t *q, srslte_regs_t *regs, 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_regs_t *regs, srslte_cell_t cell, 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); diff --git a/lib/include/srslte/phy/phch/pdsch.h b/lib/include/srslte/phy/phch/pdsch.h index ad01c4ef8..7bdaaef9c 100644 --- a/lib/include/srslte/phy/phch/pdsch.h +++ b/lib/include/srslte/phy/phch/pdsch.h @@ -49,6 +49,7 @@ typedef struct { srslte_sequence_t seq[SRSLTE_NSUBFRAMES_X_FRAME]; + srslte_sequence_t seq2[SRSLTE_NSUBFRAMES_X_FRAME]; bool sequence_generated; } srslte_pdsch_user_t; @@ -62,11 +63,13 @@ typedef struct SRSLTE_API { /* buffers */ // void buffers are shared for tx and rx - cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS]; - cf_t *symbols[SRSLTE_MAX_PORTS]; - cf_t *x[SRSLTE_MAX_PORTS]; - cf_t *d; + cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS]; /* Channel estimation (Rx only) */ + cf_t *symbols[SRSLTE_MAX_PORTS]; /* PDSCH Encoded/Decoded Symbols */ + cf_t *x[SRSLTE_MAX_LAYERS]; /* Layer mapped */ + cf_t *d; /* Modulated/Demodulated codeword 1 */ + cf_t *d2; /* Modulated/Demodulated codeword 2 */ void *e; + void *e2; /* tx & rx objects */ 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_cell_t cell); -SRSLTE_API int srslte_pdsch_init_multi(srslte_pdsch_t *q, - srslte_cell_t cell, - uint32_t nof_rx_antennas); +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, + uint32_t nof_antennas); 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 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_pdsch_cfg_t *cfg, srslte_softbuffer_tx_t *softbuffer, @@ -110,6 +124,13 @@ SRSLTE_API int srslte_pdsch_encode(srslte_pdsch_t *q, uint16_t rnti, 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_pdsch_cfg_t *cfg, 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_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 *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], float noise_estimate, uint16_t rnti, - uint8_t *data); + uint8_t *data[SRSLTE_MAX_CODEWORDS]); SRSLTE_API float srslte_pdsch_average_noi(srslte_pdsch_t *q); diff --git a/lib/include/srslte/phy/phch/pdsch_cfg.h b/lib/include/srslte/phy/phch/pdsch_cfg.h index 2745470f8..bec326338 100644 --- a/lib/include/srslte/phy/phch/pdsch_cfg.h +++ b/lib/include/srslte/phy/phch/pdsch_cfg.h @@ -41,10 +41,15 @@ typedef struct SRSLTE_API { srslte_cbsegm_t cb_segm; + srslte_cbsegm_t cb_segm2; srslte_ra_dl_grant_t grant; srslte_ra_nbits_t nbits; + srslte_ra_nbits_t nbits2; uint32_t rv; + uint32_t rv2; uint32_t sf_idx; + uint32_t nof_layers; + srslte_mimo_type_t mimo_type; } srslte_pdsch_cfg_t; #endif diff --git a/lib/include/srslte/phy/phch/ra.h b/lib/include/srslte/phy/phch/ra.h index cec2e6087..3c7c3d93c 100644 --- a/lib/include/srslte/phy/phch/ra.h +++ b/lib/include/srslte/phy/phch/ra.h @@ -209,6 +209,13 @@ SRSLTE_API void srslte_ra_dl_grant_to_nbits(srslte_ra_dl_grant_t *grant, uint32_t sf_idx, 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, uint32_t nof_prb, uint32_t nof_ctrl_symbols); diff --git a/lib/include/srslte/phy/phch/sch.h b/lib/include/srslte/phy/phch/sch.h index 4ef0b3070..0e59ecbc9 100644 --- a/lib/include/srslte/phy/phch/sch.h +++ b/lib/include/srslte/phy/phch/sch.h @@ -96,12 +96,24 @@ SRSLTE_API int srslte_dlsch_encode(srslte_sch_t *q, uint8_t *data, 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_pdsch_cfg_t *cfg, srslte_softbuffer_rx_t *softbuffer, int16_t *e_bits, 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_pusch_cfg_t *cfg, srslte_softbuffer_tx_t *softbuffer, diff --git a/lib/include/srslte/phy/rf/rf.h b/lib/include/srslte/phy/rf/rf.h index 907a5a008..d37750749 100644 --- a/lib/include/srslte/phy/rf/rf.h +++ b/lib/include/srslte/phy/rf/rf.h @@ -75,6 +75,11 @@ SRSLTE_API int srslte_rf_open_multi(srslte_rf_t *h, char *args, 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, char *devname, char *args); @@ -84,6 +89,12 @@ SRSLTE_API int srslte_rf_open_devname_multi(srslte_rf_t *h, char *args, 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 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_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 diff --git a/lib/include/srslte/phy/ue/ue_dl.h b/lib/include/srslte/phy/ue/ue_dl.h index 7c3f83320..408ba0c65 100644 --- a/lib/include/srslte/phy/ue/ue_dl.h +++ b/lib/include/srslte/phy/ue/ue_dl.h @@ -84,7 +84,7 @@ typedef struct SRSLTE_API { srslte_cfo_t sfo_correct; srslte_pdsch_cfg_t pdsch_cfg; - srslte_softbuffer_rx_t softbuffer; + srslte_softbuffer_rx_t softbuffers[SRSLTE_MAX_CODEWORDS]; srslte_ra_dl_dci_t dl_dci; srslte_cell_t cell; @@ -142,6 +142,13 @@ SRSLTE_API int srslte_ue_dl_cfg_grant(srslte_ue_dl_t *q, uint32_t sf_idx, 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, uint32_t cfi, 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, cf_t *input[SRSLTE_MAX_PORTS], - uint8_t *data, + uint8_t *data[SRSLTE_MAX_CODEWORDS], uint32_t tti); 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, cf_t *input[SRSLTE_MAX_PORTS], - uint8_t *data, + uint8_t *data[SRSLTE_MAX_CODEWORDS], uint32_t tti, uint16_t rnti); diff --git a/lib/include/srslte/phy/ue/ue_sync.h b/lib/include/srslte/phy/ue/ue_sync.h index 94d4f9136..3570e5a30 100644 --- a/lib/include/srslte/phy/ue/ue_sync.h +++ b/lib/include/srslte/phy/ue/ue_sync.h @@ -148,6 +148,13 @@ SRSLTE_API int srslte_ue_sync_init_file(srslte_ue_sync_t *q, int offset_time, float offset_freq); +SRSLTE_API int srslte_ue_sync_init_file_multi(srslte_ue_sync_t *q, + uint32_t nof_prb, + char *file_name, + int offset_time, + float offset_freq, + uint32_t nof_rx_ant); + SRSLTE_API void srslte_ue_sync_free(srslte_ue_sync_t *q); SRSLTE_API int srslte_ue_sync_start_agc(srslte_ue_sync_t *q, diff --git a/lib/include/srslte/phy/utils/debug.h b/lib/include/srslte/phy/utils/debug.h index 9233d9c61..e1021bc2a 100644 --- a/lib/include/srslte/phy/utils/debug.h +++ b/lib/include/srslte/phy/utils/debug.h @@ -63,5 +63,6 @@ SRSLTE_API extern int srslte_verbose; #define INFO(_fmt, ...) if (SRSLTE_DEBUG_ENABLED && srslte_verbose >= SRSLTE_VERBOSE_INFO) \ fprintf(stdout, "[INFO]: " _fmt, __VA_ARGS__) +#define ERROR(_fmt) fprintf(stderr, "%s.%d: " _fmt "\n", __FILE__, __LINE__) #endif // DEBUG_H diff --git a/lib/src/phy/ch_estimation/chest_dl.c b/lib/src/phy/ch_estimation/chest_dl.c index 690721b3c..3c2f4210c 100644 --- a/lib/src/phy/ch_estimation/chest_dl.c +++ b/lib/src/phy/ch_estimation/chest_dl.c @@ -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) { - // Note: use only port 0 but average across antennas - float n = 0; - for (int i=0;ilast_nof_antennas;i++) { - n += q->rsrp[i][0]; +float srslte_chest_dl_get_rsrp_port(srslte_chest_dl_t *q, uint32_t port) { + float n = 0; + for (int i = 0; i < q->last_nof_antennas; i++) { + n += q->rsrp[i][port]; } - return n/q->last_nof_antennas; + return n / q->last_nof_antennas; } +float srslte_chest_dl_get_rsrp(srslte_chest_dl_t *q) { + // Note: use only port 0 but average across antennas + return srslte_chest_dl_get_rsrp_port(q, 0); +} diff --git a/lib/src/phy/ch_estimation/test/CMakeLists.txt b/lib/src/phy/ch_estimation/test/CMakeLists.txt index fd293c273..8e1208ef5 100644 --- a/lib/src/phy/ch_estimation/test/CMakeLists.txt +++ b/lib/src/phy/ch_estimation/test/CMakeLists.txt @@ -52,4 +52,3 @@ add_test(chest_test_ul_cellid1 chest_test_ul -c 2 -r 50) - diff --git a/lib/src/phy/common/phy_common.c b/lib/src/phy/common/phy_common.c index 8386ae18b..69e39b49a 100644 --- a/lib/src/phy/common/phy_common.c +++ b/lib/src/phy/common/phy_common.c @@ -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) { switch (mod) { 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) { - if (!strcmp(mimo_type_str, "single")) { + if (!strcmp(mimo_type_str, "single") || !strcmp(mimo_type_str, "Port0")) { *type = SRSLTE_MIMO_TYPE_SINGLE_ANTENNA; - } else if (!strcmp(mimo_type_str, "diversity")) { + } else if (!strcmp(mimo_type_str, "diversity") || !strcmp(mimo_type_str, "TxDiversity")) { *type = SRSLTE_MIMO_TYPE_TX_DIVERSITY; } else if (!strcmp(mimo_type_str, "multiplex")) { *type = SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX; + } else if (!strcmp(mimo_type_str, "cdd") || !strcmp(mimo_type_str, "CDD")) { + *type = SRSLTE_MIMO_TYPE_CDD; } else { return SRSLTE_ERROR; } diff --git a/lib/src/phy/io/filesink.c b/lib/src/phy/io/filesink.c index 60a8c386e..a61c417fd 100644 --- a/lib/src/phy/io/filesink.c +++ b/lib/src/phy/io/filesink.c @@ -99,3 +99,60 @@ int srslte_filesink_write(srslte_filesink_t *q, void *buffer, int nsamples) { return i; } +int srslte_filesink_write_multi(srslte_filesink_t *q, void **buffer, int nsamples, int nchannels) { + int i, j; + float **fbuf = (float**) buffer; + _Complex float **cbuf = (_Complex float**) buffer; + _Complex short **sbuf = (_Complex short**) buffer; + int size; + + switch(q->type) { + case SRSLTE_FLOAT: + for (i=0;if, "%g%c", fbuf[j][i], (j!=(nchannels-1))?'\t':'\n'); + } + } + break; + case SRSLTE_COMPLEX_FLOAT: + for (i=0;if, "%g%+gi%c", __real__ cbuf[j][i], __imag__ cbuf[j][i], (j!=(nchannels-1))?'\t':'\n'); + } + } + break; + case SRSLTE_COMPLEX_SHORT: + for (i=0;if, "%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; +} \ No newline at end of file diff --git a/lib/src/phy/io/filesource.c b/lib/src/phy/io/filesource.c index 4010f8da4..048ecb584 100644 --- a/lib/src/phy/io/filesource.c +++ b/lib/src/phy/io/filesource.c @@ -116,3 +116,29 @@ int srslte_filesource_read(srslte_filesource_t *q, void *buffer, int nsamples) { return i; } +int srslte_filesource_read_multi(srslte_filesource_t *q, void **buffer, int nsamples, int nof_channels) { + int i, j, count = 0; + _Complex float **cbuf = (_Complex float **) buffer; + + switch (q->type) { + case SRSLTE_FLOAT: + case SRSLTE_COMPLEX_FLOAT: + case SRSLTE_COMPLEX_SHORT: + case SRSLTE_FLOAT_BIN: + case SRSLTE_COMPLEX_SHORT_BIN: + fprintf(stderr, "%s.%d:Read Mode not implemented\n", __FILE__, __LINE__); + count = SRSLTE_ERROR; + break; + case SRSLTE_COMPLEX_FLOAT_BIN: + for (i = 0; i < nsamples; i++) { + for (j = 0; j < nof_channels; j++) { + count += fread(&cbuf[j][i], sizeof(cf_t), (size_t) 1, q->f); + } + } + break; + default: + count = SRSLTE_ERROR; + break; + } + return count; +} \ No newline at end of file diff --git a/lib/src/phy/mimo/precoding.c b/lib/src/phy/mimo/precoding.c index 8781dbad2..f93c63479 100644 --- a/lib/src/phy/mimo/precoding.c +++ b/lib/src/phy/mimo/precoding.c @@ -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); } + +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= 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; case SRSLTE_MIMO_TYPE_SINGLE_ANTENNA: if (nof_ports == 1 && nof_layers == 1) { diff --git a/lib/src/phy/mimo/test/CMakeLists.txt b/lib/src/phy/mimo/test/CMakeLists.txt index e0e5578d5..42e262550 100644 --- a/lib/src/phy/mimo/test/CMakeLists.txt +++ b/lib/src/phy/mimo/test/CMakeLists.txt @@ -42,7 +42,7 @@ add_test(layermap_multiplex_24 layermap_test -n 1000 -m multiplex -c 2 -l 4) ######################################################################## -# LAYER MAPPING TEST +# PRECODING MAPPING TEST ######################################################################## add_executable(precoding_test precoder_test.c) @@ -52,6 +52,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_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) diff --git a/lib/src/phy/mimo/test/layermap_test.c b/lib/src/phy/mimo/test/layermap_test.c index 209a9ac73..6fcc72682 100644 --- a/lib/src/phy/mimo/test/layermap_test.c +++ b/lib/src/phy/mimo/test/layermap_test.c @@ -40,7 +40,7 @@ int nof_cw = 1, nof_layers = 1; char *mimo_type_name = NULL; void usage(char *prog) { - printf("Usage: %s -m [single|diversity|multiplex] -c [nof_cw] -l [nof_layers]\n", prog); + printf("Usage: %s -m [single|diversity|multiplex|cdd] -c [nof_cw] -l [nof_layers]\n", prog); printf("\t-n num_symbols [Default %d]\n", nof_symbols); } diff --git a/lib/src/phy/mimo/test/precoder_mex.c b/lib/src/phy/mimo/test/precoder_mex.c index 958f06262..b021f422a 100644 --- a/lib/src/phy/mimo/test/precoder_mex.c +++ b/lib/src/phy/mimo/test/precoder_mex.c @@ -78,9 +78,9 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) x[i] = srslte_vec_malloc(sizeof(cf_t)*nof_symbols/nof_layers); } - output = srslte_vec_malloc(sizeof(cf_t)*nof_symbols*nof_tx_ports/nof_layers); + output = srslte_vec_malloc(sizeof(cf_t)*nof_symbols*nof_tx_ports); for (int i=0;i= 1) { - mexutils_write_cf(output, &plhs[0], nof_symbols/nof_layers, nof_tx_ports); + switch (type) { + case SRSLTE_MIMO_TYPE_CDD: + mexutils_write_cf(output, &plhs[0], nof_symbols/nof_layers, nof_tx_ports); + break; + case SRSLTE_MIMO_TYPE_TX_DIVERSITY: + case SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX: + case SRSLTE_MIMO_TYPE_SINGLE_ANTENNA: + default: + mexutils_write_cf(output, &plhs[0], (uint32_t) nof_symbols, nof_tx_ports); + break; + } + } + + if (nlhs >= 2) { + mexutils_write_cf(x[0], &plhs[1], nof_symbols / nof_layers, 1); + } + if (nlhs >= 3) { + mexutils_write_cf(x[1], &plhs[2], nof_symbols / nof_layers, 1); } if (input) { diff --git a/lib/src/phy/mimo/test/precoder_test.c b/lib/src/phy/mimo/test/precoder_test.c index e935a7067..cf8dac89a 100644 --- a/lib/src/phy/mimo/test/precoder_test.c +++ b/lib/src/phy/mimo/test/precoder_test.c @@ -35,28 +35,31 @@ #include "srslte/srslte.h" -#define MSE_THRESHOLD 0.00001 +#define MSE_THRESHOLD 0.0005 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; void usage(char *prog) { printf( - "Usage: %s -m [single|diversity|multiplex] -l [nof_layers] -p [nof_ports]\n", - prog); + "Usage: %s -m [single|diversity|multiplex|cdd] -l [nof_layers] -p [nof_tx_ports]\n" + " -r [nof_rx_ports]\n", prog); printf("\t-n num_symbols [Default %d]\n", nof_symbols); } void parse_args(int argc, char **argv) { int opt; - while ((opt = getopt(argc, argv, "mpln")) != -1) { + while ((opt = getopt(argc, argv, "mplnr")) != -1) { switch (opt) { case 'n': nof_symbols = atoi(argv[optind]); break; case 'p': - nof_ports = atoi(argv[optind]); + nof_tx_ports = atoi(argv[optind]); + break; + case 'r': + nof_rx_ports = atoi(argv[optind]); break; case 'l': nof_layers = atoi(argv[optind]); @@ -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 i, j; + int i, j, k; float mse; - cf_t *x[SRSLTE_MAX_LAYERS], *r[SRSLTE_MAX_PORTS], *y[SRSLTE_MAX_PORTS], *h[SRSLTE_MAX_PORTS], + cf_t *x[SRSLTE_MAX_LAYERS], *r[SRSLTE_MAX_PORTS], *y[SRSLTE_MAX_PORTS], *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], *xr[SRSLTE_MAX_LAYERS]; srslte_mimo_type_t type; parse_args(argc, argv); - if (nof_ports > SRSLTE_MAX_PORTS || nof_layers > SRSLTE_MAX_LAYERS) { + /* Check input ranges */ + if (nof_tx_ports > SRSLTE_MAX_PORTS || nof_rx_ports > SRSLTE_MAX_PORTS || nof_layers > SRSLTE_MAX_LAYERS) { fprintf(stderr, "Invalid number of layers or ports\n"); exit(-1); } + /* Parse MIMO Type */ if (srslte_str2mimotype(mimo_type_name, &type)) { fprintf(stderr, "Invalid MIMO type %s\n", mimo_type_name); exit(-1); } + /* Check scenario conditions are OK */ + switch (type) { + case SRSLTE_MIMO_TYPE_TX_DIVERSITY: + nof_re = nof_layers*nof_symbols; + break; + case SRSLTE_MIMO_TYPE_CDD: + nof_re = nof_symbols*nof_tx_ports/nof_layers; + if (nof_rx_ports != 2 || nof_tx_ports != 2) { + fprintf(stderr, "CDD nof_tx_ports=%d nof_rx_ports=%d is not currently supported\n", nof_tx_ports, nof_rx_ports); + exit(-1); + } + break; + default: + nof_re = nof_symbols*nof_layers; + } + + /* Allocate x and xr (received symbols) in memory for each layer */ for (i = 0; i < nof_layers; i++) { + /* Source data */ x[i] = srslte_vec_malloc(sizeof(cf_t) * nof_symbols); if (!x[i]) { perror("srslte_vec_malloc"); exit(-1); } + + /* Sink data */ xr[i] = srslte_vec_malloc(sizeof(cf_t) * nof_symbols); if (!xr[i]) { perror("srslte_vec_malloc"); exit(-1); } } - for (i = 0; i < nof_ports; i++) { - y[i] = srslte_vec_malloc(sizeof(cf_t) * nof_symbols * nof_layers); - // TODO: The number of symbols per port is different in spatial multiplexing. + + /* Allocate y in memory for tx each port */ + for (i = 0; i < nof_tx_ports; i++) { + y[i] = srslte_vec_malloc(sizeof(cf_t) * nof_re); if (!y[i]) { perror("srslte_vec_malloc"); exit(-1); } - h[i] = srslte_vec_malloc(sizeof(cf_t) * nof_symbols * nof_layers); - if (!h[i]) { - perror("srslte_vec_malloc"); - exit(-1); + } + + /* Allocate h in memory for each cross channel and layer */ + for (i = 0; i < nof_tx_ports; i++) { + for (j = 0; j < nof_rx_ports; j++) { + h[i][j] = srslte_vec_malloc(sizeof(cf_t) * nof_re); + if (!h[i][j]) { + perror("srslte_vec_malloc"); + exit(-1); + } } } - /* only 1 receiver antenna supported now */ - r[0] = srslte_vec_malloc(sizeof(cf_t) * nof_symbols * nof_layers); - if (!r[0]) { - perror("srslte_vec_malloc"); - exit(-1); + /* Allocate r */ + for (i = 0; i < nof_rx_ports; i++) { + r[i] = srslte_vec_malloc(sizeof(cf_t) * nof_re); + if (!r[i]) { + perror("srslte_vec_malloc"); + exit(-1); + } } - /* generate random data */ + /* Generate source random data */ for (i = 0; i < nof_layers; i++) { for (j = 0; j < nof_symbols; j++) { - x[i][j] = (2*(rand()%2)-1+(2*(rand()%2)-1)*_Complex_I)/sqrt(2); + x[i][j] = (2 * (rand() % 2) - 1 + (2 * (rand() % 2) - 1) * _Complex_I) / sqrt(2); } } - - /* precoding */ - if (srslte_precoding_type(x, y, nof_layers, nof_ports, nof_symbols, type) < 0) { + + /* Execute Precoding (Tx) */ + if (srslte_precoding_type(x, y, nof_layers, nof_tx_ports, nof_symbols, type) < 0) { fprintf(stderr, "Error layer mapper encoder\n"); exit(-1); } /* generate channel */ - for (i = 0; i < nof_ports; i++) { - for (j = 0; j < nof_symbols; j++) { - h[i][nof_layers*j] = (float) rand()/RAND_MAX+((float) rand()/RAND_MAX)*_Complex_I; - // assume the channel is time-invariant in nlayer consecutive symbols - for (int k=0;k SRSLTE_MAX_LAYERS) { + mexErrMsgTxt("Too many layers\n"); + return; + } + + /* Read number of symbols and Rx antennas */ + ndims = mxGetNumberOfDimensions(INPUT); + nof_symbols = (uint32_t) dims[0]; + if (ndims >= 2) { - nof_rx_ants = dims[1]; + nof_rx_ants = (uint32_t) dims[1]; } - // Read channel estimates + /* Read channel estimates */ if (mexutils_read_cf(HEST, &hest) < 0) { mexErrMsgTxt("Error reading hest\n"); return; } + + /* Get number of tx ports */ dims = mxGetDimensions(HEST); ndims = mxGetNumberOfDimensions(HEST); if (ndims == 3) { - nof_tx_ports = dims[2]; + nof_tx_ports = (uint32_t) dims[2]; } - + + /* 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); - // Read noise estimate - float noise_estimate = 0; + /* Read noise estimate */ if (nrhs >= NOF_INPUTS) { - noise_estimate = mxGetScalar(NEST); + noise_estimate = (float) mxGetScalar(NEST); } - cf_t *x[SRSLTE_MAX_LAYERS]; - cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS]; - cf_t *y[SRSLTE_MAX_PORTS]; - - for (int i=0;i= NOF_INPUTS) { - txscheme = mxArrayToString(TXSCHEME); - } - srslte_mimo_type_t type = SRSLTE_MIMO_TYPE_SINGLE_ANTENNA; + mxGetString_700(TXSCHEME, txscheme, 32); + } + if (!strcmp(txscheme, "Port0")) { type = SRSLTE_MIMO_TYPE_SINGLE_ANTENNA; } else if (!strcmp(txscheme, "TxDiversity")) { type = SRSLTE_MIMO_TYPE_TX_DIVERSITY; } else if (!strcmp(txscheme, "CDD")) { type = SRSLTE_MIMO_TYPE_CDD; - } else if (!strcmp(txscheme, "SpatialMux")) { + } else if (!strcmp(txscheme, "SpatialMux")) { type = SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX; } else { mexPrintf("Unsupported TxScheme=%s\n", txscheme); return; } - int symbols_layers[SRSLTE_MAX_LAYERS]; - for (int i=0;i= 1) { - mexutils_write_cf(output, &plhs[0], nof_symbols, 1); + /* Set output pointer */ + cf_t *d[SRSLTE_MAX_CODEWORDS]; + for (i = 0; i= 1) { + mexutils_write_cf(output, &plhs[0], nof_symbols*nof_layers*nof_rx_ants/nof_tx_ports, 1); + } + + /* Free memory */ if (input) { free(input); } + if (hest) { + free(hest); + } if (output) { free(output); } - for (int i=0;itb_cw_swap; } + + /* Force MCS_idx and RV_idx in function of block enable according to 7.1.7 of 36.213 */ + if (!data->tb_en[0]) { + data->mcs_idx = 0; + data->rv_idx= 1; + } + if (!data->tb_en[1]) { + data->mcs_idx_1 = 0; + data->rv_idx_1 = 1; + } /* pack TB1 */ srslte_bit_unpack(data->mcs_idx, &y, 5); diff --git a/lib/src/phy/phch/pdcch.c b/lib/src/phy/phch/pdcch.c index cfdb19621..f4c59b321 100644 --- a/lib/src/phy/phch/pdcch.c +++ b/lib/src/phy/phch/pdcch.c @@ -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); } -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; @@ -122,19 +134,25 @@ int srslte_pdcch_init_multi(srslte_pdcch_t *q, srslte_regs_t *regs, srslte_cell_ goto clean; } - for (int i = 0; i < SRSLTE_MAX_PORTS; i++) { - for (int j=0;jnof_rx_antennas;j++) { - q->ce[i][j] = srslte_vec_malloc(sizeof(cf_t) * q->max_bits / 2); - if (!q->ce[i][j]) { - goto clean; - } + if (isReceiver) { + for (int i = 0; i < SRSLTE_MAX_PORTS; i++) { + for (int j = 0; j < q->nof_rx_antennas; j++) { + q->ce[i][j] = srslte_vec_malloc(sizeof(cf_t) * q->max_bits / 2); + if (!q->ce[i][j]) { + goto clean; + } + } } + } + + for (int i = 0; i < SRSLTE_MAX_PORTS; i++) { q->x[i] = srslte_vec_malloc(sizeof(cf_t) * q->max_bits / 2); if (!q->x[i]) { goto clean; } } - for (int j=0;jnof_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); if (!q->symbols[j]) { goto clean; diff --git a/lib/src/phy/phch/pdsch.c b/lib/src/phy/phch/pdsch.c index 9b6128c64..3d24cf175 100644 --- a/lib/src/phy/phch/pdsch.c +++ b/lib/src/phy/phch/pdsch.c @@ -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); } -int srslte_pdsch_init(srslte_pdsch_t *q, srslte_cell_t cell) -{ - 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) +/** 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) { int ret = SRSLTE_ERROR_INVALID_INPUTS; int i; if (q != NULL && srslte_cell_isvalid(&cell) && - nof_rx_antennas <= SRSLTE_MAX_PORTS) + nof_antennas <= SRSLTE_MAX_PORTS) { bzero(q, sizeof(srslte_pdsch_t)); @@ -224,8 +219,10 @@ int srslte_pdsch_init_multi(srslte_pdsch_t *q, srslte_cell_t cell, uint32_t nof_ q->cell = cell; 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, q->cell.nof_prb, q->max_re); @@ -244,20 +241,37 @@ int srslte_pdsch_init_multi(srslte_pdsch_t *q, srslte_cell_t cell, uint32_t nof_ 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); if (!q->d) { 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++) { q->x[i] = srslte_vec_malloc(sizeof(cf_t) * q->max_re); if (!q->x[i]) { goto clean; } - for (int j=0;jnof_rx_antennas;j++) { - q->ce[i][j] = srslte_vec_malloc(sizeof(cf_t) * q->max_re); - if (!q->ce[i][j]) { - goto clean; + } + + /* 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); + if (!q->ce[i][j]) { + goto clean; + } } } } @@ -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); if (!q->users) { perror("malloc"); @@ -283,15 +298,33 @@ int srslte_pdsch_init_multi(srslte_pdsch_t *q, srslte_cell_t cell, uint32_t nof_ 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) { int i; if (q->e) { free(q->e); } + if (q->e2) { + free(q->e2); + } if (q->d) { free(q->d); } + if (q->d2) { + free(q->d2); + } for (i = 0; i < q->cell.nof_ports; i++) { if (q->x[i]) { free(q->x[i]); @@ -302,7 +335,7 @@ void srslte_pdsch_free(srslte_pdsch_t *q) { } } } - for (int j=0;jnof_rx_antennas;j++) { + for (int j=0;jsymbols[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 * 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))) { 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; } @@ -374,6 +455,7 @@ void srslte_pdsch_free_rnti(srslte_pdsch_t* q, uint16_t rnti) if (q->users[rnti]) { for (int i = 0; i < SRSLTE_NSUBFRAMES_X_FRAME; i++) { srslte_sequence_free(&q->users[rnti]->seq[i]); + srslte_sequence_free(&q->users[rnti]->seq2[i]); } free(q->users[rnti]); q->users[rnti] = NULL; @@ -392,15 +474,15 @@ int srslte_pdsch_decode(srslte_pdsch_t *q, for (int i=0;icell.nof_ports;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 */ 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, - uint16_t rnti, uint8_t *data) + uint16_t rnti, uint8_t *data[SRSLTE_MAX_CODEWORDS]) { /* 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) { /* 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); } else { - srslte_predecoding_diversity_multi(q->symbols, q->ce, x, q->nof_rx_antennas, q->cell.nof_ports, cfg->nbits.nof_re); - srslte_layerdemap_diversity(x, q->d, q->cell.nof_ports, cfg->nbits.nof_re / q->cell.nof_ports); + int nof_symbols [SRSLTE_MAX_CODEWORDS]; + 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()) { - DEBUG("SAVED FILE subframe.dat: received subframe symbols\n",0); - srslte_vec_save_file("subframe.dat", sf_symbols[0], SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp)*sizeof(cf_t)); - DEBUG("SAVED FILE hest0.dat and hest1.dat: channel estimates for port 0 and port 1\n",0); - srslte_vec_save_file("hest0.dat", ce[0][0], SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp)*sizeof(cf_t)); - if (q->cell.nof_ports > 1) { - srslte_vec_save_file("hest1.dat", ce[1][0], SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp)*sizeof(cf_t)); + char filename[FILENAME_MAX]; + for (int j = 0; j < q->nof_rx_antennas; j++) { + if (snprintf(filename, FILENAME_MAX, "subframe_p%d.dat", j) < 0) { + ERROR("Generating file name"); + break; + } + DEBUG("SAVED FILE %s: received subframe symbols\n", filename); + srslte_vec_save_file(filename, sf_symbols, 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); srslte_vec_save_file("pdsch_symbols.dat", q->d, cfg->nbits.nof_re*sizeof(cf_t)); @@ -466,18 +564,40 @@ int srslte_pdsch_decode_multi(srslte_pdsch_t *q, * The MAX-log-MAP algorithm used in turbo decoding is unsensitive to SNR estimation, * thus we don't need tot set it in the LLRs normalization */ - srslte_demod_soft_demodulate_s(cfg->grant.mcs.mod, q->d, q->e, cfg->nbits.nof_re); - + if (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 */ if (q->users[rnti] && q->users[rnti]->sequence_generated) { - srslte_scrambling_s_offset(&q->users[rnti]->seq[cfg->sf_idx], q->e, 0, cfg->nbits.nof_bits); + if (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 { srslte_sequence_t seq; - if (srslte_sequence_pdsch(&seq, rnti, 0, 2 * cfg->sf_idx, q->cell.id, cfg->nbits.nof_bits)) { - return SRSLTE_ERROR; + 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_s_offset(&seq, q->e, 0, 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_s_offset(&seq, q->e2, 0, cfg->nbits2.nof_bits); + srslte_sequence_free(&seq); } - srslte_scrambling_s_offset(&seq, q->e, 0, cfg->nbits.nof_bits); - srslte_sequence_free(&seq); } if (SRSLTE_VERBOSE_ISDEBUG()) { @@ -485,7 +605,8 @@ int srslte_pdsch_decode_multi(srslte_pdsch_t *q, 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 { return SRSLTE_ERROR_INVALID_INPUTS; @@ -571,6 +692,112 @@ int srslte_pdsch_encode(srslte_pdsch_t *q, 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) { return q->dl_sch.average_nof_iterations; diff --git a/lib/src/phy/phch/pucch.c b/lib/src/phy/phch/pucch.c index 6a889b89c..a61f798fb 100644 --- a/lib/src/phy/phch/pucch.c +++ b/lib/src/phy/phch/pucch.c @@ -826,4 +826,4 @@ int srslte_pucch_decode(srslte_pucch_t* q, srslte_pucch_format_t format, } - \ No newline at end of file + diff --git a/lib/src/phy/phch/ra.c b/lib/src/phy/phch/ra.c index 976a669f4..635172762 100644 --- a/lib/src/phy/phch/ra.c +++ b/lib/src/phy/phch/ra.c @@ -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; } else { n_prb = grant->nof_prb; - grant->nof_tb = 0; if (dci->tb_en[0]) { grant->mcs.idx = dci->mcs_idx; tbs = dl_fill_ra_mcs(&grant->mcs, n_prb); @@ -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 grant->mcs.tbs = last_dl_tbs[dci->harq_process%8]; } - grant->nof_tb++; } else { 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 grant->mcs2.tbs = last_dl_tbs2[dci->harq_process%8]; } - grant->nof_tb++; } else { grant->mcs2.tbs = 0; } - } + } + grant->nof_tb = 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]) { - 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) { 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; } +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 */ 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) @@ -796,18 +813,31 @@ void srslte_ra_pdsch_fprint(FILE *f, srslte_ra_dl_dci_t *dci, uint32_t nof_prb) } break; } - fprintf(f, " - Modulation and coding scheme index:\t%d\n", dci->mcs_idx); fprintf(f, " - HARQ process:\t\t\t%d\n", dci->harq_process); - fprintf(f, " - New data indicator:\t\t\t%s\n", dci->ndi ? "Yes" : "No"); - fprintf(f, " - Redundancy version:\t\t\t%d\n", dci->rv_idx); fprintf(f, " - TPC command for PUCCH:\t\t--\n"); + fprintf(f, " - Transport blocks swapped:\t\t%s\n", (dci->tb_cw_swap)?"true":"false"); + fprintf(f, " - Transport block 1 enabled:\t\t%s\n", (dci->tb_en[0])?"true":"false"); + if (dci->tb_en[0]) { + fprintf(f, " + Modulation and coding scheme index:\t%d\n", dci->mcs_idx); + fprintf(f, " + New data indicator:\t\t\t%s\n", dci->ndi ? "Yes" : "No"); + fprintf(f, " + Redundancy version:\t\t\t%d\n", dci->rv_idx); + } + fprintf(f, " - Transport block 2 enabled:\t\t%s\n", (dci->tb_en[1])?"true":"false"); + if (dci->tb_en[1]) { + fprintf(f, " + Modulation and coding scheme index:\t%d\n", dci->mcs_idx_1); + fprintf(f, " + New data indicator:\t\t\t%s\n", dci->ndi_1 ? "Yes" : "No"); + fprintf(f, " + Redundancy version:\t\t\t%d\n", dci->rv_idx_1); + } } void srslte_ra_dl_grant_fprint(FILE *f, srslte_ra_dl_grant_t *grant) { srslte_ra_prb_fprint(f, grant); fprintf(f, " - Number of PRBs:\t\t\t%d\n", grant->nof_prb); + fprintf(f, " - 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, " - 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) { diff --git a/lib/src/phy/phch/sch.c b/lib/src/phy/phch/sch.c index dceab2506..f0515227e 100644 --- a/lib/src/phy/phch/sch.c +++ b/lib/src/phy/phch/sch.c @@ -523,6 +523,32 @@ int srslte_dlsch_decode(srslte_sch_t *q, srslte_pdsch_cfg_t *cfg, srslte_softbuf 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. * @@ -542,6 +568,35 @@ int srslte_dlsch_encode(srslte_sch_t *q, srslte_pdsch_cfg_t *cfg, srslte_softbuf 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 * Profiling show that the computation of this matrix is neglegible. */ diff --git a/lib/src/phy/phch/test/CMakeLists.txt b/lib/src/phy/phch/test/CMakeLists.txt index 6170f82fe..1c9846c76 100644 --- a/lib/src/phy/phch/test/CMakeLists.txt +++ b/lib/src/phy/phch/test/CMakeLists.txt @@ -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_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 ######################################################################## diff --git a/lib/src/phy/phch/test/dlsch_encode_test_mex.c b/lib/src/phy/phch/test/dlsch_encode_test_mex.c index 8c2318583..f391ab111 100644 --- a/lib/src/phy/phch/test/dlsch_encode_test_mex.c +++ b/lib/src/phy/phch/test/dlsch_encode_test_mex.c @@ -43,9 +43,14 @@ void help() /* the gateway function */ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) { + int i; srslte_sch_t dlsch; srslte_pdsch_cfg_t cfg; - srslte_softbuffer_tx_t softbuffer; + srslte_softbuffer_tx_t *softbuffers[SRSLTE_MAX_CODEWORDS]; + uint32_t nof_codewords = 1; + + memset(&dlsch, 0, sizeof(srslte_sch_t)); + memset(&cfg, 0, sizeof(srslte_pdsch_cfg_t)); if (nrhs < NOF_INPUTS) { help(); @@ -62,6 +67,7 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) srslte_verbose = SRSLTE_VERBOSE_NONE; uint8_t *trblkin_bits = NULL; + cfg.grant.nof_tb = 1; cfg.grant.mcs.tbs = mexutils_read_uint8(TRBLKIN, &trblkin_bits); if (cfg.grant.mcs.tbs == 0) { mexErrMsgTxt("Error trblklen is zero\n"); @@ -76,6 +82,11 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) return; } + if (mexutils_read_uint32_struct(PUSCHCFG, "NLayers", &cfg.nof_layers)) { + mexErrMsgTxt("Field NLayers not found in dlsch config\n"); + return; + } + char *mod_str = mexutils_get_char_struct(PUSCHCFG, "Modulation"); if (!strcmp(mod_str, "QPSK")) { @@ -94,9 +105,13 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) mxFree(mod_str); - if (srslte_softbuffer_tx_init(&softbuffer, cell.nof_prb)) { - mexErrMsgTxt("Error initiating DL-SCH soft buffer\n"); - return; + /* Initialise buffers */ + for (i = 0; i < nof_codewords; i++) { + 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"); + return; + } } cfg.nbits.nof_bits = mxGetScalar(OUTLEN); @@ -111,13 +126,13 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) uint32_t tmp_rv=cfg.rv; if (tmp_rv) { cfg.rv = 0; - if (srslte_dlsch_encode(&dlsch, &cfg, &softbuffer, trblkin, e_bits)) { + if (srslte_dlsch_encode_multi(&dlsch, &cfg, softbuffers, &trblkin, &e_bits)) { mexErrMsgTxt("Error encoding TB\n"); return; } cfg.rv = tmp_rv; } - if (srslte_dlsch_encode(&dlsch, &cfg, &softbuffer, trblkin, e_bits)) { + if (srslte_dlsch_encode_multi(&dlsch, &cfg, softbuffers, &trblkin, &e_bits)) { mexErrMsgTxt("Error encoding TB\n"); return; } @@ -135,7 +150,10 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) free(trblkin); free(e_bits); free(e_bits_unpacked); - + for (i = 0; i < nof_codewords; i++) { + srslte_softbuffer_tx_free(softbuffers[i]); + free(softbuffers[i]); + } return; } diff --git a/lib/src/phy/phch/test/pdcch_test.c b/lib/src/phy/phch/test/pdcch_test.c index 5d4fb0a7c..9495c497b 100644 --- a/lib/src/phy/phch/test/pdcch_test.c +++ b/lib/src/phy/phch/test/pdcch_test.c @@ -27,22 +27,26 @@ #include #include #include -#include #include +#include +#include +#include +#include #include "srslte/srslte.h" srslte_cell_t cell = { - 6, // nof_prb - 1, // nof_ports - 1, // cell_id - SRSLTE_CP_NORM, // cyclic prefix - SRSLTE_PHICH_R_1, // PHICH resources - SRSLTE_PHICH_NORM // PHICH length + .nof_prb = 6, + .nof_ports = 1, + .id = 1, + .cp = SRSLTE_CP_NORM, + .phich_resources = SRSLTE_PHICH_R_1, + .phich_length = SRSLTE_PHICH_NORM }; uint32_t cfi = 1; -bool print_dci_table; +uint32_t nof_rx_ant = 1; +bool print_dci_table; void usage(char *prog) { printf("Usage: %s [cfpndv]\n", prog); @@ -50,25 +54,29 @@ void usage(char *prog) { printf("\t-f cfi [Default %d]\n", cfi); printf("\t-p cell.nof_ports [Default %d]\n", cell.nof_ports); printf("\t-n cell.nof_prb [Default %d]\n", cell.nof_prb); + printf("\t-A nof_rx_ant [Default %d]\n", nof_rx_ant); printf("\t-d Print DCI table [Default %s]\n", print_dci_table?"yes":"no"); printf("\t-v [set srslte_verbose to debug, default none]\n"); } void parse_args(int argc, char **argv) { int opt; - while ((opt = getopt(argc, argv, "cfpndv")) != -1) { + while ((opt = getopt(argc, argv, "cfpndvA")) != -1) { switch (opt) { case 'p': - cell.nof_ports = atoi(argv[optind]); + cell.nof_ports = (uint32_t) atoi(argv[optind]); break; case 'f': - cfi = atoi(argv[optind]); + cfi = (uint32_t) atoi(argv[optind]); break; case 'n': - cell.nof_prb = atoi(argv[optind]); + cell.nof_prb = (uint32_t) atoi(argv[optind]); break; case 'c': - cell.id = atoi(argv[optind]); + cell.id = (uint32_t) atoi(argv[optind]); + break; + case 'A': + nof_rx_ant = (uint32_t) atoi(argv[optind]); break; case 'd': print_dci_table = true; @@ -85,25 +93,26 @@ void parse_args(int argc, char **argv) { int test_dci_payload_size() { int i, j; - int x[4]; - const srslte_dci_format_t formats[4] = { SRSLTE_DCI_FORMAT0, SRSLTE_DCI_FORMAT1, SRSLTE_DCI_FORMAT1A, SRSLTE_DCI_FORMAT1C }; + int x[5]; + const srslte_dci_format_t formats[] = { SRSLTE_DCI_FORMAT0, SRSLTE_DCI_FORMAT1, SRSLTE_DCI_FORMAT1A, SRSLTE_DCI_FORMAT1C, SRSLTE_DCI_FORMAT2A }; const int prb[6] = { 6, 15, 25, 50, 75, 100 }; - const int dci_sz[6][5] = { { 21, 19, 21, 8 }, { 22, 23, 22, 10 }, { 25, 27, - 25, 12 }, { 27, 31, 27, 13 }, { 27, 33, 27, 14 }, { 28, 39, 28, 15 } }; + const int dci_sz[6][5] = { { 21, 19, 21, 8, 28 }, { 22, 23, 22, 10 , 31}, { 25, 27, + 25, 12 , 36}, { 27, 31, 27, 13 , 41}, { 27, 33, 27, 14 , 42}, { 28, 39, 28, 15, 48 }}; + printf("Testing DCI payload sizes...\n"); - printf(" PRB\t0\t1\t1A\t1C\n"); + printf(" PRB\t0\t1\t1A\t1C\t2A\n"); for (i = 0; i < 6; i++) { int n = prb[i]; - for (j = 0; j < 4; j++) { - x[j] = srslte_dci_format_sizeof(formats[j], n, 1); + for (j = 0; j < 5; j++) { + x[j] = srslte_dci_format_sizeof(formats[j], (uint32_t) n, 1); if (x[j] != dci_sz[i][j]) { fprintf(stderr, "Invalid DCI payload size for %s\n", srslte_dci_format_string(formats[j])); return -1; } } - printf(" %2d:\t%2d\t%2d\t%2d\t%2d\n", n, x[0], x[1], x[2], x[3]); + printf(" %2d:\t%2d\t%2d\t%2d\t%2d\t%2d\n", n, x[0], x[1], x[2], x[3], x[4]); } printf("Ok\n"); @@ -111,8 +120,8 @@ int test_dci_payload_size() { printf("dci_sz_table[101][4] = {\n"); for (i=0;i<=100;i++) { printf(" {"); - for (int j=0;j<4;j++) { - printf("%d",srslte_dci_format_sizeof(formats[j], i, 1)); + for (j=0;j<4;j++) { + printf("%d",srslte_dci_format_sizeof(formats[j], (uint32_t) i, 1)); if (j<3) { printf(", "); } @@ -128,16 +137,23 @@ int test_dci_payload_size() { return 0; } +typedef struct { + srslte_dci_msg_t dci_tx, dci_rx; + srslte_dci_location_t dci_location; + srslte_dci_format_t dci_format; + srslte_ra_dl_dci_t ra_dl_tx; + srslte_ra_dl_dci_t ra_dl_rx; +} testcase_dci_t; + int main(int argc, char **argv) { - srslte_pdcch_t pdcch; - srslte_dci_msg_t dci_tx[2], dci_rx[2], dci_tmp; - srslte_dci_location_t dci_locations[2]; + srslte_pdcch_t pdcch_tx, pdcch_rx; + testcase_dci_t testcases[10] = {0}; srslte_ra_dl_dci_t ra_dl; srslte_regs_t regs; - int i, j; - cf_t *ce[SRSLTE_MAX_PORTS]; + int i, j, k; + cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS]; int nof_re; - cf_t *slot_symbols[SRSLTE_MAX_PORTS]; + cf_t *tx_slot_symbols[SRSLTE_MAX_PORTS], *rx_slot_symbols[SRSLTE_MAX_PORTS]; int nof_dcis; int ret = -1; @@ -152,19 +168,30 @@ int main(int argc, char **argv) { /* init memory */ for (i = 0; i < SRSLTE_MAX_PORTS; i++) { - ce[i] = malloc(sizeof(cf_t) * nof_re); - if (!ce[i]) { + for (j = 0; j < SRSLTE_MAX_PORTS; j++) { + ce[i][j] = malloc(sizeof(cf_t) * nof_re); + if (!ce[i][j]) { + perror("malloc"); + exit(-1); + } + for (k = 0; k < nof_re; k++) { + //ce[i][j][k] = (i == j) ? 1 : 0; + ce[i][j][k] = ((float)rand()/(float)RAND_MAX) + _Complex_I*((float)rand()/(float)RAND_MAX); + } + } + tx_slot_symbols[i] = malloc(sizeof(cf_t) * nof_re); + if (!tx_slot_symbols[i]) { perror("malloc"); exit(-1); } - for (j = 0; j < nof_re; j++) { - ce[i][j] = 1; - } - slot_symbols[i] = malloc(sizeof(cf_t) * nof_re); - if (!slot_symbols[i]) { + bzero(tx_slot_symbols[i], sizeof(cf_t) * nof_re); + + rx_slot_symbols[i] = malloc(sizeof(cf_t) * nof_re); + if (!rx_slot_symbols[i]) { perror("malloc"); exit(-1); } + bzero(rx_slot_symbols[i], sizeof(cf_t) * nof_re); } if (srslte_regs_init(®s, cell)) { @@ -177,12 +204,18 @@ int main(int argc, char **argv) { exit(-1); } - if (srslte_pdcch_init(&pdcch, ®s, cell)) { + if (srslte_pdcch_init_tx(&pdcch_tx, ®s, cell)) { + fprintf(stderr, "Error creating PDCCH object\n"); + exit(-1); + } + + if (srslte_pdcch_init_rx(&pdcch_rx, ®s, cell, nof_rx_ant)) { fprintf(stderr, "Error creating PDCCH object\n"); exit(-1); } - nof_dcis = 2; + /* Resource allocate init */ + nof_dcis = 0; bzero(&ra_dl, sizeof(srslte_ra_dl_dci_t)); ra_dl.harq_process = 0; ra_dl.mcs_idx = 5; @@ -190,62 +223,131 @@ int main(int argc, char **argv) { ra_dl.rv_idx = 0; ra_dl.alloc_type = SRSLTE_RA_ALLOC_TYPE0; ra_dl.type0_alloc.rbg_bitmask = 0x5; + ra_dl.tb_en[0] = true; - srslte_dci_msg_pack_pdsch(&ra_dl, SRSLTE_DCI_FORMAT1, &dci_tx[0], cell.nof_prb, cell.nof_ports, false); - srslte_dci_location_set(&dci_locations[0], 0, 0); + /* Format 1 Test case */ + testcases[nof_dcis].dci_format = SRSLTE_DCI_FORMAT1; + testcases[nof_dcis].ra_dl_tx = ra_dl; + nof_dcis++; + /* Format 1 Test case */ ra_dl.mcs_idx = 15; - srslte_dci_msg_pack_pdsch(&ra_dl, SRSLTE_DCI_FORMAT1, &dci_tx[1], cell.nof_prb, cell.nof_ports, false); - srslte_dci_location_set(&dci_locations[1], 0, 1); - + testcases[nof_dcis].dci_format = SRSLTE_DCI_FORMAT1; + testcases[nof_dcis].ra_dl_tx = ra_dl; + nof_dcis++; + + /* Tx Diversity Test case */ + if (cell.nof_ports > 1) { + ra_dl.mcs_idx_1 = 0; + ra_dl.rv_idx_1 = 0; + ra_dl.ndi_1 = false; + ra_dl.tb_en[1] = false; + testcases[nof_dcis].dci_format = SRSLTE_DCI_FORMAT2A; + testcases[nof_dcis].ra_dl_tx = ra_dl; + nof_dcis++; + } + + /* CDD Spatial Multiplexing Test case */ + if (cell.nof_ports > 1) { + ra_dl.mcs_idx_1 = 28; + ra_dl.rv_idx_1 = 1; + ra_dl.ndi_1 = false; + ra_dl.tb_en[1] = true; + testcases[nof_dcis].dci_format = SRSLTE_DCI_FORMAT2A; + testcases[nof_dcis].ra_dl_tx = ra_dl; + nof_dcis++; + } + + /* Execute Rx */ for (i=0;i= 1234 && crc_rem < 1234 + nof_dcis) { crc_rem -= 1234; - memcpy(&dci_rx[crc_rem], &dci_tmp, sizeof(srslte_dci_msg_t)); } else { printf("Received invalid DCI CRC 0x%x\n", crc_rem); goto quit; } } + + /* Compare Tx and Rx */ for (i = 0; i < nof_dcis; i++) { - if (memcmp(dci_tx[i].data, dci_rx[i].data, dci_tx[i].nof_bits)) { + if (memcmp(testcases[i].dci_tx.data, testcases[i].dci_rx.data, testcases[i].dci_tx.nof_bits)) { printf("Error in DCI %d: Received data does not match\n", i); goto quit; } + if (memcmp(&testcases[i].ra_dl_tx, &testcases[i].ra_dl_rx, sizeof(srslte_ra_dl_dci_t))) { + printf("Error in RA %d: Received data does not match\n", i); + printf(" Field | Tx | Rx \n"); + printf("--------------+----------+----------\n"); + printf(" harq_process | %8d | %8d\n", testcases[i].ra_dl_tx.harq_process, testcases[i].ra_dl_rx.harq_process); + printf(" mcs_idx | %8d | %8d\n", testcases[i].ra_dl_tx.mcs_idx, testcases[i].ra_dl_rx.mcs_idx); + printf(" rv_idx | %8d | %8d\n", testcases[i].ra_dl_tx.rv_idx, testcases[i].ra_dl_rx.rv_idx); + printf(" ndi | %8d | %8d\n", testcases[i].ra_dl_tx.ndi, testcases[i].ra_dl_rx.ndi); + printf(" mcs_idx_1 | %8d | %8d\n", testcases[i].ra_dl_tx.mcs_idx_1, testcases[i].ra_dl_rx.mcs_idx_1); + printf(" rv_idx_1 | %8d | %8d\n", testcases[i].ra_dl_tx.rv_idx_1, testcases[i].ra_dl_rx.rv_idx_1); + printf(" ndi_1 | %8d | %8d\n", testcases[i].ra_dl_tx.ndi_1, testcases[i].ra_dl_rx.ndi_1); + printf(" tb_cw_swap | %8d | %8d\n", testcases[i].ra_dl_tx.tb_cw_swap, testcases[i].ra_dl_rx.tb_cw_swap); + printf(" sram_id | %8d | %8d\n", testcases[i].ra_dl_tx.sram_id, testcases[i].ra_dl_rx.sram_id); + printf(" pinfo | %8d | %8d\n", testcases[i].ra_dl_tx.pinfo, testcases[i].ra_dl_rx.pinfo); + printf(" pconf | %8d | %8d\n", testcases[i].ra_dl_tx.pconf, testcases[i].ra_dl_rx.pconf); + printf(" power_offset | %8d | %8d\n", testcases[i].ra_dl_tx.power_offset, testcases[i].ra_dl_rx.power_offset); + printf(" tpc_pucch | %8d | %8d\n", testcases[i].ra_dl_tx.tpc_pucch, testcases[i].ra_dl_rx.tpc_pucch); + printf(" tb_en[0] | %8d | %8d\n", testcases[i].ra_dl_tx.tb_en[0], testcases[i].ra_dl_rx.tb_en[0]); + printf(" tb_en[1] | %8d | %8d\n", testcases[i].ra_dl_tx.tb_en[1], testcases[i].ra_dl_rx.tb_en[1]); + printf(" dci_is_1a | %8d | %8d\n", testcases[i].ra_dl_tx.dci_is_1a, testcases[i].ra_dl_rx.dci_is_1a); + printf(" dci_is_1c | %8d | %8d\n", testcases[i].ra_dl_tx.dci_is_1c, testcases[i].ra_dl_rx.dci_is_1c); + goto quit; + } } ret = 0; quit: - srslte_pdcch_free(&pdcch); + srslte_pdcch_free(&pdcch_tx); + srslte_pdcch_free(&pdcch_rx); srslte_regs_free(®s); for (i = 0; i < SRSLTE_MAX_PORTS; i++) { - free(ce[i]); - free(slot_symbols[i]); + for (j = 0; j < SRSLTE_MAX_PORTS; j++) { + free(ce[i][j]); + } + free(tx_slot_symbols[i]); + free(rx_slot_symbols[i]); } if (ret) { printf("Error\n"); diff --git a/lib/src/phy/phch/test/pdcch_test_mex.c b/lib/src/phy/phch/test/pdcch_test_mex.c index e30ef900f..76b0bb021 100644 --- a/lib/src/phy/phch/test/pdcch_test_mex.c +++ b/lib/src/phy/phch/test/pdcch_test_mex.c @@ -33,13 +33,14 @@ #define ENBCFG prhs[0] #define RNTI prhs[1] -#define INPUT prhs[2] -#define NOF_INPUTS 3 +#define AMP prhs[2] +#define INPUT prhs[3] +#define NOF_INPUTS 4 -srslte_dci_format_t ue_formats[] = {SRSLTE_DCI_FORMAT1A,SRSLTE_DCI_FORMAT1}; // SRSLTE_DCI_FORMAT1B should go here also -const uint32_t nof_ue_formats = 2; +srslte_dci_format_t ue_formats[] = {SRSLTE_DCI_FORMAT1A,SRSLTE_DCI_FORMAT1,SRSLTE_DCI_FORMAT2B}; // SRSLTE_DCI_FORMAT1B should go here also +const uint32_t nof_ue_formats = 3; srslte_dci_format_t common_formats[] = {SRSLTE_DCI_FORMAT1A,SRSLTE_DCI_FORMAT1C}; const uint32_t nof_common_formats = 2; @@ -162,7 +163,10 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) } else { noise_power = srslte_chest_dl_get_noise_estimate(&chest); } - mexPrintf("noise power=%f, RNTI=0x%x, cfi=%d\n", noise_power, rnti, cfi); + + float amplitude = mxGetScalar(AMP); + + srslte_viterbi_set_gain_quant(&pdcch.decoder, amplitude); srslte_pdcch_extract_llr(&pdcch, input_fft, ce, noise_power, sf_idx, cfi); diff --git a/lib/src/phy/phch/test/pdsch_test.c b/lib/src/phy/phch/test/pdsch_test.c index d4e5163d3..2dc21bab4 100644 --- a/lib/src/phy/phch/test/pdsch_test.c +++ b/lib/src/phy/phch/test/pdsch_test.c @@ -30,45 +30,60 @@ #include #include #include +#include #include "srslte/srslte.h" // Enable to measure execution time //#define DO_OFDM +#ifdef DO_OFDM +#define NOF_CE_SYMBOLS SRSLTE_SF_LEN_PRB(cell.nof_prb) +#else +#define NOF_CE_SYMBOLS SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp) +#endif + srslte_cell_t cell = { 6, // nof_prb 1, // nof_ports 0, // cell_id SRSLTE_CP_NORM, // cyclic prefix - SRSLTE_PHICH_R_1_6, // PHICH resources - SRSLTE_PHICH_NORM // PHICH length + SRSLTE_PHICH_NORM, // PHICH length + SRSLTE_PHICH_R_1_6 // PHICH resources }; uint32_t cfi = 2; uint32_t mcs = 0; +uint32_t mcs2 = 0; uint32_t subframe = 1; uint32_t rv_idx = 0; -uint16_t rnti = 1234; +uint32_t rv_idx2 = 0; +uint16_t rnti = 1234; +uint32_t nof_tb = 1; +uint32_t nof_rx_antennas = 1; char *input_file = NULL; void usage(char *prog) { - printf("Usage: %s [fmcsrRFpnv] \n", prog); + printf("Usage: %s [fmMcsrtRFpnwav] \n", prog); printf("\t-f read signal from file [Default generate it with pdsch_encode()]\n"); printf("\t-m MCS [Default %d]\n", mcs); + printf("\t-M MCS2 [Default %d]\n", mcs2); printf("\t-c cell id [Default %d]\n", cell.id); printf("\t-s subframe [Default %d]\n", subframe); printf("\t-r rv_idx [Default %d]\n", rv_idx); + printf("\t-t rv_idx2 [Default %d]\n", rv_idx2); printf("\t-R rnti [Default %d]\n", rnti); printf("\t-F cfi [Default %d]\n", cfi); printf("\t-p cell.nof_ports [Default %d]\n", cell.nof_ports); printf("\t-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"); } void parse_args(int argc, char **argv) { int opt; - while ((opt = getopt(argc, argv, "fmcsrRFpnv")) != -1) { + while ((opt = getopt(argc, argv, "fmMcsrtRFpnwav")) != -1) { switch(opt) { case 'f': input_file = argv[optind]; @@ -76,12 +91,18 @@ void parse_args(int argc, char **argv) { case 'm': mcs = atoi(argv[optind]); break; + case 'M': + mcs2 = (uint32_t) atoi(argv[optind]); + break; case 's': subframe = atoi(argv[optind]); break; case 'r': rv_idx = atoi(argv[optind]); break; + case 't': + rv_idx2 = (uint32_t) atoi(argv[optind]); + break; case 'R': rnti = atoi(argv[optind]); break; @@ -97,6 +118,12 @@ void parse_args(int argc, char **argv) { case 'c': cell.id = atoi(argv[optind]); break; + case 'w': + nof_tb = (uint32_t) atoi(argv[optind]); + break; + case 'a': + nof_rx_antennas = (uint32_t) atoi(argv[optind]); + break; case 'v': srslte_verbose++; break; @@ -107,30 +134,37 @@ void parse_args(int argc, char **argv) { } } -uint8_t *data = NULL; -cf_t *ce[SRSLTE_MAX_PORTS]; -srslte_softbuffer_rx_t softbuffer_rx; +uint8_t *data[SRSLTE_MAX_CODEWORDS] = {NULL}; +cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS]; +srslte_softbuffer_rx_t softbuffers_rx[SRSLTE_MAX_CODEWORDS]; srslte_ra_dl_grant_t grant; srslte_pdsch_cfg_t pdsch_cfg; -cf_t *sf_symbols; -cf_t *slot_symbols[SRSLTE_MAX_PORTS]; -srslte_pdsch_t pdsch; +#ifdef DO_OFDM +cf_t *tx_sf_symbols[SRSLTE_MAX_PORTS]; +cf_t *rx_sf_symbols[SRSLTE_MAX_PORTS]; +#endif /* DO_OFDM */ +cf_t *tx_slot_symbols[SRSLTE_MAX_PORTS]; +cf_t *rx_slot_symbols[SRSLTE_MAX_PORTS]; +srslte_pdsch_t pdsch_tx, pdsch_rx; srslte_ofdm_t ofdm_tx, ofdm_rx; int main(int argc, char **argv) { - uint32_t i, j; + uint32_t i, j, k; int ret = -1; struct timeval t[3]; - srslte_softbuffer_tx_t softbuffer_tx; + srslte_softbuffer_tx_t softbuffers_tx[SRSLTE_MAX_CODEWORDS]; parse_args(argc,argv); - bzero(&pdsch, sizeof(srslte_pdsch_t)); + /* Initialise to zeros */ + bzero(&pdsch_tx, sizeof(srslte_pdsch_t)); + bzero(&pdsch_rx, sizeof(srslte_pdsch_t)); bzero(&pdsch_cfg, sizeof(srslte_pdsch_cfg_t)); bzero(ce, sizeof(cf_t*)*SRSLTE_MAX_PORTS); - bzero(slot_symbols, sizeof(cf_t*)*SRSLTE_MAX_PORTS); - bzero(&softbuffer_rx, sizeof(srslte_softbuffer_rx_t)); - bzero(&softbuffer_tx, sizeof(srslte_softbuffer_tx_t)); + bzero(tx_slot_symbols, sizeof(cf_t*)*SRSLTE_MAX_PORTS); + bzero(rx_slot_symbols, sizeof(cf_t*)*SRSLTE_MAX_PORTS); + 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; bzero(&dci, sizeof(srslte_ra_dl_dci_t)); @@ -138,57 +172,136 @@ int main(int argc, char **argv) { dci.rv_idx = rv_idx; dci.type0_alloc.rbg_bitmask = 0xffffffff; 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)) { fprintf(stderr, "Error computing resource allocation\n"); return ret; } +#ifdef DO_OFDM srslte_ofdm_tx_init(&ofdm_tx, cell.cp, cell.nof_prb); srslte_ofdm_rx_init(&ofdm_rx, cell.cp, cell.nof_prb); - sf_symbols=srslte_vec_malloc(sizeof(cf_t)*SRSLTE_SF_LEN_PRB(cell.nof_prb)); - + srslte_ofdm_set_normalize(&ofdm_tx, true); + srslte_ofdm_set_normalize(&ofdm_rx, true); + + for (i = 0; i < cell.nof_ports; i++) { + tx_sf_symbols[i] = srslte_vec_malloc(sizeof(cf_t) * SRSLTE_SF_LEN_PRB(cell.nof_prb)); + } + + for (i = 0; i < nof_rx_antennas; i++) { + rx_sf_symbols[i] = srslte_vec_malloc(sizeof(cf_t) * SRSLTE_SF_LEN_PRB(cell.nof_prb)); + } +#endif /* DO_OFDM */ + /* Configure PDSCH */ - if (srslte_pdsch_cfg(&pdsch_cfg, cell, &grant, cfi, subframe, rv_idx)) { + if (srslte_pdsch_cfg_multi(&pdsch_cfg, cell, &grant, cfi, subframe, rv_idx, rv_idx2)) { fprintf(stderr, "Error configuring PDSCH\n"); 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 */ for (i=0;i 0) { - slot_symbols[0][j] += slot_symbols[i][j]; + for (j = 0; j < nof_rx_antennas; j++) { + for (k = 0; k < NOF_CE_SYMBOLS; k++) { + rx_sf_symbols[j][k] = 0.0f; + for (i = 0; i < cell.nof_ports; i++) { + rx_sf_symbols[j][k] += tx_sf_symbols[i][k] * ce[i][j][k]; + } + } + } + #else + /* combine outputs */ + for (j = 0; j < nof_rx_antennas; j++) { + for (k = 0; k < SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp); k++) { + rx_slot_symbols[j][k] = 0.0f; + for (i = 0; i < cell.nof_ports; i++) { + rx_slot_symbols[j][k] += tx_slot_symbols[i][k] * ce[i][j][k]; } - ce[i][j] = 1; } } - - #ifdef DO_OFDM - srslte_ofdm_tx_sf(&ofdm_tx, slot_symbols[0], sf_symbols); #endif - } - int M=1; + + + } + int M=10; 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); - for (i=0;iname, devname)) { rf->dev = available_devices[i]; - return available_devices[i]->srslte_rf_open_multi(args, &rf->handler, nof_rx_antennas); + return available_devices[i]->srslte_rf_open_multi(args, &rf->handler, nof_tx_antennas, nof_rx_antennas); } 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 */ int i=0; while(available_devices[i] != NULL) { - if (!available_devices[i]->srslte_rf_open_multi(args, &rf->handler, nof_rx_antennas)) { + if (!available_devices[i]->srslte_rf_open_multi(args, &rf->handler, nof_tx_antennas, nof_rx_antennas)) { rf->dev = available_devices[i]; 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); } +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) { 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); } +int srslte_rf_send_multi(srslte_rf_t *rf, + void *data[4], + int nsamples, + bool blocking, + bool is_start_of_burst, + bool is_end_of_burst) +{ + + return ((rf_dev_t*) rf->dev)->srslte_rf_send_timed_multi(rf->handler, data, nsamples, 0, 0, + false, blocking, is_start_of_burst, is_end_of_burst); +} + int srslte_rf_send(srslte_rf_t *rf, void *data, uint32_t nsamples, bool blocking) { return srslte_rf_send2(rf, data, nsamples, blocking, true, true); diff --git a/lib/src/phy/rf/rf_uhd_imp.c b/lib/src/phy/rf/rf_uhd_imp.c index 319093994..e0f3ac573 100644 --- a/lib/src/phy/rf/rf_uhd_imp.c +++ b/lib/src/phy/rf/rf_uhd_imp.c @@ -286,10 +286,10 @@ float rf_uhd_get_rssi(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) { *h = NULL; @@ -395,12 +395,11 @@ int rf_uhd_open_multi(char *args, void **h, uint32_t nof_rx_antennas) .otw_format = "sc16", .args = "", .channel_list = channel, - .n_channels = 1 + .n_channels = (nof_tx_antennas > nof_rx_antennas)?nof_tx_antennas: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 */ uhd_rx_streamer_make(&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_end_of_burst) { + void *_data[SRSLTE_MAX_PORTS]= {data, zero_mem, zero_mem, zero_mem}; + + return rf_uhd_send_timed_multi(h, _data, nsamples, secs, frac_secs, has_time_spec, blocking, is_start_of_burst, is_end_of_burst); +} + +int rf_uhd_send_timed_multi(void *h, + void *data[4], + int nsamples, + time_t secs, + double frac_secs, + bool has_time_spec, + bool blocking, + bool is_start_of_burst, + bool is_end_of_burst) { rf_uhd_handler_t* handler = (rf_uhd_handler_t*) h; + /* Resets the USRP time FIXME: this might cause problems for burst transmissions */ + if (is_start_of_burst && handler->nof_tx_channels > 1) { + uhd_usrp_set_time_now(handler->usrp, 0, 0, 0); + uhd_tx_metadata_set_time_spec(&handler->tx_md, 0, 0.1); + } + size_t txd_samples; if (has_time_spec) { uhd_tx_metadata_set_time_spec(&handler->tx_md, secs, frac_secs); @@ -657,7 +676,10 @@ int rf_uhd_send_timed(void *h, int trials = 0; if (blocking) { int n = 0; - cf_t *data_c = (cf_t*) data; + cf_t *data_c[4]; + for (int i = 0; i < 4; i++) { + data_c[i] = data[i]; + } do { size_t tx_samples = handler->tx_nof_samples; @@ -675,9 +697,12 @@ int rf_uhd_send_timed(void *h, tx_samples = nsamples - n; uhd_tx_metadata_set_end(&handler->tx_md, is_end_of_burst); } - - void *buff = (void*) &data_c[n]; - const void *buffs_ptr[4] = {buff, zero_mem, zero_mem, zero_mem}; + + const void *buffs_ptr[4]; + for (int i = 0; i < 4; i++) { + void *buff = (void*) &data_c[i][n]; + buffs_ptr[i] = buff; + } uhd_error error = uhd_tx_streamer_send(handler->tx_stream, buffs_ptr, tx_samples, &handler->tx_md, 3.0, &txd_samples); if (error) { @@ -691,7 +716,10 @@ int rf_uhd_send_timed(void *h, } while (n < nsamples && trials < 100); return nsamples; } else { - const void *buffs_ptr[4] = {data, zero_mem, zero_mem, zero_mem}; + const void *buffs_ptr[4]; + for (int i = 0; i < 4; i++) { + buffs_ptr[i] = data[i]; + } uhd_tx_metadata_set_start(&handler->tx_md, is_start_of_burst); uhd_tx_metadata_set_end(&handler->tx_md, is_end_of_burst); return uhd_tx_streamer_send(handler->tx_stream, buffs_ptr, nsamples, &handler->tx_md, 0.0, &txd_samples); diff --git a/lib/src/phy/rf/rf_uhd_imp.h b/lib/src/phy/rf/rf_uhd_imp.h index 7c26f015c..6c0ab7dc7 100644 --- a/lib/src/phy/rf/rf_uhd_imp.h +++ b/lib/src/phy/rf/rf_uhd_imp.h @@ -39,6 +39,7 @@ SRSLTE_API int rf_uhd_open(char *args, SRSLTE_API int rf_uhd_open_multi(char *args, void **handler, + uint32_t nof_tx_antennas, uint32_t nof_rx_antennas); 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_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); + diff --git a/lib/src/phy/ue/ue_dl.c b/lib/src/phy/ue/ue_dl.c index 7201f96c2..3b1a83466 100644 --- a/lib/src/phy/ue/ue_dl.c +++ b/lib/src/phy/ue/ue_dl.c @@ -38,8 +38,8 @@ #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 -const uint32_t nof_ue_formats = 2; +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 = 3; static srslte_dci_format_t common_formats[] = {SRSLTE_DCI_FORMAT1A,SRSLTE_DCI_FORMAT1C}; const uint32_t nof_common_formats = 2; @@ -97,13 +97,16 @@ int srslte_ue_dl_init_multi(srslte_ue_dl_t *q, 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"); goto clean_exit; } - if (srslte_softbuffer_rx_init(&q->softbuffer, q->cell.nof_prb)) { - fprintf(stderr, "Error initiating soft buffer\n"); - goto clean_exit; + + 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"); + goto clean_exit; + } } if (srslte_cfo_init(&q->sfo_correct, q->cell.nof_prb*SRSLTE_NRE)) { fprintf(stderr, "Error initiating SFO correct\n"); @@ -154,7 +157,9 @@ void srslte_ue_dl_free(srslte_ue_dl_t *q) { srslte_pdcch_free(&q->pdcch); srslte_pdsch_free(&q->pdsch); srslte_cfo_free(&q->sfo_correct); - srslte_softbuffer_rx_free(&q->softbuffer); + for (int i = 0; i < SRSLTE_MAX_CODEWORDS; i++) { + srslte_softbuffer_rx_free(&q->softbuffers[i]); + } for (int j=0;jnof_rx_antennas;j++) { if (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) { - 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)); } @@ -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() */ 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]; + _data[0] = data; _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); } @@ -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) { - 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_decode_rnti(srslte_ue_dl_t *q, cf_t *input, uint8_t *data, uint32_t tti, uint16_t rnti) +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) +{ + uint8_t *_data[SRSLTE_MAX_CODEWORDS]; cf_t *_input[SRSLTE_MAX_PORTS]; _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_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 rvidx2 = 0; if (dci_unpacked.rv_idx < 0) { uint32_t sfn = tti/10; uint32_t k = (sfn/2)%4; rvidx = ((uint32_t) ceilf((float)1.5*k))%4; - srslte_softbuffer_rx_reset_tbs(&q->softbuffer, grant.mcs.tbs); + 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 { - rvidx = dci_unpacked.rv_idx; - srslte_softbuffer_rx_reset_tbs(&q->softbuffer, grant.mcs.tbs); + rvidx = (uint32_t) dci_unpacked.rv_idx; + 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; } @@ -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) { - 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, noise_estimate, rnti, data); diff --git a/lib/src/phy/ue/ue_sync.c b/lib/src/phy/ue/ue_sync.c index b5b2be3d0..e011789ca 100644 --- a/lib/src/phy/ue/ue_sync.c +++ b/lib/src/phy/ue/ue_sync.c @@ -53,6 +53,11 @@ cf_t dummy_buffer1[15*2048/2]; cf_t *dummy_offset_buffer[SRSLTE_MAX_PORTS] = {dummy_buffer0, dummy_buffer1}; int srslte_ue_sync_init_file(srslte_ue_sync_t *q, uint32_t nof_prb, char *file_name, int offset_time, float offset_freq) { + return srslte_ue_sync_init_file_multi(q, nof_prb, file_name, offset_time, offset_freq, 1); +} + +int srslte_ue_sync_init_file_multi(srslte_ue_sync_t *q, uint32_t nof_prb, char *file_name, int offset_time, + float offset_freq, uint32_t nof_rx_ant) { int ret = SRSLTE_ERROR_INVALID_INPUTS; if (q != NULL && @@ -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->correct_cfo = true; q->fft_size = srslte_symbol_sz(nof_prb); + q->nof_rx_antennas = nof_rx_ant; if (srslte_cfo_init(&q->file_cfo_correct, 2*q->sf_len)) { fprintf(stderr, "Error initiating CFO\n"); @@ -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); if (offset_time) { - cf_t *file_offset_buffer = srslte_vec_malloc(offset_time * sizeof(cf_t)); + cf_t *file_offset_buffer = srslte_vec_malloc(offset_time * nof_rx_ant * sizeof(cf_t)); if (!file_offset_buffer) { perror("malloc"); goto clean_exit; } - srslte_filesource_read(&q->file_source, file_offset_buffer, offset_time); + srslte_filesource_read(&q->file_source, file_offset_buffer, offset_time * nof_rx_ant); free(file_offset_buffer); } @@ -518,26 +524,27 @@ int srslte_ue_sync_zerocopy_multi(srslte_ue_sync_t *q, cf_t *input_buffer[SRSLTE { if (q->file_mode) { - int n = srslte_filesource_read(&q->file_source, input_buffer[0], q->sf_len); + int n = srslte_filesource_read_multi(&q->file_source, (void **) input_buffer, q->sf_len, q->nof_rx_antennas); if (n < 0) { fprintf(stderr, "Error reading input file\n"); - return SRSLTE_ERROR; + return SRSLTE_ERROR; } if (n == 0) { srslte_filesource_seek(&q->file_source, 0); - q->sf_idx = 9; - int n = srslte_filesource_read(&q->file_source, input_buffer[0], q->sf_len); + q->sf_idx = 9; + n = srslte_filesource_read_multi(&q->file_source, (void **) input_buffer, q->sf_len, q->nof_rx_antennas); if (n < 0) { fprintf(stderr, "Error reading input file\n"); - return SRSLTE_ERROR; + return SRSLTE_ERROR; } } if (q->correct_cfo) { - srslte_cfo_correct(&q->file_cfo_correct, - input_buffer[0], - input_buffer[0], - q->file_cfo / 15000 / q->fft_size); - + for (int i = 0; i < q->nof_rx_antennas; i++) { + srslte_cfo_correct(&q->file_cfo_correct, + input_buffer[i], + input_buffer[i], + q->file_cfo / 15000 / q->fft_size); + } } q->sf_idx++; if (q->sf_idx == 10) { diff --git a/srsue/hdr/phy/phch_worker.h b/srsue/hdr/phy/phch_worker.h index 669422981..8cdec22c2 100644 --- a/srsue/hdr/phy/phch_worker.h +++ b/srsue/hdr/phy/phch_worker.h @@ -78,6 +78,7 @@ private: bool decode_pdcch_dl(mac_interface_phy::mac_grant_t *grant); bool decode_phich(bool *ack); bool decode_pdsch(srslte_ra_dl_grant_t *grant, uint8_t *payload, srslte_softbuffer_rx_t* softbuffer, int rv, uint16_t rnti, uint32_t pid); + bool decode_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 */ void encode_pusch(srslte_ra_ul_grant_t *grant, uint8_t *payload, uint32_t current_tx_nb, srslte_softbuffer_tx_t *softbuffer, diff --git a/srsue/src/phy/phch_worker.cc b/srsue/src/phy/phch_worker.cc index c2796e2ad..ef3640a40 100644 --- a/srsue/src/phy/phch_worker.cc +++ b/srsue/src/phy/phch_worker.cc @@ -405,8 +405,14 @@ 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) +{ + 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]; 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); #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; #ifdef LOG_EXECTIME gettimeofday(&t[2], NULL);