diff --git a/README.md b/README.md index f7c699ed3..a6eada615 100644 --- a/README.md +++ b/README.md @@ -72,6 +72,7 @@ Build Instructions * Mandatory requirements: * Common: + * cmake https://cmake.org/ * libfftw http://www.fftw.org/ * PolarSSL/mbedTLS https://tls.mbed.org * srsUE: @@ -83,7 +84,7 @@ Build Instructions For example, on Ubuntu 17.04, one can install the required libraries with: ``` -sudo apt-get install libfftw3-dev libmbedtls-dev libboost-all-dev libconfig++-dev libsctp-dev +sudo apt-get install cmake libfftw3-dev libmbedtls-dev libboost-all-dev libconfig++-dev libsctp-dev ``` Note that depending on your flavor and version of Linux, the actual package names may be different. diff --git a/lib/examples/pdsch_enodeb.c b/lib/examples/pdsch_enodeb.c index d481ff20f..844e769a7 100644 --- a/lib/examples/pdsch_enodeb.c +++ b/lib/examples/pdsch_enodeb.c @@ -27,7 +27,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -38,10 +40,11 @@ #define UE_CRNTI 0x1234 - +#define M_CRNTI 0xFFFD #ifndef DISABLE_RF #include "srslte/phy/rf/rf.h" +#include "srslte/phy/common/phy_common.h" srslte_rf_t rf; #else #warning Compiling pdsch_ue with no RF support @@ -55,52 +58,67 @@ 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_NORM, // PHICH length - SRSLTE_PHICH_R_1 // PHICH resources + 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 }; +uint16_t c = -1; + int net_port = -1; // -1 generates random dataThat means there is some problem sending samples to the device -uint32_t cfi = 1; +uint32_t cfi = 2; uint32_t mcs_idx = 1, last_mcs_idx = 1; int nof_frames = -1; + + char mimo_type_str[32] = "single"; uint32_t nof_tb = 1; uint32_t multiplex_pmi = 0; uint32_t multiplex_nof_layers = 1; +int mbsfn_area_id = -1; char *rf_args = ""; float rf_amp = 0.8, rf_gain = 70.0, rf_freq = 2400000000; bool null_file_sink=false; srslte_filesink_t fsink; srslte_ofdm_t ifft; +srslte_ofdm_t ifft_mbsfn; srslte_pbch_t pbch; srslte_pcfich_t pcfich; srslte_pdcch_t pdcch; srslte_pdsch_t pdsch; -srslte_pdsch_cfg_t pdsch_cfg; +srslte_pdsch_cfg_t pdsch_cfg; +srslte_pmch_t pmch; +srslte_pdsch_cfg_t pmch_cfg; srslte_softbuffer_tx_t *softbuffers[SRSLTE_MAX_CODEWORDS]; srslte_regs_t regs; -srslte_ra_dl_dci_t ra_dl; +srslte_ra_dl_dci_t ra_dl; int rvidx[SRSLTE_MAX_CODEWORDS] = {0, 0}; cf_t *sf_buffer[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; srslte_netsource_t net_source; srslte_netsink_t net_sink; + int prbset_num = 1, last_prbset_num = 1; int prbset_orig = 0; +//#define DATA_BUFF_SZ 1024*128 +//uint8_t data[8*DATA_BUFF_SZ], data2[DATA_BUFF_SZ]; +//uint8_t data_tmp[DATA_BUFF_SZ]; + #define DATA_BUFF_SZ 1024*1024 uint8_t *data[2], data2[DATA_BUFF_SZ]; @@ -121,6 +139,7 @@ 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 MBSFN area id [Default %d]\n", mbsfn_area_id); printf("\t-x Transmission mode[single|diversity|cdd|multiplex] [Default %s]\n", mimo_type_str); printf("\t-b Precoding Matrix Index (multiplex mode only)* [Default %d]\n", multiplex_pmi); printf("\t-w Number of codewords/layers (multiplex mode only)* [Default %d]\n", multiplex_nof_layers); @@ -132,7 +151,8 @@ void usage(char *prog) { void parse_args(int argc, char **argv) { int opt; - while ((opt = getopt(argc, argv, "aglfmoncpvutxbw")) != -1) { + while ((opt = getopt(argc, argv, "aglfmoncpvutxbwM")) != -1) { + switch (opt) { case 'a': rf_args = argv[optind]; @@ -173,6 +193,9 @@ void parse_args(int argc, char **argv) { case 'w': multiplex_nof_layers = (uint32_t) atoi(argv[optind]); break; + case 'M': + mbsfn_area_id = atoi(argv[optind]); + break; case 'v': srslte_verbose++; break; @@ -188,7 +211,7 @@ void parse_args(int argc, char **argv) { } #endif } - + void base_init() { int i; @@ -245,6 +268,7 @@ void base_init() { bzero(output_buffer[i], sizeof(cf_t) * sf_n_samples); } + /* open file or USRP */ if (output_file_name) { if (strcmp(output_file_name, "NULL")) { @@ -291,7 +315,15 @@ void base_init() { fprintf(stderr, "Error creating iFFT object\n"); exit(-1); } + if (srslte_ofdm_tx_init_mbsfn(&ifft_mbsfn, SRSLTE_CP_EXT, cell.nof_prb)) { + fprintf(stderr, "Error creating iFFT object\n"); + exit(-1); + } + srslte_ofdm_set_non_mbsfn_region(&ifft_mbsfn, 2); + srslte_ofdm_set_normalize(&ifft, true); + srslte_ofdm_set_normalize(&ifft_mbsfn, true); + if (srslte_pbch_init(&pbch)) { fprintf(stderr, "Error creating PBCH object\n"); exit(-1); @@ -300,12 +332,14 @@ void base_init() { fprintf(stderr, "Error creating PBCH object\n"); exit(-1); } + + + if (srslte_regs_init(®s, cell)) { fprintf(stderr, "Error initiating regs\n"); exit(-1); } - if (srslte_pcfich_init(&pcfich, 1)) { fprintf(stderr, "Error creating PBCH object\n"); exit(-1); @@ -340,6 +374,14 @@ void base_init() { srslte_pdsch_set_rnti(&pdsch, UE_CRNTI); + + if(mbsfn_area_id > -1){ + if (srslte_pmch_init(&pmch, cell.nof_prb)) { + fprintf(stderr, "Error creating PMCH object\n"); + } + srslte_pmch_set_area_id(&pmch, mbsfn_area_id); + } + for (i = 0; i < SRSLTE_MAX_CODEWORDS; i++) { softbuffers[i] = calloc(sizeof(srslte_softbuffer_tx_t), 1); if (!softbuffers[i]) { @@ -354,6 +396,7 @@ void base_init() { } } + void base_free() { int i; for (i = 0; i < SRSLTE_MAX_CODEWORDS; i++) { @@ -366,8 +409,12 @@ void base_free() { srslte_pdcch_free(&pdcch); srslte_regs_free(®s); srslte_pbch_free(&pbch); - + if(mbsfn_area_id > -1){ + srslte_pmch_free(&pmch); + } + srslte_ofdm_tx_free(&ifft_mbsfn); srslte_ofdm_tx_free(&ifft); + for (i = 0; i < SRSLTE_MAX_CODEWORDS; i++) { if (data[i]) { @@ -481,7 +528,7 @@ int update_radl() { srslte_ra_dl_dci_to_grant(&ra_dl, cell.nof_prb, UE_CRNTI, &dummy_grant); srslte_ra_dl_grant_to_nbits(&dummy_grant, cfi, cell, 0, &dummy_nbits); srslte_ra_dl_grant_fprint(stdout, &dummy_grant); - + dummy_grant.sf_type = SRSLTE_SF_NORM; if (pdsch_cfg.mimo_type != SRSLTE_MIMO_TYPE_SINGLE_ANTENNA) { printf("\nTransmission mode key table:\n"); printf(" Mode | 1TB | 2TB |\n"); @@ -596,6 +643,7 @@ int update_control() { } } + /** Function run in a separate thread to receive UDP data */ void *net_thread_fnc(void *arg) { int n; @@ -633,6 +681,7 @@ void *net_thread_fnc(void *arg) { return NULL; } + int main(int argc, char **argv) { int nf=0, sf_idx=0, N_id_2=0; cf_t pss_signal[SRSLTE_PSS_LEN]; @@ -645,7 +694,8 @@ int main(int argc, char **argv) { srslte_dci_msg_t dci_msg; srslte_dci_location_t locations[SRSLTE_NSUBFRAMES_X_FRAME][30]; uint32_t sfn; - srslte_chest_dl_t est; + srslte_refsignal_t csr_refs; + srslte_refsignal_t mbsfn_refs; #ifdef DISABLE_RF if (argc < 3) { @@ -674,21 +724,31 @@ int main(int argc, char **argv) { srslte_pss_generate(pss_signal, N_id_2); srslte_sss_generate(sss_signal0, sss_signal5, cell.id); - /* Generate CRS signals */ - if (srslte_chest_dl_init(&est, cell.nof_prb)) { - fprintf(stderr, "Error initializing equalizer\n"); - exit(-1); - } - if (srslte_chest_dl_set_cell(&est, cell)) { - fprintf(stderr, "Error initializing equalizer\n"); - exit(-1); - } + /* Generate reference signals */ + if(srslte_refsignal_cs_init(&csr_refs, cell.nof_prb)) { + fprintf(stderr, "Error initializing equalizer\n"); + exit(-1); + } + if(mbsfn_area_id > -1) { + if(srslte_refsignal_mbsfn_init(&mbsfn_refs, cell, mbsfn_area_id)) { + fprintf(stderr, "Error initializing equalizer\n"); + exit(-1); + } + } + + if(srslte_refsignal_cs_set_cell(&csr_refs, cell)){ + fprintf(stderr, "Error setting cell\n"); + exit(-1); + } + + 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 @@ -737,48 +797,51 @@ int main(int argc, char **argv) { /* Initiate valid DCI locations */ for (i=0;i -1){ + srslte_refsignal_mbsfn_put_sf(cell, 0,csr_refs.pilots[0][sf_idx], mbsfn_refs.pilots[0][sf_idx], sf_symbols[0]); + } else { + for (i = 0; i < cell.nof_ports; i++) { + srslte_refsignal_cs_put_sf(cell, (uint32_t) i, csr_refs.pilots[i / 2][sf_idx], sf_symbols[i]); + } } - + srslte_pbch_mib_pack(&cell, sfn, bch_payload); if (sf_idx == 0) { srslte_pbch_encode(&pbch, bch_payload, slot1_symbols, nf%4); } - srslte_pcfich_encode(&pcfich, cfi, sf_symbols, sf_idx); + srslte_pcfich_encode(&pcfich, cfi, sf_symbols, sf_idx); /* Update DL resource allocation from control port */ if (update_control(sf_idx)) { @@ -806,86 +869,134 @@ int main(int argc, char **argv) { } else { send_data = false; } - } + } if (send_data) { - srslte_dci_format_t dci_format; - switch(pdsch_cfg.mimo_type) { - case SRSLTE_MIMO_TYPE_SINGLE_ANTENNA: - dci_format = SRSLTE_DCI_FORMAT1; - break; - case SRSLTE_MIMO_TYPE_TX_DIVERSITY: - case SRSLTE_MIMO_TYPE_CDD: - dci_format = SRSLTE_DCI_FORMAT2A; - break; - case SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX: - dci_format = SRSLTE_DCI_FORMAT2; - if (multiplex_nof_layers == 1) { - ra_dl.pinfo = (uint8_t) (multiplex_pmi + 1); - } else { - ra_dl.pinfo = (uint8_t) multiplex_pmi; - } - break; - default: - fprintf(stderr, "Wrong MIMO configuration\n"); - exit(SRSLTE_ERROR); - } - /* Encode PDCCH */ - INFO("Putting DCI to location: n=%d, L=%d\n", locations[sf_idx][0].ncce, locations[sf_idx][0].L); - srslte_dci_msg_pack_pdsch(&ra_dl, 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); - } + if(sf_idx != 1 || mbsfn_area_id < 0) { // PDCCH + PDSCH + srslte_dci_format_t dci_format; + switch(pdsch_cfg.mimo_type) { + case SRSLTE_MIMO_TYPE_SINGLE_ANTENNA: + dci_format = SRSLTE_DCI_FORMAT1; + break; + case SRSLTE_MIMO_TYPE_TX_DIVERSITY: + case SRSLTE_MIMO_TYPE_CDD: + dci_format = SRSLTE_DCI_FORMAT2A; + break; + case SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX: + dci_format = SRSLTE_DCI_FORMAT2; + if (multiplex_nof_layers == 1) { + ra_dl.pinfo = (uint8_t) (multiplex_pmi + 1); + } else { + ra_dl.pinfo = (uint8_t) multiplex_pmi; + } + break; + default: + fprintf(stderr, "Wrong MIMO configuration\n"); + exit(SRSLTE_ERROR); + } + /* Encode PDCCH */ + INFO("Putting DCI to location: n=%d, L=%d\n", locations[sf_idx][0].ncce, locations[sf_idx][0].L); + srslte_dci_msg_pack_pdsch(&ra_dl, 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); + } - /* 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_mimo(&pdsch_cfg, cell, &grant, cfi, sf_idx, rvidx, pdsch_cfg.mimo_type, multiplex_pmi)) { - fprintf(stderr, "Error configuring PDSCH\n"); - exit(-1); - } - - /* Encode PDSCH */ - if (srslte_pdsch_encode(&pdsch, &pdsch_cfg, softbuffers, data, UE_CRNTI, sf_symbols)) { - fprintf(stderr, "Error encoding PDSCH\n"); - exit(-1); - } - if (net_port > 0 && net_packet_ready) { - if (null_file_sink) { - for (uint32_t tb = 0; tb < SRSLTE_MAX_CODEWORDS; tb++) { - if (pdsch_cfg.grant.tb_en[tb]) { + /* 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_mimo(&pdsch_cfg, cell, &grant, cfi, sf_idx, rvidx, pdsch_cfg.mimo_type, multiplex_pmi)) { + fprintf(stderr, "Error configuring PDSCH\n"); + exit(-1); + } + + /* Encode PDSCH */ + if (srslte_pdsch_encode(&pdsch, &pdsch_cfg, softbuffers, data, UE_CRNTI, sf_symbols)) { + fprintf(stderr, "Error encoding PDSCH\n"); + exit(-1); + } + if (net_port > 0 && net_packet_ready) { + if (null_file_sink) { + for (uint32_t tb = 0; tb < SRSLTE_MAX_CODEWORDS; tb++) { srslte_bit_pack_vector(data[tb], data_tmp, pdsch_cfg.grant.mcs[tb].tbs); if (srslte_netsink_write(&net_sink, data_tmp, 1 + (pdsch_cfg.grant.mcs[tb].tbs - 1) / 8) < 0) { fprintf(stderr, "Error sending data through UDP socket\n"); } } } + net_packet_ready = false; + sem_post(&net_sem); + } + }else{ // We're sending MCH on subframe 1 - PDCCH + PMCH + + /* 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); + if (srslte_pdcch_encode(&pdcch, &dci_msg, locations[sf_idx][0], M_CRNTI, sf_symbols, sf_idx, cfi)) { + fprintf(stderr, "Error encoding DCI message\n"); + exit(-1); + } + /* Configure pmch_cfg parameters */ + srslte_ra_dl_grant_t grant; + grant.nof_tb = 1; + grant.mcs[0].idx = 2; + grant.mcs[0].mod = SRSLTE_MOD_QPSK; + grant.nof_prb = cell.nof_prb; + grant.sf_type = SRSLTE_SF_MBSFN; + grant.Qm[0] = srslte_mod_bits_x_symbol(grant.mcs[0].mod); + srslte_dl_fill_ra_mcs(&grant.mcs[0], cell.nof_prb); + for(int i = 0; i < 2; i++){ + for(int j = 0; j < grant.nof_prb; j++){ + grant.prb_idx[i][j] = true; + } + } + + + if (srslte_pmch_cfg(&pmch_cfg, cell, &grant, cfi, sf_idx)) { + fprintf(stderr, "Error configuring PMCH\n"); + exit(-1); + } + /* Encode PMCH */ + if (srslte_pmch_encode(&pmch, &pmch_cfg, softbuffers[0], data[0], mbsfn_area_id, sf_symbols)) { + fprintf(stderr, "Error encoding PDSCH\n"); + exit(-1); + } + if (net_port > 0 && net_packet_ready) { + if (null_file_sink) { + srslte_bit_pack_vector(data[0], data_tmp, pmch_cfg.grant.mcs[0].tbs); + if (srslte_netsink_write(&net_sink, data_tmp, 1+(pmch_cfg.grant.mcs[0].tbs-1)/8) < 0) { + fprintf(stderr, "Error sending data through UDP socket\n"); + } + } + net_packet_ready = false; + sem_post(&net_sem); } - net_packet_ready = false; - sem_post(&net_sem); } } - - /* Transform to OFDM symbols */ - for (i = 0; i < cell.nof_ports; i++) { - srslte_ofdm_tx_sf(&ifft, sf_buffer[i], output_buffer[i]); - } + /* Transform to OFDM symbols */ + if(sf_idx != 1 || mbsfn_area_id < 0){ + for (i = 0; i < cell.nof_ports; i++) { + srslte_ofdm_tx_sf(&ifft, sf_buffer[i], output_buffer[i]); + } + }else{ + srslte_ofdm_tx_sf(&ifft_mbsfn, sf_buffer[0], output_buffer[0]); + } + /* send to file or usrp */ if (output_file_name) { if (!null_file_sink) { - srslte_filesink_write_multi(&fsink, (void**) output_buffer, sf_n_samples, cell.nof_ports); + srslte_filesink_write_multi(&fsink, (void**) output_buffer, sf_n_samples, cell.nof_ports); } usleep(1000); } else { #ifndef DISABLE_RF - float norm_factor = (float) cell.nof_prb/15/sqrtf(pdsch_cfg.grant.nof_prb); - 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; + float norm_factor = (float) cell.nof_prb/15/sqrtf(pdsch_cfg.grant.nof_prb); + 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 a4279ba1a..38113dbcf 100644 --- a/lib/examples/pdsch_ue.c +++ b/lib/examples/pdsch_ue.c @@ -36,10 +36,8 @@ #include #include #include -#include -#include -#include - +#include +#include "srslte/phy/io/filesink.h" #include "srslte/srslte.h" #define ENABLE_AGC_DEFAULT @@ -69,7 +67,7 @@ sem_t plot_sem; uint32_t plot_sf_idx=0; bool plot_track = true; #endif - +char *output_file_name; #define PRINT_CHANGE_SCHEDULIGN //#define CORRECT_SAMPLE_OFFSET @@ -101,6 +99,8 @@ typedef struct { int net_port_signal; char *net_address_signal; int decimate; + int mbsfn_area_id; + uint8_t non_mbsfn_region; int verbose; }prog_args_t; @@ -132,10 +132,12 @@ void args_default(prog_args_t *args) { args->net_address_signal = "127.0.0.1"; args->decimate = 0; args->cpu_affinity = -1; + args->mbsfn_area_id = -1; + args->non_mbsfn_region = 2; } void usage(prog_args_t *args, char *prog) { - printf("Usage: %s [agpPoOcildDnruv] -f rx_frequency (in Hz) | -i input_file\n", prog); + printf("Usage: %s [agpPoOcildDnruMNv] -f rx_frequency (in Hz) | -i input_file\n", prog); #ifndef DISABLE_RF printf("\t-a RF args [Default %s]\n", args->rf_args); printf("\t-A Number of RX antennas [Default %d]\n", args->rf_nof_rx_ant); @@ -169,13 +171,15 @@ void usage(prog_args_t *args, char *prog) { printf("\t-S remote UDP address to send input signal [Default %s]\n", args->net_address_signal); printf("\t-u remote TCP port to send data (-1 does nothing with it) [Default %d]\n", args->net_port); printf("\t-U remote TCP address to send data [Default %s]\n", args->net_address); + printf("\t-M MBSFN area id [Default %s]\n", args->mbsfn_area_id); + printf("\t-N Non-MBSFN region [Default %s]\n", args->non_mbsfn_region); printf("\t-v [set srslte_verbose to debug, default none]\n"); } void parse_args(prog_args_t *args, int argc, char **argv) { int opt; args_default(args); - while ((opt = getopt(argc, argv, "aAoglipPcOCtdDnvrfuUsSZy")) != -1) { + while ((opt = getopt(argc, argv, "aAoglipPcOCtdDnvrfuUsSZyWMN")) != -1) { switch (opt) { case 'i': args->input_file_name = argv[optind]; @@ -250,6 +254,15 @@ void parse_args(prog_args_t *args, int argc, char **argv) { case 'y': args->cpu_affinity = atoi(argv[optind]); break; + case 'W': + output_file_name = argv[optind]; + break; + case 'M': + args->mbsfn_area_id = atoi(argv[optind]); + break; + case 'N': + args->non_mbsfn_region = atoi(argv[optind]); + break; default: usage(args, argv[0]); exit(-1); @@ -278,6 +291,7 @@ void sig_int_handler(int signo) 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) { DEBUG(" ---- Receive %d samples ---- \n", nsamples); @@ -303,9 +317,9 @@ srslte_ue_sync_t ue_sync; prog_args_t prog_args; uint32_t sfn = 0; // system frame number -srslte_netsink_t net_sink, net_sink_signal; - +srslte_netsink_t net_sink, net_sink_signal; /* Useful macros for printing lines which will disappear */ + #define PRINT_LINE_INIT() int this_nof_lines = 0; static int prev_nof_lines = 0 #define PRINT_LINE(_fmt, ...) printf("\033[K" _fmt "\n", ##__VA_ARGS__); this_nof_lines++ #define PRINT_LINE_RESET_CURSOR() printf("\033[%dA", this_nof_lines); prev_nof_lines = this_nof_lines @@ -317,6 +331,7 @@ int main(int argc, char **argv) { srslte_cell_t cell; int64_t sf_cnt; srslte_ue_mib_t ue_mib; + #ifndef DISABLE_RF srslte_rf_t rf; #endif @@ -324,7 +339,7 @@ int main(int argc, char **argv) { uint8_t bch_payload[SRSLTE_BCH_PAYLOAD_LEN]; int sfn_offset; float cfo = 0; - + parse_args(&prog_args, argc, argv); for (int i = 0; i< SRSLTE_MAX_CODEWORDS; i++) { @@ -335,6 +350,7 @@ int main(int argc, char **argv) { } } + if(prog_args.cpu_affinity > -1) { cpu_set_t cpuset; @@ -403,6 +419,7 @@ int main(int argc, char **argv) { srslte_rf_set_rx_freq(&rf, prog_args.rf_freq + prog_args.file_offset_freq); srslte_rf_rx_wait_lo_locked(&rf); + uint32_t ntrial=0; do { ret = rf_search_and_decode_mib(&rf, prog_args.rf_nof_rx_ant, &cell_detect_config, prog_args.force_N_id_2, &cell, &cfo); @@ -455,7 +472,7 @@ 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_multi(&ue_sync, prog_args.file_nof_prb, + if (srslte_ue_sync_init_file_multi(&ue_sync, prog_args.file_nof_prb, prog_args.input_file_name, prog_args.file_offset_time, prog_args.file_offset_freq, prog_args.rf_nof_rx_ant)) { fprintf(stderr, "Error initiating ue_sync\n"); exit(-1); @@ -518,6 +535,11 @@ int main(int argc, char **argv) { /* Configure downlink receiver for the SI-RNTI since will be the only one we'll use */ srslte_ue_dl_set_rnti(&ue_dl, prog_args.rnti); + /* Configure MBSFN area id and non-MBSFN Region */ + if (prog_args.mbsfn_area_id > -1) { + srslte_ue_dl_set_mbsfn_area_id(&ue_dl, prog_args.mbsfn_area_id); + srslte_ue_dl_set_non_mbsfn_region(&ue_dl, prog_args.non_mbsfn_region); + } /* Initialize subframe counter */ sf_cnt = 0; @@ -592,7 +614,6 @@ int main(int argc, char **argv) { } } - ret = srslte_ue_sync_zerocopy_multi(&ue_sync, sf_buffer); if (ret < 0) { fprintf(stderr, "Error calling srslte_ue_sync_work()\n"); @@ -605,9 +626,12 @@ int main(int argc, char **argv) { /* srslte_ue_sync_get_buffer returns 1 if successfully read 1 aligned subframe */ if (ret == 1) { + + uint32_t sfidx = srslte_ue_sync_get_sfidx(&ue_sync); + switch (state) { case DECODE_MIB: - if (srslte_ue_sync_get_sfidx(&ue_sync) == 0) { + if (sfidx == 0) { n = srslte_ue_mib_decode(&ue_mib, sf_buffer[0], bch_payload, NULL, &sfn_offset); if (n < 0) { fprintf(stderr, "Error decoding UE MIB\n"); @@ -626,51 +650,64 @@ int main(int argc, char **argv) { decode_pdsch = true; } else { /* We are looking for SIB1 Blocks, search only in appropiate places */ - if ((srslte_ue_sync_get_sfidx(&ue_sync) == 5 && (sfn%2)==0)) { + if ((sfidx == 5 && (sfn%2)==0) || sfidx == 1) { decode_pdsch = true; } else { decode_pdsch = false; } } - - INFO("Attempting DL decode SFN=%d\n", sfn); if (decode_pdsch) { - if (cell.nof_ports == 1) { - /* Transmission mode 1 */ - n = srslte_ue_dl_decode(&ue_dl, sf_buffer, data, 0, sfn*10+srslte_ue_sync_get_sfidx(&ue_sync), acks); - } else { - if (prog_args.rf_nof_rx_ant == 1) { - /* Transmission mode 2 */ - n = srslte_ue_dl_decode(&ue_dl, sf_buffer, data, 1, sfn * 10 + srslte_ue_sync_get_sfidx(&ue_sync), - acks); + if(sfidx != 1 || prog_args.mbsfn_area_id < 0){ // Not an MBSFN subframe + if (cell.nof_ports == 1) { + /* Transmission mode 1 */ + n = srslte_ue_dl_decode(&ue_dl, sf_buffer, data, 0, sfn*10+srslte_ue_sync_get_sfidx(&ue_sync), acks); } else { - /* Transmission mode 3 */ - n = srslte_ue_dl_decode(&ue_dl, sf_buffer, data, 2, sfn * 10 + srslte_ue_sync_get_sfidx(&ue_sync), - acks); - if (n < 1) { - /* Transmission mode 4 */ - n = srslte_ue_dl_decode(&ue_dl, sf_buffer, data, 3, sfn * 10 + srslte_ue_sync_get_sfidx(&ue_sync), + if (prog_args.rf_nof_rx_ant == 1) { + /* Transmission mode 2 */ + n = srslte_ue_dl_decode(&ue_dl, sf_buffer, data, 1, sfn * 10 + srslte_ue_sync_get_sfidx(&ue_sync), acks); + } else { + /* Transmission mode 3 */ + n = srslte_ue_dl_decode(&ue_dl, sf_buffer, data, 2, sfn * 10 + srslte_ue_sync_get_sfidx(&ue_sync), + acks); + if (n < 1) { + /* Transmission mode 4 */ + n = srslte_ue_dl_decode(&ue_dl, sf_buffer, data, 3, sfn * 10 + srslte_ue_sync_get_sfidx(&ue_sync), + acks); + } } } + }else{ // MBSFN subframe + n = srslte_ue_dl_decode_mbsfn(&ue_dl, + sf_buffer, + data[0], + sfn*10+srslte_ue_sync_get_sfidx(&ue_sync)); + if(n>0){ + if(output_file_name){ + //srslte_filesink_init(&sink, output_file_name, SRSLTE_BYTE_BIN); + // srslte_filesink_write(&sink, data, n); + //srslte_filesink_free(&sink); + } + INFO("mbsfn PDU size is %d\n", n); + } } - - - if (n < 0) { // fprintf(stderr, "Error decoding UE DL\n");fflush(stdout); } else if (n > 0) { /* Send data if socket active */ if (prog_args.net_port > 0) { + if(sfidx == 1) { + srslte_netsink_write(&net_sink, data[0], 1+(n-1)/8); + } else { // FIXME: UDP Data transmission does not work - for (uint32_t tb = 0; tb < SRSLTE_MAX_CODEWORDS; tb++) { - if (ue_dl.pdsch_cfg.grant.tb_en[tb]) { - srslte_netsink_write(&net_sink, data[tb], 1 + (ue_dl.pdsch_cfg.grant.mcs[tb].tbs - 1) / 8); + for (uint32_t tb = 0; tb < SRSLTE_MAX_CODEWORDS; tb++) { + if (ue_dl.pdsch_cfg.grant.tb_en[tb]) { + srslte_netsink_write(&net_sink, data[tb], 1 + (ue_dl.pdsch_cfg.grant.mcs[tb].tbs - 1) / 8); + } } } } - #ifdef PRINT_CHANGE_SCHEDULIGN if (ue_dl.dl_dci.mcs_idx != old_dl_dci.mcs_idx || memcmp(&ue_dl.dl_dci.type0_alloc, &old_dl_dci.type0_alloc, sizeof(srslte_ra_type0_t)) || @@ -689,6 +726,7 @@ int main(int argc, char **argv) { nof_trials++; + rsrq = SRSLTE_VEC_EMA(srslte_chest_dl_get_rsrq(&ue_dl.chest), rsrq, 0.1f); rsrp0 = SRSLTE_VEC_EMA(srslte_chest_dl_get_rsrp_port(&ue_dl.chest, 0), rsrp0, 0.05f); rsrp1 = SRSLTE_VEC_EMA(srslte_chest_dl_get_rsrp_port(&ue_dl.chest, 1), rsrp1, 0.05f); @@ -696,6 +734,7 @@ int main(int argc, char **argv) { enodebrate = SRSLTE_VEC_EMA((ue_dl.pdsch_cfg.grant.mcs[0].tbs + ue_dl.pdsch_cfg.grant.mcs[1].tbs)/1000.0f, enodebrate, 0.05f); uerate = SRSLTE_VEC_EMA(((acks[0]?ue_dl.pdsch_cfg.grant.mcs[0].tbs:0) + (acks[1]?ue_dl.pdsch_cfg.grant.mcs[1].tbs:0))/1000.0f, uerate, 0.01f); + nframes++; if (isnan(rsrq)) { rsrq = 0; @@ -704,20 +743,20 @@ int main(int argc, char **argv) { noise = 0; } if (isnan(rsrp0)) { - rsrp1 = 0; + rsrp0 = 0; } - if (isnan(rsrp0)) { - rsrp1 = 0; + if (isnan(rsrp1)) { + rsrp1 = 0; } } // Plot and Printf - if (srslte_ue_sync_get_sfidx(&ue_sync) == 5 && sfn % 20 == 0) { + if (sfidx == 5) { float gain = prog_args.rf_gain; if (gain < 0) { gain = 10*log10(srslte_agc_get_gain(&ue_sync.agc)); } - + /* Print transmission scheme */ if (ue_dl.pdsch_cfg.mimo_type == SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX) { PRINT_LINE(" Tx scheme: %s (codebook_idx=%d)", srslte_mimotype2str(ue_dl.pdsch_cfg.mimo_type), @@ -733,7 +772,10 @@ int main(int argc, char **argv) { PRINT_LINE(" SNR: %+5.1f dB | %+5.1f dB", 10 * log10(rsrp0 / noise), 10 * log10(rsrp1 / noise)); PRINT_LINE(" Rb: %6.2f / %6.2f Mbps (net/maximum)", uerate, enodebrate); PRINT_LINE(" PDCCH-Miss: %5.2f%%", 100 * (1 - (float) ue_dl.nof_detected / nof_trials)); - PRINT_LINE(" PDSCH-BLER: %5.2f%%", (float) 100 * ue_dl.pkt_errors / ue_dl.pkts_total); + PRINT_LINE(" PDSCH-BLER: %5.2f%%", (float) 100 * ue_dl.pdsch_pkt_errors / ue_dl.pdsch_pkts_total); + if(prog_args.mbsfn_area_id > -1){ + PRINT_LINE(" PMCH-BLER: %5.2f%%", (float) 100 * ue_dl.pmch_pkt_errors/ue_dl.pmch_pkts_total); + } PRINT_LINE(" TB 0: mcs=%d; tbs=%d", ue_dl.pdsch_cfg.grant.mcs[0].idx, ue_dl.pdsch_cfg.grant.mcs[0].tbs); PRINT_LINE(" TB 1: mcs=%d; tbs=%d", ue_dl.pdsch_cfg.grant.mcs[1].idx, @@ -775,17 +817,20 @@ int main(int argc, char **argv) { PRINT_LINE("Press enter maximum printing debug log of 1 subframe."); PRINT_LINE(""); PRINT_LINE_RESET_CURSOR(); + } break; } - if (srslte_ue_sync_get_sfidx(&ue_sync) == 9) { + if (sfidx == 9) { sfn++; if (sfn == 1024) { sfn = 0; PRINT_LINE_ADVANCE_CURSOR(); + ue_dl.pdsch_pkt_errors = 0; + ue_dl.pdsch_pkts_total = 0; /* ue_dl.pkt_errors = 0; - ue_dl.pkts_total = 0; + ue_dl.pkts_total = 0; ue_dl.nof_detected = 0; nof_trials = 0; */ @@ -794,7 +839,7 @@ int main(int argc, char **argv) { #ifndef DISABLE_GRAPHICS if (!prog_args.disable_plots) { - if ((sfn%4) == 0 && decode_pdsch) { + if ((sfn%3) == 0 && decode_pdsch) { plot_sf_idx = srslte_ue_sync_get_sfidx(&ue_sync); plot_track = true; sem_post(&plot_sem); @@ -816,8 +861,7 @@ int main(int argc, char **argv) { sf_cnt++; } // Main loop - printf("\033[30B\n"); - + #ifndef DISABLE_GRAPHICS if (!prog_args.disable_plots) { if (!pthread_kill(plot_thread, 0)) { @@ -838,13 +882,14 @@ int main(int argc, char **argv) { free(sf_buffer[i]); } } - + #ifndef DISABLE_RF if (!prog_args.input_file_name) { srslte_ue_mib_free(&ue_mib); srslte_rf_close(&rf); } #endif + printf("\nBye\n"); 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 c3fd795cf..0e43d113c 100644 --- a/lib/include/srslte/phy/ch_estimation/chest_dl.h +++ b/lib/include/srslte/phy/ch_estimation/chest_dl.h @@ -60,7 +60,10 @@ typedef enum { typedef struct { srslte_cell_t cell; - srslte_refsignal_cs_t csr_signal; + srslte_refsignal_t csr_refs; + srslte_refsignal_t **mbsfn_refs; + + cf_t *pilot_estimates; cf_t *pilot_estimates_average; cf_t *pilot_recv_signal; @@ -75,7 +78,7 @@ typedef struct { srslte_interp_linsrslte_vec_t srslte_interp_linvec; srslte_interp_lin_t srslte_interp_lin; - + srslte_interp_lin_t srslte_interp_lin_mbsfn; float rssi[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS]; float rsrp[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS]; float noise_estimate[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS]; @@ -96,9 +99,13 @@ SRSLTE_API int srslte_chest_dl_init(srslte_chest_dl_t *q, SRSLTE_API void srslte_chest_dl_free(srslte_chest_dl_t *q); + +SRSLTE_API int srslte_chest_dl_set_mbsfn_area_id(srslte_chest_dl_t *q, + uint16_t mbsfn_area_id); SRSLTE_API int srslte_chest_dl_set_cell(srslte_chest_dl_t *q, srslte_cell_t cell); + SRSLTE_API void srslte_chest_dl_set_smooth_filter(srslte_chest_dl_t *q, float *filter, uint32_t filter_len); @@ -109,6 +116,8 @@ SRSLTE_API void srslte_chest_dl_set_smooth_filter3_coeff(srslte_chest_dl_t* q, SRSLTE_API void srslte_chest_dl_set_noise_alg(srslte_chest_dl_t *q, srslte_chest_dl_noise_alg_t noise_estimation_alg); + + SRSLTE_API int srslte_chest_dl_estimate_multi(srslte_chest_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS], cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], @@ -120,6 +129,14 @@ SRSLTE_API int srslte_chest_dl_estimate(srslte_chest_dl_t *q, cf_t *ce[SRSLTE_MAX_PORTS], uint32_t sf_idx); +SRSLTE_API int srslte_chest_dl_estimate_multi_mbsfn(srslte_chest_dl_t *q, + cf_t *input[SRSLTE_MAX_PORTS], + cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], + uint32_t sf_idx, + uint32_t nof_rx_antennas, + uint16_t mbsfn_area_id); + + SRSLTE_API int srslte_chest_dl_estimate_port(srslte_chest_dl_t *q, cf_t *input, cf_t *ce, diff --git a/lib/include/srslte/phy/ch_estimation/refsignal_dl.h b/lib/include/srslte/phy/ch_estimation/refsignal_dl.h index 6b21c4fa2..9263073a9 100644 --- a/lib/include/srslte/phy/ch_estimation/refsignal_dl.h +++ b/lib/include/srslte/phy/ch_estimation/refsignal_dl.h @@ -40,25 +40,34 @@ // Number of references in a subframe: there are 2 symbols for port_id=0,1 x 2 slots x 2 refs per prb #define SRSLTE_REFSIGNAL_NUM_SF(nof_prb, port_id) (((port_id)<2?8:4)*(nof_prb)) +#define SRSLTE_REFSIGNAL_NUM_SF_MBSFN(nof_prb, port_id) ((2 + 18)*(nof_prb)) + #define SRSLTE_REFSIGNAL_MAX_NUM_SF(nof_prb) SRSLTE_REFSIGNAL_NUM_SF(nof_prb, 0) +#define SRSLTE_REFSIGNAL_MAX_NUM_SF_MBSFN(nof_prb) SRSLTE_REFSIGNAL_NUM_SF_MBSFN(nof_prb,0) #define SRSLTE_REFSIGNAL_PILOT_IDX(i,l,cell) (2*cell.nof_prb*(l)+(i)) +#define SRSLTE_REFSIGNAL_PILOT_IDX_MBSFN(i,l,cell) ((6*cell.nof_prb*(l)+(i))) + + /** Cell-Specific Reference Signal */ typedef struct SRSLTE_API { srslte_cell_t cell; - cf_t *pilots[2][SRSLTE_NSUBFRAMES_X_FRAME]; // Saves the reference signal per subframe for ports 0,1 and ports 2,3 -} srslte_refsignal_cs_t; + cf_t *pilots[2][SRSLTE_NSUBFRAMES_X_FRAME]; // Saves the reference signal per subframe for ports 0,1 and ports 2,3 + srslte_sf_t type; + uint16_t mbsfn_area_id; +} srslte_refsignal_t; -SRSLTE_API int srslte_refsignal_cs_init(srslte_refsignal_cs_t *q, + +SRSLTE_API int srslte_refsignal_cs_init(srslte_refsignal_t *q, uint32_t max_prb); -SRSLTE_API int srslte_refsignal_cs_set_cell(srslte_refsignal_cs_t * q, +SRSLTE_API int srslte_refsignal_cs_set_cell(srslte_refsignal_t * q, srslte_cell_t cell); -SRSLTE_API void srslte_refsignal_cs_free(srslte_refsignal_cs_t *q); +SRSLTE_API void srslte_refsignal_free(srslte_refsignal_t *q); SRSLTE_API int srslte_refsignal_cs_put_sf(srslte_cell_t cell, uint32_t port_id, @@ -84,4 +93,29 @@ SRSLTE_API uint32_t srslte_refsignal_cs_v(uint32_t port_id, SRSLTE_API uint32_t srslte_refsignal_cs_nof_symbols(uint32_t port_id); +SRSLTE_API int srslte_refsignal_mbsfn_init(srslte_refsignal_t *q, srslte_cell_t cell, + uint16_t mbsfn_area_id); + +SRSLTE_API int srslte_refsignal_mbsfn_get_sf(srslte_cell_t cell, + uint32_t port_id, + cf_t *sf_symbols, + cf_t *pilots); + +SRSLTE_API uint32_t srslte_refsignal_mbsfn_nsymbol(uint32_t l); + +SRSLTE_API uint32_t srslte_refsignal_mbsfn_fidx(uint32_t l); + +SRSLTE_API uint32_t srslte_refsignal_mbsfn_nof_symbols(); + +SRSLTE_API int srslte_refsignal_mbsfn_put_sf(srslte_cell_t cell, + uint32_t port_id, + cf_t *cs_pilots, + cf_t *mbsfn_pilots, + cf_t *sf_symbols); + +SRSLTE_API int srslte_refsignal_mbsfn_gen_seq(srslte_refsignal_t * q, + srslte_cell_t cell, + uint32_t N_mbsfn_id); + + #endif diff --git a/lib/include/srslte/phy/common/phy_common.h b/lib/include/srslte/phy/common/phy_common.h index 29bf8d3a4..148a12974 100644 --- a/lib/include/srslte/phy/common/phy_common.h +++ b/lib/include/srslte/phy/common/phy_common.h @@ -63,7 +63,11 @@ #define SRSLTE_LTE_CRC16 0x11021 #define SRSLTE_LTE_CRC8 0x19B +#define SRSLTE_MAX_MBSFN_AREA_IDS 256 +#define SRSLTE_PMCH_RV 0 + typedef enum {SRSLTE_CP_NORM, SRSLTE_CP_EXT} srslte_cp_t; +typedef enum {SRSLTE_SF_NORM, SRSLTE_SF_MBSFN} srslte_sf_t; #define SRSLTE_CRNTI_START 0x000B @@ -130,6 +134,13 @@ typedef enum {SRSLTE_CP_NORM, SRSLTE_CP_EXT} srslte_cp_t; || l == SRSLTE_CP_NSYMB(cp) - 3) + +#define SRSLTE_SYMBOL_HAS_REF_MBSFN(l, s) ((l == 2 && s == 0) || (l == 0 && s == 1) || (l == 4 && s == 1)) + +#define SRSLTE_NON_MBSFN_REGION_GUARD_LENGTH(non_mbsfn_region,symbol_sz) ((non_mbsfn_region == 1)?(SRSLTE_CP_LEN_EXT(symbol_sz) - SRSLTE_CP_LEN_NORM(0, symbol_sz)):(2*SRSLTE_CP_LEN_EXT(symbol_sz) - SRSLTE_CP_LEN_NORM(0, symbol_sz)- SRSLTE_CP_LEN_NORM(1, symbol_sz))) + + + #define SRSLTE_NOF_LTE_BANDS 38 #define SRSLTE_DEFAULT_MAX_FRAMES_PBCH 500 @@ -157,6 +168,7 @@ typedef enum { SRSLTE_RNTI_TEMP, /* Temporary C-RNTI */ SRSLTE_RNTI_SPS, /* Semi-Persistent Scheduling C-RNTI */ SRSLTE_RNTI_PCH, /* Paging RNTI */ + SRSLTE_RNTI_MBSFN, SRSLTE_RNTI_NOF_TYPES } srslte_rnti_type_t; diff --git a/lib/include/srslte/phy/common/sequence.h b/lib/include/srslte/phy/common/sequence.h index 4c7c2c945..62934c7e0 100644 --- a/lib/include/srslte/phy/common/sequence.h +++ b/lib/include/srslte/phy/common/sequence.h @@ -94,4 +94,10 @@ SRSLTE_API int srslte_sequence_pucch(srslte_sequence_t *seq, uint16_t rnti, uint32_t nslot, uint32_t cell_id); + +SRSLTE_API int srslte_sequence_pmch(srslte_sequence_t *seq, + uint32_t nslot, + uint32_t mbsfn_id, + uint32_t len); + #endif diff --git a/lib/include/srslte/phy/dft/ofdm.h b/lib/include/srslte/phy/dft/ofdm.h index 175fe1ea9..1363f5638 100644 --- a/lib/include/srslte/phy/dft/ofdm.h +++ b/lib/include/srslte/phy/dft/ofdm.h @@ -56,6 +56,12 @@ typedef struct SRSLTE_API{ srslte_cp_t cp; cf_t *tmp; // for removing zero padding + bool mbsfn_subframe; + uint32_t mbsfn_guard_len; + uint32_t nof_symbols_mbsfn; + uint8_t non_mbsfn_region; + + bool freq_shift; float freq_shift_f; cf_t *shift_buffer; @@ -64,8 +70,21 @@ typedef struct SRSLTE_API{ SRSLTE_API int srslte_ofdm_init_(srslte_ofdm_t *q, srslte_cp_t cp, int symbol_sz, - int max_prb, - srslte_dft_dir_t dir); + int nof_prb, + srslte_dft_dir_t dir); + +SRSLTE_API int srslte_ofdm_init_mbsfn_(srslte_ofdm_t *q, + srslte_cp_t cp, + int symbol_sz, + int nof_prb, + srslte_dft_dir_t dir, + srslte_sf_t sf_type); + +SRSLTE_API int srslte_ofdm_rx_init_mbsfn(srslte_ofdm_t *q, + srslte_cp_t cp_type, + uint32_t nof_prb); + + SRSLTE_API int srslte_ofdm_rx_init(srslte_ofdm_t *q, srslte_cp_t cp_type, @@ -95,12 +114,22 @@ SRSLTE_API int srslte_ofdm_tx_init(srslte_ofdm_t *q, srslte_cp_t cp_type, uint32_t nof_prb); +SRSLTE_API int srslte_ofdm_tx_init_mbsfn(srslte_ofdm_t *q, + srslte_cp_t cp, + uint32_t nof_prb); + + SRSLTE_API void srslte_ofdm_tx_free(srslte_ofdm_t *q); SRSLTE_API void srslte_ofdm_tx_slot(srslte_ofdm_t *q, cf_t *input, cf_t *output); +SRSLTE_API void srslte_ofdm_tx_slot_mbsfn(srslte_ofdm_t *q, + cf_t *input, + cf_t *output); + + SRSLTE_API void srslte_ofdm_tx_sf(srslte_ofdm_t *q, cf_t *input, cf_t *output); @@ -111,4 +140,8 @@ SRSLTE_API int srslte_ofdm_set_freq_shift(srslte_ofdm_t *q, SRSLTE_API void srslte_ofdm_set_normalize(srslte_ofdm_t *q, bool normalize_enable); -#endif +SRSLTE_API void srslte_ofdm_set_non_mbsfn_region(srslte_ofdm_t *q, + uint8_t non_mbsfn_region); + + +#endif \ No newline at end of file diff --git a/lib/include/srslte/phy/enb/enb_dl.h b/lib/include/srslte/phy/enb/enb_dl.h index f465d81e2..3f835a23f 100644 --- a/lib/include/srslte/phy/enb/enb_dl.h +++ b/lib/include/srslte/phy/enb/enb_dl.h @@ -76,7 +76,7 @@ typedef struct SRSLTE_API { srslte_pdsch_t pdsch; srslte_phich_t phich; - srslte_refsignal_cs_t csr_signal; + srslte_refsignal_t csr_signal; srslte_pdsch_cfg_t pdsch_cfg; srslte_ra_dl_dci_t dl_dci; diff --git a/lib/include/srslte/phy/phch/pmch.h b/lib/include/srslte/phy/phch/pmch.h new file mode 100644 index 000000000..dfff956f1 --- /dev/null +++ b/lib/include/srslte/phy/phch/pmch.h @@ -0,0 +1,152 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsLTE library. + * + * srsLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +/****************************************************************************** + * File: pmch.h + * + * Description: Physical multicast channel + * + * Reference: 3GPP TS 36.211 version 10.0.0 Release 10 Sec. 6.5 + *****************************************************************************/ + +#ifndef PMCH_ +#define PMCH_ + +#include "srslte/config.h" +#include "srslte/phy/common/phy_common.h" +#include "srslte/phy/mimo/precoding.h" +#include "srslte/phy/mimo/layermap.h" +#include "srslte/phy/modem/mod.h" +#include "srslte/phy/modem/demod_soft.h" +#include "srslte/phy/scrambling/scrambling.h" +#include "srslte/phy/phch/dci.h" +#include "srslte/phy/phch/regs.h" +#include "srslte/phy/phch/sch.h" +#include "srslte/phy/common/sequence.h" + +typedef struct { + srslte_sequence_t seq[SRSLTE_NSUBFRAMES_X_FRAME]; +} srslte_pmch_seq_t; + +typedef struct SRSLTE_API { + srslte_cbsegm_t cb_segm; + srslte_ra_dl_grant_t grant; + srslte_ra_nbits_t nbits[SRSLTE_MAX_CODEWORDS]; + uint32_t sf_idx; +} srslte_pmch_cfg_t; + +/* PMCH object */ +typedef struct SRSLTE_API { + srslte_cell_t cell; + + uint32_t nof_rx_antennas; + + uint32_t max_re; + + /* buffers */ + // void buffers are shared for tx and rx + cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS]; + cf_t *symbols[SRSLTE_MAX_PORTS]; + cf_t *x[SRSLTE_MAX_PORTS]; + cf_t *d; + void *e; + + /* tx & rx objects */ + srslte_modem_table_t mod[4]; + + // This is to generate the scrambling seq for multiple MBSFN Area IDs + srslte_pmch_seq_t **seqs; + + srslte_sch_t dl_sch; + +} srslte_pmch_t; + + +SRSLTE_API int srslte_pmch_init(srslte_pmch_t *q, + uint32_t max_prb); + +SRSLTE_API int srslte_pmch_init_multi(srslte_pmch_t *q, + uint32_t max_prb, + uint32_t nof_rx_antennas); + +SRSLTE_API void srslte_pmch_free(srslte_pmch_t *q); + + + +SRSLTE_API int srslte_pmch_set_area_id(srslte_pmch_t *q, uint16_t area_id); + +SRSLTE_API void srslte_pmch_free_area_id(srslte_pmch_t *q, uint16_t area_id); + + + +SRSLTE_API int srslte_pmch_get(srslte_pmch_t *q, cf_t *sf_symbols, cf_t *symbols, uint32_t lstart); + +SRSLTE_API int srslte_pmch_put(srslte_pmch_t *q, cf_t *symbols, cf_t *sf_symbols, uint32_t lstart); + +SRSLTE_API int srslte_pmch_cp(srslte_pmch_t *q, cf_t *input, cf_t *output, uint32_t lstart_grant, bool put); + + + +SRSLTE_API float srslte_pmch_coderate(uint32_t tbs, + uint32_t nof_re); + + +SRSLTE_API int srslte_pmch_cfg(srslte_pdsch_cfg_t *cfg, + srslte_cell_t cell, + srslte_ra_dl_grant_t *grant, + uint32_t cfi, + uint32_t sf_idx); + +SRSLTE_API int srslte_pmch_encode(srslte_pmch_t *q, + srslte_pdsch_cfg_t *cfg, + srslte_softbuffer_tx_t *softbuffer, + uint8_t *data, + uint16_t area_id, + cf_t *sf_symbols[SRSLTE_MAX_PORTS]); + +SRSLTE_API int srslte_pmch_decode(srslte_pmch_t *q, + srslte_pdsch_cfg_t *cfg, + srslte_softbuffer_rx_t *softbuffer, + cf_t *sf_symbols, + cf_t *ce[SRSLTE_MAX_PORTS], + float noise_estimate, + uint16_t area_id, + uint8_t *data); + +SRSLTE_API int srslte_pmch_decode_multi(srslte_pmch_t *q, + srslte_pdsch_cfg_t *cfg, + srslte_softbuffer_rx_t *softbuffer, + cf_t *sf_symbols[SRSLTE_MAX_PORTS], + cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], + float noise_estimate, + uint16_t area_id, + uint8_t *data); + +SRSLTE_API float srslte_pmch_average_noi(srslte_pmch_t *q); + +SRSLTE_API uint32_t srslte_pmch_last_noi(srslte_pmch_t *q); + +#endif diff --git a/lib/include/srslte/phy/phch/ra.h b/lib/include/srslte/phy/phch/ra.h index 94cc9a084..3039455ed 100644 --- a/lib/include/srslte/phy/phch/ra.h +++ b/lib/include/srslte/phy/phch/ra.h @@ -103,7 +103,11 @@ typedef struct SRSLTE_API { bool prb_idx[2][SRSLTE_MAX_PRB]; uint32_t nof_prb; uint32_t Qm[SRSLTE_MAX_CODEWORDS]; + uint32_t Qm2[SRSLTE_MAX_CODEWORDS]; srslte_ra_mcs_t mcs[SRSLTE_MAX_CODEWORDS]; + srslte_ra_mcs_t mcs2[SRSLTE_MAX_CODEWORDS]; + uint32_t nof_tb; + srslte_sf_t sf_type; bool tb_en[SRSLTE_MAX_CODEWORDS]; uint32_t pinfo; } srslte_ra_dl_grant_t; @@ -290,4 +294,9 @@ SRSLTE_API void srslte_ra_pusch_fprint(FILE *f, SRSLTE_API void srslte_ra_ul_grant_fprint(FILE *f, srslte_ra_ul_grant_t *grant); +SRSLTE_API int srslte_dl_fill_ra_mcs_pmch(srslte_ra_mcs_t *mcs, uint32_t nprb); + +SRSLTE_API int srslte_dl_fill_ra_mcs(srslte_ra_mcs_t *mcs, uint32_t nprb); + + #endif /* RB_ALLOC_H_ */ diff --git a/lib/include/srslte/phy/phch/sch.h b/lib/include/srslte/phy/phch/sch.h index a03387448..a98ecf280 100644 --- a/lib/include/srslte/phy/phch/sch.h +++ b/lib/include/srslte/phy/phch/sch.h @@ -77,6 +77,7 @@ typedef struct SRSLTE_API { srslte_uci_cqi_pusch_t uci_cqi; } srslte_sch_t; +#include "srslte/phy/phch/pmch.h" SRSLTE_API int srslte_sch_init(srslte_sch_t *q); diff --git a/lib/include/srslte/phy/ue/ue_dl.h b/lib/include/srslte/phy/ue/ue_dl.h index d88148e9e..0b0fc44d2 100644 --- a/lib/include/srslte/phy/ue/ue_dl.h +++ b/lib/include/srslte/phy/ue/ue_dl.h @@ -48,6 +48,7 @@ #include "srslte/phy/phch/pcfich.h" #include "srslte/phy/phch/pdcch.h" #include "srslte/phy/phch/pdsch.h" +#include "srslte/phy/phch/pmch.h" #include "srslte/phy/phch/pdsch_cfg.h" #include "srslte/phy/phch/phich.h" #include "srslte/phy/phch/ra.h" @@ -76,14 +77,17 @@ typedef struct SRSLTE_API { srslte_pcfich_t pcfich; srslte_pdcch_t pdcch; srslte_pdsch_t pdsch; + srslte_pmch_t pmch; srslte_phich_t phich; srslte_regs_t regs; srslte_ofdm_t fft; + srslte_ofdm_t fft_mbsfn; srslte_chest_dl_t chest; srslte_cfo_t sfo_correct; - srslte_pdsch_cfg_t pdsch_cfg; + srslte_pdsch_cfg_t pdsch_cfg; + srslte_pdsch_cfg_t pmch_cfg; srslte_softbuffer_rx_t *softbuffers[SRSLTE_MAX_CODEWORDS]; srslte_ra_dl_dci_t dl_dci; srslte_cell_t cell; @@ -103,9 +107,14 @@ typedef struct SRSLTE_API { srslte_dci_format_t dci_format; uint64_t pkt_errors; uint64_t pkts_total; + uint64_t pdsch_pkt_errors; + uint64_t pdsch_pkts_total; + uint64_t pmch_pkt_errors; + uint64_t pmch_pkts_total; uint64_t nof_detected; uint16_t current_rnti; + uint16_t current_mbsfn_area_id; dci_blind_search_t current_ss_ue[3][10]; dci_blind_search_t current_ss_common[3]; srslte_dci_location_t last_location; @@ -127,14 +136,26 @@ SRSLTE_API void srslte_ue_dl_free(srslte_ue_dl_t *q); SRSLTE_API int srslte_ue_dl_set_cell(srslte_ue_dl_t *q, srslte_cell_t cell); -SRSLTE_API int srslte_ue_dl_decode_fft_estimate(srslte_ue_dl_t *q, +int srslte_ue_dl_decode_fft_estimate(srslte_ue_dl_t *q, + cf_t *input[SRSLTE_MAX_PORTS], + uint32_t sf_idx, + uint32_t *cfi); + +SRSLTE_API int srslte_ue_dl_decode_fft_estimate_mbsfn(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS], uint32_t sf_idx, - uint32_t *cfi); + uint32_t *cfi, + srslte_sf_t sf_type); -SRSLTE_API int srslte_ue_dl_decode_estimate(srslte_ue_dl_t *q, + +int srslte_ue_dl_decode_estimate(srslte_ue_dl_t *q, + uint32_t sf_idx, + uint32_t *cfi); + +SRSLTE_API int srslte_ue_dl_decode_estimate_mbsfn(srslte_ue_dl_t *q, uint32_t sf_idx, - uint32_t *cfi); + uint32_t *cfi, + srslte_sf_t sf_type); SRSLTE_API int srslte_ue_dl_cfg_grant(srslte_ue_dl_t *q, srslte_ra_dl_grant_t *grant, @@ -184,6 +205,18 @@ SRSLTE_API int srslte_ue_dl_decode_rnti(srslte_ue_dl_t *q, uint16_t rnti, bool acks[SRSLTE_MAX_CODEWORDS]); +/* Used by example applications - full PMCH decode for a given MBSFN area ID + * srslte_ue_dl_decode_fft_estimate_multi, + * srslte_chest_dl_get_noise_estimate, + * srslte_ue_dl_cfg_grant, + * srslte_pmch_decode_multi + */ +SRSLTE_API int srslte_ue_dl_decode_mbsfn(srslte_ue_dl_t * q, + cf_t *input[SRSLTE_MAX_PORTS], + uint8_t *data, + uint32_t tti); + + SRSLTE_API int srslte_ue_dl_ri_pmi_select(srslte_ue_dl_t *q, uint8_t *ri, uint8_t *pmi, @@ -203,6 +236,15 @@ SRSLTE_API void srslte_ue_dl_reset(srslte_ue_dl_t *q); SRSLTE_API void srslte_ue_dl_set_rnti(srslte_ue_dl_t *q, uint16_t rnti); +/* Generate signals if required, store in q->current_mbsfn_area_id */ +SRSLTE_API int srslte_ue_dl_set_mbsfn_area_id(srslte_ue_dl_t *q, + uint16_t mbsfn_area_id); + +SRSLTE_API void srslte_ue_dl_set_non_mbsfn_region(srslte_ue_dl_t *q, + uint8_t non_mbsfn_region_length); + + + SRSLTE_API void srslte_ue_dl_save_signal(srslte_ue_dl_t *q, srslte_softbuffer_rx_t *softbuffer, uint32_t tti, diff --git a/lib/src/phy/ch_estimation/chest_dl.c b/lib/src/phy/ch_estimation/chest_dl.c index edb8c5ca2..b5107f9ab 100644 --- a/lib/src/phy/ch_estimation/chest_dl.c +++ b/lib/src/phy/ch_estimation/chest_dl.c @@ -81,29 +81,46 @@ int srslte_chest_dl_init(srslte_chest_dl_t *q, uint32_t max_prb) { bzero(q, sizeof(srslte_chest_dl_t)); - ret = srslte_refsignal_cs_init(&q->csr_signal, max_prb); + + ret = srslte_refsignal_cs_init(&q->csr_refs, max_prb); if (ret != SRSLTE_SUCCESS) { fprintf(stderr, "Error initializing CSR signal (%d)\n",ret); goto clean_exit; } - q->tmp_noise = srslte_vec_malloc(sizeof(cf_t) * SRSLTE_REFSIGNAL_MAX_NUM_SF(max_prb)); + q->mbsfn_refs = calloc(SRSLTE_MAX_MBSFN_AREA_IDS, sizeof(srslte_refsignal_t*)); + if (!q->mbsfn_refs) { + fprintf(stderr, "Calloc error initializing mbsfn_refs (%d)\n", ret); + goto clean_exit; + } + + int pilot_vec_size; + if(SRSLTE_REFSIGNAL_MAX_NUM_SF_MBSFN(max_prb)>SRSLTE_REFSIGNAL_MAX_NUM_SF(max_prb)) { + pilot_vec_size = SRSLTE_REFSIGNAL_MAX_NUM_SF_MBSFN(max_prb); + }else{ + pilot_vec_size = SRSLTE_REFSIGNAL_MAX_NUM_SF(max_prb); + } + + q->tmp_noise = srslte_vec_malloc(sizeof(cf_t) * pilot_vec_size); + + if (!q->tmp_noise) { perror("malloc"); goto clean_exit; } + q->pilot_estimates = srslte_vec_malloc(sizeof(cf_t) * pilot_vec_size); - q->pilot_estimates = srslte_vec_malloc(sizeof(cf_t) * SRSLTE_REFSIGNAL_MAX_NUM_SF(max_prb)); if (!q->pilot_estimates) { perror("malloc"); goto clean_exit; } - q->pilot_estimates_average = srslte_vec_malloc(sizeof(cf_t) * SRSLTE_REFSIGNAL_MAX_NUM_SF(max_prb)); + q->pilot_estimates_average = srslte_vec_malloc(sizeof(cf_t) * pilot_vec_size); if (!q->pilot_estimates_average) { perror("malloc"); goto clean_exit; } - q->pilot_recv_signal = srslte_vec_malloc(sizeof(cf_t) * SRSLTE_REFSIGNAL_MAX_NUM_SF(max_prb)); + q->pilot_recv_signal = srslte_vec_malloc(sizeof(cf_t) * pilot_vec_size); + if (!q->pilot_recv_signal) { perror("malloc"); goto clean_exit; @@ -118,8 +135,13 @@ int srslte_chest_dl_init(srslte_chest_dl_t *q, uint32_t max_prb) fprintf(stderr, "Error initializing interpolator\n"); goto clean_exit; } + + if (srslte_interp_linear_init(&q->srslte_interp_lin_mbsfn, 6*max_prb, SRSLTE_NRE/6)) { + fprintf(stderr, "Error initializing interpolator\n"); + goto clean_exit; + } - q->noise_alg = SRSLTE_NOISE_ALG_REFS; + q->noise_alg = SRSLTE_NOISE_ALG_REFS; q->smooth_filter_len = 3; srslte_chest_dl_set_smooth_filter3_coeff(q, 0.1); @@ -137,14 +159,25 @@ clean_exit: void srslte_chest_dl_free(srslte_chest_dl_t *q) { - srslte_refsignal_cs_free(&q->csr_signal); + int i; + if(&q->csr_refs) + srslte_refsignal_free(&q->csr_refs); + + if (q->mbsfn_refs) { + for (i=0; imbsfn_refs[i]) { + srslte_refsignal_free(q->mbsfn_refs[i]); + } + } + free(q->mbsfn_refs); + } if (q->tmp_noise) { free(q->tmp_noise); } srslte_interp_linear_vector_free(&q->srslte_interp_linvec); srslte_interp_linear_free(&q->srslte_interp_lin); - + srslte_interp_linear_free(&q->srslte_interp_lin_mbsfn); if (q->pilot_estimates) { free(q->pilot_estimates); } @@ -157,6 +190,19 @@ void srslte_chest_dl_free(srslte_chest_dl_t *q) bzero(q, sizeof(srslte_chest_dl_t)); } + +int srslte_chest_dl_set_mbsfn_area_id(srslte_chest_dl_t *q, uint16_t mbsfn_area_id){ + if(!q->mbsfn_refs[mbsfn_area_id]){ + q->mbsfn_refs[mbsfn_area_id] = calloc(1, sizeof(srslte_refsignal_t)); + } + if(q->mbsfn_refs[mbsfn_area_id]) { + if(srslte_refsignal_mbsfn_init(q->mbsfn_refs[mbsfn_area_id], q->cell, mbsfn_area_id)) { + return SRSLTE_ERROR; + } + } + return SRSLTE_SUCCESS; +} + int srslte_chest_dl_set_cell(srslte_chest_dl_t *q, srslte_cell_t cell) { int ret = SRSLTE_ERROR_INVALID_INPUTS; @@ -165,7 +211,7 @@ int srslte_chest_dl_set_cell(srslte_chest_dl_t *q, srslte_cell_t cell) { if (q->cell.id != cell.id || q->cell.nof_prb == 0) { memcpy(&q->cell, &cell, sizeof(srslte_cell_t)); - ret = srslte_refsignal_cs_set_cell(&q->csr_signal, cell); + ret = srslte_refsignal_cs_set_cell(&q->csr_refs, cell); if (ret != SRSLTE_SUCCESS) { fprintf(stderr, "Error initializing CSR signal (%d)\n",ret); return SRSLTE_ERROR; @@ -187,7 +233,6 @@ int srslte_chest_dl_set_cell(srslte_chest_dl_t *q, srslte_cell_t cell) } ret = SRSLTE_SUCCESS; } - return ret; } @@ -253,46 +298,70 @@ static float estimate_noise_empty_sc(srslte_chest_dl_t *q, cf_t *input) { #define cesymb(i) ce[SRSLTE_RE_IDX(q->cell.nof_prb,i,0)] -static void interpolate_pilots(srslte_chest_dl_t *q, cf_t *pilot_estimates, cf_t *ce, uint32_t port_id) +static void interpolate_pilots(srslte_chest_dl_t *q, cf_t *pilot_estimates, cf_t *ce, uint32_t port_id, srslte_sf_t ch_mode) { /* interpolate the symbols with references in the freq domain */ uint32_t l; - uint32_t nsymbols = srslte_refsignal_cs_nof_symbols(port_id); - + uint32_t nsymbols = (ch_mode == SRSLTE_SF_MBSFN ) ? srslte_refsignal_mbsfn_nof_symbols() + 1 : srslte_refsignal_cs_nof_symbols(port_id); + uint32_t fidx_offset = 0; /* Interpolate in the frequency domain */ - for (l=0;lcell, l, port_id, 0); - srslte_interp_linear_offset(&q->srslte_interp_lin, &pilot_estimates[2*q->cell.nof_prb*l], - &ce[srslte_refsignal_cs_nsymbol(l,q->cell.cp, port_id) * q->cell.nof_prb * SRSLTE_NRE], - fidx_offset, SRSLTE_NRE/2-fidx_offset); + + // we add one to nsymbols to allow for inclusion of the non-mbms references in the channel estimation + for (l=0;l<(nsymbols);l++) { + if (ch_mode == SRSLTE_SF_MBSFN) { + if (l == 0) { + fidx_offset = srslte_refsignal_cs_fidx(q->cell, l, port_id, 0); + srslte_interp_linear_offset(&q->srslte_interp_lin, &pilot_estimates[2*q->cell.nof_prb*l], + &ce[srslte_refsignal_cs_nsymbol(l,q->cell.cp, port_id) * q->cell.nof_prb * SRSLTE_NRE], + fidx_offset, SRSLTE_NRE/2-fidx_offset); + } else { + fidx_offset = srslte_refsignal_mbsfn_fidx(l - 1); + srslte_interp_linear_offset(&q->srslte_interp_lin_mbsfn, &pilot_estimates[(2*q->cell.nof_prb) + 6*q->cell.nof_prb*(l - 1)], + &ce[srslte_refsignal_mbsfn_nsymbol(l - 1) * q->cell.nof_prb * SRSLTE_NRE], + fidx_offset, SRSLTE_NRE/6-fidx_offset); + } + } else { + fidx_offset = srslte_refsignal_cs_fidx(q->cell, l, port_id, 0); + srslte_interp_linear_offset(&q->srslte_interp_lin, &pilot_estimates[2*q->cell.nof_prb*l], + &ce[srslte_refsignal_cs_nsymbol(l,q->cell.cp, port_id) * q->cell.nof_prb * SRSLTE_NRE], + fidx_offset, SRSLTE_NRE/2-fidx_offset); + } } - + /* Now interpolate in the time domain between symbols */ - if (SRSLTE_CP_ISNORM(q->cell.cp)) { - if (nsymbols == 4) { - srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(0), &cesymb(4), &cesymb(1), 4, 3); - srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(4), &cesymb(7), &cesymb(5), 3, 2); - srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(7), &cesymb(11), &cesymb(8), 4, 3); - srslte_interp_linear_vector2(&q->srslte_interp_linvec, &cesymb(7), &cesymb(11), &cesymb(11), &cesymb(12), 4, 2); + if (ch_mode == SRSLTE_SF_MBSFN) { + srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(0), &cesymb(2), &cesymb(1), 2, 1); + srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(2), &cesymb(6), &cesymb(3), 4, 3); + srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(6), &cesymb(10), &cesymb(7), 4, 3); + srslte_interp_linear_vector2(&q->srslte_interp_linvec, &cesymb(6), &cesymb(10), &cesymb(10), &cesymb(11), 4, 1); + } else { + if (SRSLTE_CP_ISNORM(q->cell.cp)) { + if (nsymbols == 4) { + srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(0), &cesymb(4), &cesymb(1), 4, 3); + srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(4), &cesymb(7), &cesymb(5), 3, 2); + srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(7), &cesymb(11), &cesymb(8), 4, 3); + srslte_interp_linear_vector2(&q->srslte_interp_linvec, &cesymb(7), &cesymb(11), &cesymb(11), &cesymb(12), 4, 2); + } else { + srslte_interp_linear_vector2(&q->srslte_interp_linvec, &cesymb(8), &cesymb(1), &cesymb(1), &cesymb(0), 7, 1); + srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(1), &cesymb(8), &cesymb(2), 7, 6); + srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(1), &cesymb(8), &cesymb(9), 7, 5); + } } else { - srslte_interp_linear_vector2(&q->srslte_interp_linvec, &cesymb(8), &cesymb(1), &cesymb(1), &cesymb(0), 7, 1); - srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(1), &cesymb(8), &cesymb(2), 7, 6); - srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(1), &cesymb(8), &cesymb(9), 7, 5); - } - } else { - if (nsymbols == 4) { - srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(0), &cesymb(3), &cesymb(1), 3, 2); - srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(3), &cesymb(6), &cesymb(4), 3, 2); - srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(6), &cesymb(9), &cesymb(7), 3, 2); - srslte_interp_linear_vector2(&q->srslte_interp_linvec, &cesymb(6), &cesymb(9), &cesymb(9), &cesymb(10), 3, 2); - } else { - srslte_interp_linear_vector2(&q->srslte_interp_linvec, &cesymb(7), &cesymb(1), &cesymb(1), &cesymb(0), 6, 1); - srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(1), &cesymb(7), &cesymb(2), 6, 5); - srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(1), &cesymb(7), &cesymb(8), 6, 4); - } + if (nsymbols == 4) { + srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(0), &cesymb(3), &cesymb(1), 3, 2); + srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(3), &cesymb(6), &cesymb(4), 3, 2); + srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(6), &cesymb(9), &cesymb(7), 3, 2); + srslte_interp_linear_vector2(&q->srslte_interp_linvec, &cesymb(6), &cesymb(9), &cesymb(9), &cesymb(10), 3, 2); + } else { + srslte_interp_linear_vector2(&q->srslte_interp_linvec, &cesymb(7), &cesymb(1), &cesymb(1), &cesymb(0), 6, 1); + srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(1), &cesymb(7), &cesymb(2), 6, 5); + srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(1), &cesymb(7), &cesymb(8), 6, 4); + } + } } } + void srslte_chest_dl_set_smooth_filter(srslte_chest_dl_t *q, float *filter, uint32_t filter_len) { if (filter_len < SRSLTE_CHEST_MAX_SMOOTH_FIL_LEN) { if (filter) { @@ -319,9 +388,9 @@ void srslte_chest_dl_set_smooth_filter3_coeff(srslte_chest_dl_t* q, float w) q->smooth_filter[1] = 1-2*w; } -static void average_pilots(srslte_chest_dl_t *q, cf_t *input, cf_t *output, uint32_t port_id) { - uint32_t nsymbols = srslte_refsignal_cs_nof_symbols(port_id); - uint32_t nref = 2*q->cell.nof_prb; +static void average_pilots(srslte_chest_dl_t *q, cf_t *input, cf_t *output, uint32_t port_id, srslte_sf_t ch_mode) { + uint32_t nsymbols = (ch_mode == SRSLTE_SF_MBSFN)?srslte_refsignal_mbsfn_nof_symbols(port_id):srslte_refsignal_cs_nof_symbols(port_id); + uint32_t nref = (ch_mode == SRSLTE_SF_MBSFN)?6*q->cell.nof_prb:2*q->cell.nof_prb; // Average in the frequency domain for (int l=0;lcell, port_id, input, q->pilot_recv_signal); - - /* Use the known CSR signal to compute Least-squares estimates */ - srslte_vec_prod_conj_ccc(q->pilot_recv_signal, q->csr_signal.pilots[port_id/2][sf_idx], - q->pilot_estimates, SRSLTE_REFSIGNAL_NUM_SF(q->cell.nof_prb, port_id)); - - if (ce != NULL) { - +void chest_interpolate_noise_est(srslte_chest_dl_t *q, cf_t *input, cf_t *ce, uint32_t sf_idx, uint32_t port_id, uint32_t rxant_id, srslte_sf_t ch_mode){ + if (ce != NULL) { /* Smooth estimates (if applicable) and interpolate */ if (q->smooth_filter_len == 0 || (q->smooth_filter_len == 3 && q->smooth_filter[0] == 0)) { - interpolate_pilots(q, q->pilot_estimates, ce, port_id); + interpolate_pilots(q, q->pilot_estimates, ce, port_id, ch_mode); } else { - average_pilots(q, q->pilot_estimates, q->pilot_estimates_average, port_id); - interpolate_pilots(q, q->pilot_estimates_average, ce, port_id); + average_pilots(q, q->pilot_estimates, q->pilot_estimates_average, port_id, ch_mode); + interpolate_pilots(q, q->pilot_estimates_average, ce, port_id, ch_mode); } - + /* Estimate noise power */ if (q->noise_alg == SRSLTE_NOISE_ALG_REFS && q->smooth_filter_len > 0) { q->noise_estimate[rxant_id][port_id] = estimate_noise_pilots(q, port_id); @@ -371,8 +431,7 @@ int srslte_chest_dl_estimate_port(srslte_chest_dl_t *q, cf_t *input, cf_t *ce, u if (sf_idx == 0 || sf_idx == 5) { q->noise_estimate[rxant_id][port_id] = estimate_noise_empty_sc(q, input); } - } - + } } /* Compute RSRP for the channel estimates in this port */ @@ -381,10 +440,42 @@ int srslte_chest_dl_estimate_port(srslte_chest_dl_t *q, cf_t *input, cf_t *ce, u /* compute rssi only for port 0 */ q->rssi[rxant_id][port_id] = srslte_chest_dl_rssi(q, input, port_id); } +} + +int srslte_chest_dl_estimate_port(srslte_chest_dl_t *q, cf_t *input, cf_t *ce, uint32_t sf_idx, uint32_t port_id, uint32_t rxant_id) +{ + /* Get references from the input signal */ + srslte_refsignal_cs_get_sf(q->cell, port_id, input, q->pilot_recv_signal); + + /* Use the known CSR signal to compute Least-squares estimates */ + srslte_vec_prod_conj_ccc(q->pilot_recv_signal, q->csr_refs.pilots[port_id/2][sf_idx], + q->pilot_estimates, SRSLTE_REFSIGNAL_NUM_SF(q->cell.nof_prb, port_id)); + + chest_interpolate_noise_est(q, input, ce, sf_idx, port_id, rxant_id, SRSLTE_SF_NORM); + + return 0; +} +int srslte_chest_dl_estimate_port_mbsfn(srslte_chest_dl_t *q, cf_t *input, cf_t *ce, uint32_t sf_idx, uint32_t port_id, uint32_t rxant_id, uint16_t mbsfn_area_id) +{ + + /* Use the known CSR signal to compute Least-squares estimates */ + srslte_refsignal_mbsfn_get_sf(q->cell, port_id, input, q->pilot_recv_signal); + // estimate for non-mbsfn section of subframe + srslte_vec_prod_conj_ccc(q->pilot_recv_signal, q->csr_refs.pilots[port_id/2][sf_idx], + q->pilot_estimates, (2*q->cell.nof_prb)); + + srslte_vec_prod_conj_ccc(q->pilot_recv_signal+(2*q->cell.nof_prb), q->mbsfn_refs[mbsfn_area_id]->pilots[port_id/2][sf_idx], + q->pilot_estimates+(2*q->cell.nof_prb), SRSLTE_REFSIGNAL_NUM_SF_MBSFN(q->cell.nof_prb, port_id)-(2*q->cell.nof_prb)); + + chest_interpolate_noise_est(q, input, ce, sf_idx, port_id, rxant_id, SRSLTE_SF_MBSFN); return 0; } + + + + int srslte_chest_dl_estimate_multi(srslte_chest_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS], cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], uint32_t sf_idx, uint32_t nof_rx_antennas) { for (uint32_t rxant_id=0;rxant_idcell.nof_ports;port_id++) { + if (srslte_chest_dl_estimate_port_mbsfn(q, input[rxant_id], ce[port_id][rxant_id], sf_idx, port_id, rxant_id, mbsfn_area_id)) { + return SRSLTE_ERROR; + } + } + } + q->last_nof_antennas = nof_rx_antennas; + return SRSLTE_SUCCESS; +} + + + float srslte_chest_dl_get_noise_estimate(srslte_chest_dl_t *q) { float n = 0; for (int i=0;ilast_nof_antennas;i++) { diff --git a/lib/src/phy/ch_estimation/refsignal_dl.c b/lib/src/phy/ch_estimation/refsignal_dl.c index fa8a27968..4de00039e 100644 --- a/lib/src/phy/ch_estimation/refsignal_dl.c +++ b/lib/src/phy/ch_estimation/refsignal_dl.c @@ -75,17 +75,44 @@ uint32_t srslte_refsignal_cs_v(uint32_t port_id, uint32_t ref_symbol_idx) uint32_t srslte_refsignal_cs_nof_symbols(uint32_t port_id) { + uint32_t ret; if (port_id < 2) { - return 4; + ret = 4; } else { - return 2; + ret = 2; + } + return ret; +} + +uint32_t srslte_refsignal_mbsfn_nof_symbols() +{ + if(false){ + return 3; + }else{ + return 3; } } + inline uint32_t srslte_refsignal_cs_fidx(srslte_cell_t cell, uint32_t l, uint32_t port_id, uint32_t m) { return 6*m + ((srslte_refsignal_cs_v(port_id, l) + (cell.id % 6)) % 6); } +inline uint32_t srslte_refsignal_mbsfn_fidx(uint32_t l) +{ + + uint32_t ret = 0; + if(l == 0){ + ret = 0; + }else if (l == 1){ + ret = 1; + }else if(l == 2){ + ret = 0; + } + + return ret; +} + inline uint32_t srslte_refsignal_cs_nsymbol(uint32_t l, srslte_cp_t cp, uint32_t port_id) { if (port_id < 2) { if (l % 2) { @@ -97,11 +124,104 @@ inline uint32_t srslte_refsignal_cs_nsymbol(uint32_t l, srslte_cp_t cp, uint32_t return 1+l*SRSLTE_CP_NSYMB(cp); } } +inline uint32_t srslte_refsignal_mbsfn_nsymbol(uint32_t l) +{ + uint32_t ret = 0; + if(l == 0){ + ret = 2; + } else if (l == 1) { + ret = 6; + } else if (l == 2){ + ret = 10; + } + + return ret; +} + +int srslte_refsignal_mbsfn_gen_seq(srslte_refsignal_t * q, srslte_cell_t cell, uint32_t N_mbsfn_id) +{ + uint32_t c_init; + uint32_t i, ns, l, p; + uint32_t mp; + int ret = SRSLTE_ERROR; + + srslte_sequence_t seq_mbsfn; + bzero(&seq_mbsfn, sizeof(srslte_sequence_t)); + if (srslte_sequence_init(&seq_mbsfn, 20* SRSLTE_MAX_PRB)) { + goto free_and_exit; + } + + for(ns=0; nscell.nof_prb;i++) { + mp = i + 3*(SRSLTE_MAX_PRB - cell.nof_prb); + q->pilots[p][ns][ SRSLTE_REFSIGNAL_PILOT_IDX_MBSFN(i, l ,q->cell)] = (1 - 2 * (float) seq_mbsfn.c[2 * mp]) / sqrt(2) +_Complex_I * (1 - 2 * (float) seq_mbsfn.c[2 * mp + 1]) / sqrt(2); + } + } + } + } + + srslte_sequence_free(&seq_mbsfn); + ret = SRSLTE_SUCCESS; + +free_and_exit: + if (ret == SRSLTE_ERROR) { + srslte_sequence_free(&seq_mbsfn); + srslte_refsignal_free(q); + } + return ret; + +} + + +int srslte_refsignal_mbsfn_init(srslte_refsignal_t * q, srslte_cell_t cell, uint16_t mbsfn_area_id) +{ + int ret = SRSLTE_ERROR_INVALID_INPUTS; + uint32_t i, p; + if (q != NULL && + srslte_cell_isvalid(&cell)) + { + ret = SRSLTE_ERROR; + bzero(q, sizeof(srslte_refsignal_t)); + q->cell = cell; + q->type = SRSLTE_SF_MBSFN; + q->mbsfn_area_id = mbsfn_area_id; + + for (p=0;p<2;p++) { + for (i=0;ipilots[p][i] = srslte_vec_malloc(sizeof(cf_t) * q->cell.nof_prb * 18); + if (!q->pilots[p][i]) { + perror("malloc"); + goto free_and_exit; + } + } + } + + if(srslte_refsignal_mbsfn_gen_seq(q, q->cell, q->mbsfn_area_id)) { + goto free_and_exit; + } + ret = SRSLTE_SUCCESS; + } + +free_and_exit: + if (ret == SRSLTE_ERROR) { + srslte_refsignal_free(q); + } + return ret; +} + + /** Allocates memory for the 20 slots in a subframe */ -int srslte_refsignal_cs_init(srslte_refsignal_cs_t * q, uint32_t max_prb) +int srslte_refsignal_cs_init(srslte_refsignal_t * q, uint32_t max_prb) { int ret = SRSLTE_ERROR_INVALID_INPUTS; @@ -109,7 +229,6 @@ int srslte_refsignal_cs_init(srslte_refsignal_cs_t * q, uint32_t max_prb) if (q != NULL) { ret = SRSLTE_ERROR; - for (int p=0;p<2;p++) { for (int i=0;ipilots[p][i] = srslte_vec_malloc(sizeof(cf_t) * SRSLTE_REFSIGNAL_NUM_SF(max_prb, 2*p)); @@ -123,7 +242,7 @@ int srslte_refsignal_cs_init(srslte_refsignal_cs_t * q, uint32_t max_prb) } free_and_exit: if (ret == SRSLTE_ERROR) { - srslte_refsignal_cs_free(q); + srslte_refsignal_free(q); } return ret; } @@ -131,7 +250,7 @@ free_and_exit: /** Allocates and precomputes the Cell-Specific Reference (CSR) signal for * the 20 slots in a subframe */ -int srslte_refsignal_cs_set_cell(srslte_refsignal_cs_t * q, srslte_cell_t cell) +int srslte_refsignal_cs_set_cell(srslte_refsignal_t * q, srslte_cell_t cell) { uint32_t c_init; @@ -188,7 +307,7 @@ int srslte_refsignal_cs_set_cell(srslte_refsignal_cs_t * q, srslte_cell_t cell) } /** Deallocates a srslte_refsignal_cs_t object allocated with srslte_refsignal_cs_init */ -void srslte_refsignal_cs_free(srslte_refsignal_cs_t * q) +void srslte_refsignal_free(srslte_refsignal_t * q) { for (int p=0;p<2;p++) { for (int i=0;ifft_plan, symbol_sz, dir)) { fprintf(stderr, "Error: Creating DFT plan\n"); @@ -60,6 +66,7 @@ int srslte_ofdm_init_(srslte_ofdm_t *q, srslte_cp_t cp, int symbol_sz, int nof_p q->symbol_sz = (uint32_t) symbol_sz; q->nof_symbols = SRSLTE_CP_NSYMB(cp); + q->nof_symbols_mbsfn = SRSLTE_CP_NSYMB(SRSLTE_CP_EXT); q->cp = cp; q->freq_shift = false; q->nof_re = nof_prb * SRSLTE_NRE; @@ -69,10 +76,20 @@ int srslte_ofdm_init_(srslte_ofdm_t *q, srslte_cp_t cp, int symbol_sz, int nof_p DEBUG("Init %s symbol_sz=%d, nof_symbols=%d, cp=%s, nof_re=%d, nof_guards=%d\n", dir==SRSLTE_DFT_FORWARD?"FFT":"iFFT", q->symbol_sz, q->nof_symbols, q->cp==SRSLTE_CP_NORM?"Normal":"Extended", q->nof_re, q->nof_guards); - + + // MBSFN logic + if (sf_type == SRSLTE_SF_MBSFN) { + q->mbsfn_subframe = true; + q->non_mbsfn_region = 2; // default set to 2 + } + return SRSLTE_SUCCESS; } +void srslte_ofdm_set_non_mbsfn_region(srslte_ofdm_t *q, uint8_t non_mbsfn_region) +{ + q->non_mbsfn_region = non_mbsfn_region; +} int srslte_ofdm_replan_(srslte_ofdm_t *q, srslte_cp_t cp, int symbol_sz, int nof_prb) { @@ -120,6 +137,17 @@ int srslte_ofdm_rx_init(srslte_ofdm_t *q, srslte_cp_t cp, uint32_t max_prb) { return srslte_ofdm_init_(q, cp, symbol_sz, max_prb, SRSLTE_DFT_FORWARD); } +int srslte_ofdm_rx_init_mbsfn(srslte_ofdm_t *q, srslte_cp_t cp, uint32_t nof_prb) +{ + int symbol_sz = srslte_symbol_sz(nof_prb); + if (symbol_sz < 0) { + fprintf(stderr, "Error: Invalid nof_prb=%d\n", nof_prb); + return -1; + } + return srslte_ofdm_init_mbsfn_(q, cp, symbol_sz, nof_prb, SRSLTE_DFT_FORWARD, SRSLTE_SF_MBSFN); +} + + int srslte_ofdm_tx_init(srslte_ofdm_t *q, srslte_cp_t cp, uint32_t max_prb) { uint32_t i; int ret; @@ -130,8 +158,33 @@ int srslte_ofdm_tx_init(srslte_ofdm_t *q, srslte_cp_t cp, uint32_t max_prb) { return -1; } q->max_prb = max_prb; + ret = srslte_ofdm_init_(q, cp, symbol_sz, max_prb, SRSLTE_DFT_BACKWARD); - ret = srslte_ofdm_init_(q, cp, symbol_sz, max_prb, SRSLTE_DFT_BACKWARD); + + if (ret == SRSLTE_SUCCESS) { + srslte_dft_plan_set_norm(&q->fft_plan, false); + + /* set now zeros at CP */ + for (i=0;inof_symbols;i++) { + bzero(q->tmp, q->nof_guards * sizeof(cf_t)); + bzero(&q->tmp[q->nof_re + q->nof_guards], q->nof_guards * sizeof(cf_t)); + } + } + return ret; +} + +int srslte_ofdm_tx_init_mbsfn(srslte_ofdm_t *q, srslte_cp_t cp, uint32_t nof_prb) +{ + uint32_t i; + int ret; + + int symbol_sz = srslte_symbol_sz(nof_prb); + if (symbol_sz < 0) { + fprintf(stderr, "Error: Invalid nof_prb=%d\n", nof_prb); + return -1; + } + + ret = srslte_ofdm_init_mbsfn_(q, cp, symbol_sz, nof_prb, SRSLTE_DFT_BACKWARD, SRSLTE_SF_MBSFN); if (ret == SRSLTE_SUCCESS) { srslte_dft_plan_set_norm(&q->fft_plan, false); @@ -190,7 +243,6 @@ int srslte_ofdm_tx_set_prb(srslte_ofdm_t *q, srslte_cp_t cp, uint32_t nof_prb) { void srslte_ofdm_rx_free(srslte_ofdm_t *q) { srslte_ofdm_free_(q); } - /* Shifts the signal after the iFFT or before the FFT. * Freq_shift is relative to inter-carrier spacing. * Caution: This function shall not be called during run-time @@ -233,6 +285,23 @@ void srslte_ofdm_rx_slot(srslte_ofdm_t *q, cf_t *input, cf_t *output) { } } +void srslte_ofdm_rx_slot_mbsfn(srslte_ofdm_t *q, cf_t *input, cf_t *output) +{ + uint32_t i; + for(i = 0; i < q->nof_symbols_mbsfn; i++){ + if(i == q->non_mbsfn_region) { + input += SRSLTE_NON_MBSFN_REGION_GUARD_LENGTH(q->non_mbsfn_region,q->symbol_sz); + } + input += (i>=q->non_mbsfn_region)?SRSLTE_CP_LEN_EXT(q->symbol_sz):SRSLTE_CP_LEN_NORM(i, q->symbol_sz); + srslte_dft_run_c(&q->fft_plan, input, q->tmp); + memcpy(output, &q->tmp[q->nof_guards], q->nof_re * sizeof(cf_t)); + input += q->symbol_sz; + output += q->nof_re; + } +} + + + void srslte_ofdm_rx_slot_zerocopy(srslte_ofdm_t *q, cf_t *input, cf_t *output) { uint32_t i; for (i=0;inof_symbols;i++) { @@ -250,8 +319,14 @@ void srslte_ofdm_rx_sf(srslte_ofdm_t *q, cf_t *input, cf_t *output) { if (q->freq_shift) { srslte_vec_prod_ccc(input, q->shift_buffer, input, 2*q->slot_sz); } - for (n=0;n<2;n++) { - srslte_ofdm_rx_slot(q, &input[n*q->slot_sz], &output[n*q->nof_re*q->nof_symbols]); + if(!q->mbsfn_subframe){ + for (n=0;n<2;n++) { + srslte_ofdm_rx_slot(q, &input[n*q->slot_sz], &output[n*q->nof_re*q->nof_symbols]); + } + } + else{ + srslte_ofdm_rx_slot_mbsfn(q, &input[0*q->slot_sz], &output[0*q->nof_re*q->nof_symbols]); + srslte_ofdm_rx_slot(q, &input[1*q->slot_sz], &output[1*q->nof_re*q->nof_symbols]); } } @@ -271,16 +346,43 @@ void srslte_ofdm_tx_slot(srslte_ofdm_t *q, cf_t *input, cf_t *output) { } } +void srslte_ofdm_tx_slot_mbsfn(srslte_ofdm_t *q, cf_t *input, cf_t *output) +{ + uint32_t i, cp_len; + + for(i=0;inof_symbols_mbsfn;i++) { + cp_len = ( i>(q->non_mbsfn_region-1) )?SRSLTE_CP_LEN_EXT(q->symbol_sz):SRSLTE_CP_LEN_NORM(i, q->symbol_sz); + memcpy(&q->tmp[q->nof_guards], input, q->nof_re * sizeof(cf_t)); + srslte_dft_run_c(&q->fft_plan, q->tmp, &output[cp_len]); + input += q->nof_re; + /* add CP */ + memcpy(output, &output[q->symbol_sz], cp_len * sizeof(cf_t)); + output += q->symbol_sz + cp_len; + + /*skip the small section between the non mbms region and the mbms region*/ + if(i == (q->non_mbsfn_region - 1)) + output += SRSLTE_NON_MBSFN_REGION_GUARD_LENGTH(q->non_mbsfn_region,q->symbol_sz); + } +} + void srslte_ofdm_set_normalize(srslte_ofdm_t *q, bool normalize_enable) { srslte_dft_plan_set_norm(&q->fft_plan, normalize_enable); } -void srslte_ofdm_tx_sf(srslte_ofdm_t *q, cf_t *input, cf_t *output) { +void srslte_ofdm_tx_sf(srslte_ofdm_t *q, cf_t *input, cf_t *output) +{ uint32_t n; - for (n=0;n<2;n++) { - srslte_ofdm_tx_slot(q, &input[n*q->nof_re*q->nof_symbols], &output[n*q->slot_sz]); + if(!q->mbsfn_subframe){ + for (n=0;n<2;n++) { + srslte_ofdm_tx_slot(q, &input[n*q->nof_re*q->nof_symbols], &output[n*q->slot_sz]); + } + } + else{ + srslte_ofdm_tx_slot_mbsfn(q, &input[0*q->nof_re*q->nof_symbols], &output[0*q->slot_sz]); + srslte_ofdm_tx_slot(q, &input[1*q->nof_re*q->nof_symbols], &output[1*q->slot_sz]); } if (q->freq_shift) { srslte_vec_prod_ccc(output, q->shift_buffer, output, 2*q->slot_sz); } } + diff --git a/lib/src/phy/enb/enb_dl.c b/lib/src/phy/enb/enb_dl.c index fb9fe7d87..ec470ce3d 100644 --- a/lib/src/phy/enb/enb_dl.c +++ b/lib/src/phy/enb/enb_dl.c @@ -122,7 +122,7 @@ void srslte_enb_dl_free(srslte_enb_dl_t *q) srslte_pdcch_free(&q->pdcch); srslte_pdsch_free(&q->pdsch); - srslte_refsignal_cs_free(&q->csr_signal); + srslte_refsignal_free(&q->csr_signal); for (int i=0;isf_symbols[i]) { diff --git a/lib/src/phy/phch/pmch.c b/lib/src/phy/phch/pmch.c new file mode 100644 index 000000000..ee1b3554f --- /dev/null +++ b/lib/src/phy/phch/pmch.c @@ -0,0 +1,486 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsLTE library. + * + * srsLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "prb_dl.h" +#include "srslte/phy/phch/sch.h" +#include "srslte/phy/common/phy_common.h" +#include "srslte/phy/utils/bit.h" +#include "srslte/phy/utils/debug.h" +#include "srslte/phy/utils/vector.h" + + +#define MAX_PMCH_RE (2 * SRSLTE_CP_EXT_NSYMB * 12) + + +const static srslte_mod_t modulations[4] = + { SRSLTE_MOD_BPSK, SRSLTE_MOD_QPSK, SRSLTE_MOD_16QAM, SRSLTE_MOD_64QAM }; + +//#define DEBUG_IDX + +#ifdef DEBUG_IDX +cf_t *offset_original=NULL; +extern int indices[100000]; +extern int indices_ptr; +#endif + +float srslte_pmch_coderate(uint32_t tbs, uint32_t nof_re) +{ + return (float) (tbs + 24)/(nof_re); +} + +int srslte_pmch_cp(srslte_pmch_t *q, cf_t *input, cf_t *output, uint32_t lstart_grant, bool put) +{ + uint32_t s, n, l, lp, lstart, lend, nof_refs; + cf_t *in_ptr = input, *out_ptr = output; + uint32_t offset = 0; + + #ifdef DEBUG_IDX + indices_ptr = 0; + if (put) { + offset_original = output; + } else { + offset_original = input; + } + #endif + nof_refs = 6; + for (s = 0; s < 2; s++) { + for (l = 0; l < SRSLTE_CP_EXT_NSYMB; l++) { + for (n = 0; n < q->cell.nof_prb; n++) { + // If this PRB is assigned + if (true) { + if (s == 0) { + lstart = lstart_grant; + } else { + lstart = 0; + } + lend = SRSLTE_CP_EXT_NSYMB; + lp = l + s * SRSLTE_CP_EXT_NSYMB; + if (put) { + out_ptr = &output[(lp * q->cell.nof_prb + n) * SRSLTE_NRE]; + } else { + in_ptr = &input[(lp * q->cell.nof_prb + n) * SRSLTE_NRE]; + } + // This is a symbol in a normal PRB with or without references + if (l >= lstart && l < lend) { + if (SRSLTE_SYMBOL_HAS_REF_MBSFN(l,s)) { + if (l == 0 && s == 1) { + offset = 1; + } else { + offset = 0; + } + prb_cp_ref(&in_ptr, &out_ptr, offset, nof_refs, nof_refs, put); + } else { + prb_cp(&in_ptr, &out_ptr, 1); + } + } + } + } + } + } + + int r; + if (put) { + r = abs((int) (input - in_ptr)); + } else { + r = abs((int) (output - out_ptr)); + } + + return r; +} + +/** + * Puts PMCH in slot number 1 + * + * Returns the number of symbols written to sf_symbols + * + * 36.211 10.3 section 6.3.5 + */ +int srslte_pmch_put(srslte_pmch_t *q, cf_t *symbols, cf_t *sf_symbols, uint32_t lstart) +{ + return srslte_pmch_cp(q, symbols, sf_symbols, lstart, true); +} + +/** + * Extracts PMCH from slot number 1 + * + * Returns the number of symbols written to PMCH + * + * 36.211 10.3 section 6.3.5 + */ +int srslte_pmch_get(srslte_pmch_t *q, cf_t *sf_symbols, cf_t *symbols, uint32_t lstart) +{ + return srslte_pmch_cp(q, sf_symbols, symbols, lstart, false); +} + +int srslte_pmch_init(srslte_pmch_t *q, uint32_t max_prb) +{ + return srslte_pmch_init_multi(q, max_prb, 1); +} + +int srslte_pmch_init_multi(srslte_pmch_t *q, uint32_t max_prb, uint32_t nof_rx_antennas) +{ + int ret = SRSLTE_ERROR_INVALID_INPUTS; + int i; + + if (q != NULL && + nof_rx_antennas <= SRSLTE_MAX_PORTS) + { + + bzero(q, sizeof(srslte_pmch_t)); + ret = SRSLTE_ERROR; + + q->cell.nof_prb = max_prb; + q->cell.nof_ports = 1; + q->max_re = max_prb * MAX_PMCH_RE; + q->nof_rx_antennas = nof_rx_antennas; + + INFO("Init PMCH: %d PRBs, max_symbols: %d\n", + max_prb, q->max_re); + + for (i = 0; i < 4; i++) { + if (srslte_modem_table_lte(&q->mod[i], modulations[i])) { + goto clean; + } + srslte_modem_table_bytes(&q->mod[i]); + } + + srslte_sch_init(&q->dl_sch); + + // Allocate int16_t for reception (LLRs) + q->e = srslte_vec_malloc(sizeof(int16_t) * q->max_re * srslte_mod_bits_x_symbol(SRSLTE_MOD_64QAM)); + if (!q->e) { + goto clean; + } + + q->d = srslte_vec_malloc(sizeof(cf_t) * q->max_re); + if (!q->d) { + goto clean; + } + + for (i = 0; i < SRSLTE_MAX_PORTS; i++) { + q->x[i] = srslte_vec_malloc(sizeof(cf_t) * q->max_re); + if (!q->x[i]) { + goto clean; + } + 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; + } + } + } + for (int j=0;jnof_rx_antennas;j++) { + q->symbols[j] = srslte_vec_malloc(sizeof(cf_t) * q->max_re); + if (!q->symbols[j]) { + goto clean; + } + } + + q->seqs = calloc(SRSLTE_MAX_MBSFN_AREA_IDS, sizeof(srslte_pmch_seq_t*)); + if (!q->seqs) { + perror("calloc"); + goto clean; + } + + ret = SRSLTE_SUCCESS; + } + clean: + if (ret == SRSLTE_ERROR) { + srslte_pmch_free(q); + } + return ret; +} + +void srslte_pmch_free(srslte_pmch_t *q) { + uint16_t i; + + if (q->e) { + free(q->e); + } + if (q->d) { + free(q->d); + } + for (i = 0; i < q->cell.nof_ports; i++) { + if (q->x[i]) { + free(q->x[i]); + } + for (int j=0;jnof_rx_antennas;j++) { + if (q->ce[i][j]) { + free(q->ce[i][j]); + } + } + } + for (i=0;inof_rx_antennas;i++) { + if (q->symbols[i]) { + free(q->symbols[i]); + } + } + if (q->seqs) { + for (i=0; iseqs[i]) { + srslte_pmch_free_area_id(q, i); + } + } + free(q->seqs); + } + for (i = 0; i < 4; i++) { + srslte_modem_table_free(&q->mod[i]); + } + + srslte_sch_free(&q->dl_sch); + + bzero(q, sizeof(srslte_pmch_t)); + +} + + +/* Precalculate the scramble sequences for a given MBSFN area ID. This function takes a while + * to execute. + */ +int srslte_pmch_set_area_id(srslte_pmch_t *q, uint16_t area_id) { + uint32_t i; + if (!q->seqs[area_id]) { + q->seqs[area_id] = calloc(1, sizeof(srslte_pmch_seq_t)); + if (q->seqs[area_id]) { + for (i = 0; i < SRSLTE_NSUBFRAMES_X_FRAME; i++) { + if (srslte_sequence_pmch(&q->seqs[area_id]->seq[i], 2 * i , area_id, q->max_re * srslte_mod_bits_x_symbol(SRSLTE_MOD_64QAM))) { + return SRSLTE_ERROR; + } + } + } + } + return SRSLTE_SUCCESS; +} + +void srslte_pmch_free_area_id(srslte_pmch_t* q, uint16_t area_id) +{ + if (q->seqs[area_id]) { + for (int i = 0; i < SRSLTE_NSUBFRAMES_X_FRAME; i++) { + srslte_sequence_free(&q->seqs[area_id]->seq[i]); + } + free(q->seqs[area_id]); + q->seqs[area_id] = NULL; + } +} + +int srslte_pmch_cfg(srslte_pdsch_cfg_t *cfg, srslte_cell_t cell, srslte_ra_dl_grant_t *grant, uint32_t cfi, uint32_t sf_idx) +{ + if (cfg) { + if (grant) { + memcpy(&cfg->grant, grant, sizeof(srslte_ra_dl_grant_t)); + } + if (srslte_cbsegm(&cfg->cb_segm[0], cfg->grant.mcs[0].tbs)) { + fprintf(stderr, "Error computing Codeblock segmentation for TBS=%d\n", cfg->grant.mcs[0].tbs); + return SRSLTE_ERROR; + } + srslte_ra_dl_grant_to_nbits(&cfg->grant, cfi, cell, sf_idx, cfg->nbits); + cfg->sf_idx = sf_idx; + cfg->rv[0] = SRSLTE_PMCH_RV; + + return SRSLTE_SUCCESS; + } else { + return SRSLTE_ERROR_INVALID_INPUTS; + } +} + + +int srslte_pmch_decode(srslte_pmch_t *q, + srslte_pdsch_cfg_t *cfg, srslte_softbuffer_rx_t *softbuffer, + cf_t *sf_symbols, cf_t *ce[SRSLTE_MAX_PORTS], float noise_estimate, + uint16_t area_id, uint8_t *data) +{ + cf_t *_sf_symbols[SRSLTE_MAX_PORTS]; + cf_t *_ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS]; + + _sf_symbols[0] = sf_symbols; + for (int i=0;icell.nof_ports;i++) { + _ce[i][0] = ce[i]; + } + return srslte_pmch_decode_multi(q, cfg, softbuffer, _sf_symbols, _ce, noise_estimate, area_id, data); +} + +/** Decodes the pmch from the received symbols + */ +int srslte_pmch_decode_multi(srslte_pmch_t *q, + srslte_pdsch_cfg_t *cfg, srslte_softbuffer_rx_t *softbuffer, + cf_t *sf_symbols[SRSLTE_MAX_PORTS], cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], float noise_estimate, + uint16_t area_id, uint8_t *data) +{ + + /* Set pointers for layermapping & precoding */ + uint32_t i, n; + cf_t *x[SRSLTE_MAX_LAYERS]; + + if (q != NULL && + sf_symbols != NULL && + data != NULL && + cfg != NULL) + { + + INFO("Decoding PMCH SF: %d, MBSFN area ID: 0x%x, Mod %s, TBS: %d, NofSymbols: %d, NofBitsE: %d, rv_idx: %d, C_prb=%d, cfi=%d\n", + cfg->sf_idx, area_id, srslte_mod_string(cfg->grant.mcs[0].mod), cfg->grant.mcs[0].tbs, cfg->nbits[0].nof_re, + cfg->nbits[0].nof_bits, 0, cfg->grant.nof_prb, cfg->nbits[0].lstart-1); + + /* 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)); + + for (int j=0;jnof_rx_antennas;j++) { + /* extract symbols */ + n = srslte_pmch_get(q, sf_symbols[j], q->symbols[j], cfg->nbits[0].lstart); + if (n != cfg->nbits[0].nof_re) { + fprintf(stderr, "PMCH 1 extract symbols error expecting %d symbols but got %d, lstart %d\n", cfg->nbits[0].nof_re, n, cfg->nbits[0].lstart); + return SRSLTE_ERROR; + } + + /* extract channel estimates */ + for (i = 0; i < q->cell.nof_ports; i++) { + n = srslte_pmch_get(q, ce[i][j], q->ce[i][j], cfg->nbits[0].lstart); + if (n != cfg->nbits[0].nof_re) { + fprintf(stderr, "PMCH 2 extract chest error expecting %d symbols but got %d\n", cfg->nbits[0].nof_re, n); + return SRSLTE_ERROR; + } + } + } + + // No tx diversity in MBSFN + srslte_predecoding_single_multi(q->symbols, q->ce[0], q->d, q->nof_rx_antennas, cfg->nbits[0].nof_re, noise_estimate); + + if (SRSLTE_VERBOSE_ISDEBUG()) { + DEBUG("SAVED FILE subframe.dat: received subframe symbols\n",0); + srslte_vec_save_file("subframe.dat", sf_symbols, SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp)*sizeof(cf_t)); + DEBUG("SAVED FILE hest0.dat: channel estimates for port 4\n",0); + srslte_vec_save_file("hest0.dat", ce[0], SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp)*sizeof(cf_t)); + DEBUG("SAVED FILE pmch_symbols.dat: symbols after equalization\n",0); + srslte_vec_save_file("pmch_symbols.bin", q->d, cfg->nbits[0].nof_re*sizeof(cf_t)); + } + + /* demodulate symbols + * The MAX-log-MAP algorithm used in turbo decoding is unsensitive to SNR estimation, + * thus we don't need tot set it in thde LLRs normalization + */ + + srslte_demod_soft_demodulate_s(cfg->grant.mcs[0].mod, q->d, q->e, cfg->nbits[0].nof_re); + + /* descramble */ + srslte_scrambling_s_offset(&q->seqs[area_id]->seq[cfg->sf_idx], q->e, 0, cfg->nbits[0].nof_bits); + + if (SRSLTE_VERBOSE_ISDEBUG()) { + DEBUG("SAVED FILE llr.dat: LLR estimates after demodulation and descrambling\n",0); + srslte_vec_save_file("llr.dat", q->e, cfg->nbits[0].nof_bits*sizeof(int16_t)); + } + return srslte_dlsch_decode(&q->dl_sch, cfg, softbuffer, q->e, data); + } else { + return SRSLTE_ERROR_INVALID_INPUTS; + } +} + +int srslte_pmch_encode(srslte_pmch_t *q, + srslte_pdsch_cfg_t *cfg, srslte_softbuffer_tx_t *softbuffer, + uint8_t *data, uint16_t area_id, 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;icell.nof_ports;i++) { + if (sf_symbols[i] == NULL) { + return SRSLTE_ERROR_INVALID_INPUTS; + } + } + + if (cfg->grant.mcs[0].tbs == 0) { + return SRSLTE_ERROR_INVALID_INPUTS; + } + + if (cfg->nbits[0].nof_re > q->max_re) { + fprintf(stderr, + "Error too many RE per subframe (%d). PMCH configured for %d RE (%d PRB)\n", + cfg->nbits[0].nof_re, q->max_re, q->cell.nof_prb); + return SRSLTE_ERROR_INVALID_INPUTS; + } + + INFO("Encoding PMCH SF: %d, Mod %s, NofBits: %d, NofSymbols: %d, NofBitsE: %d, rv_idx: %d\n", + cfg->sf_idx, srslte_mod_string(cfg->grant.mcs[0].mod), cfg->grant.mcs[0].tbs, + cfg->nbits[0].nof_re, cfg->nbits[0].nof_bits, 0); + + /* 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)); + + // TODO: use tb_encode directly + if (srslte_dlsch_encode(&q->dl_sch, cfg, softbuffer, data, q->e)) { + fprintf(stderr, "Error encoding TB\n"); + return SRSLTE_ERROR; + } + + /* scramble */ + srslte_scrambling_bytes(&q->seqs[area_id]->seq[cfg->sf_idx], (uint8_t*) q->e, cfg->nbits[0].nof_bits); + + srslte_mod_modulate_bytes(&q->mod[cfg->grant.mcs[0].mod], (uint8_t*) q->e, q->d, cfg->nbits[0].nof_bits); + + /* No tx diversity in MBSFN */ + memcpy(q->symbols[0], q->d, cfg->nbits[0].nof_re * sizeof(cf_t)); + + /* mapping to resource elements */ + for (i = 0; i < q->cell.nof_ports; i++) { + srslte_pmch_put(q, q->symbols[i], sf_symbols[i], cfg->nbits[0].lstart); + } + + ret = SRSLTE_SUCCESS; + } + return ret; +} + +float srslte_pmch_average_noi(srslte_pmch_t *q) +{ + return q->dl_sch.average_nof_iterations; +} + +uint32_t srslte_pmch_last_noi(srslte_pmch_t *q) { + return q->dl_sch.nof_iterations; +} + + + + diff --git a/lib/src/phy/phch/ra.c b/lib/src/phy/phch/ra.c index b85d2ea2f..418aa1260 100644 --- a/lib/src/phy/phch/ra.c +++ b/lib/src/phy/phch/ra.c @@ -41,15 +41,19 @@ /* Returns the number of RE in a PRB in a slot and subframe */ uint32_t ra_re_x_prb(uint32_t subframe, uint32_t slot, uint32_t prb_idx, uint32_t nof_prb, - uint32_t nof_ports, uint32_t nof_ctrl_symbols, srslte_cp_t cp) { + uint32_t nof_ports, uint32_t nof_ctrl_symbols, srslte_cp_t cp, srslte_sf_t sf_type) { uint32_t re; - bool skip_refs = false; + bool skip_refs = true; + srslte_cp_t cp_ = cp; + if(SRSLTE_SF_MBSFN == sf_type) { + cp_ = SRSLTE_CP_EXT; + } if (slot == 0) { - re = (SRSLTE_CP_NSYMB(cp) - nof_ctrl_symbols) * SRSLTE_NRE; + re = (SRSLTE_CP_NSYMB(cp_) - nof_ctrl_symbols) * SRSLTE_NRE; } else { - re = SRSLTE_CP_NSYMB(cp) * SRSLTE_NRE; + re = SRSLTE_CP_NSYMB(cp_) * SRSLTE_NRE; } /* if it's the prb in the middle, there are less RE due to PBCH and PSS/SSS */ @@ -57,18 +61,18 @@ uint32_t ra_re_x_prb(uint32_t subframe, uint32_t slot, uint32_t prb_idx, uint32_ && (prb_idx >= nof_prb / 2 - 3 && prb_idx < nof_prb / 2 + 3 + (nof_prb%2))) { if (subframe == 0) { if (slot == 0) { - re = (SRSLTE_CP_NSYMB(cp) - nof_ctrl_symbols - 2) * SRSLTE_NRE; + re = (SRSLTE_CP_NSYMB(cp_) - nof_ctrl_symbols - 2) * SRSLTE_NRE; } else { - if (SRSLTE_CP_ISEXT(cp)) { - re = (SRSLTE_CP_NSYMB(cp) - 4) * SRSLTE_NRE; - skip_refs = true; + if (SRSLTE_CP_ISEXT(cp_)) { + re = (SRSLTE_CP_NSYMB(cp_) - 4) * SRSLTE_NRE; + skip_refs = false; } else { - re = (SRSLTE_CP_NSYMB(cp) - 4) * SRSLTE_NRE + 2 * nof_ports; + re = (SRSLTE_CP_NSYMB(cp_) - 4) * SRSLTE_NRE + 2 * nof_ports; } } } else if (subframe == 5) { if (slot == 0) { - re = (SRSLTE_CP_NSYMB(cp) - nof_ctrl_symbols - 2) * SRSLTE_NRE; + re = (SRSLTE_CP_NSYMB(cp_) - nof_ctrl_symbols - 2) * SRSLTE_NRE; } } if ((nof_prb % 2) @@ -77,7 +81,7 @@ uint32_t ra_re_x_prb(uint32_t subframe, uint32_t slot, uint32_t prb_idx, uint32_ re += 2 * SRSLTE_NRE / 2; } else if (subframe == 0) { re += 4 * SRSLTE_NRE / 2 - nof_ports; - if (SRSLTE_CP_ISEXT(cp)) { + if (SRSLTE_CP_ISEXT(cp_)) { re -= nof_ports > 2 ? 2 : nof_ports; } } @@ -85,22 +89,27 @@ uint32_t ra_re_x_prb(uint32_t subframe, uint32_t slot, uint32_t prb_idx, uint32_ } // remove references - if (!skip_refs) { - switch (nof_ports) { - case 1: - case 2: - re -= 2 * (slot + 1) * nof_ports; - break; - case 4: - if (slot == 1) { - re -= 12; - } else { - re -= 4; - if (nof_ctrl_symbols == 1) { + if (skip_refs) { + if(sf_type == SRSLTE_SF_NORM){ + switch (nof_ports) { + case 1: + case 2: + re -= 2 * (slot + 1) * nof_ports; + break; + case 4: + if (slot == 1) { + re -= 12; + } else { re -= 4; + if (nof_ctrl_symbols == 1) { + re -= 4; + } } + break; } - break; + } + if(sf_type == SRSLTE_SF_MBSFN){ + re -= 6*(slot + 1); } } return re; @@ -278,23 +287,23 @@ uint32_t srslte_ra_dl_approx_nof_re(srslte_cell_t cell, uint32_t nof_prb, uint32 /* Computes the number of RE for each PRB in the prb_dist structure */ uint32_t srslte_ra_dl_grant_nof_re(srslte_ra_dl_grant_t *grant, srslte_cell_t cell, - uint32_t sf_idx, uint32_t nof_ctrl_symbols) + uint32_t sf_idx, uint32_t nof_ctrl_symbols) { uint32_t j, s; - // Compute number of RE per PRB uint32_t nof_re = 0; for (s = 0; s < 2; s++) { for (j = 0; j < cell.nof_prb; j++) { if (grant->prb_idx[s][j]) { - nof_re += ra_re_x_prb(sf_idx, s, j, - cell.nof_prb, cell.nof_ports, nof_ctrl_symbols, cell.cp); + nof_re += ra_re_x_prb(sf_idx, s, j, cell.nof_prb, cell.nof_ports, + nof_ctrl_symbols, cell.cp, grant->sf_type); } } - } + } return nof_re; } + /** Compute PRB allocation for Downlink as defined in 7.1.6 of 36.213 * Decode dci->type?_alloc to grant * This function only reads dci->type?_alloc and dci->alloc_type fields. @@ -432,7 +441,7 @@ int srslte_ra_dl_dci_to_grant_prb_allocation(srslte_ra_dl_dci_t *dci, srslte_ra_ return SRSLTE_SUCCESS; } -int dl_fill_ra_mcs(srslte_ra_mcs_t *mcs, uint32_t nprb) { +int srslte_dl_fill_ra_mcs(srslte_ra_mcs_t *mcs, uint32_t nprb) { uint32_t i_tbs = 0; int tbs = -1; if (mcs->idx < 10) { @@ -466,6 +475,52 @@ int dl_fill_ra_mcs(srslte_ra_mcs_t *mcs, uint32_t nprb) { return tbs; } +int srslte_dl_fill_ra_mcs_pmch(srslte_ra_mcs_t *mcs, uint32_t nprb) { + uint32_t i_tbs = 0; + int tbs = -1; + if (mcs->idx < 5) { + mcs->mod = SRSLTE_MOD_QPSK; + i_tbs = mcs->idx*2; + }else if (mcs->idx < 6) { + mcs->mod = SRSLTE_MOD_16QAM; + i_tbs = mcs->idx*2; + }else if (mcs->idx < 11) { + mcs->mod = SRSLTE_MOD_16QAM; + i_tbs = mcs->idx + 5; + }else if (mcs->idx < 20) { + mcs->mod = SRSLTE_MOD_64QAM; + i_tbs = mcs->idx + 5; + }else if (mcs->idx < 28) { + //mcs->mod = SRSLTE_MOD_256QAM; + i_tbs = mcs->idx + 5; + }else if (mcs->idx == 28) { + mcs->mod = SRSLTE_MOD_QPSK; + tbs = 0; + i_tbs = 0; + }else if (mcs->idx == 29) { + mcs->mod = SRSLTE_MOD_16QAM; + tbs = 0; + i_tbs = 0; + }else if (mcs->idx == 30) { + mcs->mod = SRSLTE_MOD_64QAM; + tbs = 0; + i_tbs = 0; + }else if (mcs->idx == 31) { + mcs->mod = SRSLTE_MOD_64QAM; + tbs = 0; + i_tbs = 0; + } + + + if (tbs == -1) { + tbs = srslte_ra_tbs_from_idx(i_tbs, nprb); + if (tbs >= 0) { + mcs->tbs = tbs; + } + } + return tbs; +} + /* Modulation order and transport block size determination 7.1.7 in 36.213 * This looks at DCI type, type of RNTI and reads fields dci->type?_alloc, dci->mcs_idx, * dci->dci_is_1a and dci->dci_is_1c @@ -496,21 +551,23 @@ static int dl_dci_to_grant_mcs(srslte_ra_dl_dci_t *dci, srslte_ra_dl_grant_t *gr grant->mcs[0].tbs = (uint32_t) tbs; } else { n_prb = grant->nof_prb; + grant->nof_tb = 0; if (dci->tb_en[0]) { grant->mcs[0].idx = dci->mcs_idx; - tbs = dl_fill_ra_mcs(&grant->mcs[0], n_prb); + tbs = srslte_dl_fill_ra_mcs(&grant->mcs[0], n_prb); if (tbs) { last_dl_tbs[dci->harq_process%8] = tbs; } else { // For mcs>=29, set last TBS received for this PID grant->mcs[0].tbs = last_dl_tbs[dci->harq_process%8]; } + grant->nof_tb++; } else { grant->mcs[0].tbs = 0; } if (dci->tb_en[1]) { grant->mcs[1].idx = dci->mcs_idx_1; - tbs = dl_fill_ra_mcs(&grant->mcs[1], n_prb); + tbs = srslte_dl_fill_ra_mcs(&grant->mcs[1], n_prb); if (tbs) { last_dl_tbs2[dci->harq_process%8] = tbs; } else { @@ -545,7 +602,11 @@ void srslte_ra_dl_grant_to_nbits(srslte_ra_dl_grant_t *grant, uint32_t cfi, srsl /* Compute number of RE for first transport block */ nbits[i].nof_re = srslte_ra_dl_grant_nof_re(grant, cell, sf_idx, cell.nof_prb < 10 ? (cfi + 1) : cfi); nbits[i].lstart = cell.nof_prb < 10 ? (cfi + 1) : cfi; - nbits[i].nof_symb = 2 * SRSLTE_CP_NSYMB(cell.cp) - nbits[0].lstart; + if (SRSLTE_SF_NORM == grant->sf_type) { + nbits[i].nof_symb = 2 * SRSLTE_CP_NSYMB(cell.cp) - nbits[0].lstart; + } else if (SRSLTE_SF_MBSFN == grant->sf_type) { + nbits[i].nof_symb = 2 * SRSLTE_CP_EXT_NSYMB - nbits[0].lstart; + } nbits[i].nof_bits = nbits[i].nof_re * grant->Qm[i]; } } @@ -554,7 +615,8 @@ void srslte_ra_dl_grant_to_nbits(srslte_ra_dl_grant_t *grant, uint32_t cfi, srsl /** 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) -{ +{ + grant->sf_type = SRSLTE_SF_NORM; bool crc_is_crnti = false; if (msg_rnti >= SRSLTE_CRNTI_START && msg_rnti <= SRSLTE_CRNTI_END) { crc_is_crnti = true; @@ -844,6 +906,4 @@ void srslte_ra_prb_fprint(FILE *f, srslte_ra_dl_grant_t *grant) { } } -} - - +} \ No newline at end of file diff --git a/lib/src/phy/phch/sch.c b/lib/src/phy/phch/sch.c index a44ced2d8..efdc38846 100644 --- a/lib/src/phy/phch/sch.c +++ b/lib/src/phy/phch/sch.c @@ -32,10 +32,10 @@ #include #include #include - #include "srslte/phy/phch/pdsch.h" #include "srslte/phy/phch/pusch.h" #include "srslte/phy/phch/sch.h" +#include "srslte/phy/phch/pmch.h" #include "srslte/phy/phch/uci.h" #include "srslte/phy/common/phy_common.h" #include "srslte/phy/utils/bit.h" diff --git a/lib/src/phy/phch/sequences.c b/lib/src/phy/phch/sequences.c index 23ac410c4..dc9e45a7f 100644 --- a/lib/src/phy/phch/sequences.c +++ b/lib/src/phy/phch/sequences.c @@ -78,3 +78,9 @@ int srslte_sequence_pusch(srslte_sequence_t *seq, uint16_t rnti, uint32_t nslot, int srslte_sequence_pucch(srslte_sequence_t *seq, uint16_t rnti, uint32_t nslot, uint32_t cell_id) { return srslte_sequence_LTE_pr(seq, 20, ((((nslot/2)+1)*(2*cell_id+1))<<16)+rnti); } + +int srslte_sequence_pmch(srslte_sequence_t *seq, uint32_t nslot, uint32_t mbsfn_id , uint32_t len){ + bzero(seq,sizeof(srslte_sequence_t)); + return srslte_sequence_LTE_pr(seq, len, (((nslot/2)<<9) + mbsfn_id)); + +} \ No newline at end of file diff --git a/lib/src/phy/ue/ue_dl.c b/lib/src/phy/ue/ue_dl.c index fd04a4c85..cd7aadb4c 100644 --- a/lib/src/phy/ue/ue_dl.c +++ b/lib/src/phy/ue/ue_dl.c @@ -64,9 +64,11 @@ int srslte_ue_dl_init(srslte_ue_dl_t *q, ret = SRSLTE_ERROR; bzero(q, sizeof(srslte_ue_dl_t)); - - q->pkt_errors = 0; - q->pkts_total = 0; + + q->pdsch_pkt_errors = 0; + q->pdsch_pkts_total = 0; + q->pmch_pkt_errors = 0; + q->pmch_pkts_total = 0; q->pending_ul_dci_rnti = 0; q->sample_offset = 0; q->nof_rx_antennas = nof_rx_antennas; @@ -75,6 +77,13 @@ int srslte_ue_dl_init(srslte_ue_dl_t *q, fprintf(stderr, "Error initiating FFT\n"); goto clean_exit; } + + if (srslte_ofdm_rx_init_mbsfn(&q->fft_mbsfn, SRSLTE_CP_EXT, max_prb)) { + fprintf(stderr, "Error initiating FFT for MBSFN subframes \n"); + goto clean_exit; + } + srslte_ofdm_set_non_mbsfn_region(&q->fft_mbsfn, 2); // Set a default to init + if (srslte_chest_dl_init(&q->chest, max_prb)) { fprintf(stderr, "Error initiating channel estimator\n"); goto clean_exit; @@ -97,6 +106,11 @@ int srslte_ue_dl_init(srslte_ue_dl_t *q, fprintf(stderr, "Error creating PDSCH object\n"); goto clean_exit; } + + if (srslte_pmch_init_multi(&q->pmch, max_prb, nof_rx_antennas)) { + fprintf(stderr, "Error creating PMCH object\n"); + goto clean_exit; + } for (int i = 0; i < SRSLTE_MAX_TB; i++) { q->softbuffers[i] = srslte_vec_malloc(sizeof(srslte_softbuffer_rx_t)); if (!q->softbuffers[i]) { @@ -151,12 +165,14 @@ clean_exit: void srslte_ue_dl_free(srslte_ue_dl_t *q) { if (q) { srslte_ofdm_rx_free(&q->fft); + srslte_ofdm_rx_free(&q->fft_mbsfn); srslte_chest_dl_free(&q->chest); srslte_regs_free(&q->regs); srslte_pcfich_free(&q->pcfich); srslte_phich_free(&q->phich); srslte_pdcch_free(&q->pdcch); srslte_pdsch_free(&q->pdsch); + srslte_pmch_free(&q->pmch); srslte_cfo_free(&q->sfo_correct); for (int i = 0; i < SRSLTE_MAX_TB; i++) { srslte_softbuffer_rx_free(q->softbuffers[i]); @@ -258,6 +274,34 @@ void srslte_ue_dl_set_rnti(srslte_ue_dl_t *q, uint16_t rnti) { q->current_rnti = rnti; } +/* Set the area ID on pmch and chest_dl to generate scrambling sequence and reference + * signals. + */ +int srslte_ue_dl_set_mbsfn_area_id(srslte_ue_dl_t *q, + uint16_t mbsfn_area_id) { + int ret = SRSLTE_ERROR_INVALID_INPUTS; + if(q != NULL) { + ret = SRSLTE_ERROR; + if(srslte_chest_dl_set_mbsfn_area_id(&q->chest, mbsfn_area_id)) { + fprintf(stderr, "Error setting MBSFN area ID \n"); + return ret; + } + if(srslte_pmch_set_area_id(&q->pmch, mbsfn_area_id)) { + fprintf(stderr, "Error setting MBSFN area ID \n"); + return ret; + } + q->current_mbsfn_area_id = mbsfn_area_id; + ret = SRSLTE_SUCCESS; + } + return ret; +} + +void srslte_ue_dl_set_non_mbsfn_region(srslte_ue_dl_t *q, + uint8_t non_mbsfn_region_length) { + srslte_ofdm_set_non_mbsfn_region(&q->fft_mbsfn, non_mbsfn_region_length); +} + + void srslte_ue_dl_reset(srslte_ue_dl_t *q) { for(int i = 0; i < SRSLTE_MAX_CODEWORDS; i++){ @@ -279,39 +323,60 @@ void srslte_ue_dl_set_sample_offset(srslte_ue_dl_t * q, float sample_offset) { */ int srslte_ue_dl_decode(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS], uint8_t *data[SRSLTE_MAX_CODEWORDS], uint32_t tm, uint32_t tti, bool acks[SRSLTE_MAX_CODEWORDS]) { - return srslte_ue_dl_decode_rnti(q, input, data, tm, tti, q->current_rnti, acks); + return srslte_ue_dl_decode_rnti(q, input, data, tm, tti, q->current_rnti, acks); } -int srslte_ue_dl_decode_fft_estimate(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS], uint32_t sf_idx, uint32_t *cfi) + +int srslte_ue_dl_decode_fft_estimate(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS], uint32_t sf_idx, uint32_t *cfi){ + + return srslte_ue_dl_decode_fft_estimate_mbsfn(q, input, sf_idx, cfi, SRSLTE_SF_NORM); +} + +int srslte_ue_dl_decode_fft_estimate_mbsfn(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS], uint32_t sf_idx, uint32_t *cfi, srslte_sf_t sf_type) { if (input && q && cfi && sf_idx < SRSLTE_NSUBFRAMES_X_FRAME) { /* Run FFT for all subframe data */ for (int j=0;jnof_rx_antennas;j++) { - srslte_ofdm_rx_sf(&q->fft, input[j], q->sf_symbols_m[j]); + if(sf_type == SRSLTE_SF_MBSFN ) { + srslte_ofdm_rx_sf(&q->fft_mbsfn, input[j], q->sf_symbols_m[j]); + }else{ + srslte_ofdm_rx_sf(&q->fft, input[j], q->sf_symbols_m[j]); + } /* Correct SFO multiplying by complex exponential in the time domain */ if (q->sample_offset) { - for (int i=0;i<2*SRSLTE_CP_NSYMB(q->cell.cp);i++) { - srslte_cfo_correct(&q->sfo_correct, + int nsym = (sf_type == SRSLTE_SF_MBSFN)?SRSLTE_CP_EXT_NSYMB:SRSLTE_CP_NSYMB(q->cell.cp); + for (int i=0;i<2*nsym;i++) { + srslte_cfo_correct(&q->sfo_correct, &q->sf_symbols_m[j][i*q->cell.nof_prb*SRSLTE_NRE], &q->sf_symbols_m[j][i*q->cell.nof_prb*SRSLTE_NRE], q->sample_offset / q->fft.symbol_sz); } } } - return srslte_ue_dl_decode_estimate(q, sf_idx, cfi); + return srslte_ue_dl_decode_estimate_mbsfn(q, sf_idx, cfi, sf_type); } else { return SRSLTE_ERROR_INVALID_INPUTS; } } - int srslte_ue_dl_decode_estimate(srslte_ue_dl_t *q, uint32_t sf_idx, uint32_t *cfi) { + + return srslte_ue_dl_decode_estimate_mbsfn(q, sf_idx, cfi, SRSLTE_SF_NORM); +} + + +int srslte_ue_dl_decode_estimate_mbsfn(srslte_ue_dl_t *q, uint32_t sf_idx, uint32_t *cfi, srslte_sf_t sf_type) { float cfi_corr; if (q && cfi && sf_idx < SRSLTE_NSUBFRAMES_X_FRAME) { /* Get channel estimates for each port */ - srslte_chest_dl_estimate_multi(&q->chest, q->sf_symbols_m, q->ce_m, sf_idx, q->nof_rx_antennas); + if(sf_type == SRSLTE_SF_MBSFN){ + srslte_chest_dl_estimate_multi_mbsfn(&q->chest, q->sf_symbols_m, q->ce_m, sf_idx, q->nof_rx_antennas, q->current_mbsfn_area_id); + }else{ + srslte_chest_dl_estimate_multi(&q->chest, q->sf_symbols_m, q->ce_m, sf_idx, q->nof_rx_antennas); + } + /* First decode PCFICH and obtain CFI */ if (srslte_pcfich_decode_multi(&q->pcfich, q->sf_symbols_m, q->ce_m, @@ -358,7 +423,11 @@ int srslte_ue_dl_cfg_grant(srslte_ue_dl_t *q, srslte_ra_dl_grant_t *grant, uint3 } } } - return srslte_pdsch_cfg_mimo(&q->pdsch_cfg, q->cell, grant, cfi, sf_idx, rvidx, mimo_type, pmi); + if(SRSLTE_SF_MBSFN == grant->sf_type) { + return srslte_pmch_cfg(&q->pmch_cfg, q->cell, grant, cfi, sf_idx); + } else { + return srslte_pdsch_cfg_mimo(&q->pdsch_cfg, q->cell, grant, cfi, sf_idx, rvidx, mimo_type, pmi); + } } int srslte_ue_dl_decode_rnti(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS], @@ -372,7 +441,7 @@ int srslte_ue_dl_decode_rnti(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS], uint32_t cfi; uint32_t sf_idx = tti%10; - if ((ret = srslte_ue_dl_decode_fft_estimate(q, input, sf_idx, &cfi)) < 0) { + if ((ret = srslte_ue_dl_decode_fft_estimate_mbsfn(q, input, sf_idx, &cfi, SRSLTE_SF_NORM)) < 0) { return ret; } @@ -476,12 +545,13 @@ int srslte_ue_dl_decode_rnti(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS], noise_estimate, rnti, data, acks); + for (int tb = 0; tb < SRSLTE_MAX_TB; tb++) { if (grant.tb_en[tb]) { if (!acks[tb]) { - q->pkt_errors++; + q->pdsch_pkt_errors++; } - q->pkts_total++; + q->pdsch_pkts_total++; } } @@ -510,6 +580,69 @@ int srslte_ue_dl_decode_rnti(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS], } } + + +int srslte_ue_dl_decode_mbsfn(srslte_ue_dl_t * q, + cf_t *input[SRSLTE_MAX_PORTS], + uint8_t *data, + uint32_t tti) +{ + srslte_ra_dl_grant_t grant; + int ret = SRSLTE_ERROR; + uint32_t cfi; + uint32_t sf_idx = tti%10; + + if ((ret = srslte_ue_dl_decode_fft_estimate_mbsfn(q, input, sf_idx, &cfi, SRSLTE_SF_MBSFN)) < 0) { + return ret; + } + + float noise_estimate = srslte_chest_dl_get_noise_estimate(&q->chest); + // Uncoment next line to do ZF by default in pdsch_ue example + //float noise_estimate = 0; + + grant.sf_type = SRSLTE_SF_MBSFN; + grant.nof_tb = 1; + grant.mcs[0].idx = 2; + + grant.nof_prb = q->pmch.cell.nof_prb; + srslte_dl_fill_ra_mcs(&grant.mcs[0], grant.nof_prb); + srslte_softbuffer_rx_reset_tbs(q->softbuffers[0], (uint32_t) grant.mcs[0].tbs); + for(int j = 0; j < 2; j++){ + for(int f = 0; f < grant.nof_prb; f++){ + grant.prb_idx[j][f] = true; + } + } + grant.Qm[0] = srslte_mod_bits_x_symbol(grant.mcs[0].mod); + + // redundancy version is set to 0 for the PMCH + if (srslte_ue_dl_cfg_grant(q, &grant, cfi, sf_idx, SRSLTE_PMCH_RV, SRSLTE_MIMO_TYPE_SINGLE_ANTENNA)) { + return SRSLTE_ERROR; + } + + if (q->pmch_cfg.grant.mcs[0].mod > 0 && q->pmch_cfg.grant.mcs[0].tbs >= 0) { + ret = srslte_pmch_decode_multi(&q->pmch, &q->pmch_cfg, q->softbuffers[0], + q->sf_symbols_m, q->ce_m, + noise_estimate, + q->current_mbsfn_area_id, data); + + if (ret == SRSLTE_ERROR) { + q->pmch_pkt_errors++; + } else if (ret == SRSLTE_ERROR_INVALID_INPUTS) { + fprintf(stderr, "Error calling srslte_pmch_decode()\n"); + } + } +printf("q->pmch_pkts_total %d \n", q->pmch_pkts_total); +printf("qq->pmch_pkt_errors %d \n", q->pmch_pkt_errors); + q->pmch_pkts_total++; + + if (ret == SRSLTE_SUCCESS) { + return q->pmch_cfg.grant.mcs[0].tbs; + } else { + return 0; + } +} + + /* Compute the Rank Indicator (RI) and Precoder Matrix Indicator (PMI) by computing the Signal to Interference plus * Noise Ratio (SINR), valid for TM4 */ int srslte_ue_dl_ri_pmi_select(srslte_ue_dl_t *q, uint8_t *ri, uint8_t *pmi, float *current_sinr) { diff --git a/lib/src/phy/ue/ue_sync.c b/lib/src/phy/ue/ue_sync.c index 3f5b131eb..f121c5bac 100644 --- a/lib/src/phy/ue/ue_sync.c +++ b/lib/src/phy/ue/ue_sync.c @@ -676,6 +676,7 @@ int srslte_ue_sync_zerocopy_multi(srslte_ue_sync_t *q, cf_t *input_buffer[SRSLTE /* Track PSS/SSS around the expected PSS position * In tracking phase, the subframe carrying the PSS is always the last one of the frame */ + switch(srslte_sync_find(&q->strack, input_buffer[0], q->frame_len - q->sf_len/2 - q->fft_size - q->strack.max_offset/2, &track_idx))