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/cell_measurement.c b/lib/examples/cell_measurement.c index 143ee784e..37796682f 100644 --- a/lib/examples/cell_measurement.c +++ b/lib/examples/cell_measurement.c @@ -335,10 +335,9 @@ int main(int argc, char **argv) { fprintf(stderr, "Error decoding UE DL\n");fflush(stdout); return -1; } else if (n == 0) { - printf("CFO: %+6.4f kHz, SFO: %+6.4f kHz, NOI: %.2f, PDCCH-Det: %.3f\r", + printf("CFO: %+6.4f kHz, SFO: %+6.4f kHz, PDCCH-Det: %.3f\r", srslte_ue_sync_get_cfo(&ue_sync)/1000, srslte_ue_sync_get_sfo(&ue_sync)/1000, - srslte_pdsch_average_noi(&ue_dl.pdsch), - (float) ue_dl.nof_detected/nof_trials); + (float) ue_dl.nof_detected/nof_trials); nof_trials++; } else { printf("Decoded SIB1. Payload: "); 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..9d7282cdd 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; + int32_t 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 %d]\n", args->mbsfn_area_id); + printf("\t-N Non-MBSFN region [Default %d]\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/common/common.h b/lib/include/srslte/common/common.h index ad88d9dcc..7156fbfc9 100644 --- a/lib/include/srslte/common/common.h +++ b/lib/include/srslte/common/common.h @@ -50,7 +50,7 @@ #define SRSLTE_MAX_BUFFER_SIZE_BYTES 12756 #define SRSLTE_BUFFER_HEADER_OFFSET 1024 -#define SRSLTE_BUFFER_POOL_LOG_ENABLED +//#define SRSLTE_BUFFER_POOL_LOG_ENABLED #ifdef SRSLTE_BUFFER_POOL_LOG_ENABLED #define pool_allocate (pool->allocate(__FUNCTION__)) diff --git a/lib/include/srslte/common/interfaces_common.h b/lib/include/srslte/common/interfaces_common.h index d919d9fe5..a027b6230 100644 --- a/lib/include/srslte/common/interfaces_common.h +++ b/lib/include/srslte/common/interfaces_common.h @@ -71,8 +71,9 @@ public: /* Timer services with ms resolution. * timer_id must be lower than MAC_NOF_UPPER_TIMERS */ - virtual timers::timer* get(uint32_t timer_id) = 0; - virtual uint32_t get_unique_id() = 0; + virtual timers::timer* timer_get(uint32_t timer_id) = 0; + virtual void timer_release_id(uint32_t timer_id) = 0; + virtual uint32_t timer_get_unique_id() = 0; }; class read_pdu_interface diff --git a/lib/include/srslte/common/metrics_hub.h b/lib/include/srslte/common/metrics_hub.h index 9575347a2..7ea3c3190 100644 --- a/lib/include/srslte/common/metrics_hub.h +++ b/lib/include/srslte/common/metrics_hub.h @@ -24,7 +24,7 @@ template class metrics_listener { public: - virtual void set_metrics(metrics_t &m) = 0; + virtual void set_metrics(metrics_t &m, float report_period_secs=1.0) = 0; }; template @@ -38,6 +38,7 @@ public: } void stop() { thread_cancel(); + wait_thread_finish(); } void add_listener(metrics_listener *listener) { @@ -46,7 +47,8 @@ public: private: void run_period() { - metrics_t metric; + metrics_t metric; + bzero(&metric, sizeof(metrics_t)); m->get_metrics(metric); for (uint32_t i=0;iset_metrics(metric); diff --git a/lib/include/srslte/common/timers.h b/lib/include/srslte/common/timers.h index 377df7b1d..a8563af37 100644 --- a/lib/include/srslte/common/timers.h +++ b/lib/include/srslte/common/timers.h @@ -74,7 +74,7 @@ public: } void step() { if (running) { - counter++; + counter++; if (is_expired()) { running = false; if (callback) { @@ -145,7 +145,7 @@ public: } uint32_t get_unique_id() { if (nof_used_timers >= nof_timers) { - fprintf(stderr, "Error getting uinque timer id: no more timers available\n"); + fprintf(stderr, "Error getting unique timer id: no more timers available\n"); return 0; } else { while(used_timers[next_timer]) { diff --git a/lib/include/srslte/interfaces/enb_interfaces.h b/lib/include/srslte/interfaces/enb_interfaces.h index ed2478896..9c85814f8 100644 --- a/lib/include/srslte/interfaces/enb_interfaces.h +++ b/lib/include/srslte/interfaces/enb_interfaces.h @@ -244,7 +244,7 @@ public: class gtpu_interface_rrc { public: - virtual void add_bearer(uint16_t rnti, uint32_t lcid, uint32_t teid_out, uint32_t *teid_in) = 0; + virtual void add_bearer(uint16_t rnti, uint32_t lcid, uint32_t addr, uint32_t teid_out, uint32_t *teid_in) = 0; virtual void rem_bearer(uint16_t rnti, uint32_t lcid) = 0; virtual void rem_user(uint16_t rnti) = 0; }; diff --git a/lib/include/srslte/interfaces/enb_metrics_interface.h b/lib/include/srslte/interfaces/enb_metrics_interface.h index 6893b4c2f..ee00e3453 100644 --- a/lib/include/srslte/interfaces/enb_metrics_interface.h +++ b/lib/include/srslte/interfaces/enb_metrics_interface.h @@ -32,7 +32,7 @@ #include "upper/common_enb.h" #include "upper/s1ap_metrics.h" #include "upper/rrc_metrics.h" -#include "srslte/upper/gw_metrics.h" +#include "../../../../srsue/hdr/upper/gw_metrics.h" #include "srslte/upper/rlc_metrics.h" #include "mac/mac_metrics.h" #include "phy/phy_metrics.h" diff --git a/lib/include/srslte/interfaces/ue_interfaces.h b/lib/include/srslte/interfaces/ue_interfaces.h index cf8a7c861..2c29bd4d4 100644 --- a/lib/include/srslte/interfaces/ue_interfaces.h +++ b/lib/include/srslte/interfaces/ue_interfaces.h @@ -98,6 +98,7 @@ class nas_interface_rrc { public: virtual bool is_attached() = 0; + virtual bool is_attaching() = 0; virtual void notify_connection_setup() = 0; virtual void write_pdu(uint32_t lcid, srslte::byte_buffer_t *pdu) = 0; virtual uint32_t get_ul_count() = 0; @@ -113,6 +114,13 @@ public: virtual void deattach_request() = 0; }; +// NAS interface for UE +class nas_interface_gw +{ +public: + virtual void attach_request() = 0; +}; + // RRC interface for MAC class rrc_interface_mac_common { @@ -172,6 +180,7 @@ class pdcp_interface_gw { public: virtual void write_sdu(uint32_t lcid, srslte::byte_buffer_t *sdu) = 0; + virtual bool is_drb_enabled(uint32_t lcid) = 0; }; // PDCP interface for RRC @@ -295,11 +304,11 @@ public: } mac_grant_t; typedef struct { - bool decode_enabled; + bool decode_enabled[SRSLTE_MAX_TB]; int rv[SRSLTE_MAX_TB]; uint16_t rnti; bool generate_ack; - bool default_ack; + bool default_ack[SRSLTE_MAX_TB]; // If non-null, called after tb_decoded_ok to determine if ack needs to be sent bool (*generate_ack_callback)(void*); void *generate_ack_callback_arg; @@ -518,19 +527,18 @@ public: /* Cell search and selection procedures */ virtual void cell_search_start() = 0; + virtual void cell_search_stop() = 0; virtual void cell_search_next() = 0; virtual bool cell_select(uint32_t earfcn, srslte_cell_t cell) = 0; - virtual bool sync_stop() = 0; /* Is the PHY downlink synchronized? */ virtual bool sync_status() = 0; + virtual void sync_reset() = 0; /* Configure UL using parameters written with set_param() */ virtual void configure_ul_params(bool pregen_disabled = false) = 0; virtual void reset() = 0; - - virtual void resync_sfn() = 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..7c3166e5c 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; @@ -88,6 +88,8 @@ typedef struct SRSLTE_API { float sss_signal5[SRSLTE_SSS_LEN]; float tx_amp; + + uint8_t tmp[1024*128]; } srslte_enb_dl_t; @@ -176,5 +178,12 @@ SRSLTE_API int srslte_enb_dl_put_pdcch_ul(srslte_enb_dl_t *q, uint16_t rnti, uint32_t sf_idx); +SRSLTE_API void srslte_enb_dl_save_signal(srslte_enb_dl_t *q, + srslte_softbuffer_tx_t *softbuffer, + uint8_t *data, + uint32_t tti, + uint32_t rv_idx, + uint16_t rnti, + uint32_t cfi); #endif diff --git a/lib/include/srslte/phy/fec/turbodecoder.h b/lib/include/srslte/phy/fec/turbodecoder.h index d42a20ae6..ac05422bc 100644 --- a/lib/include/srslte/phy/fec/turbodecoder.h +++ b/lib/include/srslte/phy/fec/turbodecoder.h @@ -50,20 +50,14 @@ #define SRSLTE_TCOD_MAX_LEN_CODED (SRSLTE_TCOD_RATE*SRSLTE_TCOD_MAX_LEN_CB+SRSLTE_TCOD_TOTALTAIL) #include "srslte/phy/fec/turbodecoder_gen.h" - -#ifdef LV_HAVE_SSE #include "srslte/phy/fec/turbodecoder_simd.h" -#else -#define SRSLTE_TDEC_NPAR 1 -#endif typedef struct SRSLTE_API { -#ifdef LV_HAVE_SSE - srslte_tdec_simd_t tdec_simd; -#else - float *input_conv; - srslte_tdec_gen_t tdec_gen; -#endif + float *input_conv; + union { + srslte_tdec_simd_t tdec_simd; + srslte_tdec_gen_t tdec_gen; + }; } srslte_tdec_t; SRSLTE_API int srslte_tdec_init(srslte_tdec_t * h, @@ -80,7 +74,7 @@ SRSLTE_API int srslte_tdec_reset_cb(srslte_tdec_t * h, SRSLTE_API int srslte_tdec_get_nof_iterations_cb(srslte_tdec_t * h, uint32_t cb_idx); -SRSLTE_API int srslte_tdec_get_nof_parallel(srslte_tdec_t * h); +SRSLTE_API uint32_t srslte_tdec_get_nof_parallel(srslte_tdec_t * h); SRSLTE_API void srslte_tdec_iteration(srslte_tdec_t * h, int16_t* input, @@ -101,15 +95,15 @@ SRSLTE_API int srslte_tdec_run_all(srslte_tdec_t * h, uint32_t long_cb); SRSLTE_API void srslte_tdec_iteration_par(srslte_tdec_t * h, - int16_t* input[SRSLTE_TDEC_NPAR], + int16_t* input[SRSLTE_TDEC_MAX_NPAR], uint32_t long_cb); SRSLTE_API void srslte_tdec_decision_par(srslte_tdec_t * h, - uint8_t *output[SRSLTE_TDEC_NPAR], + uint8_t *output[SRSLTE_TDEC_MAX_NPAR], uint32_t long_cb); SRSLTE_API void srslte_tdec_decision_byte_par(srslte_tdec_t * h, - uint8_t *output[SRSLTE_TDEC_NPAR], + uint8_t *output[SRSLTE_TDEC_MAX_NPAR], uint32_t long_cb); SRSLTE_API void srslte_tdec_decision_byte_par_cb(srslte_tdec_t * h, @@ -118,8 +112,8 @@ SRSLTE_API void srslte_tdec_decision_byte_par_cb(srslte_tdec_t * h, uint32_t long_cb); SRSLTE_API int srslte_tdec_run_all_par(srslte_tdec_t * h, - int16_t * input[SRSLTE_TDEC_NPAR], - uint8_t *output[SRSLTE_TDEC_NPAR], + int16_t * input[SRSLTE_TDEC_MAX_NPAR], + uint8_t *output[SRSLTE_TDEC_MAX_NPAR], uint32_t nof_iterations, uint32_t long_cb); diff --git a/lib/include/srslte/phy/fec/turbodecoder_simd.h b/lib/include/srslte/phy/fec/turbodecoder_simd.h index d7bc284d2..a899a5964 100644 --- a/lib/include/srslte/phy/fec/turbodecoder_simd.h +++ b/lib/include/srslte/phy/fec/turbodecoder_simd.h @@ -43,23 +43,8 @@ #include "srslte/phy/fec/tc_interl.h" #include "srslte/phy/fec/cbsegm.h" -//#define ENABLE_SIMD_INTER - -// The constant SRSLTE_TDEC_NPAR defines the maximum number of parallel CB supported by all SIMD decoders -#ifdef ENABLE_SIMD_INTER - #include "srslte/phy/fec/turbodecoder_simd_inter.h" - #ifdef LV_HAVE_AVX2 - #define SRSLTE_TDEC_NPAR_INTRA 2 - #else - #define SRSLTE_TDEC_NPAR_INTRA 1 - #endif -#else - #ifdef LV_HAVE_AVX2 - #define SRSLTE_TDEC_NPAR 2 - #else - #define SRSLTE_TDEC_NPAR 1 - #endif -#endif +// Define maximum number of CB decoded in parallel (2 for AVX2) +#define SRSLTE_TDEC_MAX_NPAR 2 #define SRSLTE_TCOD_RATE 3 #define SRSLTE_TCOD_TOTALTAIL 12 @@ -80,18 +65,18 @@ typedef struct SRSLTE_API { map_gen_t dec; - int16_t *app1[SRSLTE_TDEC_NPAR]; - int16_t *app2[SRSLTE_TDEC_NPAR]; - int16_t *ext1[SRSLTE_TDEC_NPAR]; - int16_t *ext2[SRSLTE_TDEC_NPAR]; - int16_t *syst[SRSLTE_TDEC_NPAR]; - int16_t *parity0[SRSLTE_TDEC_NPAR]; - int16_t *parity1[SRSLTE_TDEC_NPAR]; + int16_t *app1[SRSLTE_TDEC_MAX_NPAR]; + int16_t *app2[SRSLTE_TDEC_MAX_NPAR]; + int16_t *ext1[SRSLTE_TDEC_MAX_NPAR]; + int16_t *ext2[SRSLTE_TDEC_MAX_NPAR]; + int16_t *syst[SRSLTE_TDEC_MAX_NPAR]; + int16_t *parity0[SRSLTE_TDEC_MAX_NPAR]; + int16_t *parity1[SRSLTE_TDEC_MAX_NPAR]; int cb_mask; int current_cbidx; srslte_tc_interl_t interleaver[SRSLTE_NOF_TC_CB_SIZES]; - int n_iter[SRSLTE_TDEC_NPAR]; + int n_iter[SRSLTE_TDEC_MAX_NPAR]; } srslte_tdec_simd_t; SRSLTE_API int srslte_tdec_simd_init(srslte_tdec_simd_t * h, @@ -103,6 +88,8 @@ SRSLTE_API void srslte_tdec_simd_free(srslte_tdec_simd_t * h); SRSLTE_API int srslte_tdec_simd_reset(srslte_tdec_simd_t * h, uint32_t long_cb); +SRSLTE_API + SRSLTE_API int srslte_tdec_simd_get_nof_iterations_cb(srslte_tdec_simd_t * h, uint32_t cb_idx); @@ -110,15 +97,15 @@ SRSLTE_API int srslte_tdec_simd_reset_cb(srslte_tdec_simd_t * h, uint32_t cb_idx); SRSLTE_API void srslte_tdec_simd_iteration(srslte_tdec_simd_t * h, - int16_t * input[SRSLTE_TDEC_NPAR], + int16_t * input[SRSLTE_TDEC_MAX_NPAR], uint32_t long_cb); SRSLTE_API void srslte_tdec_simd_decision(srslte_tdec_simd_t * h, - uint8_t *output[SRSLTE_TDEC_NPAR], + uint8_t *output[SRSLTE_TDEC_MAX_NPAR], uint32_t long_cb); SRSLTE_API void srslte_tdec_simd_decision_byte(srslte_tdec_simd_t * h, - uint8_t *output[SRSLTE_TDEC_NPAR], + uint8_t *output[SRSLTE_TDEC_MAX_NPAR], uint32_t long_cb); SRSLTE_API void srslte_tdec_simd_decision_byte_cb(srslte_tdec_simd_t * h, @@ -127,8 +114,8 @@ SRSLTE_API void srslte_tdec_simd_decision_byte_cb(srslte_tdec_simd_t * h, uint32_t long_cb); SRSLTE_API int srslte_tdec_simd_run_all(srslte_tdec_simd_t * h, - int16_t * input[SRSLTE_TDEC_NPAR], - uint8_t *output[SRSLTE_TDEC_NPAR], + int16_t * input[SRSLTE_TDEC_MAX_NPAR], + uint8_t *output[SRSLTE_TDEC_MAX_NPAR], uint32_t nof_iterations, uint32_t long_cb); diff --git a/lib/include/srslte/phy/fec/turbodecoder_simd_inter.h b/lib/include/srslte/phy/fec/turbodecoder_simd_inter.h index 402faa314..c80785809 100644 --- a/lib/include/srslte/phy/fec/turbodecoder_simd_inter.h +++ b/lib/include/srslte/phy/fec/turbodecoder_simd_inter.h @@ -49,9 +49,9 @@ #include "srslte/phy/fec/cbsegm.h" #if LV_HAVE_AVX2 - #define SRSLTE_TDEC_NPAR 16 + #define SRSLTE_TDEC_MAX_NPAR 16 #else - #define SRSLTE_TDEC_NPAR 8 + #define SRSLTE_TDEC_MAX_NPAR 8 #endif @@ -71,7 +71,7 @@ typedef struct SRSLTE_API { int current_cbidx; uint32_t current_long_cb; srslte_tc_interl_t interleaver[SRSLTE_NOF_TC_CB_SIZES]; - int n_iter[SRSLTE_TDEC_NPAR]; + int n_iter[SRSLTE_TDEC_MAX_NPAR]; } srslte_tdec_simd_inter_t; SRSLTE_API int srslte_tdec_simd_inter_init(srslte_tdec_simd_inter_t * h, @@ -90,17 +90,17 @@ SRSLTE_API int srslte_tdec_simd_inter_reset_cb(srslte_tdec_simd_inter_t * h, uint32_t cb_idx); SRSLTE_API void srslte_tdec_simd_inter_iteration(srslte_tdec_simd_inter_t * h, - int16_t * input[SRSLTE_TDEC_NPAR], + int16_t * input[SRSLTE_TDEC_MAX_NPAR], uint32_t nof_cb, uint32_t long_cb); SRSLTE_API void srslte_tdec_simd_inter_decision(srslte_tdec_simd_inter_t * h, - uint8_t *output[SRSLTE_TDEC_NPAR], + uint8_t *output[SRSLTE_TDEC_MAX_NPAR], uint32_t nof_cb, uint32_t long_cb); SRSLTE_API void srslte_tdec_simd_inter_decision_byte(srslte_tdec_simd_inter_t * h, - uint8_t *output[SRSLTE_TDEC_NPAR], + uint8_t *output[SRSLTE_TDEC_MAX_NPAR], uint32_t nof_cb, uint32_t long_cb); @@ -110,8 +110,8 @@ SRSLTE_API void srslte_tdec_simd_inter_decision_byte_cb(srslte_tdec_simd_inter_t uint32_t long_cb); SRSLTE_API int srslte_tdec_simd_inter_run_all(srslte_tdec_simd_inter_t * h, - int16_t *input[SRSLTE_TDEC_NPAR], - uint8_t *output[SRSLTE_TDEC_NPAR], + int16_t *input[SRSLTE_TDEC_MAX_NPAR], + uint8_t *output[SRSLTE_TDEC_MAX_NPAR], uint32_t nof_iterations, uint32_t nof_cb, uint32_t long_cb); diff --git a/lib/include/srslte/phy/phch/pdsch.h b/lib/include/srslte/phy/phch/pdsch.h index 7ef2d9b3d..459bcc209 100644 --- a/lib/include/srslte/phy/phch/pdsch.h +++ b/lib/include/srslte/phy/phch/pdsch.h @@ -58,7 +58,8 @@ typedef struct SRSLTE_API { srslte_cell_t cell; uint32_t nof_rx_antennas; - + uint32_t last_nof_iterations[SRSLTE_MAX_CODEWORDS]; + uint32_t max_re; uint16_t ue_rnti; @@ -149,10 +150,12 @@ SRSLTE_API int srslte_pdsch_cn_compute(srslte_pdsch_t *q, uint32_t nof_ce, float *cn); -SRSLTE_API void srslte_pdsch_set_max_noi(srslte_pdsch_t *q, uint32_t max_iter); +SRSLTE_API void srslte_pdsch_set_max_noi(srslte_pdsch_t *q, + uint32_t max_iter); -SRSLTE_API float srslte_pdsch_average_noi(srslte_pdsch_t *q); +SRSLTE_API float srslte_pdsch_last_noi(srslte_pdsch_t *q); -SRSLTE_API uint32_t srslte_pdsch_last_noi(srslte_pdsch_t *q); +SRSLTE_API uint32_t srslte_pdsch_last_noi_cw(srslte_pdsch_t *q, + uint32_t cw_idx); #endif diff --git a/lib/include/srslte/phy/phch/phich.h b/lib/include/srslte/phy/phch/phich.h index f560fdc80..0645e22b1 100644 --- a/lib/include/srslte/phy/phch/phich.h +++ b/lib/include/srslte/phy/phch/phich.h @@ -101,8 +101,8 @@ SRSLTE_API void srslte_phich_calc(srslte_phich_t *q, uint32_t *nseq); SRSLTE_API int srslte_phich_decode(srslte_phich_t *q, - cf_t *slot_symbols, - cf_t *ce[SRSLTE_MAX_PORTS], + cf_t *slot_symbols[SRSLTE_MAX_PORTS], + cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], float noise_estimate, uint32_t ngroup, uint32_t nseq, @@ -110,16 +110,6 @@ SRSLTE_API int srslte_phich_decode(srslte_phich_t *q, uint8_t *ack, float *distance); -SRSLTE_API int srslte_phich_decode_multi(srslte_phich_t *q, - cf_t *slot_symbols[SRSLTE_MAX_PORTS], - cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], - float noise_estimate, - uint32_t ngroup, - uint32_t nseq, - uint32_t nsubframe, - uint8_t *ack, - float *distance); - SRSLTE_API int srslte_phich_encode(srslte_phich_t *q, uint8_t ack, uint32_t ngroup, 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..e8066e4cd 100644 --- a/lib/include/srslte/phy/phch/sch.h +++ b/lib/include/srslte/phy/phch/sch.h @@ -56,10 +56,9 @@ /* DL-SCH AND UL-SCH common functions */ typedef struct SRSLTE_API { - uint32_t max_iterations; - uint32_t nof_iterations; - float average_nof_iterations; - + uint32_t max_iterations; + uint32_t nof_iterations; + /* buffers */ uint8_t *cb_in; uint8_t *parity_bits; @@ -77,6 +76,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); @@ -86,8 +86,6 @@ SRSLTE_API void srslte_sch_free(srslte_sch_t *q); SRSLTE_API void srslte_sch_set_max_noi(srslte_sch_t *q, uint32_t max_iterations); -SRSLTE_API float srslte_sch_average_noi(srslte_sch_t *q); - SRSLTE_API uint32_t srslte_sch_last_noi(srslte_sch_t *q); SRSLTE_API int srslte_dlsch_encode(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/include/srslte/radio/radio.h b/lib/include/srslte/radio/radio.h index 30d274f44..329dd825a 100644 --- a/lib/include/srslte/radio/radio.h +++ b/lib/include/srslte/radio/radio.h @@ -57,8 +57,7 @@ namespace srslte { bzero(&end_of_burst_time, sizeof(srslte_timestamp_t)); bzero(zeros, burst_preamble_max_samples*sizeof(cf_t)); - sf_len = 0; - burst_preamble_sec = 0; + burst_preamble_sec = 0; is_start_of_burst = false; burst_preamble_samples = 0; burst_preamble_time_rounded = 0; @@ -72,13 +71,12 @@ namespace srslte { rx_freq = 0; trace_enabled = false; tti = 0; - agc_enabled = false; - offset = 0; - + agc_enabled = false; }; bool init(char *args = NULL, char *devname = NULL); - void stop(); + void stop(); + void reset(); bool start_agc(bool tx_gain_same_rx); void set_burst_preamble(double preamble_us); @@ -123,9 +121,8 @@ namespace srslte { void stop_rx(); void set_tti(uint32_t tti); - void tx_offset(int offset); - void set_tti_len(uint32_t sf_len); - uint32_t get_tti_len(); + + bool is_first_of_burst(); void register_error_handler(srslte_rf_error_handler_t h); @@ -168,8 +165,10 @@ namespace srslte { bool trace_enabled; uint32_t tti; bool agc_enabled; - int offset; - uint32_t sf_len; + + char saved_args[128]; + char saved_devname[128]; + }; } diff --git a/lib/include/srslte/upper/pdcp.h b/lib/include/srslte/upper/pdcp.h index abdbeeaea..ce6ece151 100644 --- a/lib/include/srslte/upper/pdcp.h +++ b/lib/include/srslte/upper/pdcp.h @@ -50,6 +50,9 @@ public: uint8_t direction_); void stop(); + // GW interface + bool is_drb_enabled(uint32_t lcid); + // RRC interface void reset(); void write_sdu(uint32_t lcid, byte_buffer_t *sdu); diff --git a/lib/include/srslte/upper/rlc_am.h b/lib/include/srslte/upper/rlc_am.h index a92c9a0ad..afbd18544 100644 --- a/lib/include/srslte/upper/rlc_am.h +++ b/lib/include/srslte/upper/rlc_am.h @@ -78,6 +78,7 @@ public: mac_interface_timers *mac_timers); void configure(srslte_rlc_config_t cnfg); void reset(); + void stop(); void empty_queue(); rlc_mode_t get_mode(); diff --git a/lib/include/srslte/upper/rlc_common.h b/lib/include/srslte/upper/rlc_common.h index c68e3e6f3..494cc6174 100644 --- a/lib/include/srslte/upper/rlc_common.h +++ b/lib/include/srslte/upper/rlc_common.h @@ -158,6 +158,7 @@ public: srslte::mac_interface_timers *mac_timers_) = 0; virtual void configure(srslte_rlc_config_t cnfg) = 0; virtual void reset() = 0; + virtual void stop() = 0; virtual void empty_queue() = 0; virtual rlc_mode_t get_mode() = 0; diff --git a/lib/include/srslte/upper/rlc_entity.h b/lib/include/srslte/upper/rlc_entity.h index 651af72fb..e9c41fa30 100644 --- a/lib/include/srslte/upper/rlc_entity.h +++ b/lib/include/srslte/upper/rlc_entity.h @@ -56,6 +56,7 @@ public: void configure(srslte_rlc_config_t cnfg); void reset(); + void stop(); void empty_queue(); bool active(); diff --git a/lib/include/srslte/upper/rlc_tm.h b/lib/include/srslte/upper/rlc_tm.h index def968a92..4a55e33dd 100644 --- a/lib/include/srslte/upper/rlc_tm.h +++ b/lib/include/srslte/upper/rlc_tm.h @@ -48,6 +48,7 @@ public: mac_interface_timers *mac_timers); void configure(srslte_rlc_config_t cnfg); void reset(); + void stop(); void empty_queue(); rlc_mode_t get_mode(); diff --git a/lib/include/srslte/upper/rlc_um.h b/lib/include/srslte/upper/rlc_um.h index 4325bd029..0a2469a7c 100644 --- a/lib/include/srslte/upper/rlc_um.h +++ b/lib/include/srslte/upper/rlc_um.h @@ -58,6 +58,7 @@ public: mac_interface_timers *mac_timers_); void configure(srslte_rlc_config_t cnfg); void reset(); + void stop(); void empty_queue(); rlc_mode_t get_mode(); @@ -124,7 +125,8 @@ private: * Timers * Ref: 3GPP TS 36.322 v10.0.0 Section 7 ***************************************************************************/ - uint32_t reordering_timeout_id; + srslte::timers::timer *reordering_timer; + uint32_t reordering_timer_id; bool pdu_lost; 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..2ba179399 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]) { @@ -336,3 +336,33 @@ int srslte_enb_dl_put_pdsch(srslte_enb_dl_t *q, srslte_ra_dl_grant_t *grant, srs } return SRSLTE_SUCCESS; } + + + +void srslte_enb_dl_save_signal(srslte_enb_dl_t *q, srslte_softbuffer_tx_t *softbuffer, uint8_t *data, uint32_t tti, uint32_t rv_idx, uint16_t rnti, uint32_t cfi) +{ + char tmpstr[64]; + + snprintf(tmpstr,64,"output/sf_symbols_%d",tti); + srslte_vec_save_file(tmpstr, q->sf_symbols[0], SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp)*sizeof(cf_t)); + + snprintf(tmpstr,64,"output/e_%d",tti); + srslte_bit_unpack_vector(q->pdsch.e[0], q->tmp, q->pdsch_cfg.nbits[0].nof_bits); + srslte_vec_save_file(tmpstr, q->tmp, q->pdsch_cfg.nbits[0].nof_bits*sizeof(uint8_t)); + + /* + int cb_len = q->pdsch_cfg.cb_segm[0].K1; + for (int i=0;ipdsch_cfg.cb_segm[0].C;i++) { + snprintf(tmpstr,64,"output/rmout_%d_%d",i,tti); + srslte_bit_unpack_vector(softbuffer->buffer_b[i], q->tmp, (3*cb_len+12)); + srslte_vec_save_file(tmpstr, q->tmp, (3*cb_len+12)*sizeof(uint8_t)); + }*/ + + snprintf(tmpstr,64,"output/data_%d",tti); + srslte_bit_unpack_vector(data, q->tmp, q->pdsch_cfg.grant.mcs[0].tbs); + srslte_vec_save_file(tmpstr, q->tmp, q->pdsch_cfg.grant.mcs[0].tbs*sizeof(uint8_t)); + + //printf("Saved files for tti=%d, sf=%d, cfi=%d, mcs=%d, tbs=%d, rv=%d, rnti=0x%x\n", tti, tti%10, cfi, + // q->pdsch_cfg.grant.mcs[0].idx, q->pdsch_cfg.grant.mcs[0].tbs, rv_idx, rnti); +} + diff --git a/lib/src/phy/fec/test/turbodecoder_test.c b/lib/src/phy/fec/test/turbodecoder_test.c index df1d4b884..aeac21433 100644 --- a/lib/src/phy/fec/test/turbodecoder_test.c +++ b/lib/src/phy/fec/test/turbodecoder_test.c @@ -117,7 +117,7 @@ int main(int argc, char **argv) { float *llr; short *llr_s; uint8_t *llr_c; - uint8_t *data_tx, *data_rx, *data_rx_bytes[SRSLTE_TDEC_NPAR], *symbols; + uint8_t *data_tx, *data_rx, *data_rx_bytes[SRSLTE_TDEC_MAX_NPAR], *symbols; uint32_t i, j; float var[SNR_POINTS]; uint32_t snr_points; @@ -159,7 +159,7 @@ int main(int argc, char **argv) { perror("malloc"); exit(-1); } - for (int cb=0;cbtdec_simd, SRSLTE_TDEC_NPAR, max_long_cb); + return srslte_tdec_simd_init(&h->tdec_simd, SRSLTE_TDEC_MAX_NPAR, max_long_cb); #else h->input_conv = srslte_vec_malloc(sizeof(float) * (3*max_long_cb+12)); if (!h->input_conv) { @@ -91,7 +91,7 @@ int srslte_tdec_get_nof_iterations_cb(srslte_tdec_t * h, uint32_t cb_idx) #endif } -void srslte_tdec_iteration_par(srslte_tdec_t * h, int16_t* input[SRSLTE_TDEC_NPAR], uint32_t long_cb) { +void srslte_tdec_iteration_par(srslte_tdec_t * h, int16_t* input[SRSLTE_TDEC_MAX_NPAR], uint32_t long_cb) { #ifdef LV_HAVE_SSE srslte_tdec_simd_iteration(&h->tdec_simd, input, long_cb); #else @@ -101,12 +101,12 @@ void srslte_tdec_iteration_par(srslte_tdec_t * h, int16_t* input[SRSLTE_TDEC_NPA } void srslte_tdec_iteration(srslte_tdec_t * h, int16_t* input, uint32_t long_cb) { - int16_t *input_par[SRSLTE_TDEC_NPAR]; + int16_t *input_par[SRSLTE_TDEC_MAX_NPAR]; input_par[0] = input; return srslte_tdec_iteration_par(h, input_par, long_cb); } -void srslte_tdec_decision_par(srslte_tdec_t * h, uint8_t *output[SRSLTE_TDEC_NPAR], uint32_t long_cb) { +void srslte_tdec_decision_par(srslte_tdec_t * h, uint8_t *output[SRSLTE_TDEC_MAX_NPAR], uint32_t long_cb) { #ifdef LV_HAVE_SSE return srslte_tdec_simd_decision(&h->tdec_simd, output, long_cb); #else @@ -114,13 +114,21 @@ void srslte_tdec_decision_par(srslte_tdec_t * h, uint8_t *output[SRSLTE_TDEC_NPA #endif } +uint32_t srslte_tdec_get_nof_parallel(srslte_tdec_t *h) { +#ifdef LV_HAVE_AVX2 + return 2; +#else + return 1; +#endif +} + void srslte_tdec_decision(srslte_tdec_t * h, uint8_t *output, uint32_t long_cb) { - uint8_t *output_par[SRSLTE_TDEC_NPAR]; + uint8_t *output_par[SRSLTE_TDEC_MAX_NPAR]; output_par[0] = output; srslte_tdec_decision_par(h, output_par, long_cb); } -void srslte_tdec_decision_byte_par(srslte_tdec_t * h, uint8_t *output[SRSLTE_TDEC_NPAR], uint32_t long_cb) { +void srslte_tdec_decision_byte_par(srslte_tdec_t * h, uint8_t *output[SRSLTE_TDEC_MAX_NPAR], uint32_t long_cb) { #ifdef LV_HAVE_SSE srslte_tdec_simd_decision_byte(&h->tdec_simd, output, long_cb); #else @@ -137,13 +145,13 @@ void srslte_tdec_decision_byte_par_cb(srslte_tdec_t * h, uint8_t *output, uint32 } void srslte_tdec_decision_byte(srslte_tdec_t * h, uint8_t *output, uint32_t long_cb) { - uint8_t *output_par[SRSLTE_TDEC_NPAR]; + uint8_t *output_par[SRSLTE_TDEC_MAX_NPAR]; output_par[0] = output; srslte_tdec_decision_byte_par(h, output_par, long_cb); } -int srslte_tdec_run_all_par(srslte_tdec_t * h, int16_t * input[SRSLTE_TDEC_NPAR], - uint8_t *output[SRSLTE_TDEC_NPAR], +int srslte_tdec_run_all_par(srslte_tdec_t * h, int16_t * input[SRSLTE_TDEC_MAX_NPAR], + uint8_t *output[SRSLTE_TDEC_MAX_NPAR], uint32_t nof_iterations, uint32_t long_cb) { #ifdef LV_HAVE_SSE return srslte_tdec_simd_run_all(&h->tdec_simd, input, output, nof_iterations, long_cb); @@ -155,9 +163,9 @@ int srslte_tdec_run_all_par(srslte_tdec_t * h, int16_t * input[SRSLTE_TDEC_NPAR] int srslte_tdec_run_all(srslte_tdec_t * h, int16_t * input, uint8_t *output, uint32_t nof_iterations, uint32_t long_cb) { - uint8_t *output_par[SRSLTE_TDEC_NPAR]; + uint8_t *output_par[SRSLTE_TDEC_MAX_NPAR]; output_par[0] = output; - int16_t *input_par[SRSLTE_TDEC_NPAR]; + int16_t *input_par[SRSLTE_TDEC_MAX_NPAR]; input_par[0] = input; return srslte_tdec_run_all_par(h, input_par, output_par, nof_iterations, long_cb); diff --git a/lib/src/phy/fec/turbodecoder_avx.c b/lib/src/phy/fec/turbodecoder_avx.c index 2a2f6f925..2e877cbde 100644 --- a/lib/src/phy/fec/turbodecoder_avx.c +++ b/lib/src/phy/fec/turbodecoder_avx.c @@ -81,7 +81,7 @@ static inline int16_t hMax1(__m256i masked_value) } /* Computes beta values */ -void map_avx_beta(map_gen_t * s, int16_t * output[SRSLTE_TDEC_NPAR], uint32_t long_cb) +void map_avx_beta(map_gen_t * s, int16_t * output[SRSLTE_TDEC_MAX_NPAR], uint32_t long_cb) { int k; uint32_t end = long_cb + 3; diff --git a/lib/src/phy/fec/turbodecoder_simd.c b/lib/src/phy/fec/turbodecoder_simd.c index e245c84a4..a32d52962 100644 --- a/lib/src/phy/fec/turbodecoder_simd.c +++ b/lib/src/phy/fec/turbodecoder_simd.c @@ -54,13 +54,13 @@ void map_sse_alpha(map_gen_t * s, uint32_t long_cb); void map_sse_gamma(map_gen_t * h, int16_t *input, int16_t *app, int16_t *parity, uint32_t long_cb); #ifdef LV_HAVE_AVX2 -void map_avx_beta(map_gen_t * s, int16_t * output[SRSLTE_TDEC_NPAR], uint32_t long_cb); +void map_avx_beta(map_gen_t * s, int16_t * output[SRSLTE_TDEC_MAX_NPAR], uint32_t long_cb); void map_avx_alpha(map_gen_t * s, uint32_t long_cb); void map_avx_gamma(map_gen_t * h, int16_t *input, int16_t *app, int16_t *parity, uint32_t cbidx, uint32_t long_cb); #endif -void map_simd_beta(map_gen_t * s, int16_t * output[SRSLTE_TDEC_NPAR], uint32_t nof_cb, uint32_t long_cb) +void map_simd_beta(map_gen_t * s, int16_t * output[SRSLTE_TDEC_MAX_NPAR], uint32_t nof_cb, uint32_t long_cb) { if (nof_cb == 1) { map_sse_beta(s, output[0], long_cb); @@ -128,12 +128,12 @@ void map_simd_free(map_gen_t * h) } /* Runs one instance of a decoder */ -void map_simd_dec(map_gen_t * h, int16_t * input[SRSLTE_TDEC_NPAR], int16_t *app[SRSLTE_TDEC_NPAR], int16_t * parity[SRSLTE_TDEC_NPAR], - int16_t *output[SRSLTE_TDEC_NPAR], uint32_t cb_mask, uint32_t long_cb) +void map_simd_dec(map_gen_t * h, int16_t * input[SRSLTE_TDEC_MAX_NPAR], int16_t *app[SRSLTE_TDEC_MAX_NPAR], int16_t * parity[SRSLTE_TDEC_MAX_NPAR], + int16_t *output[SRSLTE_TDEC_MAX_NPAR], uint32_t cb_mask, uint32_t long_cb) { uint32_t nof_cb = 1; - int16_t *outptr[SRSLTE_TDEC_NPAR]; + int16_t *outptr[SRSLTE_TDEC_MAX_NPAR]; // Compute branch metrics switch(cb_mask) { @@ -354,21 +354,21 @@ void deinterleave_input_simd(srslte_tdec_simd_t *h, int16_t *input, uint32_t cbi } /* Runs 1 turbo decoder iteration */ -void srslte_tdec_simd_iteration(srslte_tdec_simd_t * h, int16_t * input[SRSLTE_TDEC_NPAR], uint32_t long_cb) +void srslte_tdec_simd_iteration(srslte_tdec_simd_t * h, int16_t * input[SRSLTE_TDEC_MAX_NPAR], uint32_t long_cb) { - int16_t *tmp_app[SRSLTE_TDEC_NPAR]; + int16_t *tmp_app[SRSLTE_TDEC_MAX_NPAR]; if (h->current_cbidx >= 0) { uint16_t *inter = h->interleaver[h->current_cbidx].forward; uint16_t *deinter = h->interleaver[h->current_cbidx].reverse; -#if SRSLTE_TDEC_NPAR == 2 - h->cb_mask = (input[0]?1:0) | (input[1]?2:0); -#else - h->cb_mask = input[0]?1:0; +#ifndef LV_HAVE_AVX2 + input[1] = NULL; #endif - + + h->cb_mask = (input[0]?1:0) | (input[1]?2:0); + for (int i=0;imax_par_cb;i++) { if (h->n_iter[i] == 0 && input[i]) { //printf("deinterleaveing %d\n",i); @@ -484,7 +484,7 @@ void tdec_simd_decision(srslte_tdec_simd_t * h, uint8_t *output, uint32_t cbidx, } } -void srslte_tdec_simd_decision(srslte_tdec_simd_t * h, uint8_t *output[SRSLTE_TDEC_NPAR], uint32_t long_cb) +void srslte_tdec_simd_decision(srslte_tdec_simd_t * h, uint8_t *output[SRSLTE_TDEC_MAX_NPAR], uint32_t long_cb) { for (int i=0;imax_par_cb;i++) { tdec_simd_decision(h, output[i], i, long_cb); @@ -510,7 +510,7 @@ void srslte_tdec_simd_decision_byte_cb(srslte_tdec_simd_t * h, uint8_t *output, } } -void srslte_tdec_simd_decision_byte(srslte_tdec_simd_t * h, uint8_t *output[SRSLTE_TDEC_NPAR], uint32_t long_cb) +void srslte_tdec_simd_decision_byte(srslte_tdec_simd_t * h, uint8_t *output[SRSLTE_TDEC_MAX_NPAR], uint32_t long_cb) { for (int i=0;imax_par_cb;i++) { srslte_tdec_simd_decision_byte_cb(h, output[i], i, long_cb); @@ -519,7 +519,7 @@ void srslte_tdec_simd_decision_byte(srslte_tdec_simd_t * h, uint8_t *output[SRSL /* Runs nof_iterations iterations and decides the output bits */ -int srslte_tdec_simd_run_all(srslte_tdec_simd_t * h, int16_t * input[SRSLTE_TDEC_NPAR], uint8_t *output[SRSLTE_TDEC_NPAR], +int srslte_tdec_simd_run_all(srslte_tdec_simd_t * h, int16_t * input[SRSLTE_TDEC_MAX_NPAR], uint8_t *output[SRSLTE_TDEC_MAX_NPAR], uint32_t nof_iterations, uint32_t long_cb) { if (srslte_tdec_simd_reset(h, long_cb)) { diff --git a/lib/src/phy/fec/turbodecoder_simd_inter.c b/lib/src/phy/fec/turbodecoder_simd_inter.c index 05d8b2cf5..3c04e2136 100644 --- a/lib/src/phy/fec/turbodecoder_simd_inter.c +++ b/lib/src/phy/fec/turbodecoder_simd_inter.c @@ -172,7 +172,7 @@ void extract_input(srslte_tdec_simd_inter_t *h, int16_t *input, uint32_t cbidx, } } -void srslte_tdec_simd_inter_iteration(srslte_tdec_simd_inter_t * h, int16_t *input[SRSLTE_TDEC_NPAR], uint32_t nof_cb, uint32_t long_cb) +void srslte_tdec_simd_inter_iteration(srslte_tdec_simd_inter_t * h, int16_t *input[SRSLTE_TDEC_MAX_NPAR], uint32_t nof_cb, uint32_t long_cb) { if (h->current_cbidx >= 0) { @@ -239,7 +239,7 @@ void srslte_tdec_simd_inter_decision_cb(srslte_tdec_simd_inter_t * h, uint8_t *o } } -void srslte_tdec_simd_inter_decision(srslte_tdec_simd_inter_t * h, uint8_t *output[SRSLTE_TDEC_NPAR], uint32_t nof_cb, uint32_t long_cb) +void srslte_tdec_simd_inter_decision(srslte_tdec_simd_inter_t * h, uint8_t *output[SRSLTE_TDEC_MAX_NPAR], uint32_t nof_cb, uint32_t long_cb) { for (int i=0;i int srslte_predecoding_single_sse(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS], cf_t *x, int nof_rxant, int nof_symbols, float noise_estimate); int srslte_predecoding_diversity2_sse(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], cf_t *x[SRSLTE_MAX_LAYERS], int nof_rxant, int nof_symbols); #endif #ifdef LV_HAVE_AVX +#include int srslte_predecoding_single_avx(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_PORTS], cf_t *x, int nof_rxant, int nof_symbols, float noise_estimate); #endif +#include "srslte/phy/utils/mat.h" static srslte_mimo_decoder_t mimo_decoder = SRSLTE_MIMO_DECODER_MMSE; @@ -1364,7 +1367,7 @@ int srslte_predecoding_multiplex(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_P int nof_rxant, int nof_ports, int nof_layers, int codebook_idx, int nof_symbols, float noise_estimate) { - if (nof_ports == 2 && nof_rxant == 2) { + if (nof_ports == 2 && nof_rxant <= 2) { if (nof_layers == 2) { switch (mimo_decoder) { case SRSLTE_MIMO_DECODER_ZF: @@ -1404,7 +1407,7 @@ int srslte_predecoding_multiplex(cf_t *y[SRSLTE_MAX_PORTS], cf_t *h[SRSLTE_MAX_P } else if (nof_ports == 4) { ERROR("Error predecoding multiplex: not implemented for %d Tx ports", nof_ports); } else { - ERROR("Error predecoding multiplex: Invalid combination of ports %d and rx antennax %d\n", nof_ports, nof_rxant); + ERROR("Error predecoding multiplex: Invalid combination of ports %d and rx antennas %d\n", nof_ports, nof_rxant); } return SRSLTE_ERROR; } diff --git a/lib/src/phy/phch/pdsch.c b/lib/src/phy/phch/pdsch.c index 0908793db..b438a2957 100644 --- a/lib/src/phy/phch/pdsch.c +++ b/lib/src/phy/phch/pdsch.c @@ -29,15 +29,11 @@ #include #include #include -#include -#include -#include #include "prb_dl.h" #include "srslte/phy/phch/pdsch.h" #include "srslte/phy/utils/debug.h" #include "srslte/phy/utils/vector.h" -#include "srslte/phy/utils/bit.h" #define MAX_PDSCH_RE(cp) (2 * SRSLTE_CP_NSYMB(cp) * 12) @@ -246,7 +242,7 @@ static int pdsch_init(srslte_pdsch_t *q, uint32_t max_prb, bool is_ue, uint32_t goto clean; } if (q->is_ue) { - for (int j=0;jnof_rx_antennas;j++) { + for (int j = 0; j < SRSLTE_MAX_PORTS; j++) { q->ce[i][j] = srslte_vec_malloc(sizeof(cf_t) * q->max_re); if (!q->ce[i][j]) { goto clean; @@ -309,7 +305,7 @@ void srslte_pdsch_free(srslte_pdsch_t *q) { free(q->symbols[i]); } if (q->is_ue) { - for (int j=0;jnof_rx_antennas;j++) { + for (int j = 0; j < SRSLTE_MAX_PORTS; j++) { if (q->ce[i][j]) { free(q->ce[i][j]); } @@ -606,6 +602,9 @@ static int srslte_pdsch_codeword_decode(srslte_pdsch_t *q, srslte_pdsch_cfg_t *c /* Return */ ret = srslte_dlsch_decode2(&q->dl_sch, cfg, softbuffer, q->e[codeword_idx], data, codeword_idx); + + q->last_nof_iterations[codeword_idx] = srslte_sch_last_noi(&q->dl_sch); + if (ret == SRSLTE_SUCCESS) { *ack = true; } else if (ret == SRSLTE_ERROR) { @@ -613,7 +612,7 @@ static int srslte_pdsch_codeword_decode(srslte_pdsch_t *q, srslte_pdsch_cfg_t *c ret = SRSLTE_SUCCESS; } } else { - ERROR("Detected NULL pointer"); + ERROR("Detected NULL pointer in TB%d &softbuffer=%p &data=%p &ack=%p", codeword_idx, softbuffer, (void*)data, ack); } return ret; @@ -686,10 +685,10 @@ int srslte_pdsch_decode(srslte_pdsch_t *q, srslte_layerdemap_type(x, q->d, cfg->nof_layers, nof_tb, nof_symbols[0], nof_symbols, cfg->mimo_type); } - // Codeword decoding for (uint32_t tb = 0; tb < SRSLTE_MAX_CODEWORDS; tb ++) { - if (cfg->grant.tb_en[tb]) { + /* Decode only if transport block is enabled and the default ACK is not true */ + if (cfg->grant.tb_en[tb] && !acks[tb]) { int ret = srslte_pdsch_codeword_decode(q, cfg, softbuffers[tb], rnti, data[tb], tb, &acks[tb]); /* Check if there has been any execution error */ @@ -712,8 +711,9 @@ int srslte_pdsch_pmi_select(srslte_pdsch_t *q, cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], float noise_estimate, uint32_t nof_ce, uint32_t pmi[SRSLTE_MAX_LAYERS], float sinr[SRSLTE_MAX_LAYERS][SRSLTE_MAX_CODEBOOKS]) { - if (q->cell.nof_ports == 2 && q->nof_rx_antennas == 2) { - for (int nof_layers = 1; nof_layers <= 2; nof_layers++ ) { + if (q->cell.nof_ports == 2 && q->nof_rx_antennas <= 2) { + int nof_layers = 1; + for (; nof_layers <= q->nof_rx_antennas; nof_layers++ ) { if (sinr[nof_layers - 1] && pmi) { if (srslte_precoding_pmi_select(ce, nof_ce, noise_estimate, nof_layers, &pmi[nof_layers - 1], sinr[nof_layers - 1]) < 0) { @@ -722,6 +722,16 @@ int srslte_pdsch_pmi_select(srslte_pdsch_t *q, } } } + + /* FIXME: Set other layers to 0 */ + for (; nof_layers <= SRSLTE_MAX_LAYERS; nof_layers++ ) { + if (sinr[nof_layers - 1] && pmi) { + for (int cb = 0; cb < SRSLTE_MAX_CODEBOOKS; cb++) { + sinr[nof_layers - 1][cb] = -INFINITY; + } + pmi[nof_layers - 1] = 0; + } + } } else { ERROR("Not implemented configuration"); return SRSLTE_ERROR_INVALID_INPUTS; @@ -816,14 +826,13 @@ void srslte_pdsch_set_max_noi(srslte_pdsch_t *q, uint32_t max_iter) { srslte_sch_set_max_noi(&q->dl_sch, max_iter); } -float srslte_pdsch_average_noi(srslte_pdsch_t *q) { - return q->dl_sch.average_nof_iterations; +float srslte_pdsch_last_noi(srslte_pdsch_t *q) { + return srslte_pdsch_last_noi_cw(q, 0); } -uint32_t srslte_pdsch_last_noi(srslte_pdsch_t *q) { - return q->dl_sch.nof_iterations; +uint32_t srslte_pdsch_last_noi_cw(srslte_pdsch_t *q, uint32_t cw_idx) { + return q->last_nof_iterations[cw_idx]; } - diff --git a/lib/src/phy/phch/phich.c b/lib/src/phy/phch/phich.c index a7cb282fd..14a0d5426 100644 --- a/lib/src/phy/phch/phich.c +++ b/lib/src/phy/phch/phich.c @@ -173,26 +173,9 @@ void srslte_phich_ack_encode(uint8_t ack, uint8_t bits[SRSLTE_PHICH_NBITS]) { memset(bits, ack, 3 * sizeof(uint8_t)); } -int srslte_phich_decode(srslte_phich_t *q, cf_t *sf_symbols, cf_t *ce[SRSLTE_MAX_PORTS], float noise_estimate, - uint32_t ngroup, uint32_t nseq, uint32_t subframe, uint8_t *ack, float *distance) -{ - 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_phich_decode_multi(q, _sf_symbols, _ce, noise_estimate, ngroup, nseq, subframe, ack, distance); -} -/* Decodes the phich channel and saves the CFI in the cfi pointer. - * - * Returns 1 if successfully decoded the CFI, 0 if not and -1 on error - */ -int srslte_phich_decode_multi(srslte_phich_t *q, cf_t *sf_symbols[SRSLTE_MAX_PORTS], cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], float noise_estimate, - uint32_t ngroup, uint32_t nseq, uint32_t subframe, uint8_t *ack, float *distance) -{ +int srslte_phich_decode(srslte_phich_t *q, cf_t *sf_symbols[SRSLTE_MAX_PORTS], + cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], float noise_estimate, + uint32_t ngroup, uint32_t nseq, uint32_t subframe, uint8_t *ack, float *distance) { /* Set pointers for layermapping & precoding */ int i, j; diff --git a/lib/src/phy/phch/pmch.c b/lib/src/phy/phch/pmch.c new file mode 100644 index 000000000..4ce869b1c --- /dev/null +++ b/lib/src/phy/phch/pmch.c @@ -0,0 +1,481 @@ +/** + * + * \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; +} + +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..e76fa6aef 100644 --- a/lib/src/phy/phch/sch.c +++ b/lib/src/phy/phch/sch.c @@ -32,12 +32,7 @@ #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/uci.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" @@ -174,15 +169,10 @@ void srslte_sch_set_max_noi(srslte_sch_t *q, uint32_t max_iterations) { q->max_iterations = max_iterations; } -float srslte_sch_average_noi(srslte_sch_t *q) { - return q->average_nof_iterations; -} - uint32_t srslte_sch_last_noi(srslte_sch_t *q) { return q->nof_iterations; } - /* Encode a transport block according to 36.212 5.3.2 * */ @@ -320,8 +310,8 @@ bool decode_tb_cb(srslte_sch_t *q, bool cb_map[SRSLTE_MAX_CODEBLOCKS]; - uint32_t cb_idx[SRSLTE_TDEC_NPAR]; - int16_t *decoder_input[SRSLTE_TDEC_NPAR]; + uint32_t cb_idx[SRSLTE_TDEC_MAX_NPAR]; + int16_t *decoder_input[SRSLTE_TDEC_MAX_NPAR]; uint32_t nof_cb = cb_size_group?cb_segm->C2:cb_segm->C1; uint32_t first_cb = cb_size_group?cb_segm->C1:0; @@ -338,9 +328,9 @@ bool decode_tb_cb(srslte_sch_t *q, return false; } - for (int i=0;idecoder);i++) { cb_idx[i] = i+first_cb; - decoder_input[i] = false; + decoder_input[i] = NULL; } for (int i=0;idecoder, cb_len); - uint32_t remaining_cb = nof_cb; - + uint32_t remaining_cb = nof_cb; + + q->nof_iterations = 0; + while(remaining_cb>0) { // Unratematch the codeblocks left to decode - for (int i=0;idecoder);i++) { if (!decoder_input[i] && remaining_cb > 0) { // Find an unprocessed CB @@ -372,25 +364,23 @@ bool decode_tb_cb(srslte_sch_t *q, n_e2 = n_e+Qm; rp = (cb_segm->C - gamma)*n_e + (cb_idx[i]-(cb_segm->C - gamma))*n_e2; } - + INFO("CB %d: rp=%d, n_e=%d, i=%d\n", cb_idx[i], rp, n_e2, i); if (srslte_rm_turbo_rx_lut(&e_bits[rp], softbuffer->buffer_f[cb_idx[i]], n_e2, cb_len_idx, rv)) { fprintf(stderr, "Error in rate matching\n"); return SRSLTE_ERROR; } - decoder_input[i] = softbuffer->buffer_f[cb_idx[i]]; + decoder_input[i] = softbuffer->buffer_f[cb_idx[i]]; } } } - // Run 1 iteration for up to TDEC_NPAR codeblocks + // Run 1 iteration for the codeblocks in queue srslte_tdec_iteration_par(&q->decoder, decoder_input, cb_len); - q->nof_iterations = srslte_tdec_get_nof_iterations_cb(&q->decoder, 0); - // Decide output bits and compute CRC - for (int i=0;idecoder);i++) { if (decoder_input[i]) { srslte_tdec_decision_byte_par_cb(&q->decoder, q->cb_in, i, cb_len); @@ -409,24 +399,30 @@ bool decode_tb_cb(srslte_sch_t *q, if (!srslte_crc_checksum_byte(crc_ptr, q->cb_in, len_crc)) { memcpy(&data[(cb_idx[i]*rlen)/8], q->cb_in, rlen/8 * sizeof(uint8_t)); - + + q->nof_iterations += srslte_tdec_get_nof_iterations_cb(&q->decoder, i); + // Reset number of iterations for that CB in the decoder srslte_tdec_reset_cb(&q->decoder, i); remaining_cb--; decoder_input[i] = NULL; cb_idx[i] = 0; - - // CRC is error and exceeded maximum iterations for this CB. + + // CRC is error and exceeded maximum iterations for this CB. // Early stop the whole transport block. } else if (srslte_tdec_get_nof_iterations_cb(&q->decoder, i) >= q->max_iterations) { INFO("CB %d: Error. CB is erroneous. remaining_cb=%d, i=%d, first_cb=%d, nof_cb=%d\n", - cb_idx[i], remaining_cb, i, first_cb, nof_cb); - return false; + cb_idx[i], remaining_cb, i, first_cb, nof_cb); + + q->nof_iterations += q->max_iterations; + q->nof_iterations /= (nof_cb-remaining_cb+1); + return false; } } } } - + + q->nof_iterations /= nof_cb; return true; } @@ -478,7 +474,7 @@ static int decode_tb(srslte_sch_t *q, data[cb_segm->tbs/8+1] = 0; data[cb_segm->tbs/8+2] = 0; - // Process Codeblocks in groups of equal CB size to parallelize according to SRSLTE_TDEC_NPAR + // Process Codeblocks in groups of equal CB size to parallelize according to SRSLTE_TDEC_MAX_NPAR for (uint32_t i=0;igrant.Qm, H_prime_total, cfg->nbits.nof_symb, cfg->cp, &ack_bits[cfg->grant.Qm*i]); + rx_ack += (int32_t) decode_ri_ack(q_bits, c_seq, &ack_bits[cfg->grant.Qm*i]); + } + + if (acks) { + acks[0] = rx_ack>0; + } + return (int) Qprime; +} +#else + static void decode_ri_ack(int16_t *q_bits, uint8_t *c_seq, srslte_uci_bit_t *pos, uint32_t Qm, int32_t data[3]) { uint32_t p0 = pos[Qm * 0 + 0].position; @@ -603,10 +645,6 @@ static void decode_ri_ack(int16_t *q_bits, uint8_t *c_seq, srslte_uci_bit_t *pos data[2] -= q2 + q5; } - -/* Decode UCI HARQ/ACK bits as described in 5.2.2.6 of 36.212 - * Currently only supporting 1-bit HARQ - */ int srslte_uci_decode_ack(srslte_pusch_cfg_t *cfg, int16_t *q_bits, uint8_t *c_seq, float beta, uint32_t H_prime_total, uint32_t O_cqi, srslte_uci_bit_t *ack_bits, uint8_t acks[2], uint32_t nof_acks) @@ -635,6 +673,7 @@ int srslte_uci_decode_ack(srslte_pusch_cfg_t *cfg, int16_t *q_bits, uint8_t *c_s } return (int) Qprime; } +#endif /* Encode UCI HARQ/ACK bits as described in 5.2.2.6 of 36.212 * Currently only supporting 1-bit HARQ @@ -681,7 +720,7 @@ int srslte_uci_decode_ri(srslte_pusch_cfg_t *cfg, int16_t *q_bits, uint8_t *c_se for (uint32_t i=0;igrant.Qm, H_prime_total, cfg->nbits.nof_symb, cfg->cp, &ri_bits[cfg->grant.Qm*i]); if ((i % 3 == 0) && i > 0) { - decode_ri_ack(q_bits, &c_seq[0], &ri_bits[cfg->grant.Qm*(i-3)], cfg->grant.Qm, ri_sum); + //decode_ri_ack(q_bits, &c_seq[0], &ri_bits[cfg->grant.Qm*(i-3)], cfg->grant.Qm, ri_sum); } } diff --git a/lib/src/phy/rf/rf_uhd_imp.c b/lib/src/phy/rf/rf_uhd_imp.c index 16fb2e07e..95287a628 100644 --- a/lib/src/phy/rf/rf_uhd_imp.c +++ b/lib/src/phy/rf/rf_uhd_imp.c @@ -76,9 +76,10 @@ static void log_overflow(rf_uhd_handler_t *h) { } } -static void log_late(rf_uhd_handler_t *h) { +static void log_late(rf_uhd_handler_t *h, bool is_rx) { if (h->uhd_error_handler) { - srslte_rf_error_t error; + srslte_rf_error_t error; + error.opt = is_rx?1:0; bzero(&error, sizeof(srslte_rf_error_t)); error.type = SRSLTE_RF_ERROR_LATE; h->uhd_error_handler(error); @@ -109,7 +110,7 @@ static void* async_thread(void *h) { event_code == UHD_ASYNC_METADATA_EVENT_CODE_UNDERFLOW_IN_PACKET) { log_underflow(handler); } else if (event_code == UHD_ASYNC_METADATA_EVENT_CODE_TIME_ERROR) { - log_late(handler); + log_late(handler, false); } } } else { @@ -290,6 +291,13 @@ int rf_uhd_open(char *args, void **h) return rf_uhd_open_multi(args, h, 1); } +static void remove_substring(char *s,const char *toremove) +{ + while((s=strstr(s,toremove))) { + memmove(s,s+strlen(toremove),1+strlen(s+strlen(toremove))); + } +} + int rf_uhd_open_multi(char *args, void **h, uint32_t nof_channels) { if (h) { @@ -324,7 +332,31 @@ int rf_uhd_open_multi(char *args, void **h, uint32_t nof_channels) handler->uhd_error_handler = NULL; bzero(zero_mem, sizeof(cf_t)*64*1024); - + + // Check external clock argument + enum {DEFAULT, EXTERNAL, GPSDO} clock_src; + if (strstr(args, "clock=external")) { + remove_substring(args, "clock=external"); + clock_src = EXTERNAL; + } else if (strstr(args, "clock=gpsdo")) { + printf("Using GPSDO clock\n"); + remove_substring(args, "clock=gpsdo"); + clock_src = GPSDO; + } else { + clock_src = DEFAULT; + } + + // Set over the wire format + char *otw_format = "sc16"; + if (strstr(args, "otw_format=sc12")) { + otw_format = "sc12"; + } else if (strstr(args, "otw_format=sc16")) { + /* Do nothing */ + } else if (strstr(args, "otw_format=")) { + fprintf(stderr, "Wrong over the wire format. Valid formats: sc12, sc16\n"); + return -1; + } + /* If device type or name not given in args, choose a B200 */ if (args[0]=='\0') { if (find_string(devices_str, "type=b200") && !strstr(args, "recv_frame_size")) { @@ -379,15 +411,13 @@ int rf_uhd_open_multi(char *args, void **h, uint32_t nof_channels) } // Set external clock reference - if (strstr(args, "clock=external")) { + if (clock_src == EXTERNAL) { uhd_usrp_set_clock_source(handler->usrp, "external", 0); - } else if (strstr(args, "clock=gpsdo")) { - printf("Using GPSDO clock\n"); - uhd_usrp_set_clock_source(handler->usrp, "gpsdo", 0); + } else if (clock_src == GPSDO) { + uhd_usrp_set_clock_source(handler->usrp, "gpsdo", 0); } - - handler->has_rssi = get_has_rssi(handler); + handler->has_rssi = get_has_rssi(handler); if (handler->has_rssi) { uhd_sensor_value_make_from_realnum(&handler->rssi_value, "rssi", 0, "dBm", "%f"); } @@ -395,7 +425,7 @@ int rf_uhd_open_multi(char *args, void **h, uint32_t nof_channels) size_t channel[4] = {0, 1, 2, 3}; uhd_stream_args_t stream_args = { .cpu_format = "fc32", - .otw_format = "sc16", + .otw_format = otw_format, .args = "", .channel_list = channel, .n_channels = nof_channels, @@ -405,9 +435,11 @@ int rf_uhd_open_multi(char *args, void **h, uint32_t nof_channels) handler->nof_tx_channels = nof_channels; /* Set default rate to avoid decimation warnings */ - uhd_usrp_set_rx_rate(handler->usrp, 1.92e6, 0); - uhd_usrp_set_tx_rate(handler->usrp, 1.92e6, 0); - + for (int i=0;iusrp, 1.92e6, i); + uhd_usrp_set_tx_rate(handler->usrp, 1.92e6, i); + } + /* Initialize rx and tx stremers */ uhd_rx_streamer_make(&handler->rx_stream); error = uhd_usrp_get_rx_stream(handler->usrp, &stream_args, handler->rx_stream); @@ -626,9 +658,10 @@ int rf_uhd_recv_with_time_multi(void *h, if (error_code == UHD_RX_METADATA_ERROR_CODE_OVERFLOW) { log_overflow(handler); } else if (error_code == UHD_RX_METADATA_ERROR_CODE_LATE_COMMAND) { - log_late(handler); + log_late(handler, true); } else if (error_code == UHD_RX_METADATA_ERROR_CODE_TIMEOUT) { - fprintf(stderr, "Error timed out while receiving asynchronoous messages from UHD.\n"); + fprintf(stderr, "Error timed out while receiving samples from UHD.\n"); + return -1; } else if (error_code != UHD_RX_METADATA_ERROR_CODE_NONE ) { fprintf(stderr, "Error code 0x%x was returned during streaming. Aborting.\n", error_code); } @@ -677,11 +710,11 @@ int rf_uhd_send_timed_multi(void *h, } size_t txd_samples; - if (has_time_spec) { - uhd_tx_metadata_set_time_spec(&handler->tx_md, secs, frac_secs); - } - int trials = 0; + int trials = 0; if (blocking) { + if (has_time_spec) { + uhd_tx_metadata_set_time_spec(&handler->tx_md, secs, frac_secs); + } int n = 0; cf_t *data_c[4]; for (int i = 0; i < 4; i++) { @@ -689,8 +722,8 @@ int rf_uhd_send_timed_multi(void *h, } do { size_t tx_samples = handler->tx_nof_samples; - - // First packet is start of burst if so defined, others are never + + // First packet is start of burst if so defined, others are never if (n == 0) { uhd_tx_metadata_set_start(&handler->tx_md, is_start_of_burst); } else { @@ -727,9 +760,15 @@ int rf_uhd_send_timed_multi(void *h, for (int i = 0; i < 4; i++) { buffs_ptr[i] = data[i]; } + uhd_tx_metadata_set_has_time_spec(&handler->tx_md, is_start_of_burst); uhd_tx_metadata_set_start(&handler->tx_md, is_start_of_burst); uhd_tx_metadata_set_end(&handler->tx_md, is_end_of_burst); - return uhd_tx_streamer_send(handler->tx_stream, buffs_ptr, nsamples, &handler->tx_md, 0.0, &txd_samples); + uhd_error error = uhd_tx_streamer_send(handler->tx_stream, buffs_ptr, nsamples, &handler->tx_md, 3.0, &txd_samples); + if (error) { + fprintf(stderr, "Error sending to UHD: %d\n", error); + return -1; + } + return txd_samples; } } diff --git a/lib/src/phy/rf/uhd_c_api.cpp b/lib/src/phy/rf/uhd_c_api.cpp index da348c17b..d98c3c92a 100644 --- a/lib/src/phy/rf/uhd_c_api.cpp +++ b/lib/src/phy/rf/uhd_c_api.cpp @@ -38,6 +38,12 @@ void uhd_tx_metadata_set_start(uhd_tx_metadata_handle *md, bool is_start_of_burs (*md)->tx_metadata_cpp.start_of_burst = is_start_of_burst; } +void uhd_tx_metadata_set_has_time_spec(uhd_tx_metadata_handle *md, bool has_time_spec) +{ + (*md)->tx_metadata_cpp.has_time_spec = has_time_spec; +} + + void uhd_tx_metadata_set_end(uhd_tx_metadata_handle *md, bool is_end_of_burst) { (*md)->tx_metadata_cpp.end_of_burst = is_end_of_burst; diff --git a/lib/src/phy/rf/uhd_c_api.h b/lib/src/phy/rf/uhd_c_api.h index 15bb5f33c..8f6cb2743 100644 --- a/lib/src/phy/rf/uhd_c_api.h +++ b/lib/src/phy/rf/uhd_c_api.h @@ -32,5 +32,6 @@ SRSLTE_API void rf_uhd_register_msg_handler_c(void (*new_handler)(const char*)); SRSLTE_API void uhd_tx_metadata_set_time_spec(uhd_tx_metadata_handle *md, time_t secs, double frac_secs); SRSLTE_API void uhd_tx_metadata_set_start(uhd_tx_metadata_handle *md, bool is_start_of_burst); +SRSLTE_API void uhd_tx_metadata_set_has_time_spec(uhd_tx_metadata_handle *md, bool has_time_spec); SRSLTE_API void uhd_tx_metadata_set_end(uhd_tx_metadata_handle *md, bool is_end_of_burst); SRSLTE_API void uhd_tx_metadata_add_time_spec(uhd_tx_metadata_handle *md, double frac_secs); diff --git a/lib/src/phy/ue/ue_cell_search.c b/lib/src/phy/ue/ue_cell_search.c index 51b0858bb..dc35fb48c 100644 --- a/lib/src/phy/ue/ue_cell_search.c +++ b/lib/src/phy/ue/ue_cell_search.c @@ -297,7 +297,7 @@ int srslte_ue_cellsearch_scan_N_id_2(srslte_ue_cellsearch_t * q, ret = srslte_ue_sync_zerocopy_multi(&q->ue_sync, q->sf_buffer); if (ret < 0) { fprintf(stderr, "Error calling srslte_ue_sync_work()\n"); - break; + return -1; } else if (ret == 1) { /* This means a peak was found and ue_sync is now in tracking state */ ret = srslte_sync_get_cell_id(&q->ue_sync.strack); diff --git a/lib/src/phy/ue/ue_dl.c b/lib/src/phy/ue/ue_dl.c index 46dfea566..583368b53 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]) { @@ -115,7 +129,7 @@ int srslte_ue_dl_init(srslte_ue_dl_t *q, } srslte_cfo_set_tol(&q->sfo_correct, 1e-5f/q->fft.symbol_sz); - for (int j=0;jsf_symbols_m[j] = srslte_vec_malloc(MAX_SFLEN_RE * sizeof(cf_t)); if (!q->sf_symbols_m[j]) { perror("malloc"); @@ -127,6 +141,7 @@ int srslte_ue_dl_init(srslte_ue_dl_t *q, perror("malloc"); goto clean_exit; } + bzero(q->ce_m[i][j], MAX_SFLEN_RE * sizeof(cf_t)); } } @@ -150,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]); @@ -163,7 +180,7 @@ void srslte_ue_dl_free(srslte_ue_dl_t *q) { free(q->softbuffers[i]); } } - for (int j=0;jnof_rx_antennas;j++) { + for (int j = 0; j < SRSLTE_MAX_PORTS; j++) { if (q->sf_symbols_m[j]) { free(q->sf_symbols_m[j]); } @@ -257,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++){ @@ -278,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, @@ -357,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], @@ -371,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; } @@ -475,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++; } } @@ -509,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) { @@ -516,10 +650,10 @@ int srslte_ue_dl_ri_pmi_select(srslte_ue_dl_t *q, uint8_t *ri, uint8_t *pmi, flo float best_sinr = -INFINITY; uint8_t best_pmi = 0, best_ri = 0; - if (q->cell.nof_ports < 2 || q->nof_rx_antennas < 2) { + if (q->cell.nof_ports < 2) { /* Do nothing */ return SRSLTE_SUCCESS; - } else if (q->cell.nof_ports == 2 && q->nof_rx_antennas == 2) { + } else { if (srslte_pdsch_pmi_select(&q->pdsch, &q->pdsch_cfg, q->ce_m, noise_estimate, SRSLTE_SF_LEN_RE(q->cell.nof_prb, q->cell.cp), q->pmi, q->sinr)) { ERROR("SINR calculation error"); @@ -527,7 +661,7 @@ int srslte_ue_dl_ri_pmi_select(srslte_ue_dl_t *q, uint8_t *ri, uint8_t *pmi, flo } /* Select the best Rank indicator (RI) and Precoding Matrix Indicator (PMI) */ - for (uint32_t nof_layers = 1; nof_layers <= 2; nof_layers++) { + for (uint32_t nof_layers = 1; nof_layers <= SRSLTE_MAX_LAYERS; nof_layers++) { float _sinr = q->sinr[nof_layers - 1][q->pmi[nof_layers - 1]] * nof_layers * nof_layers; if (_sinr > best_sinr + 0.1) { best_sinr = _sinr; @@ -535,37 +669,34 @@ int srslte_ue_dl_ri_pmi_select(srslte_ue_dl_t *q, uint8_t *ri, uint8_t *pmi, flo best_ri = (uint8_t) (nof_layers - 1); } } + } - /* Set RI */ - if (ri != NULL) { - *ri = best_ri; - } + /* Print Trace */ + if (ri != NULL && pmi != NULL && current_sinr != NULL) { + INFO("PDSCH Select RI=%d; PMI=%d; Current SINR=%.1fdB (nof_layers=%d, codebook_idx=%d)\n", *ri, *pmi, + 10*log10(*current_sinr), q->pdsch_cfg.nof_layers, q->pdsch_cfg.codebook_idx); + } - /* Set PMI */ - if (pmi != NULL) { - *pmi = best_pmi; - } + /* Set RI */ + if (ri != NULL) { + *ri = best_ri; + } - /* Set current SINR */ - if (current_sinr != NULL && q->pdsch_cfg.mimo_type == SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX) { - if (q->pdsch_cfg.nof_layers == 1) { - *current_sinr = q->sinr[0][q->pdsch_cfg.codebook_idx]; - } else if (q->pdsch_cfg.nof_layers == 2) { - *current_sinr = q->sinr[1][q->pdsch_cfg.codebook_idx - 1]; - } else { - ERROR("Not implemented number of layers (%d)", q->pdsch_cfg.nof_layers); - return SRSLTE_ERROR; - } - } + /* Set PMI */ + if (pmi != NULL) { + *pmi = best_pmi; + } - /* Print Trace */ - if (ri != NULL && pmi != NULL && current_sinr != NULL) { - INFO("PDSCH Select RI=%d; PMI=%d; Current SINR=%.1fdB (nof_layers=%d, codebook_idx=%d)\n", *ri, *pmi, - 10*log10(*current_sinr), q->pdsch_cfg.nof_layers, q->pdsch_cfg.codebook_idx); + /* Set current SINR */ + if (current_sinr != NULL && q->pdsch_cfg.mimo_type == SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX) { + if (q->pdsch_cfg.nof_layers == 1) { + *current_sinr = q->sinr[0][q->pdsch_cfg.codebook_idx]; + } else if (q->pdsch_cfg.nof_layers == 2) { + *current_sinr = q->sinr[1][q->pdsch_cfg.codebook_idx - 1]; + } else { + ERROR("Not implemented number of layers (%d)", q->pdsch_cfg.nof_layers); + return SRSLTE_ERROR; } - } else { - ERROR("Not implemented configuration"); - return SRSLTE_ERROR_INVALID_INPUTS; } return SRSLTE_SUCCESS; @@ -776,13 +907,7 @@ bool srslte_ue_dl_decode_phich(srslte_ue_dl_t *q, uint32_t sf_idx, uint32_t n_pr sf_idx, n_prb_lowest, n_dmrs, ngroup, nseq, srslte_phich_ngroups(&q->phich), srslte_phich_nsf(&q->phich)); - cf_t *ce0[SRSLTE_MAX_PORTS]; - for (int i=0;ice_m[i][0]; - } - - - if (!srslte_phich_decode(&q->phich, q->sf_symbols_m[0], ce0, 0, ngroup, nseq, sf_idx, &ack_bit, &distance)) { + if (!srslte_phich_decode(&q->phich, q->sf_symbols_m, q->ce_m, 0, ngroup, nseq, sf_idx, &ack_bit, &distance)) { INFO("Decoded PHICH %d with distance %f\n", ack_bit, distance); } else { fprintf(stderr, "Error decoding PHICH\n"); @@ -815,16 +940,16 @@ void srslte_ue_dl_save_signal(srslte_ue_dl_t *q, srslte_softbuffer_rx_t *softbuf srslte_vec_save_file("pdcch_llr", q->pdcch.llr, q->pdcch.nof_cce*72*sizeof(float)); - srslte_vec_save_file("pdsch_symbols", q->pdsch.d, q->pdsch_cfg.nbits[0].nof_re*sizeof(cf_t)); - srslte_vec_save_file("llr", q->pdsch.e, q->pdsch_cfg.nbits[0].nof_bits*sizeof(cf_t)); + srslte_vec_save_file("pdsch_symbols", q->pdsch.d[0], q->pdsch_cfg.nbits[0].nof_re*sizeof(cf_t)); + srslte_vec_save_file("llr", q->pdsch.e[0], q->pdsch_cfg.nbits[0].nof_bits*sizeof(cf_t)); int cb_len = q->pdsch_cfg.cb_segm[0].K1; for (int i=0;ipdsch_cfg.cb_segm[0].C;i++) { char tmpstr[64]; snprintf(tmpstr,64,"rmout_%d.dat",i); srslte_vec_save_file(tmpstr, softbuffer->buffer_f[i], (3*cb_len+12)*sizeof(int16_t)); } - printf("Saved files for tti=%d, sf=%d, cfi=%d, mcs=%d, rv=%d, rnti=0x%x\n", tti, tti%10, cfi, - q->pdsch_cfg.grant.mcs[0].idx, rv_idx, rnti); + printf("Saved files for tti=%d, sf=%d, cfi=%d, mcs=%d, tbs=%d, rv=%d, rnti=0x%x\n", tti, tti%10, cfi, + q->pdsch_cfg.grant.mcs[0].idx, q->pdsch_cfg.grant.mcs[0].tbs, rv_idx, rnti); } diff --git a/lib/src/phy/ue/ue_mib.c b/lib/src/phy/ue/ue_mib.c index 49ab30657..23fec7f6e 100644 --- a/lib/src/phy/ue/ue_mib.c +++ b/lib/src/phy/ue/ue_mib.c @@ -271,7 +271,7 @@ int srslte_ue_mib_sync_decode(srslte_ue_mib_sync_t * q, ret = srslte_ue_sync_zerocopy_multi(&q->ue_sync, q->sf_buffer); if (ret < 0) { fprintf(stderr, "Error calling srslte_ue_sync_work()\n"); - break; + return -1; } else if (srslte_ue_sync_get_sfidx(&q->ue_sync) == 0) { if (ret == 1) { mib_ret = srslte_ue_mib_decode(&q->ue_mib, q->sf_buffer[0], bch_payload, nof_tx_ports, sfn_offset); diff --git a/lib/src/phy/ue/ue_sync.c b/lib/src/phy/ue/ue_sync.c index 2126950a6..f121c5bac 100644 --- a/lib/src/phy/ue/ue_sync.c +++ b/lib/src/phy/ue/ue_sync.c @@ -513,7 +513,7 @@ static int track_peak_ok(srslte_ue_sync_t *q, uint32_t track_idx) { discard the offseted samples to align next frame */ if (q->next_rf_sample_offset > 0 && q->next_rf_sample_offset < MAX_TIME_OFFSET) { DEBUG("Positive time offset %d samples.\n", q->next_rf_sample_offset); - if (q->recv_callback(q->stream, dummy_offset_buffer, (uint32_t) q->next_rf_sample_offset, &q->last_timestamp) < 0) { + if (q->recv_callback(q->stream, dummy_offset_buffer, (uint32_t) q->next_rf_sample_offset, NULL) < 0) { fprintf(stderr, "Error receiving from USRP\n"); return SRSLTE_ERROR; } @@ -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)) diff --git a/lib/src/radio/radio.cc b/lib/src/radio/radio.cc index c3592f168..c0e828f71 100644 --- a/lib/src/radio/radio.cc +++ b/lib/src/radio/radio.cc @@ -30,6 +30,7 @@ extern "C" { } #include "srslte/radio/radio.h" #include +#include namespace srslte { @@ -60,7 +61,14 @@ bool radio::init(char *args, char *devname) } else { printf("\nWarning burst preamble is not calibrated for device %s. Set a value manually\n\n", srslte_rf_name(&rf_device)); } - + + if (args) { + strncpy(saved_args, args, 128); + } + if (devname) { + strncpy(saved_devname, devname, 128); + } + return true; } @@ -69,6 +77,16 @@ void radio::stop() srslte_rf_close(&rf_device); } +void radio::reset() +{ + printf("Resetting Radio...\n"); + srslte_rf_close(&rf_device); + sleep(3); + if (srslte_rf_open_devname(&rf_device, saved_devname, saved_args)) { + fprintf(stderr, "Error opening RF device\n"); + } +} + void radio::set_manual_calibration(rf_cal_t* calibration) { srslte_rf_cal_t tx_cal; @@ -102,11 +120,6 @@ void radio::set_tx_adv_neg(bool tx_adv_is_neg) { tx_adv_negative = tx_adv_is_neg; } -void radio::tx_offset(int offset_) -{ - offset = offset_; -} - bool radio::start_agc(bool tx_gain_same_rx) { if (srslte_rf_start_gain_thread(&rf_device, tx_gain_same_rx)) { @@ -167,6 +180,12 @@ bool radio::has_rssi() return srslte_rf_has_rssi(&rf_device); } +bool radio::is_first_of_burst() { + return is_start_of_burst; +} + +#define BLOCKING_TX true + bool radio::tx(void* buffer, uint32_t nof_samples, srslte_timestamp_t tx_time) { void *iq_samples[4] = {(void *) zeros, (void *) zeros, (void *) zeros, (void *) zeros}; @@ -185,7 +204,7 @@ bool radio::tx(void* buffer, uint32_t nof_samples, srslte_timestamp_t tx_time) save_trace(1, &tx_time_pad); srslte_rf_send_timed_multi(&rf_device, iq_samples, burst_preamble_samples, tx_time_pad.full_secs, tx_time_pad.frac_secs, true, true, false); is_start_of_burst = false; - } + } } // Save possible end of burst time @@ -194,9 +213,10 @@ bool radio::tx(void* buffer, uint32_t nof_samples, srslte_timestamp_t tx_time) save_trace(0, &tx_time); iq_samples[0] = buffer; - int ret = srslte_rf_send_timed_multi(&rf_device, (void**) iq_samples, nof_samples+offset, tx_time.full_secs, tx_time.frac_secs, true, is_start_of_burst, false); - offset = 0; - is_start_of_burst = false; + int ret = srslte_rf_send_timed_multi(&rf_device, (void**) iq_samples, nof_samples, + tx_time.full_secs, tx_time.frac_secs, + BLOCKING_TX, is_start_of_burst, false); + is_start_of_burst = false; if (ret > 0) { return true; } else { @@ -204,16 +224,6 @@ bool radio::tx(void* buffer, uint32_t nof_samples, srslte_timestamp_t tx_time) } } -uint32_t radio::get_tti_len() -{ - return sf_len; -} - -void radio::set_tti_len(uint32_t sf_len_) -{ - sf_len = sf_len_; -} - void radio::tx_end() { if (!is_start_of_burst) { diff --git a/lib/src/radio/radio_multi.cc b/lib/src/radio/radio_multi.cc index 0bb538c8d..018a675ac 100644 --- a/lib/src/radio/radio_multi.cc +++ b/lib/src/radio/radio_multi.cc @@ -29,7 +29,14 @@ bool radio_multi::init_multi(uint32_t nof_rx_antennas, char* args, char* devname } else { printf("\nWarning burst preamble is not calibrated for device %s. Set a value manually\n\n", srslte_rf_name(&rf_device)); } - + + if (args) { + strncpy(saved_args, args, 128); + } + if (devname) { + strncpy(saved_devname, devname, 128); + } + return true; } diff --git a/lib/src/upper/pdcp.cc b/lib/src/upper/pdcp.cc index 5f4afbd62..0acc7f6bd 100644 --- a/lib/src/upper/pdcp.cc +++ b/lib/src/upper/pdcp.cc @@ -65,6 +65,15 @@ void pdcp::reset() /******************************************************************************* RRC/GW interface *******************************************************************************/ +bool pdcp::is_drb_enabled(uint32_t lcid) +{ + if(lcid >= SRSLTE_N_RADIO_BEARERS) { + pdcp_log->error("Radio bearer id must be in [0:%d] - %d\n", SRSLTE_N_RADIO_BEARERS, lcid); + return false; + } + return pdcp_array[lcid].is_active(); +} + void pdcp::write_sdu(uint32_t lcid, byte_buffer_t *sdu) { if(valid_lcid(lcid)) diff --git a/lib/src/upper/rlc.cc b/lib/src/upper/rlc.cc index 0cc551a1f..f506ebc63 100644 --- a/lib/src/upper/rlc.cc +++ b/lib/src/upper/rlc.cc @@ -65,7 +65,10 @@ void rlc::reset_metrics() void rlc::stop() { - reset(); + for(uint32_t i=0; istop(); + rlc = NULL; +} void rlc_entity::empty_queue() { diff --git a/lib/src/upper/rlc_tm.cc b/lib/src/upper/rlc_tm.cc index e3bef0a99..627752494 100644 --- a/lib/src/upper/rlc_tm.cc +++ b/lib/src/upper/rlc_tm.cc @@ -66,6 +66,11 @@ void rlc_tm::reset() empty_queue(); } +void rlc_tm::stop() +{ + reset(); +} + rlc_mode_t rlc_tm::get_mode() { return RLC_MODE_TM; diff --git a/lib/src/upper/rlc_um.cc b/lib/src/upper/rlc_um.cc index 3d6bb9553..d44df6348 100644 --- a/lib/src/upper/rlc_um.cc +++ b/lib/src/upper/rlc_um.cc @@ -62,7 +62,8 @@ void rlc_um::init(srslte::log *log_, pdcp = pdcp_; rrc = rrc_; mac_timers = mac_timers_; - reordering_timeout_id = mac_timers->get_unique_id(); + reordering_timer_id = mac_timers->timer_get_unique_id(); + reordering_timer = mac_timers->timer_get(reordering_timer_id); } void rlc_um::configure(srslte_rlc_config_t cnfg_) @@ -102,6 +103,12 @@ void rlc_um::empty_queue() { } } +void rlc_um::stop() +{ + reset(); + mac_timers->timer_release_id(reordering_timer_id); +} + void rlc_um::reset() { @@ -119,7 +126,7 @@ void rlc_um::reset() if(tx_sdu) tx_sdu->reset(); if(mac_timers) - mac_timers->get(reordering_timeout_id)->stop(); + reordering_timer->stop(); // Drop all messages in RX window std::map::iterator it; @@ -203,7 +210,7 @@ void rlc_um::write_pdu(uint8_t *payload, uint32_t nof_bytes) void rlc_um::timer_expired(uint32_t timeout_id) { - if(reordering_timeout_id == timeout_id) + if(reordering_timer_id == timeout_id) { pthread_mutex_lock(&mutex); @@ -221,11 +228,11 @@ void rlc_um::timer_expired(uint32_t timeout_id) reassemble_rx_sdus(); log->debug("Finished reassemble from timeout id=%d\n", timeout_id); } - mac_timers->get(reordering_timeout_id)->stop(); + reordering_timer->stop(); if(RX_MOD_BASE(vr_uh) > RX_MOD_BASE(vr_ur)) { - mac_timers->get(reordering_timeout_id)->set(this, cfg.t_reordering); - mac_timers->get(reordering_timeout_id)->run(); + reordering_timer->set(this, cfg.t_reordering); + reordering_timer->run(); vr_ux = vr_uh; } @@ -236,7 +243,7 @@ void rlc_um::timer_expired(uint32_t timeout_id) bool rlc_um::reordering_timeout_running() { - return mac_timers->get(reordering_timeout_id)->is_running(); + return reordering_timer->is_running(); } /**************************************************************************** @@ -398,20 +405,20 @@ void rlc_um::handle_data_pdu(uint8_t *payload, uint32_t nof_bytes) log->debug("Finished reassemble from received PDU\n"); // Update reordering variables and timers - if(mac_timers->get(reordering_timeout_id)->is_running()) + if(reordering_timer->is_running()) { if(RX_MOD_BASE(vr_ux) <= RX_MOD_BASE(vr_ur) || (!inside_reordering_window(vr_ux) && vr_ux != vr_uh)) { - mac_timers->get(reordering_timeout_id)->stop(); + reordering_timer->stop(); } } - if(!mac_timers->get(reordering_timeout_id)->is_running()) + if(!reordering_timer->is_running()) { if(RX_MOD_BASE(vr_uh) > RX_MOD_BASE(vr_ur)) { - mac_timers->get(reordering_timeout_id)->set(this, cfg.t_reordering); - mac_timers->get(reordering_timeout_id)->run(); + reordering_timer->set(this, cfg.t_reordering); + reordering_timer->run(); vr_ux = vr_uh; } } @@ -506,11 +513,20 @@ void rlc_um::reassemble_rx_sdus() } // Handle last segment - memcpy(&rx_sdu->msg[rx_sdu->N_bytes], rx_window[vr_ur].buf->msg, rx_window[vr_ur].buf->N_bytes); - rx_sdu->N_bytes += rx_window[vr_ur].buf->N_bytes; - log->debug("Writting last segment in SDU buffer. Updating vr_ur=%d, Buffer size=%d, segment size=%d\n", - vr_ur, rx_sdu->N_bytes, rx_window[vr_ur].buf->N_bytes); - vr_ur_in_rx_sdu = vr_ur; + // Handle last segment + if (rx_sdu->N_bytes < SRSLTE_MAX_BUFFER_SIZE_BYTES || + rx_window[vr_ur].buf->N_bytes < SRSLTE_MAX_BUFFER_SIZE_BYTES || + rx_window[vr_ur].buf->N_bytes + rx_sdu->N_bytes < SRSLTE_MAX_BUFFER_SIZE_BYTES) { + + memcpy(&rx_sdu->msg[rx_sdu->N_bytes], rx_window[vr_ur].buf->msg, rx_window[vr_ur].buf->N_bytes); + rx_sdu->N_bytes += rx_window[vr_ur].buf->N_bytes; + log->debug("Writting last segment in SDU buffer. Updating vr_ur=%d, Buffer size=%d, segment size=%d\n", + vr_ur, rx_sdu->N_bytes, rx_window[vr_ur].buf->N_bytes); + } else { + log->error("Out of bounds while reassembling SDU buffer in UM: sdu_len=%d, window_buffer_len=%d, vr_ur=%d\n", + rx_sdu->N_bytes, rx_window[vr_ur].buf->N_bytes, vr_ur); + } + vr_ur_in_rx_sdu = vr_ur; if(rlc_um_end_aligned(rx_window[vr_ur].header.fi)) { if(pdu_lost && !rlc_um_start_aligned(rx_window[vr_ur].header.fi)) { diff --git a/lib/test/upper/rlc_am_test.cc b/lib/test/upper/rlc_am_test.cc index c7ab2aa74..7a37d0d5d 100644 --- a/lib/test/upper/rlc_am_test.cc +++ b/lib/test/upper/rlc_am_test.cc @@ -38,11 +38,12 @@ class mac_dummy_timers :public srslte::mac_interface_timers { public: - srslte::timers::timer* get(uint32_t timer_id) + srslte::timers::timer* timer_get(uint32_t timer_id) { return &t; } - uint32_t get_unique_id(){return 0;} + uint32_t timer_get_unique_id(){return 0;} + void timer_release_id(uint32_t id){} private: srslte::timers::timer t; diff --git a/lib/test/upper/rlc_um_test.cc b/lib/test/upper/rlc_um_test.cc index 739c9ebf8..0894a2a8b 100644 --- a/lib/test/upper/rlc_um_test.cc +++ b/lib/test/upper/rlc_um_test.cc @@ -38,16 +38,16 @@ class mac_dummy_timers :public srslte::mac_interface_timers { public: - srslte::timers::timer* get(uint32_t timer_id) + srslte::timers::timer* timer_get(uint32_t timer_id) { return &t; } - uint32_t get_unique_id(){return 0;} + uint32_t timer_get_unique_id(){return 0;} void step() { t.step(); } - + void timer_release_id(uint32_t timer_id) {} private: srslte::timers::timer t; }; @@ -205,8 +205,8 @@ void loss_test() } // Step the reordering timer until expiry - while(!timers.get(1)->is_expired()) - timers.get(1)->step(); + while(!timers.timer_get(1)->is_expired()) + timers.timer_get(1)->step(); assert(NBUFS-1 == tester.n_sdus); } diff --git a/srsenb/enb.conf.example b/srsenb/enb.conf.example index 6847f7392..391eb8af6 100644 --- a/srsenb/enb.conf.example +++ b/srsenb/enb.conf.example @@ -58,8 +58,8 @@ drb_config = drb.conf ##################################################################### [rf] dl_earfcn = 3400 -tx_gain = 80 -rx_gain = 50 +tx_gain = 70 +rx_gain = 40 #device_name = auto #device_args = auto @@ -98,8 +98,9 @@ filename = /tmp/enb.pcap # Logging layers: phy, mac, rlc, pdcp, rrc, nas, gtpu, usim, all # Logging levels: debug, info, warning, error, none # -# filename: File path to use for log output -##################################################################### +# filename: File path to use for log output. Can be set to stdout +# to print logs to standard output +git c##################################################################### [log] all_level = info all_hex_limit = 32 diff --git a/srsenb/hdr/enb.h b/srsenb/hdr/enb.h index 8b847302e..7b1681cd6 100644 --- a/srsenb/hdr/enb.h +++ b/srsenb/hdr/enb.h @@ -138,8 +138,6 @@ typedef struct { Main UE class *******************************************************************************/ -//#define LOG_STDOUT - class enb :public enb_metrics_interface { public: @@ -180,11 +178,10 @@ private: srsenb::gtpu gtpu; srsenb::s1ap s1ap; -#ifdef LOG_STDOUT - srslte::logger_stdout logger; -#else - srslte::logger_file logger; -#endif + srslte::logger_stdout logger_stdout; + srslte::logger_file logger_file; + srslte::logger *logger; + srslte::log_filter rf_log; std::vector phy_log; srslte::log_filter mac_log; diff --git a/srsenb/hdr/mac/mac.h b/srsenb/hdr/mac/mac.h index 97be1825b..4620c9629 100644 --- a/srsenb/hdr/mac/mac.h +++ b/srsenb/hdr/mac/mac.h @@ -102,28 +102,15 @@ public: int rlc_buffer_state(uint16_t rnti, uint32_t lc_id, uint32_t tx_queue, uint32_t retx_queue); bool process_pdus(); - - void timer_expired(uint32_t timer_id); - - srslte::timers::timer* get(uint32_t timer_id); - u_int32_t get_unique_id(); - + + // Interface for upper-layer timers + srslte::timers::timer* timer_get(uint32_t timer_id); + void timer_release_id(uint32_t timer_id); + u_int32_t timer_get_unique_id(); + uint32_t get_current_tti(); void get_metrics(mac_metrics_t metrics[ENB_METRICS_MAX_USERS]); - - enum { - HARQ_RTT, - TIME_ALIGNMENT, - CONTENTION_TIMER, - BSR_TIMER_PERIODIC, - BSR_TIMER_RETX, - PHR_TIMER_PERIODIC, - PHR_TIMER_PROHIBIT, - NOF_MAC_TIMERS - } mac_timers_t; - - static const int MAC_NOF_UPPER_TIMERS = 20; - + private: void log_step_ul(uint32_t tti); @@ -192,21 +179,18 @@ private: /* Class to run upper-layer timers with normal priority */ - class upper_timers : public thread { - public: - upper_timers() : timers_db(MAC_NOF_UPPER_TIMERS),ttisync(10240) {start();} + class timer_thread : public thread { + public: + timer_thread(srslte::timers *t) : ttisync(10240),timers(t),running(false) {start();} void tti_clock(); void stop(); - void reset(); - srslte::timers::timer* get(uint32_t timer_id); - uint32_t get_unique_id(); private: void run_thread(); - srslte::timers timers_db; srslte::tti_sync_cv ttisync; + srslte::timers *timers; bool running; }; - upper_timers upper_timers_thread; + timer_thread timers_thread; /* Class to process MAC PDUs from DEMUX unit */ class pdu_process : public thread { diff --git a/srsenb/hdr/upper/gtpu.h b/srsenb/hdr/upper/gtpu.h index 9ad9441fa..6ec371655 100644 --- a/srsenb/hdr/upper/gtpu.h +++ b/srsenb/hdr/upper/gtpu.h @@ -75,7 +75,7 @@ public: void stop(); // gtpu_interface_rrc - void add_bearer(uint16_t rnti, uint32_t lcid, uint32_t teid_out, uint32_t *teid_in); + void add_bearer(uint16_t rnti, uint32_t lcid, uint32_t addr, uint32_t teid_out, uint32_t *teid_in); void rem_bearer(uint16_t rnti, uint32_t lcid); void rem_user(uint16_t rnti); @@ -86,7 +86,7 @@ public: private: static const int THREAD_PRIO = 7; static const int GTPU_PORT = 2152; - srslte::byte_buffer_pool *pool; + srslte::byte_buffer_pool *pool; bool running; bool run_enable; @@ -98,11 +98,13 @@ private: typedef struct{ uint32_t teids_in[SRSENB_N_RADIO_BEARERS]; uint32_t teids_out[SRSENB_N_RADIO_BEARERS]; + uint32_t spgw_addrs[SRSENB_N_RADIO_BEARERS]; }bearer_map; std::map rnti_bearers; - srslte_netsink_t snk; - srslte_netsource_t src; + // Socket file descriptors + int snk_fd; + int src_fd; void run_thread(); diff --git a/srsenb/hdr/upper/rrc.h b/srsenb/hdr/upper/rrc.h index 49a02d0b9..e0b9dd158 100644 --- a/srsenb/hdr/upper/rrc.h +++ b/srsenb/hdr/upper/rrc.h @@ -195,6 +195,9 @@ public: bool setup_erabs(LIBLTE_S1AP_E_RABTOBESETUPLISTCTXTSUREQ_STRUCT *e); bool setup_erabs(LIBLTE_S1AP_E_RABTOBESETUPLISTBEARERSUREQ_STRUCT *e); + void setup_erab(uint8_t id, LIBLTE_S1AP_E_RABLEVELQOSPARAMETERS_STRUCT *qos, + LIBLTE_S1AP_TRANSPORTLAYERADDRESS_STRUCT *addr, uint32_t teid_out, + LIBLTE_S1AP_NAS_PDU_STRUCT *nas_pdu); bool release_erabs(); void notify_s1ap_ue_ctxt_setup_complete(); diff --git a/srsenb/src/enb.cc b/srsenb/src/enb.cc index e2c1c9a29..82b4e8145 100644 --- a/srsenb/src/enb.cc +++ b/srsenb/src/enb.cc @@ -26,6 +26,7 @@ #include #include +#include #include "enb.h" namespace srsenb { @@ -68,30 +69,32 @@ bool enb::init(all_args_t *args_) { args = args_; -#ifndef LOG_STDOUT - logger.init(args->log.filename); -#endif - rf_log.init("RF ", &logger); + if (!args->log.filename.compare("stdout")) { + logger = &logger_stdout; + } else { + logger_file.init(args->log.filename); + logger_file.log("\n\n"); + logger = &logger_file; + } + + rf_log.init("RF ", logger); // Create array of pointers to phy_logs for (int i=0;iexpert.phy.nof_phy_threads;i++) { srslte::log_filter *mylog = new srslte::log_filter; char tmp[16]; sprintf(tmp, "PHY%d",i); - mylog->init(tmp, &logger, true); + mylog->init(tmp, logger, true); phy_log.push_back((void*) mylog); } - mac_log.init("MAC ", &logger, true); - rlc_log.init("RLC ", &logger); - pdcp_log.init("PDCP", &logger); - rrc_log.init("RRC ", &logger); - gtpu_log.init("GTPU", &logger); - s1ap_log.init("S1AP", &logger); + mac_log.init("MAC ", logger, true); + rlc_log.init("RLC ", logger); + pdcp_log.init("PDCP", logger); + rrc_log.init("RRC ", logger); + gtpu_log.init("GTPU", logger); + s1ap_log.init("S1AP", logger); // Init logs -#ifndef LOG_STDOUT - logger.log("\n\n"); -#endif rf_log.set_level(srslte::LOG_LEVEL_INFO); for (int i=0;iexpert.phy.nof_phy_threads;i++) { ((srslte::log_filter*) phy_log[i])->set_level(level(args->log.phy_level)); @@ -225,15 +228,15 @@ void enb::stop() { if(started) { - mac.stop(); + gtpu.stop(); phy.stop(); - usleep(1e5); + mac.stop(); + usleep(100000); rlc.stop(); pdcp.stop(); - gtpu.stop(); rrc.stop(); - + usleep(1e5); if(args->pcap.enable) { diff --git a/srsenb/src/mac/mac.cc b/srsenb/src/mac/mac.cc index 284cef3e7..7cb30cc65 100644 --- a/srsenb/src/mac/mac.cc +++ b/srsenb/src/mac/mac.cc @@ -42,7 +42,8 @@ namespace srsenb { -mac::mac() : timers_db((uint32_t) NOF_MAC_TIMERS), +mac::mac() : timers_db(128), + timers_thread(&timers_db), rar_pdu_msg(sched_interface::MAX_RAR_LIST), pdu_process_thread(this) { @@ -99,7 +100,7 @@ void mac::stop() srslte_softbuffer_tx_free(&pcch_softbuffer_tx); srslte_softbuffer_tx_free(&rar_softbuffer_tx); started = false; - upper_timers_thread.stop(); + timers_thread.stop(); pdu_process_thread.stop(); } @@ -109,8 +110,7 @@ void mac::reset() Info("Resetting MAC\n"); timers_db.stop_all(); - upper_timers_thread.reset(); - + tti = 0; last_rnti = 70; @@ -119,18 +119,6 @@ void mac::reset() } -uint32_t mac::get_unique_id() -{ - return upper_timers_thread.get_unique_id(); -} - -/* Front-end to upper-layer timers */ -srslte::timers::timer* mac::get(uint32_t timer_id) -{ - return upper_timers_thread.get(timer_id); -} - - void mac::start_pcap(srslte::mac_pcap* pcap_) { pcap = pcap_; @@ -453,8 +441,7 @@ int mac::get_dl_sched(uint32_t tti, dl_sched_t *dl_sched_res) dl_sched_res->sched_grants[n].data = ue_db[rnti]->generate_pdu(sched_result.data[i].pdu, sched_result.data[i].nof_pdu_elems, sched_result.data[i].tbs); - srslte_softbuffer_tx_reset_tbs(dl_sched_res->sched_grants[n].softbuffer, sched_result.data[i].tbs); - + if (pcap) { pcap->write_dl_crnti(dl_sched_res->sched_grants[n].data, sched_result.data[i].tbs, rnti, true, tti); } @@ -474,7 +461,6 @@ int mac::get_dl_sched(uint32_t tti, dl_sched_t *dl_sched_res) // Set softbuffer (there are no retx in RAR but a softbuffer is required) dl_sched_res->sched_grants[n].softbuffer = &rar_softbuffer_tx; - srslte_softbuffer_tx_reset_tbs(&rar_softbuffer_tx, sched_result.rar[i].tbs); // TBS is usually 54-bit // Assemble PDU dl_sched_res->sched_grants[n].data = assemble_rar(sched_result.rar[i].grants, sched_result.rar[i].nof_grants, i, sched_result.rar[i].tbs); @@ -497,9 +483,6 @@ int mac::get_dl_sched(uint32_t tti, dl_sched_t *dl_sched_res) // Set softbuffer if (sched_result.bc[i].type == sched_interface::dl_sched_bc_t::BCCH) { dl_sched_res->sched_grants[n].softbuffer = &bcch_softbuffer_tx[sched_result.bc[i].index]; - if (sched_result.bc[i].dci.rv_idx == 0) { - srslte_softbuffer_tx_reset_tbs(dl_sched_res->sched_grants[n].softbuffer, sched_result.bc[i].tbs*8); - } dl_sched_res->sched_grants[n].data = assemble_si(sched_result.bc[i].index); #ifdef WRITE_SIB_PCAP if (pcap) { @@ -508,7 +491,6 @@ int mac::get_dl_sched(uint32_t tti, dl_sched_t *dl_sched_res) #endif } else { dl_sched_res->sched_grants[n].softbuffer = &pcch_softbuffer_tx; - srslte_softbuffer_tx_reset_tbs(dl_sched_res->sched_grants[n].softbuffer, sched_result.bc[i].tbs*8); dl_sched_res->sched_grants[n].data = pcch_payload_buffer; rlc_h->read_pdu_pcch(pcch_payload_buffer, pcch_payload_buffer_len); @@ -640,46 +622,59 @@ void mac::log_step_dl(uint32_t tti) void mac::tti_clock() { - upper_timers_thread.tti_clock(); + timers_thread.tti_clock(); } + + + /******************************************************** * - * Class to run upper-layer timers with normal priority + * Interface for upper layer timers * *******************************************************/ -void mac::upper_timers::run_thread() +uint32_t mac::timer_get_unique_id() +{ + return timers_db.get_unique_id(); +} + +void mac::timer_release_id(uint32_t timer_id) +{ + timers_db.release_id(timer_id); +} + +/* Front-end to upper-layer timers */ +srslte::timers::timer* mac::timer_get(uint32_t timer_id) +{ + return timers_db.get(timer_id); +} + + + +/******************************************************** + * + * Class to run timers with normal priority + * + *******************************************************/ +void mac::timer_thread::run_thread() { running=true; ttisync.set_producer_cntr(0); ttisync.resync(); while(running) { ttisync.wait(); - timers_db.step_all(); + timers->step_all(); } } -srslte::timers::timer* mac::upper_timers::get(uint32_t timer_id) -{ - return timers_db.get(timer_id%MAC_NOF_UPPER_TIMERS); -} -uint32_t mac::upper_timers::get_unique_id() -{ - return timers_db.get_unique_id(); -} - -void mac::upper_timers::stop() +void mac::timer_thread::stop() { running=false; ttisync.increase(); wait_thread_finish(); } -void mac::upper_timers::reset() -{ - timers_db.stop_all(); -} -void mac::upper_timers::tti_clock() +void mac::timer_thread::tti_clock() { ttisync.increase(); } diff --git a/srsenb/src/mac/scheduler_ue.cc b/srsenb/src/mac/scheduler_ue.cc index b9a3093c2..1534d12ef 100644 --- a/srsenb/src/mac/scheduler_ue.cc +++ b/srsenb/src/mac/scheduler_ue.cc @@ -635,7 +635,7 @@ uint32_t sched_ue::get_required_prb_ul(uint32_t req_bytes) return 0; } - for (n=1;n<=cell.nof_prb && nbytes < req_bytes + 4;n++) { + for (n=1;n max_coderate); + } while(l<3 && 1.5*coderate > max_coderate); Debug("SCHED: CQI=%d, l=%d, nof_bits=%d, coderate=%.2f, max_coderate=%.2f\n", dl_cqi, l, nof_bits, coderate, max_coderate); return l; } @@ -815,7 +815,7 @@ int sched_ue::alloc_tbs(uint32_t nof_prb, // TODO: Compute real spectral efficiency based on PUSCH-UCI configuration if (has_pucch && is_ul) { - cqi-=2; + cqi-=3; } int tbs = cqi_to_tbs(cqi, nof_prb, nof_re, max_mcs, max_Qm, &sel_mcs)/8; diff --git a/srsenb/src/phy/phch_worker.cc b/srsenb/src/phy/phch_worker.cc index ab7df91af..3a1fb8ca4 100644 --- a/srsenb/src/phy/phch_worker.cc +++ b/srsenb/src/phy/phch_worker.cc @@ -434,8 +434,6 @@ int phch_worker::decode_pusch(srslte_enb_ul_pusch_t *grants, uint32_t nof_pusch, ue_db[rnti].phich_info.n_prb_lowest = enb_ul.pusch_cfg.grant.n_prb_tilde[0]; ue_db[rnti].phich_info.n_dmrs = phy_grant.ncs_dmrs; - - char cqi_str[64]; if (cqi_enabled) { srslte_cqi_value_unpack(uci_data.uci_cqi, &cqi_value); @@ -689,10 +687,12 @@ int phch_worker::encode_pdsch(srslte_enb_dl_pdsch_t *grants, uint32_t nof_grants rnti, phy_grant.nof_prb, grant_str, grants[i].grant.harq_process, phy_grant.mcs[0].tbs/8, phy_grant.mcs[0].idx, grants[i].grant.rv_idx, tti_tx); } + srslte_softbuffer_tx_t *sb[SRSLTE_MAX_CODEWORDS] = {grants[i].softbuffer, NULL}; uint8_t *d[SRSLTE_MAX_CODEWORDS] = {grants[i].data, NULL}; int rv[SRSLTE_MAX_CODEWORDS] = {grants[i].grant.rv_idx, 0}; + if (srslte_enb_dl_put_pdsch(&enb_dl, &phy_grant, sb, rnti, rv, sf_idx, d, SRSLTE_MIMO_TYPE_SINGLE_ANTENNA, 0)) { fprintf(stderr, "Error putting PDSCH %d\n",i); diff --git a/srsenb/src/upper/gtpu.cc b/srsenb/src/upper/gtpu.cc index 83f7a1b75..ddd695ffe 100644 --- a/srsenb/src/upper/gtpu.cc +++ b/srsenb/src/upper/gtpu.cc @@ -26,6 +26,9 @@ #include "upper/gtpu.h" #include +#include +#include +#include using namespace srslte; @@ -42,16 +45,51 @@ bool gtpu::init(std::string gtp_bind_addr_, std::string mme_addr_, srsenb::pdcp_ pool = byte_buffer_pool::get_instance(); - if(0 != srslte_netsource_init(&src, gtp_bind_addr.c_str(), GTPU_PORT, SRSLTE_NETSOURCE_UDP)) { - gtpu_log->error("Failed to create source socket on %s:%d", gtp_bind_addr.c_str(), GTPU_PORT); + // Set up sink socket + snk_fd = socket(AF_INET, SOCK_DGRAM, 0); + if (snk_fd < 0) { + gtpu_log->error("Failed to create sink socket\n"); return false; } - if(0 != srslte_netsink_init(&snk, mme_addr.c_str(), GTPU_PORT, SRSLTE_NETSINK_UDP)) { - gtpu_log->error("Failed to create sink socket on %s:%d", mme_addr.c_str(), GTPU_PORT); + if (fcntl(snk_fd, F_SETFL, O_NONBLOCK)) { + gtpu_log->error("Failed to set non-blocking sink socket\n"); + return false; + } + int enable = 1; +#if defined (SO_REUSEADDR) + if (setsockopt(snk_fd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int)) < 0) + gtpu_log->error("setsockopt(SO_REUSEADDR) failed\n"); +#endif +#if defined (SO_REUSEPORT) + if (setsockopt(snk_fd, SOL_SOCKET, SO_REUSEPORT, &enable, sizeof(int)) < 0) + gtpu_log->error("setsockopt(SO_REUSEPORT) failed\n"); +#endif + + + // Set up source socket + src_fd = socket(AF_INET, SOCK_DGRAM, 0); + if (src_fd < 0) { + gtpu_log->error("Failed to create source socket\n"); + return false; + } +#if defined (SO_REUSEADDR) + if (setsockopt(src_fd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int)) < 0) + gtpu_log->error("setsockopt(SO_REUSEADDR) failed\n"); +#endif +#if defined (SO_REUSEPORT) + if (setsockopt(src_fd, SOL_SOCKET, SO_REUSEPORT, &enable, sizeof(int)) < 0) + gtpu_log->error("setsockopt(SO_REUSEPORT) failed\n"); +#endif + + struct sockaddr_in bindaddr; + bindaddr.sin_family = AF_INET; + bindaddr.sin_addr.s_addr = inet_addr(gtp_bind_addr.c_str()); + bindaddr.sin_port = htons(GTPU_PORT); + + if (bind(src_fd, (struct sockaddr *)&bindaddr, sizeof(struct sockaddr_in))) { + gtpu_log->error("Failed to bind on address %s, port %d\n", gtp_bind_addr, GTPU_PORT); return false; } - - srslte_netsink_set_nonblocking(&snk); // Setup a thread to receive packets from the src socket start(THREAD_PRIO); @@ -61,7 +99,7 @@ bool gtpu::init(std::string gtp_bind_addr_, std::string mme_addr_, srsenb::pdcp_ void gtpu::stop() { - if(run_enable) { + if (run_enable) { run_enable = false; // Wait thread to exit gracefully otherwise might leave a mutex locked int cnt=0; @@ -75,8 +113,12 @@ void gtpu::stop() wait_thread_finish(); } - srslte_netsink_free(&snk); - srslte_netsource_free(&src); + if (snk_fd) { + close(snk_fd); + } + if (src_fd) { + close(src_fd); + } } // gtpu_interface_pdcp @@ -89,28 +131,35 @@ void gtpu::write_pdu(uint16_t rnti, uint32_t lcid, srslte::byte_buffer_t* pdu) header.length = pdu->N_bytes; header.teid = rnti_bearers[rnti].teids_out[lcid]; + struct sockaddr_in servaddr; + servaddr.sin_family = AF_INET; + servaddr.sin_addr.s_addr = htonl(rnti_bearers[rnti].spgw_addrs[lcid]); + servaddr.sin_port = htons(GTPU_PORT); + gtpu_write_header(&header, pdu); - srslte_netsink_write(&snk, pdu->msg, pdu->N_bytes); + sendto(snk_fd, pdu->msg, pdu->N_bytes, MSG_EOR, (struct sockaddr*)&servaddr, sizeof(struct sockaddr_in)); pool->deallocate(pdu); } // gtpu_interface_rrc -void gtpu::add_bearer(uint16_t rnti, uint32_t lcid, uint32_t teid_out, uint32_t *teid_in) +void gtpu::add_bearer(uint16_t rnti, uint32_t lcid, uint32_t addr, uint32_t teid_out, uint32_t *teid_in) { // Allocate a TEID for the incoming tunnel rntilcid_to_teidin(rnti, lcid, teid_in); - gtpu_log->info("Adding bearer for rnti: 0x%x, lcid: %d, teid_out: 0x%x, teid_in: 0x%x\n", rnti, lcid, teid_out, *teid_in); + gtpu_log->info("Adding bearer for rnti: 0x%x, lcid: %d, addr: 0x%x, teid_out: 0x%x, teid_in: 0x%x\n", rnti, lcid, addr, teid_out, *teid_in); // Initialize maps if it's a new RNTI if(rnti_bearers.count(rnti) == 0) { for(int i=0;ireset(); gtpu_log->debug("Waiting for read...\n"); - pdu->N_bytes = srslte_netsource_read(&src, pdu->msg, SRSENB_MAX_BUFFER_SIZE_BYTES - SRSENB_BUFFER_HEADER_OFFSET); + do{ + pdu->N_bytes = recv(src_fd, pdu->msg, SRSENB_MAX_BUFFER_SIZE_BYTES - SRSENB_BUFFER_HEADER_OFFSET, 0); + }while (pdu->N_bytes == -1 && errno == EAGAIN); + if (pdu->N_bytes == -1) { + gtpu_log->error("Failed to read from socket\n"); + } gtpu_header_t header; gtpu_read_header(pdu, &header); diff --git a/srsenb/src/upper/rrc.cc b/srsenb/src/upper/rrc.cc index f803500f2..b1280cf55 100644 --- a/srsenb/src/upper/rrc.cc +++ b/srsenb/src/upper/rrc.cc @@ -223,7 +223,8 @@ void rrc::rem_user(uint16_t rnti) rrc_log->console("Disconnecting rnti=0x%x.\n", rnti); rrc_log->info("Disconnecting rnti=0x%x.\n", rnti); /* **Caution** order of removal here is imporant: from bottom to top */ - mac->ue_rem(rnti); // MAC handles PHY + mac->ue_rem(rnti); // MAC handles PHY + usleep(50000); rlc->rem_user(rnti); pdcp->rem_user(rnti); gtpu->rem_user(rnti); @@ -945,20 +946,16 @@ bool rrc::ue::setup_erabs(LIBLTE_S1AP_E_RABTOBESETUPLISTCTXTSUREQ_STRUCT *e) if(erab->iE_Extensions_present) { parent->rrc_log->warning("Not handling LIBLTE_S1AP_E_RABTOBESETUPITEMCTXTSUREQ_STRUCT extensions\n"); } - - uint8_t id = erab->e_RAB_ID.E_RAB_ID; - erabs[id].id = id; - memcpy(&erabs[id].qos_params, &erab->e_RABlevelQoSParameters, sizeof(LIBLTE_S1AP_E_RABLEVELQOSPARAMETERS_STRUCT)); - memcpy(&erabs[id].address, &erab->transportLayerAddress, sizeof(LIBLTE_S1AP_TRANSPORTLAYERADDRESS_STRUCT)); - uint8_to_uint32(erab->gTP_TEID.buffer, &erabs[id].teid_out); - - uint8_t lcid = id - 2; // Map e.g. E-RAB 5 to LCID 3 (==DRB1) - parent->gtpu->add_bearer(rnti, lcid, erabs[id].teid_out, &(erabs[id].teid_in)); - - if(erab->nAS_PDU_present) { - memcpy(parent->erab_info.msg, erab->nAS_PDU.buffer, erab->nAS_PDU.n_octets); - parent->erab_info.N_bytes = erab->nAS_PDU.n_octets; + if(erab->transportLayerAddress.n_bits > 32) { + parent->rrc_log->error("IPv6 addresses not currently supported\n"); + return false; } + + uint32_t teid_out; + uint8_to_uint32(erab->gTP_TEID.buffer, &teid_out); + LIBLTE_S1AP_NAS_PDU_STRUCT *nas_pdu = erab->nAS_PDU_present ? &erab->nAS_PDU : NULL; + setup_erab(erab->e_RAB_ID.E_RAB_ID, &erab->e_RABlevelQoSParameters, + &erab->transportLayerAddress, teid_out, nas_pdu); } return true; } @@ -973,25 +970,43 @@ bool rrc::ue::setup_erabs(LIBLTE_S1AP_E_RABTOBESETUPLISTBEARERSUREQ_STRUCT *e) if(erab->iE_Extensions_present) { parent->rrc_log->warning("Not handling LIBLTE_S1AP_E_RABTOBESETUPITEMCTXTSUREQ_STRUCT extensions\n"); } + if(erab->transportLayerAddress.n_bits > 32) { + parent->rrc_log->error("IPv6 addresses not currently supported\n"); + return false; + } - uint8_t id = erab->e_RAB_ID.E_RAB_ID; - erabs[id].id = id; - memcpy(&erabs[id].qos_params, &erab->e_RABlevelQoSParameters, sizeof(LIBLTE_S1AP_E_RABLEVELQOSPARAMETERS_STRUCT)); - memcpy(&erabs[id].address, &erab->transportLayerAddress, sizeof(LIBLTE_S1AP_TRANSPORTLAYERADDRESS_STRUCT)); - uint8_to_uint32(erab->gTP_TEID.buffer, &erabs[id].teid_out); - - uint8_t lcid = id - 2; // Map e.g. E-RAB 5 to LCID 3 (==DRB1) - parent->gtpu->add_bearer(rnti, lcid, erabs[id].teid_out, &(erabs[id].teid_in)); - - memcpy(parent->erab_info.msg, erab->nAS_PDU.buffer, erab->nAS_PDU.n_octets); - parent->erab_info.N_bytes = erab->nAS_PDU.n_octets; + uint32_t teid_out; + uint8_to_uint32(erab->gTP_TEID.buffer, &teid_out); + setup_erab(erab->e_RAB_ID.E_RAB_ID, &erab->e_RABlevelQoSParameters, + &erab->transportLayerAddress, teid_out, &erab->nAS_PDU); } + // Work in progress notify_s1ap_ue_erab_setup_response(e); send_connection_reconf_new_bearer(e); return true; } +void rrc::ue::setup_erab(uint8_t id, LIBLTE_S1AP_E_RABLEVELQOSPARAMETERS_STRUCT *qos, + LIBLTE_S1AP_TRANSPORTLAYERADDRESS_STRUCT *addr, uint32_t teid_out, + LIBLTE_S1AP_NAS_PDU_STRUCT *nas_pdu) +{ + erabs[id].id = id; + memcpy(&erabs[id].qos_params, qos, sizeof(LIBLTE_S1AP_E_RABLEVELQOSPARAMETERS_STRUCT)); + memcpy(&erabs[id].address, addr, sizeof(LIBLTE_S1AP_TRANSPORTLAYERADDRESS_STRUCT)); + erabs[id].teid_out = teid_out; + + uint8_t* bit_ptr = addr->buffer; + uint32_t addr_ = liblte_bits_2_value(&bit_ptr, addr->n_bits); + uint8_t lcid = id - 2; // Map e.g. E-RAB 5 to LCID 3 (==DRB1) + parent->gtpu->add_bearer(rnti, lcid, addr_, erabs[id].teid_out, &(erabs[id].teid_in)); + + if(nas_pdu) { + memcpy(parent->erab_info.msg, nas_pdu->buffer, nas_pdu->n_octets); + parent->erab_info.N_bytes = nas_pdu->n_octets; + } +} + bool rrc::ue::release_erabs() { typedef std::map::iterator it_t; diff --git a/srsue/hdr/mac/demux.h b/srsue/hdr/mac/demux.h index 2f38a4dfc..8b722e8c9 100644 --- a/srsue/hdr/mac/demux.h +++ b/srsue/hdr/mac/demux.h @@ -42,7 +42,7 @@ class demux : public srslte::pdu_queue::process_callback { public: demux(uint8_t nof_harq_proc_); - void init(phy_interface_mac_common* phy_h_, rlc_interface_mac *rlc, srslte::log* log_h_, srslte::timers* timers_db_); + void init(phy_interface_mac_common* phy_h_, rlc_interface_mac *rlc, srslte::log* log_h_, srslte::timers::timer* time_alignment_timer); bool process_pdus(); uint8_t* request_buffer(uint32_t pid, uint32_t len); @@ -74,7 +74,7 @@ private: phy_interface_mac_common *phy_h; srslte::log *log_h; - srslte::timers *timers_db; + srslte::timers::timer *time_alignment_timer; rlc_interface_mac *rlc; uint8_t nof_harq_proc; diff --git a/srsue/hdr/mac/dl_harq.h b/srsue/hdr/mac/dl_harq.h index e897ac76f..ee925596f 100644 --- a/srsue/hdr/mac/dl_harq.h +++ b/srsue/hdr/mac/dl_harq.h @@ -35,7 +35,6 @@ #include "srslte/common/log.h" #include "srslte/common/timers.h" #include "mac/demux.h" -#include "mac/mac_common.h" #include "mac/dl_sps.h" #include "srslte/common/mac_pcap.h" @@ -58,9 +57,9 @@ public: pcap = NULL; } - bool init(srslte::log *log_h_, srslte::timers *timers_, demux *demux_unit_) + bool init(srslte::log *log_h_, srslte::timers::timer *timer_aligment_timer_, demux *demux_unit_) { - timers_db = timers_; + timer_aligment_timer = timer_aligment_timer_; demux_unit = demux_unit_; si_window_start = 0; log_h = log_h_; @@ -102,7 +101,7 @@ public: } else { if (grant.is_sps_release) { dl_sps_assig.clear(); - if (timers_db->get(TIME_ALIGNMENT)->is_running()) { + if (timer_aligment_timer->is_running()) { //phy_h->send_sps_ack(); Warning("PHY Send SPS ACK not implemented\n"); } @@ -168,12 +167,14 @@ private: void new_grant_dl(Tgrant grant, Taction *action) { /* Fill action structure */ bzero(action, sizeof(Taction)); - action->default_ack = false; action->generate_ack = true; - action->decode_enabled = false; + action->rnti = grant.rnti; /* For each subprocess... */ for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) { + action->default_ack[tb] = false; + action->decode_enabled[tb] = false; + action->phy_grant.dl.tb_en[tb] = grant.tb_en[tb]; if (grant.tb_en[tb]) { subproc[tb].new_grant_dl(grant, action); } @@ -210,6 +211,7 @@ private: return false; } else { pid = pid_; + is_first_tb = true; is_initiated = true; harq_entity = parent; log_h = harq_entity->log_h; @@ -218,6 +220,7 @@ private: } void reset(void) { + is_first_tb = true; ack = false; payload_buffer_ptr = NULL; bzero(&cur_grant, sizeof(Tgrant)); @@ -239,7 +242,12 @@ private: } } calc_is_new_transmission(grant); - if (is_new_transmission) { + // If this is a new transmission or the size of the TB has changed + if (is_new_transmission || (cur_grant.n_bytes[tid] != grant.n_bytes[tid])) { + if (!is_new_transmission) { + Warning("DL PID %d: Size of grant changed during a retransmission %d!=%d\n", pid, + cur_grant.n_bytes[tid], grant.n_bytes[tid]); + } ack = false; srslte_softbuffer_rx_reset_tbs(&softbuffer, cur_grant.n_bytes[tid] * 8); n_retx = 0; @@ -258,23 +266,22 @@ private: cur_grant.n_bytes[tid]); action->payload_ptr[tid] = payload_buffer_ptr; if (!action->payload_ptr) { - action->decode_enabled = false; + action->decode_enabled[tid] = false; Error("Can't get a buffer for TBS=%d\n", cur_grant.n_bytes[tid]); return; } - action->decode_enabled = true; + action->decode_enabled[tid]= true; action->rv[tid] = cur_grant.rv[tid]; - action->rnti = cur_grant.rnti; action->softbuffers[tid] = &softbuffer; memcpy(&action->phy_grant, &cur_grant.phy_grant, sizeof(Tphygrant)); n_retx++; } else { + action->default_ack[tid] = true; Warning("DL PID %d: Received duplicate TB. Discarting and retransmitting ACK\n", pid); - action->phy_grant.dl.tb_en[tid] = false; } - if (pid == HARQ_BCCH_PID || harq_entity->timers_db->get(TIME_ALIGNMENT)->is_expired()) { + if (pid == HARQ_BCCH_PID || harq_entity->timer_aligment_timer->is_expired()) { // Do not generate ACK Debug("Not generating ACK\n"); action->generate_ack = false; @@ -336,17 +343,14 @@ private: int get_current_tbs(void) { return cur_grant.n_bytes[tid] * 8; } private: + // Determine if it's a new transmission 5.3.2.2 bool calc_is_new_transmission(Tgrant grant) { - bool is_new_tb = true; - if ((srslte_tti_interval(grant.tti, cur_grant.tti) <= 8 && (grant.n_bytes[tid] == cur_grant.n_bytes[tid])) || - pid == HARQ_BCCH_PID) { - is_new_tb = false; - } - if ((grant.ndi[tid] != cur_grant.ndi[tid] && !is_new_tb) || // NDI toggled for same TB - is_new_tb || // is new TB - (pid == HARQ_BCCH_PID && grant.rv[tid] == 0)) // Broadcast PID and 1st TX (RV=0) + if ((grant.ndi[tid] != cur_grant.ndi[tid]) || // 1st condition (NDI has changed) + (pid == HARQ_BCCH_PID && grant.rv[tid] == 0) || // 2nd condition (Broadcast and 1st transmission) + is_first_tb) // 3rd condition (first TB) { + is_first_tb = false; is_new_transmission = true; Debug("Set HARQ for new transmission\n"); } else { @@ -361,6 +365,7 @@ private: dl_harq_entity *harq_entity; srslte::log *log_h; + bool is_first_tb; bool is_new_transmission; uint32_t pid; /* HARQ Proccess ID */ @@ -391,7 +396,7 @@ private: std::vector proc; - srslte::timers *timers_db; + srslte::timers::timer *timer_aligment_timer; demux *demux_unit; srslte::log *log_h; srslte::mac_pcap *pcap; diff --git a/srsue/hdr/mac/mac.h b/srsue/hdr/mac/mac.h index 51bb467f2..a306af187 100644 --- a/srsue/hdr/mac/mac.h +++ b/srsue/hdr/mac/mac.h @@ -48,9 +48,9 @@ namespace srsue { class mac :public mac_interface_phy ,public mac_interface_rrc + ,public srslte::timer_callback ,public srslte::mac_interface_timers ,public thread - ,public srslte::timer_callback { public: mac(); @@ -90,17 +90,20 @@ public: void set_contention_id(uint64_t uecri); void get_rntis(ue_rnti_t *rntis); - - void timer_expired(uint32_t timer_id); + void start_pcap(srslte::mac_pcap* pcap); - - srslte::timers::timer* get(uint32_t timer_id); - u_int32_t get_unique_id(); - + + // Timer callback interface + void timer_expired(uint32_t timer_id); + uint32_t get_current_tti(); - - static const int MAC_NOF_UPPER_TIMERS = 20; - + + // Interface for upper-layer timers + srslte::timers::timer* timer_get(uint32_t timer_id); + void timer_release_id(uint32_t timer_id); + uint32_t timer_get_unique_id(); + + private: void run_thread(); @@ -144,13 +147,17 @@ private: /* Buffers for PCH reception (not included in DL HARQ) */ const static uint32_t pch_payload_buffer_sz = 8*1024; srslte_softbuffer_rx_t pch_softbuffer; - uint8_t pch_payload_buffer[pch_payload_buffer_sz]; - + uint8_t pch_payload_buffer[pch_payload_buffer_sz]; + + /* Functions for MAC Timers */ - srslte::timers timers_db; + uint32_t timer_alignment; + uint32_t contention_resolution_timer; void setup_timers(); - void timeAlignmentTimerExpire(); - + void timer_alignment_expire(); + srslte::timers timers; + + // pointer to MAC PCAP object srslte::mac_pcap* pcap; bool is_first_ul_grant; @@ -158,22 +165,6 @@ private: mac_metrics_t metrics; - - /* Class to run upper-layer timers with normal priority */ - class upper_timers : public periodic_thread { - public: - upper_timers(); - void reset(); - srslte::timers::timer* get(uint32_t timer_id); - uint32_t get_unique_id(); - private: - void run_period(); - srslte::timers timers_db; - }; - upper_timers upper_timers_thread; - - - /* Class to process MAC PDUs from DEMUX unit */ class pdu_process : public thread { public: diff --git a/srsue/hdr/mac/mac_common.h b/srsue/hdr/mac/mac_common.h deleted file mode 100644 index d40d179eb..000000000 --- a/srsue/hdr/mac/mac_common.h +++ /dev/null @@ -1,45 +0,0 @@ -/** - * - * \section COPYRIGHT - * - * Copyright 2013-2015 Software Radio Systems Limited - * - * \section LICENSE - * - * This file is part of the srsUE library. - * - * srsUE 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. - * - * srsUE is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * A copy of the GNU Affero General Public License can be found in - * the LICENSE file in the top-level directory of this distribution - * and at http://www.gnu.org/licenses/. - * - */ - -#ifndef MAC_COMMON_H -#define MAC_COMMON_H - -namespace srsue { - -typedef enum { - HARQ_RTT, - TIME_ALIGNMENT, - CONTENTION_TIMER, - BSR_TIMER_PERIODIC, - BSR_TIMER_RETX, - PHR_TIMER_PERIODIC, - PHR_TIMER_PROHIBIT, - NOF_MAC_TIMERS -} mac_timers_t; - -} // namespace srsue - -#endif // MAC_COMMON_H diff --git a/srsue/hdr/mac/proc_bsr.h b/srsue/hdr/mac/proc_bsr.h index 21f278e29..656e9a7a3 100644 --- a/srsue/hdr/mac/proc_bsr.h +++ b/srsue/hdr/mac/proc_bsr.h @@ -81,6 +81,9 @@ private: bool generate_bsr(bsr_t *bsr, uint32_t nof_padding_bytes); char* bsr_type_tostring(triggered_bsr_type_t type); char* bsr_format_tostring(bsr_format_t format); + + uint32_t timer_periodic_id; + uint32_t timer_retx_id; }; } // namespace srsue diff --git a/srsue/hdr/mac/proc_phr.h b/srsue/hdr/mac/proc_phr.h index 942f30456..240a7bab7 100644 --- a/srsue/hdr/mac/proc_phr.h +++ b/srsue/hdr/mac/proc_phr.h @@ -49,7 +49,9 @@ public: bool generate_phr_on_ul_grant(float *phr); void timer_expired(uint32_t timer_id); - + + void start_timer(); + private: bool pathloss_changed(); @@ -59,11 +61,15 @@ private: phy_interface_mac* phy_h; srslte::timers* timers_db; bool initiated; - int timer_prohibit; - int timer_periodic; + int timer_prohibit_value; + int timer_periodic_value; int dl_pathloss_change; int last_pathloss_db; bool phr_is_triggered; + + uint32_t timer_periodic_id; + uint32_t timer_prohibit_id; + }; } // namespace srsue diff --git a/srsue/hdr/mac/proc_ra.h b/srsue/hdr/mac/proc_ra.h index c1bdf3644..2bd2dd807 100644 --- a/srsue/hdr/mac/proc_ra.h +++ b/srsue/hdr/mac/proc_ra.h @@ -59,8 +59,7 @@ class ra_proc : public srslte::timer_callback phy_h = NULL; log_h = NULL; mac_cfg = NULL; - timers_db = NULL; - mux_unit = NULL; + mux_unit = NULL; demux_unit = NULL; rrc = NULL; transmitted_contention_id = 0; @@ -69,7 +68,10 @@ class ra_proc : public srslte::timer_callback started_by_pdcch = false; rar_grant_nbytes = 0; rar_grant_tti = 0; - msg3_flushed = false; + msg3_flushed = false; + + time_alignment_timer = NULL; + contention_resolution_timer = NULL; }; ~ra_proc(); @@ -78,8 +80,9 @@ class ra_proc : public srslte::timer_callback rrc_interface_mac *rrc_, srslte::log *log_h, mac_interface_rrc::ue_rnti_t *rntis, - mac_interface_rrc::mac_cfg_t *mac_cfg, - srslte::timers *timers_db, + mac_interface_rrc::mac_cfg_t *mac_cfg, + srslte::timers::timer* time_alignment_timer_, + srslte::timers::timer* contention_resolution_timer_, mux *mux_unit, demux *demux_unit); void reset(); @@ -101,9 +104,9 @@ class ra_proc : public srslte::timer_callback void start_pcap(srslte::mac_pcap* pcap); private: static bool uecrid_callback(void *arg, uint64_t uecri); - + bool contention_resolution_id_received(uint64_t uecri); - void process_timeadv_cmd(uint32_t ta_cmd); + void process_timeadv_cmd(uint32_t ta_cmd); void step_initialization(); void step_resource_selection(); void step_preamble_transmission(); @@ -114,14 +117,14 @@ private: void step_contention_resolution(); void step_completition(); - // Buffer to receive RAR PDU + // Buffer to receive RAR PDU static const uint32_t MAX_RAR_PDU_LEN = 2048; uint8_t rar_pdu_buffer[MAX_RAR_PDU_LEN]; - srslte::rar_pdu rar_pdu_msg; - + srslte::rar_pdu rar_pdu_msg; + // Random Access parameters provided by higher layers defined in 5.1.1 uint32_t configIndex; - uint32_t nof_preambles; + uint32_t nof_preambles; uint32_t nof_groupA_preambles; uint32_t nof_groupB_preambles; uint32_t messagePowerOffsetGroupB; @@ -130,26 +133,25 @@ private: uint32_t powerRampingStep; uint32_t preambleTransMax; uint32_t iniReceivedTargetPower; - int delta_preamble_db; - uint32_t contentionResolutionTimer; - uint32_t maskIndex; - int preambleIndex; - uint32_t new_ra_msg_len; - + int delta_preamble_db; + uint32_t contentionResolutionTimer; + uint32_t maskIndex; + int preambleIndex; + uint32_t new_ra_msg_len; + // Internal variables - uint32_t preambleTransmissionCounter; - uint32_t backoff_param_ms; - uint32_t sel_maskIndex; - uint32_t sel_preamble; + uint32_t preambleTransmissionCounter; + uint32_t backoff_param_ms; + uint32_t sel_maskIndex; + uint32_t sel_preamble; uint32_t backoff_interval_start; uint32_t backoff_inteval; - int received_target_power_dbm; - uint32_t ra_rnti; - uint32_t current_ta; - - srslte_softbuffer_rx_t softbuffer_rar; - - + int received_target_power_dbm; + uint32_t ra_rnti; + uint32_t current_ta; + + srslte_softbuffer_rx_t softbuffer_rar; + enum { IDLE = 0, INITIALIZATION, // Section 5.1.1 @@ -163,36 +165,38 @@ private: COMPLETION, // Section 5.1.6 COMPLETION_DONE, RA_PROBLEM // Section 5.1.5 last part - } state; - + } state; + typedef enum {RA_GROUP_A, RA_GROUP_B} ra_group_t; - - ra_group_t last_msg3_group; - bool msg3_transmitted; - bool first_rar_received; + + ra_group_t last_msg3_group; + bool msg3_transmitted; + bool first_rar_received; void read_params(); - + phy_interface_mac *phy_h; srslte::log *log_h; - srslte::timers *timers_db; mux *mux_unit; demux *demux_unit; srslte::mac_pcap *pcap; rrc_interface_mac *rrc; + srslte::timers::timer *time_alignment_timer; + srslte::timers::timer *contention_resolution_timer; + mac_interface_rrc::ue_rnti_t *rntis; mac_interface_rrc::mac_cfg_t *mac_cfg; - + uint64_t transmitted_contention_id; - uint16_t transmitted_crnti; - + uint16_t transmitted_crnti; + enum { - PDCCH_CRNTI_NOT_RECEIVED = 0, - PDCCH_CRNTI_UL_GRANT, - PDCCH_CRNTI_DL_GRANT + PDCCH_CRNTI_NOT_RECEIVED = 0, + PDCCH_CRNTI_UL_GRANT, + PDCCH_CRNTI_DL_GRANT } pdcch_to_crnti_received; - bool started_by_pdcch; + bool started_by_pdcch; uint32_t rar_grant_nbytes; uint32_t rar_grant_tti; bool msg3_flushed; diff --git a/srsue/hdr/mac/ul_harq.h b/srsue/hdr/mac/ul_harq.h index e57af77ba..4749971b6 100644 --- a/srsue/hdr/mac/ul_harq.h +++ b/srsue/hdr/mac/ul_harq.h @@ -35,7 +35,6 @@ #include "srslte/interfaces/ue_interfaces.h" #include "srslte/common/log.h" #include "mac/mux.h" -#include "mac/mac_common.h" #include "mac/ul_sps.h" #include "srslte/common/mac_pcap.h" #include "srslte/common/timers.h" @@ -55,9 +54,10 @@ public: ul_harq_entity() : proc(N) { - pcap = NULL; - timers_db = NULL; - mux_unit = NULL; + contention_timer = NULL; + + pcap = NULL; + mux_unit = NULL; log_h = NULL; params = NULL; rntis = NULL; @@ -68,14 +68,14 @@ public: bool init(srslte::log *log_h_, mac_interface_rrc_common::ue_rnti_t *rntis_, mac_interface_rrc_common::ul_harq_params_t *params_, - srslte::timers* timers_db_, + srslte::timers::timer* contention_timer_, mux *mux_unit_) { log_h = log_h_; mux_unit = mux_unit_; params = params_; rntis = rntis_; - timers_db = timers_db_; + contention_timer = contention_timer_; for (uint32_t i=0;itimers_db->get(CONTENTION_TIMER)->reset(); + harq_entity->contention_timer->reset(); } harq_entity->mux_unit->pusch_retx(tti_tx, pid); @@ -368,6 +368,7 @@ private: current_tx_nb = 0; current_irv = 0; is_msg3 = is_msg3_; + Info("UL %d: New TX%s, RV=%d, TBS=%d, RNTI=%d\n", pid, is_msg3?" for Msg3":"", get_rv(), cur_grant.n_bytes[0], is_msg3?harq_entity->rntis->temp_rnti:cur_grant.rnti); @@ -415,7 +416,7 @@ private: ul_sps ul_sps_assig; - srslte::timers *timers_db; + srslte::timers::timer *contention_timer; mux *mux_unit; std::vector proc; srslte::log *log_h; diff --git a/srsue/hdr/metrics_csv.h b/srsue/hdr/metrics_csv.h new file mode 100644 index 000000000..a897265d2 --- /dev/null +++ b/srsue/hdr/metrics_csv.h @@ -0,0 +1,64 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE 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. + * + * srsUE 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: metrics_csv.h + * Description: Metrics class writing to CSV file. + *****************************************************************************/ + +#ifndef METRICS_CSV_H +#define METRICS_CSV_H + +#include +#include +#include +#include +#include + +#include "srslte/common/metrics_hub.h" +#include "ue_metrics_interface.h" + +namespace srsue { + +class metrics_csv : public srslte::metrics_listener +{ +public: + metrics_csv(std::string filename); + + void set_metrics(ue_metrics_t &m, float report_period_secs); + void set_ue_handle(ue_metrics_interface *ue_); + +private: + std::string float_to_string(float f, int digits, bool add_semicolon = true); + + std::ofstream file; + ue_metrics_interface* ue; + uint32_t n_reports; +}; + +} // namespace srsue + +#endif // METRICS_CSV_H diff --git a/srsue/hdr/metrics_stdout.h b/srsue/hdr/metrics_stdout.h index cd3efc1a3..8ae33b24e 100644 --- a/srsue/hdr/metrics_stdout.h +++ b/srsue/hdr/metrics_stdout.h @@ -36,36 +36,28 @@ #include #include +#include "srslte/common/metrics_hub.h" #include "ue_metrics_interface.h" namespace srsue { -class metrics_stdout +class metrics_stdout : public srslte::metrics_listener { public: metrics_stdout(); - bool init(ue_metrics_interface *u, float report_period_secs=1.0); - void stop(); void toggle_print(bool b); - static void* metrics_thread_start(void *m); - void metrics_thread_run(); + void set_metrics(ue_metrics_t &m, float report_period_secs); + void set_ue_handle(ue_metrics_interface *ue_); private: - void print_metrics(); - void print_disconnect(); std::string float_to_string(float f, int digits); std::string float_to_eng_string(float f, int digits); std::string int_to_eng_string(int f, int digits); - - ue_metrics_interface *ue_; - bool started; - bool do_print; - pthread_t metrics_thread; - ue_metrics_t metrics; - float metrics_report_period; // seconds - uint8_t n_reports; + bool do_print; + uint8_t n_reports; + ue_metrics_interface* ue; }; } // namespace srsue diff --git a/srsue/hdr/phy/phch_common.h b/srsue/hdr/phy/phch_common.h index 7f0075e33..aa64fe9ea 100644 --- a/srsue/hdr/phy/phch_common.h +++ b/srsue/hdr/phy/phch_common.h @@ -27,6 +27,9 @@ #ifndef UEPHYWORKERCOMMON_H #define UEPHYWORKERCOMMON_H +#define TX_MODE_CONTINUOUS 1 + + #include #include #include @@ -36,8 +39,6 @@ #include "srslte/common/log.h" #include "phy/phy_metrics.h" -//#define CONTINUOUS_TX - namespace srsue { @@ -47,8 +48,8 @@ namespace srsue { /* Common variables used by all phy workers */ phy_interface_rrc::phy_cfg_t *config; - phy_args_t *args; - srslte::log *log_h; + phy_args_t *args; + rrc_interface_phy *rrc; mac_interface_phy *mac; srslte_ue_ul_t ue_ul; @@ -69,7 +70,8 @@ namespace srsue { void init(phy_interface_rrc::phy_cfg_t *config, phy_args_t *args, srslte::log *_log, - srslte::radio *_radio, + srslte::radio *_radio, + rrc_interface_phy *rrc, mac_interface_phy *_mac); /* For RNTI searches, -1 means now or forever */ @@ -116,7 +118,8 @@ namespace srsue { bool is_first_of_burst; srslte::radio *radio_h; float cfo; - + srslte::log *log_h; + bool ul_rnti_active(uint32_t tti); bool dl_rnti_active(uint32_t tti); diff --git a/srsue/hdr/phy/phch_recv.h b/srsue/hdr/phy/phch_recv.h index 784d99abc..044960760 100644 --- a/srsue/hdr/phy/phch_recv.h +++ b/srsue/hdr/phy/phch_recv.h @@ -52,13 +52,12 @@ public: void stop(); void set_agc_enable(bool enable); - void resync_sfn(); - void set_earfcn(std::vector earfcn); - bool stop_sync(); + void reset_sync(); void cell_search_start(); - void cell_search_next(); + void cell_search_stop(); + void cell_search_next(bool reset = false); bool cell_select(uint32_t earfcn, srslte_cell_t cell); uint32_t get_current_tti(); @@ -68,26 +67,42 @@ public: void set_time_adv_sec(float time_adv_sec); void get_current_cell(srslte_cell_t *cell); - const static int MUTEX_X_WORKER = 4; + const static int MUTEX_X_WORKER = 4; + + // public variables needed by callback function + uint32_t current_sflen; + srslte::radio_multi *radio_h; + int next_offset; + private: std::vector earfcn; + void reset(); + void radio_error(); + bool wait_radio_reset(); void set_ue_sync_opts(srslte_ue_sync_t *q); void run_thread(); void set_sampling_rate(); bool set_frequency(); + void resync_sfn(bool is_connected = false); + bool stop_sync(); void cell_search_inc(); - bool init_cell(); - void free_cell(); + bool init_cell(); + void free_cell(); + + void stop_rx(); + void start_rx(); + bool radio_is_rx; + + bool radio_is_resetting; bool running; - srslte::radio_multi *radio_h; mac_interface_phy *mac; rrc_interface_phy *rrc; srslte::log *log_h; @@ -114,6 +129,7 @@ private: IDLE = 0, CELL_SEARCH, CELL_SELECT, + CELL_RESELECT, CELL_MEASURE, CELL_CAMP } phy_state; @@ -123,6 +139,7 @@ private: enum { SRATE_NONE=0, SRATE_FIND, SRATE_CAMP } srate_mode; + float current_srate; srslte_cell_t cell; bool cell_is_set; @@ -148,12 +165,11 @@ private: float measure_rsrp; srslte_ue_dl_t ue_dl_measure; - const static int RSRP_MEASURE_NOF_FRAMES = 5; int cell_sync_sfn(); int cell_meas_rsrp(); - bool cell_search(int force_N_id_2 = -1); + int cell_search(int force_N_id_2 = -1); bool set_cell(); }; diff --git a/srsue/hdr/phy/phch_worker.h b/srsue/hdr/phy/phch_worker.h index e6fce4f02..0811723e0 100644 --- a/srsue/hdr/phy/phch_worker.h +++ b/srsue/hdr/phy/phch_worker.h @@ -45,14 +45,14 @@ public: ~phch_worker(); void reset(); void set_common(phch_common *phy); - bool init(uint32_t max_prb); + bool init(uint32_t max_prb, srslte::log *log); bool set_cell(srslte_cell_t cell); /* Functions used by main PHY thread */ cf_t* get_buffer(uint32_t antenna_idx); void set_tti(uint32_t tti, uint32_t tx_tti); - void set_tx_time(srslte_timestamp_t tx_time); + void set_tx_time(srslte_timestamp_t tx_time, uint32_t next_offset); void set_cfo(float cfo); void set_sample_offset(float sample_offset); @@ -113,6 +113,7 @@ private: /* Common objects */ phch_common *phy; + srslte::log *log_h; srslte_cell_t cell; bool mem_initiated; bool cell_initiated; @@ -122,7 +123,9 @@ private: bool pregen_enabled; uint32_t last_dl_pdcch_ncce; bool rnti_is_set; - + + uint32_t next_offset; + /* Objects for DL */ srslte_ue_dl_t ue_dl; uint32_t cfi; diff --git a/srsue/hdr/phy/phy.h b/srsue/hdr/phy/phy.h index c8d88ee44..0c77360b2 100644 --- a/srsue/hdr/phy/phy.h +++ b/srsue/hdr/phy/phy.h @@ -52,8 +52,8 @@ public: phy(); bool init(srslte::radio_multi *radio_handler, mac_interface_phy *mac, - rrc_interface_phy *rrc, - srslte::log *log_h, + rrc_interface_phy *rrc, + std::vector log_vec, phy_args_t *args = NULL); void stop(); @@ -79,19 +79,19 @@ public: /********** RRC INTERFACE ********************/ void reset(); + void sync_reset(); void configure_ul_params(bool pregen_disabled = false); - void resync_sfn(); void cell_search_start(); + void cell_search_stop(); void cell_search_next(); bool cell_select(uint32_t earfcn, srslte_cell_t phy_cell); /********** MAC INTERFACE ********************/ /* Functions to synchronize with a cell */ bool sync_status(); // this is also RRC interface - bool sync_stop(); /* Sets a C-RNTI allowing the PHY to pregenerate signals if necessary */ - void set_crnti(uint16_t rnti); + void set_crnti(uint16_t rnti); /* Instructs the PHY to configure using the parameters written by set_param() */ void configure_prach_params(); @@ -148,6 +148,7 @@ private: const static int WORKERS_THREAD_PRIO = 0; srslte::radio_multi *radio_handler; + std::vector log_vec; srslte::log *log_h; srsue::mac_interface_phy *mac; srsue::rrc_interface_phy *rrc; diff --git a/srsue/hdr/ue.h b/srsue/hdr/ue.h index 11565ec00..4e48f6b6d 100644 --- a/srsue/hdr/ue.h +++ b/srsue/hdr/ue.h @@ -45,7 +45,7 @@ #include "srslte/upper/pdcp.h" #include "upper/rrc.h" #include "upper/nas.h" -#include "srslte/upper/gw.h" +#include "upper/gw.h" #include "upper/usim.h" #include "srslte/common/buffer_pool.h" @@ -57,8 +57,6 @@ namespace srsue { -//#define LOG_STDOUT - /******************************************************************************* Main UE class *******************************************************************************/ @@ -82,9 +80,6 @@ public: void pregenerate_signals(bool enable); - // Testing - void test_con_restablishment(); - private: virtual ~ue(); @@ -97,16 +92,15 @@ private: srslte::pdcp pdcp; srsue::rrc rrc; srsue::nas nas; - srslte::gw gw; + srsue::gw gw; srsue::usim usim; -#ifdef LOG_STDOUT - srslte::logger_stdout logger; -#else - srslte::logger_file logger; -#endif - srslte::log_filter rf_log; - srslte::log_filter phy_log; + srslte::logger_stdout logger_stdout; + srslte::logger_file logger_file; + srslte::logger *logger; + + // rf_log is on ue_base + std::vector phy_log; srslte::log_filter mac_log; srslte::log_filter rlc_log; srslte::log_filter pdcp_log; @@ -119,8 +113,7 @@ private: all_args_t *args; bool started; - rf_metrics_t rf_metrics; - + bool check_srslte_version(); }; diff --git a/srsue/hdr/ue_base.h b/srsue/hdr/ue_base.h index b105b2088..411896f70 100644 --- a/srsue/hdr/ue_base.h +++ b/srsue/hdr/ue_base.h @@ -107,6 +107,8 @@ typedef struct { float metrics_period_secs; bool pregenerate_signals; std::string ue_cateogry; + bool metrics_csv_enable; + std::string metrics_csv_filename; }expert_args_t; typedef struct { diff --git a/srsue/hdr/ue_metrics_interface.h b/srsue/hdr/ue_metrics_interface.h index 70688863e..20ee6f031 100644 --- a/srsue/hdr/ue_metrics_interface.h +++ b/srsue/hdr/ue_metrics_interface.h @@ -29,7 +29,8 @@ #include -#include "srslte/upper/gw_metrics.h" +#include "srslte/common/metrics_hub.h" +#include "upper/gw_metrics.h" #include "srslte/upper/rlc_metrics.h" #include "mac/mac_metrics.h" #include "phy/phy_metrics.h" @@ -48,14 +49,15 @@ typedef struct { phy_metrics_t phy; mac_metrics_t mac; srslte::rlc_metrics_t rlc; - srslte::gw_metrics_t gw; + gw_metrics_t gw; }ue_metrics_t; // UE interface -class ue_metrics_interface +class ue_metrics_interface : public srslte::metrics_interface { public: virtual bool get_metrics(ue_metrics_t &m) = 0; + virtual bool is_attached() = 0; }; } // namespace srsue diff --git a/lib/include/srslte/upper/gw.h b/srsue/hdr/upper/gw.h similarity index 77% rename from lib/include/srslte/upper/gw.h rename to srsue/hdr/upper/gw.h index aa92ddc32..800b31624 100644 --- a/lib/include/srslte/upper/gw.h +++ b/srsue/hdr/upper/gw.h @@ -33,39 +33,40 @@ #include "srslte/common/msg_queue.h" #include "srslte/interfaces/ue_interfaces.h" #include "srslte/common/threads.h" -#include "srslte/upper/gw_metrics.h" +#include "gw_metrics.h" #include -namespace srslte { +namespace srsue { class gw - :public srsue::gw_interface_pdcp - ,public srsue::gw_interface_nas + :public gw_interface_pdcp + ,public gw_interface_nas ,public thread { public: gw(); - void init(srsue::pdcp_interface_gw *pdcp_, srsue::ue_interface *ue_, log *gw_log_, uint32_t lcid_); + void init(pdcp_interface_gw *pdcp_, nas_interface_gw *nas_, srslte::log *gw_log_, uint32_t lcid_); void stop(); void get_metrics(gw_metrics_t &m); // PDCP interface - void write_pdu(uint32_t lcid, byte_buffer_t *pdu); + void write_pdu(uint32_t lcid, srslte::byte_buffer_t *pdu); // NAS interface - error_t setup_if_addr(uint32_t ip_addr, char *err_str); + srslte::error_t setup_if_addr(uint32_t ip_addr, char *err_str); private: static const int GW_THREAD_PRIO = 7; - srsue::pdcp_interface_gw *pdcp; - srsue::ue_interface *ue; + pdcp_interface_gw *pdcp; + nas_interface_gw *nas; - byte_buffer_pool *pool; - log *gw_log; + srslte::byte_buffer_pool *pool; + + srslte::log *gw_log; bool running; bool run_enable; int32 tun_fd; @@ -81,7 +82,7 @@ private: struct timeval metrics_time[3]; void run_thread(); - error_t init_if(char *err_str); + srslte::error_t init_if(char *err_str); }; } // namespace srsue diff --git a/lib/include/srslte/upper/gw_metrics.h b/srsue/hdr/upper/gw_metrics.h similarity index 98% rename from lib/include/srslte/upper/gw_metrics.h rename to srsue/hdr/upper/gw_metrics.h index b5d8eaf23..e596046c9 100644 --- a/lib/include/srslte/upper/gw_metrics.h +++ b/srsue/hdr/upper/gw_metrics.h @@ -28,7 +28,7 @@ #define UE_GW_METRICS_H -namespace srslte { +namespace srsue { struct gw_metrics_t { diff --git a/srsue/hdr/upper/nas.h b/srsue/hdr/upper/nas.h index 0f9b36bf8..68d00ba06 100644 --- a/srsue/hdr/upper/nas.h +++ b/srsue/hdr/upper/nas.h @@ -63,7 +63,10 @@ typedef enum { } plmn_selection_state_t; class nas - : public nas_interface_rrc, public nas_interface_ue { + : public nas_interface_rrc, + public nas_interface_ue, + public nas_interface_gw +{ public: nas(); void init(usim_interface_nas *usim_, @@ -83,6 +86,7 @@ public: uint32_t get_ul_count(); bool is_attached(); + bool is_attaching(); bool get_s_tmsi(LIBLTE_RRC_S_TMSI_STRUCT *s_tmsi); @@ -106,6 +110,7 @@ private: plmn_selection_state_t plmn_selection; LIBLTE_RRC_PLMN_IDENTITY_STRUCT current_plmn; + LIBLTE_RRC_PLMN_IDENTITY_STRUCT selecting_plmn; LIBLTE_RRC_PLMN_IDENTITY_STRUCT home_plmn; std::vector known_plmns; diff --git a/srsue/hdr/upper/rrc.h b/srsue/hdr/upper/rrc.h index 81514b559..8dfa7f70d 100644 --- a/srsue/hdr/upper/rrc.h +++ b/srsue/hdr/upper/rrc.h @@ -78,8 +78,6 @@ public: // Timeout callback interface void timer_expired(uint32_t timeout_id); - void test_con_restablishment(); - void liblte_rrc_log(char *str); private: @@ -130,7 +128,6 @@ private: uint32_t n310_cnt, N310; uint32_t n311_cnt, N311; uint32_t t301, t310, t311; - uint32_t safe_reset_timer; int ue_category; typedef struct { @@ -155,6 +152,10 @@ private: } si_acquire_state_t; si_acquire_state_t si_acquire_state; + void run_si_acquisition_procedure(); + uint32_t sib_start_tti(uint32_t tti, uint32_t period, uint32_t x); + uint32_t nof_sib1_trials; + uint32_t last_win_start; void select_next_cell_in_plmn(); LIBLTE_RRC_PLMN_IDENTITY_STRUCT selected_plmn_id; @@ -242,12 +243,10 @@ private: void parse_dl_info_transfer(uint32_t lcid, byte_buffer_t *pdu); // Helpers - void reset_ue(); void rrc_connection_release(); void radio_link_failure(); static void* start_sib_thread(void *rrc_); void sib_search(); - uint32_t sib_start_tti(uint32_t tti, uint32_t period, uint32_t x); void apply_sib2_configs(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT *sib2); void handle_con_setup(LIBLTE_RRC_CONNECTION_SETUP_STRUCT *setup); void handle_con_reest(LIBLTE_RRC_CONNECTION_REESTABLISHMENT_STRUCT *setup); diff --git a/srsue/hdr/upper/rrc_common.h b/srsue/hdr/upper/rrc_common.h index 40edfb467..95b909620 100644 --- a/srsue/hdr/upper/rrc_common.h +++ b/srsue/hdr/upper/rrc_common.h @@ -38,14 +38,16 @@ typedef enum { RRC_STATE_CELL_SELECTED, RRC_STATE_CONNECTING, RRC_STATE_CONNECTED, + RRC_STATE_LEAVE_CONNECTED, RRC_STATE_N_ITEMS, } rrc_state_t; static const char rrc_state_text[RRC_STATE_N_ITEMS][100] = {"IDLE", "PLMN SELECTION", - "CELL SELECTION", + "CELL SELECTING", + "CELL SELECTED", "CONNECTING", "CONNECTED", - "RRC CONNECTED"}; + "LEAVE CONNECTED"}; } // namespace srsue diff --git a/srsue/src/CMakeLists.txt b/srsue/src/CMakeLists.txt index 5c6000f63..0755a6490 100644 --- a/srsue/src/CMakeLists.txt +++ b/srsue/src/CMakeLists.txt @@ -31,7 +31,7 @@ if (RPATH) set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE) endif (RPATH) -add_executable(srsue main.cc ue_base.cc ue.cc metrics_stdout.cc) +add_executable(srsue main.cc ue_base.cc ue.cc metrics_stdout.cc metrics_csv.cc) target_link_libraries(srsue srsue_mac srsue_phy srsue_upper diff --git a/srsue/src/mac/demux.cc b/srsue/src/mac/demux.cc index 4fcb402fc..75bafd1b4 100644 --- a/srsue/src/mac/demux.cc +++ b/srsue/src/mac/demux.cc @@ -40,12 +40,12 @@ demux::demux(uint8_t nof_harq_proc_) : mac_msg(20), pending_mac_msg(20), nof_har { } -void demux::init(phy_interface_mac_common* phy_h_, rlc_interface_mac *rlc_, srslte::log* log_h_, srslte::timers* timers_db_) +void demux::init(phy_interface_mac_common* phy_h_, rlc_interface_mac *rlc_, srslte::log* log_h_, srslte::timers::timer* time_alignment_timer_) { phy_h = phy_h_; log_h = log_h_; - rlc = rlc_; - timers_db = timers_db_; + rlc = rlc_; + time_alignment_timer = time_alignment_timer_; pdus.init(this, log_h); } @@ -190,8 +190,8 @@ bool demux::process_ce(srslte::sch_subh *subh) { Info("Received TA=%d\n", subh->get_ta_cmd()); // Start or restart timeAlignmentTimer - timers_db->get(TIME_ALIGNMENT)->reset(); - timers_db->get(TIME_ALIGNMENT)->run(); + time_alignment_timer->reset(); + time_alignment_timer->run(); break; case srslte::sch_subh::PADDING: break; diff --git a/srsue/src/mac/mac.cc b/srsue/src/mac/mac.cc index f28e43553..60327fcd4 100644 --- a/srsue/src/mac/mac.cc +++ b/srsue/src/mac/mac.cc @@ -42,62 +42,64 @@ namespace srsue { mac::mac() : ttisync(10240), - timers_db((uint32_t) NOF_MAC_TIMERS), + timers(64), mux_unit(MAC_NOF_HARQ_PROC), demux_unit(SRSLTE_MAX_TB*MAC_NOF_HARQ_PROC), pdu_process_thread(&demux_unit) { - started = false; - pcap = NULL; + started = false; + pcap = NULL; bzero(&metrics, sizeof(mac_metrics_t)); } - + bool mac::init(phy_interface_mac *phy, rlc_interface_mac *rlc, rrc_interface_mac *rrc, srslte::log *log_h_) { - started = false; + started = false; phy_h = phy; - rlc_h = rlc; - rrc_h = rrc; - log_h = log_h_; - tti = 0; - is_synchronized = false; - last_temporal_crnti = 0; - phy_rnti = 0; - + rlc_h = rlc; + rrc_h = rrc; + log_h = log_h_; + tti = 0; + is_synchronized = false; + last_temporal_crnti = 0; + phy_rnti = 0; + srslte_softbuffer_rx_init(&pch_softbuffer, 100); - - bsr_procedure.init( rlc_h, log_h, &config, &timers_db); - phr_procedure.init(phy_h, log_h, &config, &timers_db); + + timer_alignment = timers.get_unique_id(); + contention_resolution_timer = timers.get_unique_id(); + + bsr_procedure.init( rlc_h, log_h, &config, &timers); + phr_procedure.init(phy_h, log_h, &config, &timers); mux_unit.init ( rlc_h, log_h, &bsr_procedure, &phr_procedure); - demux_unit.init (phy_h, rlc_h, log_h, &timers_db); - ra_procedure.init (phy_h, rrc, log_h, &uernti, &config, &timers_db, &mux_unit, &demux_unit); + demux_unit.init (phy_h, rlc_h, log_h, timers.get(timer_alignment)); + ra_procedure.init (phy_h, rrc, log_h, &uernti, &config, timers.get(timer_alignment), timers.get(contention_resolution_timer), &mux_unit, &demux_unit); sr_procedure.init (phy_h, rrc, log_h, &config); - ul_harq.init ( log_h, &uernti, &config.ul_harq_params, &timers_db, &mux_unit); - dl_harq.init ( log_h, &timers_db, &demux_unit); + ul_harq.init ( log_h, &uernti, &config.ul_harq_params, timers.get(contention_resolution_timer), &mux_unit); + dl_harq.init ( log_h, timers.get(timer_alignment), &demux_unit); reset(); - - started = true; + + started = true; start(MAC_MAIN_THREAD_PRIO); - - - return started; + + + return started; } void mac::stop() { srslte_softbuffer_rx_free(&pch_softbuffer); - started = false; + started = false; ttisync.increase(); - upper_timers_thread.thread_cancel(); pdu_process_thread.stop(); wait_thread_finish(); } void mac::start_pcap(srslte::mac_pcap* pcap_) { - pcap = pcap_; + pcap = pcap_; dl_harq.start_pcap(pcap); ul_harq.start_pcap(pcap); ra_procedure.start_pcap(pcap); @@ -113,75 +115,72 @@ void mac::reconfiguration() void mac::reset() { bzero(&metrics, sizeof(mac_metrics_t)); - + Info("Resetting MAC\n"); - - timers_db.stop_all(); - upper_timers_thread.reset(); - + + timers.stop_all(); + ul_harq.reset_ndi(); - + mux_unit.msg3_flush(); mux_unit.reset(); - - ra_procedure.reset(); + + ra_procedure.reset(); sr_procedure.reset(); bsr_procedure.reset(); phr_procedure.reset(); - + dl_harq.reset(); phy_h->pdcch_dl_search_reset(); phy_h->pdcch_ul_search_reset(); - + is_first_ul_grant = true; - + bzero(&uernti, sizeof(ue_rnti_t)); } void mac::run_thread() { int cnt=0; + while (!phy_h->sync_status() && started) { + usleep(5000); + if (phy_h->sync_status()) { + Debug("Setting ttysync to %d\n", phy_h->get_current_tti()); + ttisync.set_producer_cntr(phy_h->get_current_tti()); + } + } + while(started) { - while (!phy_h->sync_status() && started) { - usleep(5000); - if (phy_h->sync_status()) { - Debug("Setting ttysync to %d\n", phy_h->get_current_tti()); - ttisync.set_producer_cntr(phy_h->get_current_tti()); - } + /* Warning: Here order of invocation of procedures is important!! */ + ttisync.wait(); + tti = phy_h->get_current_tti(); + + log_h->step(tti); + timers.step_all(); + + // Step all procedures + bsr_procedure.step(tti); + phr_procedure.step(tti); + + // Check if BSR procedure need to start SR + + if (bsr_procedure.need_to_send_sr(tti)) { + Debug("Starting SR procedure by BSR request, PHY TTI=%d\n", tti); + sr_procedure.start(); } - - if (started && phy_h->sync_status()) { - /* Warning: Here order of invocation of procedures is important!! */ - ttisync.wait(); - tti = phy_h->get_current_tti(); - - log_h->step(tti); - timers_db.step_all(); - - // Step all procedures - bsr_procedure.step(tti); - phr_procedure.step(tti); - - // Check if BSR procedure need to start SR - - if (bsr_procedure.need_to_send_sr(tti)) { - Debug("Starting SR procedure by BSR request, PHY TTI=%d\n", tti); - sr_procedure.start(); - } - if (bsr_procedure.need_to_reset_sr()) { - Debug("Resetting SR procedure by BSR request\n"); - sr_procedure.reset(); - } - sr_procedure.step(tti); - - // Check SR if we need to start RA - if (sr_procedure.need_random_access()) { - ra_procedure.start_mac_order(); - } - ra_procedure.step(tti); + if (bsr_procedure.need_to_reset_sr()) { + Debug("Resetting SR procedure by BSR request\n"); + sr_procedure.reset(); } - } + sr_procedure.step(tti); + + // Check SR if we need to start RA + if (sr_procedure.need_random_access()) { + ra_procedure.start_mac_order(); + } + ra_procedure.step(tti); + } } void mac::bcch_start_rx() @@ -197,7 +196,7 @@ void mac::bcch_start_rx(int si_window_start, int si_window_length) } else { phy_h->pdcch_dl_search(SRSLTE_RNTI_SI, SRSLTE_SIRNTI, si_window_start); } - Info("SCHED: Searching for DL grant for SI-RNTI window_st=%d, window_len=%d\n", si_window_start, si_window_length); + Info("SCHED: Searching for DL grant for SI-RNTI window_st=%d, window_len=%d\n", si_window_start, si_window_length); } void mac::bcch_stop_rx() @@ -208,7 +207,7 @@ void mac::bcch_stop_rx() void mac::pcch_start_rx() { phy_h->pdcch_dl_search(SRSLTE_RNTI_PCH, SRSLTE_PRNTI); - Info("SCHED: Searching for DL grant for P-RNTI\n"); + Info("SCHED: Searching for DL grant for P-RNTI\n"); } void mac::pcch_stop_rx() @@ -224,9 +223,9 @@ void mac::tti_clock(uint32_t tti) void mac::bch_decoded_ok(uint8_t* payload, uint32_t len) { - // Send MIB to RLC + // Send MIB to RLC rlc_h->write_pdu_bcch_bch(payload, len); - + if (pcap) { pcap->write_dl_bch(payload, len, true, phy_h->get_current_tti()); } @@ -234,9 +233,9 @@ void mac::bch_decoded_ok(uint8_t* payload, uint32_t len) void mac::pch_decoded_ok(uint32_t len) { - // Send PCH payload to RLC + // Send PCH payload to RLC rlc_h->write_pdu_pcch(pch_payload_buffer, len); - + if (pcap) { pcap->write_dl_pch(pch_payload_buffer, len, true, phy_h->get_current_tti()); } @@ -267,8 +266,8 @@ void mac::new_grant_dl(mac_interface_phy::mac_grant_t grant, mac_interface_phy:: } else if (grant.rnti_type == SRSLTE_RNTI_PCH) { memcpy(&action->phy_grant, &grant.phy_grant, sizeof(srslte_phy_grant_t)); - action->generate_ack = false; - action->decode_enabled = true; + action->generate_ack = false; + action->decode_enabled[0] = true; srslte_softbuffer_rx_reset_cb(&pch_softbuffer, 1); action->payload_ptr[0] = pch_payload_buffer; action->softbuffers[0] = &pch_softbuffer; @@ -276,12 +275,12 @@ void mac::new_grant_dl(mac_interface_phy::mac_grant_t grant, mac_interface_phy:: action->rv[0] = grant.rv[0]; if (grant.n_bytes[0] > pch_payload_buffer_sz) { Error("Received grant for PCH (%d bytes) exceeds buffer (%d bytes)\n", grant.n_bytes[0], pch_payload_buffer_sz); - action->decode_enabled = false; + action->decode_enabled[0] = false; } } else { // If PDCCH for C-RNTI and RA procedure in Contention Resolution, notify it if (grant.rnti_type == SRSLTE_RNTI_USER && ra_procedure.is_contention_resolution()) { - ra_procedure.pdcch_to_crnti(false); + ra_procedure.pdcch_to_crnti(false); } dl_harq.new_grant_dl(grant, action); } @@ -296,11 +295,11 @@ void mac::new_grant_ul(mac_interface_phy::mac_grant_t grant, mac_interface_phy:: { /* Start PHR Periodic timer on first UL grant */ if (is_first_ul_grant) { - is_first_ul_grant = false; - timers_db.get(PHR_TIMER_PERIODIC)->run(); + is_first_ul_grant = false; + phr_procedure.start_timer(); } if (grant.rnti_type == SRSLTE_RNTI_USER && ra_procedure.is_contention_resolution()) { - ra_procedure.pdcch_to_crnti(true); + ra_procedure.pdcch_to_crnti(true); } ul_harq.new_grant_ul(grant, action); metrics.tx_pkts++; @@ -308,6 +307,7 @@ void mac::new_grant_ul(mac_interface_phy::mac_grant_t grant, mac_interface_phy:: void mac::new_grant_ul_ack(mac_interface_phy::mac_grant_t grant, bool ack, mac_interface_phy::tb_action_ul_t* action) { + log_h->info("new_grant_ul_ack\n"); int tbs = ul_harq.get_current_tbs(tti); ul_harq.new_grant_ul_ack(grant, ack, action); if (!ack) { @@ -343,25 +343,23 @@ void mac::setup_timers() { int value = liblte_rrc_time_alignment_timer_num[config.main.time_alignment_timer]; if (value > 0) { - timers_db.get(TIME_ALIGNMENT)->set(this, value); + timers.get(timer_alignment)->set(this, value); } } void mac::timer_expired(uint32_t timer_id) { - switch(timer_id) { - case TIME_ALIGNMENT: - timeAlignmentTimerExpire(); - break; - default: - break; + if(timer_id == timer_alignment) { + timer_alignment_expire(); + } else { + Warning("Received callback from unknown timer_id=%d\n", timer_id); } } /* Function called on expiry of TimeAlignmentTimer */ -void mac::timeAlignmentTimerExpire() +void mac::timer_alignment_expire() { - printf("timeAlignmentTimer has expired value=%d ms\n", timers_db.get(TIME_ALIGNMENT)->get_timeout()); + printf("TimeAlignment timer has expired value=%d ms\n", timers.get(timer_alignment)->get_timeout()); rrc_h->release_pucch_srs(); dl_harq.reset(); ul_harq.reset(); @@ -374,7 +372,7 @@ void mac::get_rntis(ue_rnti_t* rntis) void mac::set_contention_id(uint64_t uecri) { - uernti.contention_id = uecri; + uernti.contention_id = uecri; } void mac::get_config(mac_cfg_t* mac_cfg) @@ -407,25 +405,13 @@ void mac::set_config_sr(LIBLTE_RRC_SCHEDULING_REQUEST_CONFIG_STRUCT* sr_cfg) void mac::setup_lcid(uint32_t lcid, uint32_t lcg, uint32_t priority, int PBR_x_tti, uint32_t BSD) { - Info("Logical Channel Setup: LCID=%d, LCG=%d, priority=%d, PBR=%d, BSd=%d\n", + Info("Logical Channel Setup: LCID=%d, LCG=%d, priority=%d, PBR=%d, BSd=%d\n", lcid, lcg, priority, PBR_x_tti, BSD); mux_unit.set_priority(lcid, priority, PBR_x_tti, BSD); bsr_procedure.setup_lcg(lcid, lcg); bsr_procedure.set_priority(lcid, priority); } -uint32_t mac::get_unique_id() -{ - return upper_timers_thread.get_unique_id(); -} - -/* Front-end to upper-layer timers */ -srslte::timers::timer* mac::get(uint32_t timer_id) -{ - return upper_timers_thread.get(timer_id); -} - - void mac::get_metrics(mac_metrics_t &m) { Info("DL retx: %.2f \%%, perpkt: %.2f, UL retx: %.2f \%% perpkt: %.2f\n", @@ -440,39 +426,28 @@ void mac::get_metrics(mac_metrics_t &m) } + + /******************************************************** * - * Class to run upper-layer timers with normal priority + * Interface for timers used by upper layers * *******************************************************/ - -mac::upper_timers::upper_timers() : timers_db(MAC_NOF_UPPER_TIMERS) +srslte::timers::timer* mac::timer_get(uint32_t timer_id) { - start_periodic(1000, MAC_MAIN_THREAD_PRIO+1); + return timers.get(timer_id); } -void mac::upper_timers::run_period() +void mac::timer_release_id(uint32_t timer_id) { - timers_db.step_all(); -} - -srslte::timers::timer* mac::upper_timers::get(uint32_t timer_id) -{ - return timers_db.get(timer_id%MAC_NOF_UPPER_TIMERS); + timers.release_id(timer_id); } -uint32_t mac::upper_timers::get_unique_id() +uint32_t mac::timer_get_unique_id() { - return timers_db.get_unique_id(); + return timers.get_unique_id(); } -void mac::upper_timers::reset() -{ - timers_db.stop_all(); -} - - - /******************************************************** * diff --git a/srsue/src/mac/proc_bsr.cc b/srsue/src/mac/proc_bsr.cc index 3117eeffc..898943ab9 100644 --- a/srsue/src/mac/proc_bsr.cc +++ b/srsue/src/mac/proc_bsr.cc @@ -50,17 +50,21 @@ void bsr_proc::init(rlc_interface_mac *rlc_, srslte::log* log_h_, mac_interface_ log_h = log_h_; rlc = rlc_; mac_cfg = mac_cfg_; - timers_db = timers_db_; + timers_db = timers_db_; + + timer_periodic_id = timers_db->get_unique_id(); + timer_retx_id = timers_db->get_unique_id(); + reset(); initiated = true; } void bsr_proc::reset() { - timers_db->get(BSR_TIMER_PERIODIC)->stop(); - timers_db->get(BSR_TIMER_PERIODIC)->reset(); - timers_db->get(BSR_TIMER_RETX)->stop(); - timers_db->get(BSR_TIMER_RETX)->reset(); + timers_db->get(timer_periodic_id)->stop(); + timers_db->get(timer_periodic_id)->reset(); + timers_db->get(timer_retx_id)->stop(); + timers_db->get(timer_retx_id)->reset(); reset_sr = false; sr_is_sent = false; @@ -77,23 +81,20 @@ void bsr_proc::reset() /* Process Periodic BSR */ void bsr_proc::timer_expired(uint32_t timer_id) { - switch(timer_id) { - case BSR_TIMER_PERIODIC: - if (triggered_bsr_type == NONE) { - // Check condition 4 in Sec 5.4.5 - triggered_bsr_type = PERIODIC; - Debug("BSR: Triggering Periodic BSR\n"); - } - break; - case BSR_TIMER_RETX: - // Enable reTx of SR only if periodic timer is not infinity - int periodic = liblte_rrc_periodic_bsr_timer_num[mac_cfg->main.ulsch_cnfg.periodic_bsr_timer]; - if (periodic >= 0) { - triggered_bsr_type = REGULAR; - Debug("BSR: Triggering BSR reTX\n"); - sr_is_sent = false; - } - break; + if(timer_id == timer_periodic_id) { + if (triggered_bsr_type == NONE) { + // Check condition 4 in Sec 5.4.5 + triggered_bsr_type = PERIODIC; + Debug("BSR: Triggering Periodic BSR\n"); + } + } else if (timer_id == timer_retx_id) { + // Enable reTx of SR only if periodic timer is not infinity + int periodic = liblte_rrc_periodic_bsr_timer_num[mac_cfg->main.ulsch_cnfg.periodic_bsr_timer]; + if (periodic >= 0) { + triggered_bsr_type = REGULAR; + Debug("BSR: Triggering BSR reTX\n"); + sr_is_sent = false; + } } } @@ -222,17 +223,17 @@ void bsr_proc::step(uint32_t tti) } int periodic = liblte_rrc_periodic_bsr_timer_num[mac_cfg->main.ulsch_cnfg.periodic_bsr_timer]; - if (periodic > 0 && (uint32_t)periodic != timers_db->get(BSR_TIMER_PERIODIC)->get_timeout()) + if (periodic > 0 && (uint32_t)periodic != timers_db->get(timer_periodic_id)->get_timeout()) { - timers_db->get(BSR_TIMER_PERIODIC)->set(this, periodic); - timers_db->get(BSR_TIMER_PERIODIC)->run(); + timers_db->get(timer_periodic_id)->set(this, periodic); + timers_db->get(timer_periodic_id)->run(); Info("BSR: Configured timer periodic %d ms\n", periodic); } int retx = liblte_rrc_retransmission_bsr_timer_num[mac_cfg->main.ulsch_cnfg.retx_bsr_timer]; - if (retx > 0 && (uint32_t)retx != timers_db->get(BSR_TIMER_RETX)->get_timeout()) + if (retx > 0 && (uint32_t)retx != timers_db->get(timer_retx_id)->get_timeout()) { - timers_db->get(BSR_TIMER_RETX)->set(this, retx); - timers_db->get(BSR_TIMER_RETX)->run(); + timers_db->get(timer_retx_id)->set(this, retx); + timers_db->get(timer_retx_id)->run(); Info("BSR: Configured timer reTX %d ms\n", retx); } @@ -309,18 +310,18 @@ bool bsr_proc::need_to_send_bsr_on_ul_grant(uint32_t grant_size, bsr_t *bsr) grant_size, total_data, bsr_sz); ret = true; } - if (timers_db->get(BSR_TIMER_PERIODIC)->get_timeout() && bsr->format != TRUNC_BSR) { - timers_db->get(BSR_TIMER_PERIODIC)->reset(); - timers_db->get(BSR_TIMER_PERIODIC)->run(); + if (timers_db->get(timer_periodic_id)->get_timeout() && bsr->format != TRUNC_BSR) { + timers_db->get(timer_periodic_id)->reset(); + timers_db->get(timer_periodic_id)->run(); } } // Cancel all triggered BSR and SR triggered_bsr_type = NONE; reset_sr = true; // Restart or Start ReTX timer - if (timers_db->get(BSR_TIMER_RETX)->get_timeout()) { - timers_db->get(BSR_TIMER_RETX)->reset(); - timers_db->get(BSR_TIMER_RETX)->run(); + if (timers_db->get(timer_retx_id)->get_timeout()) { + timers_db->get(timer_retx_id)->reset(); + timers_db->get(timer_retx_id)->run(); } return ret; } @@ -340,9 +341,9 @@ bool bsr_proc::generate_padding_bsr(uint32_t nof_padding_bytes, bsr_t *bsr) bsr_type_tostring(triggered_bsr_type), bsr_format_tostring(bsr->format), bsr->buff_size[0], bsr->buff_size[1], bsr->buff_size[2], bsr->buff_size[3]); - if (timers_db->get(BSR_TIMER_PERIODIC)->get_timeout() && bsr->format != TRUNC_BSR) { - timers_db->get(BSR_TIMER_PERIODIC)->reset(); - timers_db->get(BSR_TIMER_PERIODIC)->run(); + if (timers_db->get(timer_periodic_id)->get_timeout() && bsr->format != TRUNC_BSR) { + timers_db->get(timer_periodic_id)->reset(); + timers_db->get(timer_periodic_id)->run(); } } diff --git a/srsue/src/mac/proc_phr.cc b/srsue/src/mac/proc_phr.cc index 11828f306..ead0bf153 100644 --- a/srsue/src/mac/proc_phr.cc +++ b/srsue/src/mac/proc_phr.cc @@ -49,14 +49,18 @@ void phr_proc::init(phy_interface_mac* phy_h_, srslte::log* log_h_, mac_interfac mac_cfg = mac_cfg_; timers_db = timers_db_; initiated = true; + + timer_periodic_id = timers_db->get_unique_id(); + timer_prohibit_id = timers_db->get_unique_id(); + reset(); } void phr_proc::reset() { phr_is_triggered = false; - timer_periodic = -2; - timer_prohibit = -2; + timer_periodic_value = -2; + timer_prohibit_value = -2; dl_pathloss_change = -2; } @@ -72,23 +76,26 @@ bool phr_proc::pathloss_changed() { return false; } } + +void phr_proc::start_timer() { + timers_db->get(timer_periodic_id)->run(); +} /* Trigger PHR when timers exire */ void phr_proc::timer_expired(uint32_t timer_id) { - switch(timer_id) { - case PHR_TIMER_PERIODIC: - timers_db->get(PHR_TIMER_PERIODIC)->reset(); - timers_db->get(PHR_TIMER_PERIODIC)->run(); - Debug("PHR: Triggered by timer periodic (timer expired).\n"); - phr_is_triggered = true; - break; - case PHR_TIMER_PROHIBIT: - int pathloss_db = liblte_rrc_dl_pathloss_change_num[mac_cfg->main.phr_cnfg.dl_pathloss_change]; - if (pathloss_changed()) { - Info("PHR: Triggered by pathloss difference. cur_pathloss_db=%f (timer expired)\n", last_pathloss_db); - phr_is_triggered = true; - } - break; + if(timer_id == timer_periodic_id) { + timers_db->get(timer_periodic_id)->reset(); + timers_db->get(timer_periodic_id)->run(); + Debug("PHR: Triggered by timer periodic (timer expired).\n"); + phr_is_triggered = true; + } else if (timer_id == timer_prohibit_id) { + int pathloss_db = liblte_rrc_dl_pathloss_change_num[mac_cfg->main.phr_cnfg.dl_pathloss_change]; + if (pathloss_changed()) { + Info("PHR: Triggered by pathloss difference. cur_pathloss_db=%f (timer expired)\n", last_pathloss_db); + phr_is_triggered = true; + } + } else { + log_h->warning("Received timer callback from unknown timer_id=%d\n", timer_id); } } @@ -102,28 +109,28 @@ void phr_proc::step(uint32_t tti) int cfg_timer_periodic = liblte_rrc_periodic_phr_timer_num[mac_cfg->main.phr_cnfg.periodic_phr_timer]; // Setup timers and trigger PHR when configuration changed by higher layers - if (timer_periodic != cfg_timer_periodic && cfg_timer_periodic > 0) + if (timer_periodic_value != cfg_timer_periodic && cfg_timer_periodic > 0) { - timer_periodic = cfg_timer_periodic; - timers_db->get(PHR_TIMER_PERIODIC)->set(this, timer_periodic); - timers_db->get(PHR_TIMER_PERIODIC)->run(); + timer_periodic_value = cfg_timer_periodic; + timers_db->get(timer_periodic_id)->set(this, timer_periodic_value); + timers_db->get(timer_periodic_id)->run(); phr_is_triggered = true; - Info("PHR: Configured timer periodic %d ms\n", timer_periodic); + Info("PHR: Configured timer periodic %d ms\n", timer_periodic_value); } } int cfg_timer_prohibit = liblte_rrc_prohibit_phr_timer_num[mac_cfg->main.phr_cnfg.prohibit_phr_timer]; - if (timer_prohibit != cfg_timer_prohibit && cfg_timer_prohibit > 0) + if (timer_prohibit_value != cfg_timer_prohibit && cfg_timer_prohibit > 0) { - timer_prohibit = cfg_timer_prohibit; - timers_db->get(PHR_TIMER_PROHIBIT)->set(this, timer_prohibit); - timers_db->get(PHR_TIMER_PROHIBIT)->run(); - Info("PHR: Configured timer prohibit %d ms\n", timer_prohibit); + timer_prohibit_value = cfg_timer_prohibit; + timers_db->get(timer_prohibit_id)->set(this, timer_prohibit_value); + timers_db->get(timer_prohibit_id)->run(); + Info("PHR: Configured timer prohibit %d ms\n", timer_prohibit_value); phr_is_triggered = true; } - if (pathloss_changed() && timers_db->get(PHR_TIMER_PROHIBIT)->is_expired()) + if (pathloss_changed() && timers_db->get(timer_prohibit_id)->is_expired()) { Info("PHR: Triggered by pathloss difference. cur_pathloss_db=%f\n", last_pathloss_db); phr_is_triggered = true; @@ -140,10 +147,10 @@ bool phr_proc::generate_phr_on_ul_grant(float *phr) Debug("PHR: Generating PHR=%f\n", phr?*phr:0.0); - timers_db->get(PHR_TIMER_PERIODIC)->reset(); - timers_db->get(PHR_TIMER_PROHIBIT)->reset(); - timers_db->get(PHR_TIMER_PERIODIC)->run(); - timers_db->get(PHR_TIMER_PROHIBIT)->run(); + timers_db->get(timer_periodic_id)->reset(); + timers_db->get(timer_prohibit_id)->reset(); + timers_db->get(timer_periodic_id)->run(); + timers_db->get(timer_prohibit_id)->run(); phr_is_triggered = false; diff --git a/srsue/src/mac/proc_ra.cc b/srsue/src/mac/proc_ra.cc index 28a2b47e3..4bceef2a5 100644 --- a/srsue/src/mac/proc_ra.cc +++ b/srsue/src/mac/proc_ra.cc @@ -53,7 +53,8 @@ void ra_proc::init(phy_interface_mac* phy_h_, srslte::log* log_h_, mac_interface_rrc::ue_rnti_t *rntis_, mac_interface_rrc::mac_cfg_t *mac_cfg_, - srslte::timers* timers_db_, + srslte::timers::timer* time_alignment_timer_, + srslte::timers::timer* contention_resolution_timer_, mux* mux_unit_, demux* demux_unit_) { @@ -61,10 +62,13 @@ void ra_proc::init(phy_interface_mac* phy_h_, log_h = log_h_; mac_cfg = mac_cfg_; rntis = rntis_; - timers_db = timers_db_; mux_unit = mux_unit_; demux_unit= demux_unit_; - rrc = rrc_; + rrc = rrc_; + + time_alignment_timer = time_alignment_timer_; + contention_resolution_timer = contention_resolution_timer_; + srslte_softbuffer_rx_init(&softbuffer_rar, 10); // Tell demux to call us when a UE CRID is received @@ -119,7 +123,7 @@ void ra_proc::read_params() { delta_preamble_db = delta_preamble_db_table[configIndex%5]; if (contentionResolutionTimer > 0) { - timers_db->get(CONTENTION_TIMER)->set(this, contentionResolutionTimer); + contention_resolution_timer->set(this, contentionResolutionTimer); } } @@ -169,14 +173,14 @@ void ra_proc::process_timeadv_cmd(uint32_t ta) { if (preambleIndex == 0) { // Preamble not selected by UE MAC phy_h->set_timeadv_rar(ta); - timers_db->get(TIME_ALIGNMENT)->reset(); - timers_db->get(TIME_ALIGNMENT)->run(); + time_alignment_timer->reset(); + time_alignment_timer->run(); Debug("Applying RAR TA CMD %d\n", ta); } else { // Preamble selected by UE MAC - if (!timers_db->get(TIME_ALIGNMENT)->is_running()) { + if (!time_alignment_timer->is_running()) { phy_h->set_timeadv_rar(ta); - timers_db->get(TIME_ALIGNMENT)->run(); + time_alignment_timer->run(); Debug("Applying RAR TA CMD %d\n", ta); } else { // Ignore TA CMD @@ -275,8 +279,9 @@ void ra_proc::new_grant_dl(mac_interface_phy::mac_grant_t grant, mac_interface_p { if (grant.n_bytes[0] < MAX_RAR_PDU_LEN) { rDebug("DL grant found RA-RNTI=%d\n", ra_rnti); - action->decode_enabled = true; - action->default_ack = false; + action->decode_enabled[0] = true; + action->decode_enabled[1] = false; + action->default_ack[0] = false; action->generate_ack = false; action->payload_ptr[0] = rar_pdu_buffer; action->rnti = grant.rnti; @@ -290,7 +295,8 @@ void ra_proc::new_grant_dl(mac_interface_phy::mac_grant_t grant, mac_interface_p } } else { rError("Received RAR grant exceeds buffer length (%d>%d)\n", grant.n_bytes[0], MAX_RAR_PDU_LEN); - action->decode_enabled = false; + action->decode_enabled[0] = false; + action->decode_enabled[1] = false; state = RESPONSE_ERROR; } } @@ -359,8 +365,8 @@ void ra_proc::tb_decoded_ok() { state = CONTENTION_RESOLUTION; // Start contention resolution timer - timers_db->get(CONTENTION_TIMER)->reset(); - timers_db->get(CONTENTION_TIMER)->run(); + contention_resolution_timer->reset(); + contention_resolution_timer->run(); } } else { rDebug("Found RAR for preamble %d\n", rar_pdu_msg.get()->get_rapid()); @@ -421,7 +427,7 @@ bool ra_proc::contention_resolution_id_received(uint64_t rx_contention_id) { rDebug("MAC PDU Contains Contention Resolution ID CE\n"); // MAC PDU successfully decoded and contains MAC CE contention Id - timers_db->get(CONTENTION_TIMER)->stop(); + contention_resolution_timer->stop(); if (transmitted_contention_id == rx_contention_id) { @@ -457,7 +463,7 @@ void ra_proc::step_contention_resolution() { (started_by_pdcch && pdcch_to_crnti_received != PDCCH_CRNTI_NOT_RECEIVED)) { rDebug("PDCCH for C-RNTI received\n"); - timers_db->get(CONTENTION_TIMER)->stop(); + contention_resolution_timer->stop(); rntis->temp_rnti = 0; state = COMPLETION; } @@ -569,7 +575,7 @@ void ra_proc::pdcch_to_crnti(bool contains_uplink_grant) { void ra_proc::harq_retx() { - timers_db->get(CONTENTION_TIMER)->reset(); + contention_resolution_timer->reset(); } } diff --git a/srsue/src/main.cc b/srsue/src/main.cc index f095a60c4..569083998 100644 --- a/srsue/src/main.cc +++ b/srsue/src/main.cc @@ -38,6 +38,8 @@ #include "ue.h" #include "metrics_stdout.h" +#include "metrics_csv.h" +#include "srslte/common/metrics_hub.h" #include "srslte/version.h" using namespace std; @@ -103,6 +105,7 @@ void parse_args(all_args_t *args, int argc, char *argv[]) { ("log.usim_level", bpo::value(&args->log.usim_level), "USIM log level") ("log.usim_hex_limit", bpo::value(&args->log.usim_hex_limit), "USIM log hex dump limit") + ("log.all_level", bpo::value(&args->log.all_level)->default_value("info"), "ALL log level") ("log.all_hex_limit", bpo::value(&args->log.all_hex_limit)->default_value(32), "ALL log hex dump limit") @@ -133,6 +136,14 @@ void parse_args(all_args_t *args, int argc, char *argv[]) { bpo::value(&args->expert.metrics_period_secs)->default_value(1.0), "Periodicity for metrics in seconds") + ("expert.metrics_csv_enable", + bpo::value(&args->expert.metrics_csv_enable)->default_value(false), + "Write UE metrics to CSV file") + + ("expert.metrics_csv_filename", + bpo::value(&args->expert.metrics_csv_filename)->default_value("/tmp/ue_metrics.csv"), + "Metrics CSV filename") + ("expert.pregenerate_signals", bpo::value(&args->expert.pregenerate_signals)->default_value(false), "Pregenerate uplink signals after attach. Improves CPU performance.") @@ -319,13 +330,13 @@ void parse_args(all_args_t *args, int argc, char *argv[]) { static bool running = true; static bool do_metrics = false; +metrics_stdout metrics_screen; void sig_int_handler(int signo) { running = false; } void *input_loop(void *m) { - metrics_stdout *metrics = (metrics_stdout *) m; char key; while (running) { cin >> key; @@ -336,7 +347,7 @@ void *input_loop(void *m) { } else { cout << "Enter t to restart trace." << endl; } - metrics->toggle_print(do_metrics); + metrics_screen.toggle_print(do_metrics); } } return NULL; @@ -344,6 +355,7 @@ void *input_loop(void *m) { int main(int argc, char *argv[]) { + srslte::metrics_hub metricshub; signal(SIGINT, sig_int_handler); all_args_t args; parse_args(&args, argc, argv); @@ -360,11 +372,18 @@ int main(int argc, char *argv[]) exit(1); } - metrics_stdout metrics; - metrics.init(ue, args.expert.metrics_period_secs); + metricshub.init(ue, args.expert.metrics_period_secs); + metricshub.add_listener(&metrics_screen); + metrics_screen.set_ue_handle(ue); + + metrics_csv metrics_file(args.expert.metrics_csv_filename); + if (args.expert.metrics_csv_enable) { + metricshub.add_listener(&metrics_file); + metrics_file.set_ue_handle(ue); + } pthread_t input; - pthread_create(&input, NULL, &input_loop, &metrics); + pthread_create(&input, NULL, &input_loop, &args); bool plot_started = false; bool signals_pregenerated = false; @@ -382,7 +401,7 @@ int main(int argc, char *argv[]) sleep(1); } pthread_cancel(input); - metrics.stop(); + metricshub.stop(); ue->stop(); ue->cleanup(); cout << "--- exiting ---" << endl; diff --git a/srsue/src/metrics_csv.cc b/srsue/src/metrics_csv.cc new file mode 100644 index 000000000..f9bdce213 --- /dev/null +++ b/srsue/src/metrics_csv.cc @@ -0,0 +1,105 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2015 The srsUE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE 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. + * + * srsUE 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 "metrics_csv.h" + +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace std; + +namespace srsue{ + +metrics_csv::metrics_csv(std::string filename) + :n_reports(0) + ,ue(NULL) +{ + file.open(filename.c_str()); +} + +void metrics_csv::set_ue_handle(ue_metrics_interface *ue_) +{ + ue = ue_; +} + +void metrics_csv::set_metrics(ue_metrics_t &metrics, float metrics_report_period) +{ + if (file.is_open() && ue != NULL) { + if(n_reports == 0) { + file << "time;rsrp;pl;cfo;dl_mcs;dl_snr;dl_turbo;dl_brate;dl_bler;ul_mcs;ul_buff;ul_brate;ul_bler;rf_o;rf_u;rf_l;is_attached" << endl; + } + file << (metrics_report_period*n_reports) << ";"; + file << float_to_string(metrics.phy.dl.rsrp, 2); + file << float_to_string(metrics.phy.dl.pathloss, 2); + file << float_to_string(metrics.phy.sync.cfo, 2); + file << float_to_string(metrics.phy.dl.mcs, 2); + file << float_to_string(metrics.phy.dl.sinr, 2); + file << float_to_string(metrics.phy.dl.turbo_iters, 2); + file << float_to_string((float) metrics.mac.rx_brate/metrics_report_period, 2); + if (metrics.mac.rx_pkts > 0) { + file << float_to_string((float) 100*metrics.mac.rx_errors/metrics.mac.rx_pkts, 1); + } else { + file << float_to_string(0, 2); + } + file << float_to_string(metrics.phy.ul.mcs, 2); + file << float_to_string((float) metrics.mac.ul_buffer, 2); + file << float_to_string((float) metrics.mac.tx_brate/metrics_report_period, 2); + if (metrics.mac.tx_pkts > 0) { + file << float_to_string((float) 100*metrics.mac.tx_errors/metrics.mac.tx_pkts, 1); + } else { + file << float_to_string(0, 2); + } + file << float_to_string(metrics.rf.rf_o, 2); + file << float_to_string(metrics.rf.rf_u, 2); + file << float_to_string(metrics.rf.rf_l, 2); + file << (ue->is_attached() ? "1.0" : "0.0"); + file << endl; + + n_reports++; + } else { + std::cout << "Error, couldn't write CSV file." << std::endl; + } +} + +std::string metrics_csv::float_to_string(float f, int digits, bool add_semicolon) +{ + std::ostringstream os; + const int precision = (f == 0.0) ? digits-1 : digits - log10(fabs(f))-2*DBL_EPSILON; + os << std::fixed << std::setprecision(precision) << f; + if (add_semicolon) + os << ';'; + return os.str(); +} + +} // namespace srsue diff --git a/srsue/src/metrics_stdout.cc b/srsue/src/metrics_stdout.cc index 0a86683d2..6828c912f 100644 --- a/srsue/src/metrics_stdout.cc +++ b/srsue/src/metrics_stdout.cc @@ -48,29 +48,15 @@ char const * const prefixes[2][9] = }; metrics_stdout::metrics_stdout() - :started(false) - ,do_print(false) + :do_print(false) ,n_reports(10) + ,ue(NULL) { } -bool metrics_stdout::init(ue_metrics_interface *u, float report_period_secs) +void metrics_stdout::set_ue_handle(ue_metrics_interface *ue_) { - ue_ = u; - metrics_report_period = report_period_secs; - - started = true; - pthread_create(&metrics_thread, NULL, &metrics_thread_start, this); - return true; -} - -void metrics_stdout::stop() -{ - if(started) - { - started = false; - pthread_join(metrics_thread, NULL); - } + ue = ue_; } void metrics_stdout::toggle_print(bool b) @@ -78,31 +64,17 @@ void metrics_stdout::toggle_print(bool b) do_print = b; } -void* metrics_stdout::metrics_thread_start(void *m_) -{ - metrics_stdout *m = (metrics_stdout*)m_; - m->metrics_thread_run(); - return NULL; -} -void metrics_stdout::metrics_thread_run() +void metrics_stdout::set_metrics(ue_metrics_t &metrics, float metrics_report_period) { - while(started) - { - usleep(metrics_report_period*1e6); - if(ue_->get_metrics(metrics)) { - print_metrics(); - } else { - print_disconnect(); - } - } -} - -void metrics_stdout::print_metrics() -{ - if(!do_print) + if(!do_print || ue == NULL) return; + if (!ue->is_attached()) { + cout << "--- disconnected ---" << endl; + return; + } + if(++n_reports > 10) { n_reports = 0; @@ -138,13 +110,6 @@ void metrics_stdout::print_metrics() } -void metrics_stdout::print_disconnect() -{ - if(do_print) { - cout << "--- disconnected ---" << endl; - } -} - std::string metrics_stdout::float_to_string(float f, int digits) { std::ostringstream os; diff --git a/srsue/src/phy/phch_common.cc b/srsue/src/phy/phch_common.cc index c65ec7c77..d49b1ced2 100644 --- a/srsue/src/phy/phch_common.cc +++ b/srsue/src/phy/phch_common.cc @@ -34,8 +34,6 @@ #define Info(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->info_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) #define Debug(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->debug_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) -#define TX_MODE_CONTINUOUS 0 - namespace srsue { cf_t zeros[50000]; @@ -63,6 +61,10 @@ phch_common::phch_common(uint32_t max_mutex_) : tx_mutex(max_mutex_) cur_pusch_power = 0; bzero(zeros, 50000*sizeof(cf_t)); + // FIXME: This is an ungly fix to avoid the TX filters to empty + for (int i=0;i<50000;i++) { + zeros[i] = 0.01*cexpf(((float) i/50000)*0.1*_Complex_I); + } bzero(&dl_metrics, sizeof(dl_metrics_t)); dl_metrics_read = true; dl_metrics_count = 0; @@ -74,10 +76,11 @@ phch_common::phch_common(uint32_t max_mutex_) : tx_mutex(max_mutex_) sync_metrics_count = 0; } -void phch_common::init(phy_interface_rrc::phy_cfg_t *_config, phy_args_t *_args, srslte::log *_log, srslte::radio *_radio, mac_interface_phy *_mac) +void phch_common::init(phy_interface_rrc::phy_cfg_t *_config, phy_args_t *_args, srslte::log *_log, srslte::radio *_radio, rrc_interface_phy *_rrc, mac_interface_phy *_mac) { log_h = _log; - radio_h = _radio; + radio_h = _radio; + rrc = _rrc; mac = _mac; config = _config; args = _args; diff --git a/srsue/src/phy/phch_recv.cc b/srsue/src/phy/phch_recv.cc index 5b725d49f..dad2c82b8 100644 --- a/srsue/src/phy/phch_recv.cc +++ b/srsue/src/phy/phch_recv.cc @@ -39,14 +39,16 @@ namespace srsue { -int radio_recv_wrapper_cs(void *h, cf_t *data[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte_timestamp_t *rx_time) { - srslte::radio_multi *radio_h = (srslte::radio_multi *) h; +int radio_recv_wrapper_cs(void *obj, cf_t *data[SRSLTE_MAX_PORTS], uint32_t nsamples, srslte_timestamp_t *rx_time) { + phch_recv *h = (phch_recv*) obj; + srslte::radio_multi *radio_h = h->radio_h; + if (radio_h->rx_now(data, nsamples, rx_time)) { - int offset = nsamples - radio_h->get_tti_len(); + int offset = nsamples - h->current_sflen; if (abs(offset) < 10 && offset != 0) { - radio_h->tx_offset(offset); + h->next_offset = offset; } else if (nsamples < 10) { - radio_h->tx_offset(nsamples); + h->next_offset = nsamples; } return nsamples; } else { @@ -78,15 +80,7 @@ void phch_recv:: init(srslte::radio_multi *_radio_handler, mac_interface_phy *_ prach_buffer = _prach_buffer; nof_rx_antennas = nof_rx_antennas_; - tx_mutex_cnt = 0; - running = true; - phy_state = IDLE; - time_adv_sec = 0; - cell_is_set = false; - sync_sfn_cnt = 0; - srate_mode = SRATE_NONE; - cell_search_in_progress = false; - current_earfcn = 0; + reset(); for (uint32_t i = 0; i < nof_rx_antennas; i++) { sf_buffer[i] = (cf_t *) srslte_vec_malloc(sizeof(cf_t) * 3 * SRSLTE_SF_LEN_PRB(100)); @@ -94,7 +88,7 @@ void phch_recv:: init(srslte::radio_multi *_radio_handler, mac_interface_phy *_ if (srslte_ue_cellsearch_init_multi(&cs, 5, radio_recv_wrapper_cs, nof_rx_antennas, - radio_h)) { + this)) { Error("SYNC: Initiating UE cell search\n"); return; } @@ -118,12 +112,12 @@ void phch_recv:: init(srslte::radio_multi *_radio_handler, mac_interface_phy *_ return; } - if (srslte_ue_sync_init_multi(&ue_sync, SRSLTE_MAX_PRB, false, radio_recv_wrapper_cs, nof_rx_antennas, radio_h)) { + if (srslte_ue_sync_init_multi(&ue_sync, SRSLTE_MAX_PRB, false, radio_recv_wrapper_cs, nof_rx_antennas, this)) { Error("SYNC: Initiating ue_sync\n"); return; } - if (srslte_ue_mib_sync_init_multi(&ue_mib_sync, radio_recv_wrapper_cs, nof_rx_antennas, radio_h)) { + if (srslte_ue_mib_sync_init_multi(&ue_mib_sync, radio_recv_wrapper_cs, nof_rx_antennas, this)) { Error("SYNC: Initiating UE MIB synchronization\n"); return; } @@ -156,12 +150,55 @@ void phch_recv::stop() { wait_thread_finish(); } +void phch_recv::reset() { + tx_mutex_cnt = 0; + running = true; + phy_state = IDLE; + time_adv_sec = 0; + next_offset = 0; + cell_is_set = false; + sync_sfn_cnt = 0; + srate_mode = SRATE_NONE; + cell_search_in_progress = false; + current_earfcn = 0; + radio_is_resetting = false; +} + +void phch_recv::radio_error() { + log_h->error("SYNC: Receiving from radio.\n"); + phy_state = IDLE; + radio_is_resetting=true; + + // Need to find a method to effectively reset radio, reloading the driver does not work + //radio_h->reset(); + + fprintf(stdout, "Error while receiving samples. Restart srsUE\n"); + exit(-1); + + reset(); + radio_is_resetting=false; +} + +bool phch_recv::wait_radio_reset() { + int cnt=0; + while(cnt < 20 && radio_is_resetting) { + sleep(1); + cnt++; + } + return radio_is_resetting; +} + void phch_recv::set_agc_enable(bool enable) { do_agc = enable; } void phch_recv::set_time_adv_sec(float _time_adv_sec) { - time_adv_sec = _time_adv_sec; + if (TX_MODE_CONTINUOUS && !radio_h->is_first_of_burst()) { + int nsamples = ceil(current_srate*_time_adv_sec); + next_offset = -nsamples; + } else { + time_adv_sec = _time_adv_sec; + } } void phch_recv::set_ue_sync_opts(srslte_ue_sync_t *q) { @@ -217,7 +254,6 @@ bool phch_recv::set_cell() { return false; } } - radio_h->set_tti_len(SRSLTE_SF_LEN_PRB(cell.nof_prb)); if (do_agc) { srslte_ue_sync_start_agc(&ue_sync, callback_set_rx_gain, last_gain); } @@ -226,7 +262,7 @@ bool phch_recv::set_cell() { return cell_is_set; } -bool phch_recv::cell_search(int force_N_id_2) { +int phch_recv::cell_search(int force_N_id_2) { uint8_t bch_payload[SRSLTE_BCH_PAYLOAD_LEN]; srslte_ue_cellsearch_result_t found_cells[3]; @@ -238,7 +274,7 @@ bool phch_recv::cell_search(int force_N_id_2) { srate_mode = SRATE_FIND; radio_h->set_rx_srate(1.92e6); } - radio_h->start_rx(); + start_rx(); /* Find a cell in the given N_id_2 or go through the 3 of them to find the strongest */ uint32_t max_peak_cell = 0; @@ -257,13 +293,12 @@ bool phch_recv::cell_search(int force_N_id_2) { last_gain = srslte_agc_get_gain(&cs.ue_sync.agc); if (ret < 0) { - radio_h->stop_rx(); Error("SYNC: Error decoding MIB: Error searching PSS\n"); - return false; + return -1; } else if (ret == 0) { - radio_h->stop_rx(); + stop_rx(); Info("SYNC: Could not find any cell in this frequency\n"); - return false; + return 0; } // Save result cell.id = found_cells[max_peak_cell].cell_id; @@ -294,7 +329,7 @@ bool phch_recv::cell_search(int force_N_id_2) { ret = srslte_ue_mib_sync_decode(&ue_mib_sync, 40, bch_payload, &cell.nof_ports, &sfn_offset); - radio_h->stop_rx(); + stop_rx(); last_gain = srslte_agc_get_gain(&ue_mib_sync.ue_sync.agc); cellsearch_cfo = srslte_ue_sync_get_cfo(&ue_mib_sync.ue_sync); @@ -311,9 +346,12 @@ bool phch_recv::cell_search(int force_N_id_2) { cell.id, cell.nof_prb, cell.nof_ports, cellsearch_cfo/1000); return true; - } else { + } else if (ret == 0) { Warning("SYNC: Found PSS but could not decode PBCH\n"); - return false; + return 0; + } else { + Error("SYNC: Receiving MIB\n"); + return -1; } } @@ -390,13 +428,16 @@ int phch_recv::cell_meas_rsrp() { return 0; } -void phch_recv::resync_sfn() { - radio_h->stop_rx(); - radio_h->start_rx(); +void phch_recv::resync_sfn(bool is_connected) { + + wait_radio_reset(); + + stop_rx(); + start_rx(); srslte_ue_mib_reset(&ue_mib); Info("SYNC: Starting SFN synchronization\n"); sync_sfn_cnt = 0; - phy_state = CELL_SELECT; + phy_state = is_connected?CELL_RESELECT:CELL_SELECT; } void phch_recv::set_earfcn(std::vector earfcn) { @@ -404,37 +445,57 @@ void phch_recv::set_earfcn(std::vector earfcn) { } bool phch_recv::stop_sync() { - Info("SYNC: Going to IDLE\n"); - phy_state = IDLE; - int cnt=0; - while(!is_in_idle && cnt<100) { - usleep(10000); - cnt++; + + wait_radio_reset(); + + if (phy_state == IDLE && is_in_idle) { + return true; + } else { + Info("SYNC: Going to IDLE\n"); + phy_state = IDLE; + int cnt = 0; + while (!is_in_idle && cnt < 100) { + usleep(10000); + cnt++; + } + return is_in_idle; } - return is_in_idle; +} + +void phch_recv::reset_sync() { + + wait_radio_reset(); + + Warning("SYNC: Resetting sync, cell_search_in_progress=%s\n", cell_search_in_progress?"yes":"no"); + srslte_ue_sync_reset(&ue_mib_sync.ue_sync); + srslte_ue_sync_reset(&ue_sync); + resync_sfn(true); } void phch_recv::cell_search_inc() { cur_earfcn_index++; - Info("SYNC: Cell Search idx %d/%d\n", cur_earfcn_index, earfcn.size()); if (cur_earfcn_index >= 0) { if (cur_earfcn_index >= (int) earfcn.size() - 1) { cur_earfcn_index = 0; } } + Info("SYNC: Cell Search idx %d/%d\n", cur_earfcn_index, earfcn.size()); if (current_earfcn != earfcn[cur_earfcn_index]) { current_earfcn = earfcn[cur_earfcn_index]; set_frequency(); } } -void phch_recv::cell_search_next() { - if (cell_search_in_progress) { +void phch_recv::cell_search_next(bool reset) { + if (cell_search_in_progress || reset) { cell_search_in_progress = false; if (!stop_sync()) { log_h->warning("SYNC: Couldn't stop PHY\n"); } + if (reset) { + cur_earfcn_index = -1; + } cell_search_inc(); phy_state = CELL_SEARCH; cell_search_in_progress = true; @@ -443,16 +504,22 @@ void phch_recv::cell_search_next() { void phch_recv::cell_search_start() { if (earfcn.size() > 0) { - cell_search_in_progress = true; - cur_earfcn_index = -1; - cell_search_next(); - log_h->info("SYNC: Starting Cell Search procedure in %d EARFCNs...\n", earfcn.size()); + Info("SYNC: Starting Cell Search procedure in %d EARFCNs...\n", earfcn.size()); + cell_search_next(true); } else { - log_h->info("SYNC: Empty EARFCN list. Stopping cell search...\n"); + Info("SYNC: Empty EARFCN list. Stopping cell search...\n"); log_h->console("Empty EARFCN list. Stopping cell search...\n"); } } +void phch_recv::cell_search_stop() { + Info("SYNC: Stopping Cell Search procedure...\n"); + if (!stop_sync()) { + Error("SYNC: Stopping cell search\n"); + } + cell_search_in_progress = false; +} + bool phch_recv::cell_select(uint32_t earfcn, srslte_cell_t cell) { // Check if we are already camping in this cell @@ -476,6 +543,8 @@ bool phch_recv::cell_select(uint32_t earfcn, srslte_cell_t cell) { current_earfcn = earfcn; + printf("cell select called set frequency\n"); + if (set_frequency()) { this->cell = cell; log_h->info("Cell Select: Configuring cell...\n"); @@ -521,22 +590,25 @@ bool phch_recv::set_frequency() void phch_recv::set_sampling_rate() { - float srate = (float) srslte_sampling_freq_hz(cell.nof_prb); + current_srate = (float) srslte_sampling_freq_hz(cell.nof_prb); + current_sflen = SRSLTE_SF_LEN_PRB(cell.nof_prb); + if (current_srate != -1) { + Info("SYNC: Setting sampling rate %.2f MHz\n", current_srate/1000000); - Info("SYNC: Setting sampling rate %.2f MHz\n", srate/1000000); - - if (30720 % ((int) srate / 1000) == 0) { - radio_h->set_master_clock_rate(30.72e6); + if (30720 % ((int) current_srate / 1000) == 0) { + radio_h->set_master_clock_rate(30.72e6); + } else { + radio_h->set_master_clock_rate(23.04e6); + } + srate_mode = SRATE_CAMP; + radio_h->set_rx_srate(current_srate); + radio_h->set_tx_srate(current_srate); } else { - radio_h->set_master_clock_rate(23.04e6); + Error("Error setting sampling rate for cell with %d PRBs\n", cell.nof_prb); } - srate_mode = SRATE_CAMP; - radio_h->set_rx_srate(srate); - radio_h->set_tx_srate(srate); } void phch_recv::run_thread() { - int sync_res; phch_worker *worker = NULL; cf_t *buffer[SRSLTE_MAX_PORTS]; phy_state = IDLE; @@ -549,32 +621,36 @@ void phch_recv::run_thread() { } switch (phy_state) { case CELL_SEARCH: - if (cell_search() && cell_search_in_progress) { - if (!srslte_cell_isvalid(&cell)) { - Error("SYNC: Detected invalid cell\n"); - phy_state = IDLE; + if (cell_search_in_progress) { + switch(cell_search()) { + case 1: + if (!srslte_cell_isvalid(&cell)) { + Error("SYNC: Detected invalid cell\n"); + phy_state = IDLE; + break; + } + if (set_cell()) { + set_sampling_rate(); + resync_sfn(); + } + break; + case 0: + if (cell_search_in_progress) { + cell_search_inc(); + } + break; + default: + radio_error(); break; - } - if (set_cell()) { - set_sampling_rate(); - resync_sfn(); - } - - } else { - if (cell_search_in_progress) { - cell_search_inc(); } } break; + case CELL_RESELECT: case CELL_SELECT: srslte_ue_sync_decode_sss_on_track(&ue_sync, true); switch (cell_sync_sfn()) { - default: - log_h->console("SYNC: Going IDLE\n"); - phy_state = IDLE; - break; case 1: srslte_ue_sync_set_agc_period(&ue_sync, 20); if (!cell_search_in_progress) { @@ -588,12 +664,19 @@ void phch_recv::run_thread() { break; case 0: break; + default: + radio_error(); + break; } sync_sfn_cnt++; if (sync_sfn_cnt >= SYNC_SFN_TIMEOUT) { sync_sfn_cnt = 0; - phy_state = CELL_SEARCH; log_h->warning("SYNC: Timeout while synchronizing SFN\n"); + if (phy_state == CELL_SELECT) { + phy_state = CELL_SEARCH; + } else { + phy_state = IDLE; + } } break; case CELL_MEASURE: @@ -606,8 +689,8 @@ void phch_recv::run_thread() { case 0: break; default: - log_h->error("SYNC: Getting RSRP cell measurement.\n"); - cell_search_next(); + radio_error(); + break; } break; case CELL_CAMP: @@ -618,53 +701,54 @@ void phch_recv::run_thread() { buffer[i] = worker->get_buffer(i); } - sync_res = srslte_ue_sync_zerocopy_multi(&ue_sync, buffer); - if (sync_res == 1) { + switch(srslte_ue_sync_zerocopy_multi(&ue_sync, buffer)) { + case 1: - log_h->step(tti); + log_h->step(tti); - Debug("SYNC: Worker %d synchronized\n", worker->get_id()); + Debug("SYNC: Worker %d synchronized\n", worker->get_id()); - metrics.sfo = srslte_ue_sync_get_sfo(&ue_sync); - metrics.cfo = srslte_ue_sync_get_cfo(&ue_sync); - worker->set_cfo(ul_dl_factor * metrics.cfo / 15000); - worker_com->set_sync_metrics(metrics); + metrics.sfo = srslte_ue_sync_get_sfo(&ue_sync); + metrics.cfo = srslte_ue_sync_get_cfo(&ue_sync); + worker->set_cfo(ul_dl_factor * metrics.cfo / 15000); + worker_com->set_sync_metrics(metrics); - float sample_offset = (float) srslte_ue_sync_get_sfo(&ue_sync) / 1000; - worker->set_sample_offset(sample_offset); + worker->set_sample_offset(srslte_ue_sync_get_sfo(&ue_sync)/1000); - /* Compute TX time: Any transmission happens in TTI4 thus advance 4 ms the reception time */ - srslte_timestamp_t rx_time, tx_time, tx_time_prach; - srslte_ue_sync_get_last_timestamp(&ue_sync, &rx_time); - srslte_timestamp_copy(&tx_time, &rx_time); - srslte_timestamp_add(&tx_time, 0, 4e-3 - time_adv_sec); - worker->set_tx_time(tx_time); + /* Compute TX time: Any transmission happens in TTI4 thus advance 4 ms the reception time */ + srslte_timestamp_t rx_time, tx_time, tx_time_prach; + srslte_ue_sync_get_last_timestamp(&ue_sync, &rx_time); + srslte_timestamp_copy(&tx_time, &rx_time); + srslte_timestamp_add(&tx_time, 0, 4e-3 - time_adv_sec); + worker->set_tx_time(tx_time, next_offset); + next_offset = 0; - Debug("SYNC: Setting TTI=%d, tx_mutex=%d to worker %d\n", tti, tx_mutex_cnt, worker->get_id()); - worker->set_tti(tti, tx_mutex_cnt); - tx_mutex_cnt = (tx_mutex_cnt+1) % nof_tx_mutex; + Debug("SYNC: Setting TTI=%d, tx_mutex=%d to worker %d\n", tti, tx_mutex_cnt, worker->get_id()); + worker->set_tti(tti, tx_mutex_cnt); + tx_mutex_cnt = (tx_mutex_cnt+1) % nof_tx_mutex; - // Check if we need to TX a PRACH - if (prach_buffer->is_ready_to_send(tti)) { - srslte_timestamp_copy(&tx_time_prach, &rx_time); - srslte_timestamp_add(&tx_time_prach, 0, prach::tx_advance_sf * 1e-3); - prach_buffer->send(radio_h, ul_dl_factor * metrics.cfo / 15000, worker_com->pathloss, tx_time_prach); - radio_h->tx_end(); - worker_com->p0_preamble = prach_buffer->get_p0_preamble(); - worker_com->cur_radio_power = SRSLTE_MIN(SRSLTE_PC_MAX, worker_com->pathloss+worker_com->p0_preamble); - } - workers_pool->start_worker(worker); - // Notify RRC in-sync every 1 frame - if ((tti % 10) == 0) { - rrc->in_sync(); - log_h->debug("SYNC: Sending in-sync to RRC\n"); - } - } else { - log_h->error("SYNC: Sync error. Sending out-of-sync to RRC\n"); - // Notify RRC of out-of-sync frame - rrc->out_of_sync(); - worker->release(); - worker_com->reset_ul(); + // Check if we need to TX a PRACH + if (prach_buffer->is_ready_to_send(tti)) { + srslte_timestamp_copy(&tx_time_prach, &rx_time); + srslte_timestamp_add(&tx_time_prach, 0, prach::tx_advance_sf * 1e-3); + prach_buffer->send(radio_h, ul_dl_factor * metrics.cfo / 15000, worker_com->pathloss, tx_time_prach); + radio_h->tx_end(); + worker_com->p0_preamble = prach_buffer->get_p0_preamble(); + worker_com->cur_radio_power = SRSLTE_MIN(SRSLTE_PC_MAX, worker_com->pathloss+worker_com->p0_preamble); + } + workers_pool->start_worker(worker); + break; + case 0: + log_h->error("SYNC: Sync error. Sending out-of-sync to RRC\n"); + // Notify RRC of out-of-sync frame + rrc->out_of_sync(); + worker->release(); + worker_com->reset_ul(); + mac->tti_clock(tti); + break; + default: + radio_error(); + break; } } else { // wait_worker() only returns NULL if it's being closed. Quit now to avoid unnecessary loops here @@ -673,15 +757,34 @@ void phch_recv::run_thread() { break; case IDLE: if (!is_in_idle) { - radio_h->stop_rx(); + stop_rx(); } is_in_idle = true; usleep(1000); + // Keep running MAC timer from system clock + tti = (tti+1) % 10240; + mac->tti_clock(tti); break; } } } +void phch_recv::stop_rx() { + if (radio_is_rx) { + Info("SYNC: Stopping RX streaming\n"); + radio_h->stop_rx(); + } + radio_is_rx = false; +} + +void phch_recv::start_rx() { + if (!radio_is_rx) { + Info("SYNC: Starting RX streaming\n"); + radio_h->start_rx(); + } + radio_is_rx = true; +} + uint32_t phch_recv::get_current_tti() { return tti; } diff --git a/srsue/src/phy/phch_worker.cc b/srsue/src/phy/phch_worker.cc index 0290c0745..1c9abc1ca 100644 --- a/srsue/src/phy/phch_worker.cc +++ b/srsue/src/phy/phch_worker.cc @@ -30,10 +30,10 @@ #include "srslte/interfaces/ue_interfaces.h" #include "srslte/asn1/liblte_rrc.h" -#define Error(fmt, ...) if (SRSLTE_DEBUG_ENABLED) phy->log_h->error_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) -#define Warning(fmt, ...) if (SRSLTE_DEBUG_ENABLED) phy->log_h->warning_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) -#define Info(fmt, ...) if (SRSLTE_DEBUG_ENABLED) phy->log_h->info_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) -#define Debug(fmt, ...) if (SRSLTE_DEBUG_ENABLED) phy->log_h->debug_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define Error(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->error_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define Warning(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->warning_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define Info(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->info_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) +#define Debug(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->debug_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) /* This is to visualize the channel response */ @@ -106,8 +106,9 @@ void phch_worker::set_common(phch_common* phy_) phy = phy_; } -bool phch_worker::init(uint32_t max_prb) +bool phch_worker::init(uint32_t max_prb, srslte::log *log_h) { + this->log_h = log_h; // ue_sync in phy.cc requires a buffer for 3 subframes for (uint32_t i=0;iargs->nof_rx_ant;i++) { signal_buffer[i] = (cf_t*) srslte_vec_malloc(3 * sizeof(cf_t) * SRSLTE_SF_LEN_PRB(max_prb)); @@ -166,6 +167,7 @@ void phch_worker::set_tti(uint32_t tti_, uint32_t tx_tti_) { tti = tti_; tx_tti = tx_tti_; + log_h->step(tti); } void phch_worker::set_cfo(float cfo_) @@ -217,11 +219,14 @@ void phch_worker::work_imp() bzero(&ul_action, sizeof(mac_interface_phy::tb_action_ul_t)); /* Do FFT and extract PDCCH LLR, or quit if no actions are required in this subframe */ - if (extract_fft_and_pdcch_llr()) { - - + bool chest_ok = extract_fft_and_pdcch_llr(); + + bool snr_th_ok = 10*log10(srslte_chest_dl_get_snr(&ue_dl.chest))>1.0; + + if (chest_ok && snr_th_ok) { + /***** Downlink Processing *******/ - + /* PDCCH DL + PDSCH */ dl_grant_available = decode_pdcch_dl(&dl_mac_grant); if(dl_grant_available) { @@ -230,18 +235,18 @@ void phch_worker::work_imp() /* Set DL ACKs to default */ for (uint32_t tb = 0; tb < SRSLTE_MAX_CODEWORDS; tb++) { - dl_ack[tb] = dl_action.default_ack; + dl_ack[tb] = dl_action.default_ack[tb]; } /* Decode PDSCH if instructed to do so */ - if (dl_action.decode_enabled) { + if (dl_action.decode_enabled[0] || dl_action.decode_enabled[1]) { decode_pdsch(&dl_action.phy_grant.dl, dl_action.payload_ptr, dl_action.softbuffers, dl_action.rv, dl_action.rnti, dl_mac_grant.pid, dl_ack); } - if (dl_action.generate_ack_callback && dl_action.decode_enabled) { + if (dl_action.generate_ack_callback) { for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) { - if (dl_mac_grant.tb_en[tb]) { + if (dl_action.decode_enabled[tb]) { phy->mac->tb_decoded(dl_ack[tb], tb, dl_mac_grant.rnti_type, dl_mac_grant.pid); dl_ack[tb] = dl_action.generate_ack_callback(dl_action.generate_ack_callback_arg); Debug("Calling generate ACK callback for TB %d returned=%d\n", tb, dl_ack[tb]); @@ -255,9 +260,17 @@ void phch_worker::work_imp() /* Select Rank Indicator by computing Condition Number */ if (phy->config->dedicated.antenna_info_explicit_value.tx_mode == LIBLTE_RRC_TRANSMISSION_MODE_3) { - float cn = 0.0f; - srslte_ue_dl_ri_select(&ue_dl, &uci_data.uci_ri, &cn); - uci_data.uci_ri_len = 1; + if (ue_dl.nof_rx_antennas > 1) { + /* If 2 ort more receiving antennas, select RI */ + float cn = 0.0f; + srslte_ue_dl_ri_select(&ue_dl, &uci_data.uci_ri, &cn); + uci_data.uci_ri_len = 1; + } else { + /* If only one receiving antenna, force RI for 1 layer */ + uci_data.uci_ri = 0; + uci_data.uci_ri_len = 1; + Warning("Only one receiving antenna with TM3. Forcing RI=1 layer.\n"); + } } else if (phy->config->dedicated.antenna_info_explicit_value.tx_mode == LIBLTE_RRC_TRANSMISSION_MODE_4){ float sinr = 0.0f; uint8 packed_pmi = 0; @@ -271,12 +284,17 @@ void phch_worker::work_imp() uci_data.uci_pmi_len = 1; uci_data.uci_dif_cqi_len = 3; } + + /* If only one antenna in TM4 print limitation warning */ + if (ue_dl.nof_rx_antennas < 2) { + Warning("Only one receiving antenna with TM4. Forcing RI=1 layer (PMI=%d).\n", packed_pmi); + } } } } // Decode PHICH - bool ul_ack; + bool ul_ack = false; bool ul_ack_available = decode_phich(&ul_ack); /***** Uplink Processing + Transmission *******/ @@ -329,15 +347,19 @@ void phch_worker::work_imp() } tr_log_end(); - - phy->worker_end(tx_tti, signal_ready, signal_buffer[0], SRSLTE_SF_LEN_PRB(cell.nof_prb), tx_time); - - if (dl_action.decode_enabled && !dl_action.generate_ack_callback) { - if (dl_mac_grant.rnti_type == SRSLTE_RNTI_PCH) { + + if (next_offset > 0) { + phy->worker_end(tx_tti, signal_ready, signal_buffer[0], SRSLTE_SF_LEN_PRB(cell.nof_prb)+next_offset, tx_time); + } else { + phy->worker_end(tx_tti, signal_ready, &signal_buffer[0][-next_offset], SRSLTE_SF_LEN_PRB(cell.nof_prb)+next_offset, tx_time); + } + + if (!dl_action.generate_ack_callback) { + if (dl_mac_grant.rnti_type == SRSLTE_RNTI_PCH && dl_action.decode_enabled[0]) { phy->mac->pch_decoded_ok(dl_mac_grant.n_bytes[0]); } else { for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) { - if (dl_mac_grant.tb_en[tb]) { + if (dl_action.decode_enabled[tb]) { phy->mac->tb_decoded(dl_ack[tb], tb, dl_mac_grant.rnti_type, dl_mac_grant.pid); } } @@ -345,6 +367,17 @@ void phch_worker::work_imp() } update_measurements(); + + if (chest_ok) { + if (snr_th_ok) { + phy->rrc->in_sync(); + log_h->debug("SYNC: Sending in-sync to RRC\n"); + } else { + phy->rrc->out_of_sync(); + log_h->debug("SNR=%.1f dB under threshold. Sending out-of-sync to RRC\n", + 10*log10(srslte_chest_dl_get_snr(&ue_dl.chest))); + } + } /* Tell the plotting thread to draw the plots */ #ifdef ENABLE_GUI @@ -464,7 +497,7 @@ bool phch_worker::decode_pdcch_dl(srsue::mac_interface_phy::mac_grant_t* grant) char hexstr[16]; hexstr[0]='\0'; - if (phy->log_h->get_level() >= srslte::LOG_LEVEL_INFO) { + if (log_h->get_level() >= srslte::LOG_LEVEL_INFO) { srslte_vec_sprint_hex(hexstr, dci_msg.data, dci_msg.nof_bits); } Info("PDCCH: DL DCI %s cce_index=%2d, L=%d, n_data_bits=%d, hex=%s\n", srslte_dci_format_string(dci_msg.format), @@ -481,6 +514,8 @@ int phch_worker::decode_pdsch(srslte_ra_dl_grant_t *grant, uint8_t *payload[SRSL int rv[SRSLTE_MAX_CODEWORDS], uint16_t rnti, uint32_t harq_pid, bool acks[SRSLTE_MAX_CODEWORDS]) { char timestr[64]; + char commonstr[128]; + char tbstr[2][128]; bool valid_config = true; timestr[0]='\0'; srslte_mimo_type_t mimo_type = SRSLTE_MIMO_TYPE_SINGLE_ANTENNA; @@ -508,20 +543,22 @@ int phch_worker::decode_pdsch(srslte_ra_dl_grant_t *grant, uint8_t *payload[SRSL case LIBLTE_RRC_TRANSMISSION_MODE_3: if (SRSLTE_RA_DL_GRANT_NOF_TB(grant) == 1) { mimo_type = SRSLTE_MIMO_TYPE_TX_DIVERSITY; - } else if (SRSLTE_RA_DL_GRANT_NOF_TB(grant) == 2) { + } else if (ue_dl.nof_rx_antennas > 1 && SRSLTE_RA_DL_GRANT_NOF_TB(grant) == 2) { mimo_type = SRSLTE_MIMO_TYPE_CDD; } else { - Error("Wrong number of transport blocks (%d) for TM3\n", SRSLTE_RA_DL_GRANT_NOF_TB(grant)); + Error("Wrong combination of antennas (%d) or transport blocks (%d) for TM3\n", ue_dl.nof_rx_antennas, + SRSLTE_RA_DL_GRANT_NOF_TB(grant)); valid_config = false; } break; case LIBLTE_RRC_TRANSMISSION_MODE_4: if (SRSLTE_RA_DL_GRANT_NOF_TB(grant) == 1) { mimo_type = (grant->pinfo == 0) ? SRSLTE_MIMO_TYPE_TX_DIVERSITY : SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX; - } else if (SRSLTE_RA_DL_GRANT_NOF_TB(grant) == 2) { + } else if (ue_dl.nof_rx_antennas > 1 && SRSLTE_RA_DL_GRANT_NOF_TB(grant) == 2) { mimo_type = SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX; } else { - Error("Wrong number of transport blocks (%d) for TM4\n", SRSLTE_RA_DL_GRANT_NOF_TB(grant)); + Error("Wrong combination of antennas (%d) or transport blocks (%d) for TM3\n", ue_dl.nof_rx_antennas, + SRSLTE_RA_DL_GRANT_NOF_TB(grant)); valid_config = false; } break; @@ -575,14 +612,18 @@ int phch_worker::decode_pdsch(srslte_ra_dl_grant_t *grant, uint8_t *payload[SRSL snprintf(timestr, 64, ", dec_time=%4d us", (int) t[0].tv_usec); #endif - Info( - "PDSCH: l_crb=%2d, harq=%d, scheme=%s, tb_en={%s, %s}, tbs={%d, %d}, mcs={%d, %d}, rv={%d, %d}, crc={%s, %s}, snr=%.1f dB, n_iter=%d, %s\n", - grant->nof_prb, harq_pid, srslte_mimotype2str(mimo_type), grant->tb_en[0] ? "on" : "off", - grant->tb_en[1] ? "on" : "off", grant->mcs[0].tbs / 8, grant->mcs[1].tbs / 8, grant->mcs[0].idx, - grant->mcs[1].idx, rv[0], rv[1], acks[0] ? "OK" : "KO", acks[1] ? "OK" : "KO", - 10 * log10(srslte_chest_dl_get_snr(&ue_dl.chest)), - srslte_pdsch_last_noi(&ue_dl.pdsch), - timestr); + snprintf(commonstr, 128, "PDSCH: l_crb=%2d, harq=%d, snr=%.1f dB", grant->nof_prb, harq_pid, + 10 * log10(srslte_chest_dl_get_snr(&ue_dl.chest))); + + for (int i=0;itb_en[i]) { + snprintf(tbstr[i], 128, ", TB%d: tbs=%d, mcs=%d, rv=%d, crc=%s, it=%d", + i, grant->mcs[i].tbs/8, grant->mcs[i].idx, rv[i], acks[i] ? "OK" : "KO", + srslte_pdsch_last_noi_cw(&ue_dl.pdsch, i)); + } + } + + Info("%s%s%s%s\n", commonstr, grant->tb_en[0]?tbstr[0]:"", grant->tb_en[1]?tbstr[1]:"", timestr); // Store metrics dl_metrics.mcs = grant->mcs[0].idx; @@ -663,7 +704,7 @@ bool phch_worker::decode_pdcch_ul(mac_interface_phy::mac_grant_t* grant) char hexstr[16]; hexstr[0]='\0'; - if (phy->log_h->get_level() >= srslte::LOG_LEVEL_INFO) { + if (log_h->get_level() >= srslte::LOG_LEVEL_INFO) { srslte_vec_sprint_hex(hexstr, dci_msg.data, dci_msg.nof_bits); } // Change to last_location_ul @@ -768,7 +809,7 @@ void phch_worker::set_uci_periodic_cqi() cqi_report.type = SRSLTE_CQI_TYPE_SUBBAND; cqi_report.subband.subband_cqi = srslte_cqi_from_snr(phy->avg_snr_db); cqi_report.subband.subband_label = 0; - phy->log_h->console("Warning: Subband CQI periodic reports not implemented\n"); + log_h->console("Warning: Subband CQI periodic reports not implemented\n"); Info("PUCCH: Periodic CQI=%d, SNR=%.1f dB\n", cqi_report.subband.subband_cqi, phy->avg_snr_db); } else { cqi_report.type = SRSLTE_CQI_TYPE_WIDEBAND; @@ -836,8 +877,9 @@ bool phch_worker::srs_is_ready_to_send() { return false; } -void phch_worker::set_tx_time(srslte_timestamp_t _tx_time) +void phch_worker::set_tx_time(srslte_timestamp_t _tx_time, uint32_t next_offset) { + this->next_offset = next_offset; memcpy(&tx_time, &_tx_time, sizeof(srslte_timestamp_t)); } @@ -923,12 +965,14 @@ void phch_worker::encode_pucch() float tx_power = srslte_ue_ul_pucch_power(&ue_ul, phy->pathloss, ue_ul.last_pucch_format, uci_data.uci_cqi_len, uci_data.uci_ack_len); float gain = set_power(tx_power); - Info("PUCCH: power=%.2f dBm, tti_tx=%d, n_cce=%3d, n_pucch=%d, n_prb=%d, ack=%s%s, ri=%s, sr=%s, cfo=%.1f Hz%s\n", - tx_power, (tti+4)%10240, + Info("PUCCH: tti_tx=%d, n_cce=%3d, n_pucch=%d, n_prb=%d, ack=%s%s, ri=%s, pmi=%s%s, sr=%s, cfo=%.1f Hz%s\n", + (tti+4)%10240, last_dl_pdcch_ncce, ue_ul.pucch.last_n_pucch, ue_ul.pucch.last_n_prb, uci_data.uci_ack_len>0?(uci_data.uci_ack?"1":"0"):"no", uci_data.uci_ack_len>1?(uci_data.uci_ack_2?"1":"0"):"", uci_data.uci_ri_len>0?(uci_data.uci_ri?"1":"0"):"no", + uci_data.uci_pmi_len>0?(uci_data.uci_pmi[1]?"1":"0"):"no", + uci_data.uci_pmi_len>0?(uci_data.uci_pmi[0]?"1":"0"):"", uci_data.scheduling_request?"yes":"no", cfo*15000, timestr); } @@ -1101,13 +1145,13 @@ void phch_worker::start_plot() { #ifdef ENABLE_GUI if (plot_worker_id == -1) { plot_worker_id = get_id(); - phy->log_h->console("Starting plot for worker_id=%d\n", plot_worker_id); + log_h->console("Starting plot for worker_id=%d\n", plot_worker_id); init_plots(this); } else { - phy->log_h->console("Trying to start a plot but already started by worker_id=%d\n", plot_worker_id); + log_h->console("Trying to start a plot but already started by worker_id=%d\n", plot_worker_id); } #else - phy->log_h->console("Trying to start a plot but plots are disabled (ENABLE_GUI constant in phch_worker.cc)\n"); + log_h->console("Trying to start a plot but plots are disabled (ENABLE_GUI constant in phch_worker.cc)\n"); #endif } diff --git a/srsue/src/phy/phy.cc b/srsue/src/phy/phy.cc index d3933df13..e74107661 100644 --- a/srsue/src/phy/phy.cc +++ b/srsue/src/phy/phy.cc @@ -96,12 +96,13 @@ bool phy::check_args(phy_args_t *args) } bool phy::init(srslte::radio_multi* radio_handler, mac_interface_phy *mac, rrc_interface_phy *rrc, - srslte::log *log_h, phy_args_t *phy_args) { + std::vector log_vec, phy_args_t *phy_args) { mlockall(MCL_CURRENT | MCL_FUTURE); n_ta = 0; - this->log_h = log_h; + this->log_vec = log_vec; + this->log_h = (srslte::log*) log_vec[0]; this->radio_handler = radio_handler; this->mac = mac; this->rrc = rrc; @@ -128,12 +129,12 @@ bool phy::init(srslte::radio_multi* radio_handler, mac_interface_phy *mac, rrc_i void phy::run_thread() { prach_buffer.init(&config.common.prach_cnfg, SRSLTE_MAX_PRB, args, log_h); - workers_common.init(&config, args, log_h, radio_handler, mac); + workers_common.init(&config, args, (srslte::log*) log_vec[0], radio_handler, rrc, mac); // Add workers to workers pool and start threads for (uint32_t i=0;iworker_cpu_mask); } @@ -232,11 +233,20 @@ void phy::cell_search_start() sf_recv.cell_search_start(); } +void phy::cell_search_stop() +{ + sf_recv.cell_search_stop(); +} + void phy::cell_search_next() { sf_recv.cell_search_next(); } +void phy::sync_reset() { + sf_recv.reset_sync(); +} + bool phy::cell_select(uint32_t earfcn, srslte_cell_t phy_cell) { return sf_recv.cell_select(earfcn, phy_cell); @@ -293,8 +303,8 @@ int phy::prach_tx_tti() void phy::reset() { - // TODO - n_ta = 0; + Info("Resetting PHY\n"); + n_ta = 0; pdcch_dl_search_reset(); for(uint32_t i=0;i earfcns) { sf_recv.set_earfcn(earfcns); @@ -331,11 +337,6 @@ bool phy::sync_status() return sf_recv.status_is_sync(); } -bool phy::sync_stop() -{ - return sf_recv.stop_sync(); -} - void phy::set_rar_grant(uint32_t tti, uint8_t grant_payload[SRSLTE_RAR_GRANT_LEN]) { workers_common.set_rar_grant(tti, grant_payload); diff --git a/srsue/src/ue.cc b/srsue/src/ue.cc index 55e0c7d92..03e4b6546 100644 --- a/srsue/src/ue.cc +++ b/srsue/src/ue.cc @@ -32,6 +32,7 @@ #include #include #include +#include using namespace srslte; @@ -52,25 +53,37 @@ bool ue::init(all_args_t *args_) { args = args_; -#ifndef LOG_STDOUT - logger.init(args->log.filename); -#endif - rf_log.init("RF ", &logger); - phy_log.init("PHY ", &logger, true); - mac_log.init("MAC ", &logger, true); - rlc_log.init("RLC ", &logger); - pdcp_log.init("PDCP", &logger); - rrc_log.init("RRC ", &logger); - nas_log.init("NAS ", &logger); - gw_log.init("GW ", &logger); - usim_log.init("USIM", &logger); + if (!args->log.filename.compare("stdout")) { + logger = &logger_stdout; + } else { + logger_file.init(args->log.filename); + logger_file.log("\n\n"); + logger = &logger_file; + } + + rf_log.init("RF ", logger); + // Create array of pointers to phy_logs + for (int i=0;iexpert.phy.nof_phy_threads;i++) { + srslte::log_filter *mylog = new srslte::log_filter; + char tmp[16]; + sprintf(tmp, "PHY%d",i); + mylog->init(tmp, logger, true); + phy_log.push_back((void*) mylog); + } + + mac_log.init("MAC ", logger, true); + rlc_log.init("RLC ", logger); + pdcp_log.init("PDCP", logger); + rrc_log.init("RRC ", logger); + nas_log.init("NAS ", logger); + gw_log.init("GW ", logger); + usim_log.init("USIM", logger); // Init logs -#ifndef LOG_STDOUT - logger.log("\n\n"); -#endif rf_log.set_level(srslte::LOG_LEVEL_INFO); - phy_log.set_level(level(args->log.phy_level)); + for (int i=0;iexpert.phy.nof_phy_threads;i++) { + ((srslte::log_filter*) phy_log[i])->set_level(level(args->log.phy_level)); + } mac_log.set_level(level(args->log.mac_level)); rlc_log.set_level(level(args->log.rlc_level)); pdcp_log.set_level(level(args->log.pdcp_level)); @@ -79,7 +92,9 @@ bool ue::init(all_args_t *args_) gw_log.set_level(level(args->log.gw_level)); usim_log.set_level(level(args->log.usim_level)); - phy_log.set_hex_limit(args->log.phy_hex_limit); + for (int i=0;iexpert.phy.nof_phy_threads;i++) { + ((srslte::log_filter*) phy_log[i])->set_hex_limit(args->log.phy_hex_limit); + } mac_log.set_hex_limit(args->log.mac_hex_limit); rlc_log.set_hex_limit(args->log.rlc_hex_limit); pdcp_log.set_hex_limit(args->log.pdcp_hex_limit); @@ -104,7 +119,7 @@ bool ue::init(all_args_t *args_) // PHY initis in background, start before radio args->expert.phy.nof_rx_ant = args->rf.nof_rx_ant; - phy.init(&radio, &mac, &rrc, &phy_log, &args->expert.phy); + phy.init(&radio, &mac, &rrc, phy_log, &args->expert.phy); /* Start Radio */ char *dev_name = NULL; @@ -167,7 +182,7 @@ bool ue::init(all_args_t *args_) pdcp.init(&rlc, &rrc, &gw, &pdcp_log, 0 /* RB_ID_SRB0 */, SECURITY_DIRECTION_UPLINK); nas.init(&usim, &rrc, &gw, &nas_log, 1 /* RB_ID_SRB1 */); - gw.init(&pdcp, this, &gw_log, 3 /* RB_ID_DRB1 */); + gw.init(&pdcp, &nas, &gw_log, 3 /* RB_ID_DRB1 */); usim.init(&args->usim, &usim_log); @@ -195,10 +210,6 @@ void ue::pregenerate_signals(bool enable) phy.enable_pregen_signals(enable); } -void ue::test_con_restablishment() { - rrc.test_con_restablishment(); -} - void ue::stop() { if(started) @@ -236,7 +247,7 @@ void ue::stop() bool ue::is_attached() { - return (EMM_STATE_REGISTERED == nas.get_state()); + return (RRC_STATE_CONNECTED == rrc.get_state()); } void ue::start_plot() { diff --git a/srsue/src/ue_base.cc b/srsue/src/ue_base.cc index c84393ae4..94b9b5155 100644 --- a/srsue/src/ue_base.cc +++ b/srsue/src/ue_base.cc @@ -88,7 +88,7 @@ void ue_base::handle_rf_msg(srslte_rf_error_t error) } else if(error.type == srslte_rf_error_t::SRSLTE_RF_ERROR_LATE) { rf_metrics.rf_l++; rf_metrics.rf_error = true; - rf_log.warning("Late\n"); + rf_log.warning("Late (detected in %s)\n", error.opt?"rx call":"asynchronous thread"); } else if (error.type == srslte_rf_error_t::SRSLTE_RF_ERROR_OTHER) { std::string str(error.msg); str.erase(std::remove(str.begin(), str.end(), '\n'), str.end()); diff --git a/lib/src/upper/gw.cc b/srsue/src/upper/gw.cc similarity index 52% rename from lib/src/upper/gw.cc rename to srsue/src/upper/gw.cc index 321d8d9e9..07ac36989 100644 --- a/lib/src/upper/gw.cc +++ b/srsue/src/upper/gw.cc @@ -25,7 +25,7 @@ */ -#include "srslte/upper/gw.h" +#include "../../hdr/upper/gw.h" #include #include @@ -38,7 +38,7 @@ #include -namespace srslte { +namespace srsue { gw::gw() :if_up(false) @@ -46,11 +46,11 @@ gw::gw() current_ip_addr = 0; } -void gw::init(srsue::pdcp_interface_gw *pdcp_, srsue::ue_interface *ue_, log *gw_log_, uint32_t lcid_) +void gw::init(pdcp_interface_gw *pdcp_, nas_interface_gw *nas_, srslte::log *gw_log_, uint32_t lcid_) { - pool = byte_buffer_pool::get_instance(); + pool = srslte::byte_buffer_pool::get_instance(); pdcp = pdcp_; - ue = ue_; + nas = nas_; gw_log = gw_log_; lcid = lcid_; run_enable = true; @@ -107,7 +107,7 @@ void gw::get_metrics(gw_metrics_t &m) /******************************************************************************* PDCP interface *******************************************************************************/ -void gw::write_pdu(uint32_t lcid, byte_buffer_t *pdu) +void gw::write_pdu(uint32_t lcid, srslte::byte_buffer_t *pdu) { gw_log->info_hex(pdu->msg, pdu->N_bytes, "RX PDU"); gw_log->info("RX PDU. Stack latency: %ld us\n", pdu->get_latency_us()); @@ -128,7 +128,7 @@ void gw::write_pdu(uint32_t lcid, byte_buffer_t *pdu) /******************************************************************************* NAS interface *******************************************************************************/ -error_t gw::setup_if_addr(uint32_t ip_addr, char *err_str) +srslte::error_t gw::setup_if_addr(uint32_t ip_addr, char *err_str) { if (ip_addr != current_ip_addr) { if(!if_up) @@ -136,7 +136,7 @@ error_t gw::setup_if_addr(uint32_t ip_addr, char *err_str) if(init_if(err_str)) { gw_log->error("init_if failed\n"); - return(ERROR_CANT_START); + return(srslte::ERROR_CANT_START); } } @@ -149,7 +149,7 @@ error_t gw::setup_if_addr(uint32_t ip_addr, char *err_str) err_str = strerror(errno); gw_log->debug("Failed to set socket address: %s\n", err_str); close(tun_fd); - return(ERROR_CANT_START); + return(srslte::ERROR_CANT_START); } ifr.ifr_netmask.sa_family = AF_INET; ((struct sockaddr_in *)&ifr.ifr_netmask)->sin_addr.s_addr = inet_addr("255.255.255.0"); @@ -158,7 +158,7 @@ error_t gw::setup_if_addr(uint32_t ip_addr, char *err_str) err_str = strerror(errno); gw_log->debug("Failed to set socket netmask: %s\n", err_str); close(tun_fd); - return(ERROR_CANT_START); + return(srslte::ERROR_CANT_START); } current_ip_addr = ip_addr; @@ -167,59 +167,59 @@ error_t gw::setup_if_addr(uint32_t ip_addr, char *err_str) start(GW_THREAD_PRIO); } - return(ERROR_NONE); + return(srslte::ERROR_NONE); } -error_t gw::init_if(char *err_str) +srslte::error_t gw::init_if(char *err_str) { - if(if_up) - { - return(ERROR_ALREADY_STARTED); - } + if(if_up) + { + return(srslte::ERROR_ALREADY_STARTED); + } - char dev[IFNAMSIZ] = "tun_srsue"; + char dev[IFNAMSIZ] = "tun_srsue"; - // Construct the TUN device - tun_fd = open("/dev/net/tun", O_RDWR); - gw_log->info("TUN file descriptor = %d\n", tun_fd); - if(0 > tun_fd) - { - err_str = strerror(errno); - gw_log->debug("Failed to open TUN device: %s\n", err_str); - return(ERROR_CANT_START); - } - memset(&ifr, 0, sizeof(ifr)); - ifr.ifr_flags = IFF_TUN | IFF_NO_PI; - strncpy(ifr.ifr_ifrn.ifrn_name, dev, IFNAMSIZ); - if(0 > ioctl(tun_fd, TUNSETIFF, &ifr)) - { - err_str = strerror(errno); - gw_log->debug("Failed to set TUN device name: %s\n", err_str); - close(tun_fd); - return(ERROR_CANT_START); - } + // Construct the TUN device + tun_fd = open("/dev/net/tun", O_RDWR); + gw_log->info("TUN file descriptor = %d\n", tun_fd); + if(0 > tun_fd) + { + err_str = strerror(errno); + gw_log->debug("Failed to open TUN device: %s\n", err_str); + return(srslte::ERROR_CANT_START); + } + memset(&ifr, 0, sizeof(ifr)); + ifr.ifr_flags = IFF_TUN | IFF_NO_PI; + strncpy(ifr.ifr_ifrn.ifrn_name, dev, IFNAMSIZ); + if(0 > ioctl(tun_fd, TUNSETIFF, &ifr)) + { + err_str = strerror(errno); + gw_log->debug("Failed to set TUN device name: %s\n", err_str); + close(tun_fd); + return(srslte::ERROR_CANT_START); + } - // Bring up the interface - sock = socket(AF_INET, SOCK_DGRAM, 0); - if(0 > ioctl(sock, SIOCGIFFLAGS, &ifr)) - { - err_str = strerror(errno); - gw_log->debug("Failed to bring up socket: %s\n", err_str); - close(tun_fd); - return(ERROR_CANT_START); - } - ifr.ifr_flags |= IFF_UP | IFF_RUNNING; - if(0 > ioctl(sock, SIOCSIFFLAGS, &ifr)) - { - err_str = strerror(errno); - gw_log->debug("Failed to set socket flags: %s\n", err_str); - close(tun_fd); - return(ERROR_CANT_START); - } + // Bring up the interface + sock = socket(AF_INET, SOCK_DGRAM, 0); + if(0 > ioctl(sock, SIOCGIFFLAGS, &ifr)) + { + err_str = strerror(errno); + gw_log->debug("Failed to bring up socket: %s\n", err_str); + close(tun_fd); + return(srslte::ERROR_CANT_START); + } + ifr.ifr_flags |= IFF_UP | IFF_RUNNING; + if(0 > ioctl(sock, SIOCSIFFLAGS, &ifr)) + { + err_str = strerror(errno); + gw_log->debug("Failed to set socket flags: %s\n", err_str); + close(tun_fd); + return(srslte::ERROR_CANT_START); + } - if_up = true; + if_up = true; - return(ERROR_NONE); + return(srslte::ERROR_NONE); } /********************/ @@ -227,65 +227,92 @@ error_t gw::init_if(char *err_str) /********************/ void gw::run_thread() { - struct iphdr *ip_pkt; - uint32 idx = 0; - int32 N_bytes; - byte_buffer_t *pdu = pool_allocate; + struct iphdr *ip_pkt; + uint32 idx = 0; + int32 N_bytes; + srslte::byte_buffer_t *pdu = pool_allocate; - gw_log->info("GW IP packet receiver thread run_enable\n"); + const static uint32_t ATTACH_TIMEOUT_MS = 10000; + const static uint32_t ATTACH_MAX_ATTEMPTS = 3; + uint32_t attach_cnt = 0; + uint32_t attach_attempts = 0; - running = true; - while(run_enable) + gw_log->info("GW IP packet receiver thread run_enable\n"); + + running = true; + while(run_enable) + { + if (SRSLTE_MAX_BUFFER_SIZE_BYTES-SRSLTE_BUFFER_HEADER_OFFSET > idx) { + N_bytes = read(tun_fd, &pdu->msg[idx], SRSLTE_MAX_BUFFER_SIZE_BYTES-SRSLTE_BUFFER_HEADER_OFFSET - idx); + } else { + gw_log->error("GW pdu buffer full - gw receive thread exiting.\n"); + gw_log->console("GW pdu buffer full - gw receive thread exiting.\n"); + break; + } + gw_log->debug("Read %d bytes from TUN fd=%d, idx=%d\n", N_bytes, tun_fd, idx); + if(N_bytes > 0) { - if (SRSLTE_MAX_BUFFER_SIZE_BYTES-SRSLTE_BUFFER_HEADER_OFFSET > idx) { - N_bytes = read(tun_fd, &pdu->msg[idx], SRSLTE_MAX_BUFFER_SIZE_BYTES-SRSLTE_BUFFER_HEADER_OFFSET - idx); - } else { - gw_log->error("GW pdu buffer full - gw receive thread exiting.\n"); - gw_log->console("GW pdu buffer full - gw receive thread exiting.\n"); - break; - } - gw_log->debug("Read %d bytes from TUN fd=%d, idx=%d\n", N_bytes, tun_fd, idx); - if(N_bytes > 0) - { - pdu->N_bytes = idx + N_bytes; - ip_pkt = (struct iphdr*)pdu->msg; + pdu->N_bytes = idx + N_bytes; + ip_pkt = (struct iphdr*)pdu->msg; - // Warning: Accept only IPv4 packets - if (ip_pkt->version == 4) { - // Check if entire packet was received - if(ntohs(ip_pkt->tot_len) == pdu->N_bytes) - { - gw_log->info_hex(pdu->msg, pdu->N_bytes, "TX PDU"); + // Warning: Accept only IPv4 packets + if (ip_pkt->version == 4) { + // Check if entire packet was received + if(ntohs(ip_pkt->tot_len) == pdu->N_bytes) + { + gw_log->info_hex(pdu->msg, pdu->N_bytes, "TX PDU"); - if (!run_enable) { - break; + while(run_enable && !pdcp->is_drb_enabled(lcid) && attach_attempts < ATTACH_MAX_ATTEMPTS) { + if (attach_cnt == 0) { + gw_log->info("LCID=%d not active, requesting NAS attach (%d/%d)\n", lcid, attach_attempts, ATTACH_MAX_ATTEMPTS); + nas->attach_request(); + attach_attempts++; } - - // Send PDU directly to PDCP + attach_cnt++; + if (attach_cnt == ATTACH_TIMEOUT_MS) { + attach_cnt = 0; + } + usleep(1000); + } + + if (attach_attempts == ATTACH_MAX_ATTEMPTS) { + gw_log->warning("LCID=%d was not active after %d attempts\n", lcid, ATTACH_MAX_ATTEMPTS); + } + + attach_attempts = 0; + attach_cnt = 0; + + if (!run_enable) { + break; + } + + // Send PDU directly to PDCP + if (pdcp->is_drb_enabled(lcid)) { pdu->set_timestamp(); ul_tput_bytes += pdu->N_bytes; pdcp->write_sdu(lcid, pdu); - + do { pdu = pool_allocate; if (!pdu) { printf("Not enough buffers in pool\n"); usleep(100000); } - } while(!pdu); + } while(!pdu); idx = 0; - }else{ - idx += N_bytes; - } - } - }else{ - gw_log->error("Failed to read from TUN interface - gw receive thread exiting.\n"); - gw_log->console("Failed to read from TUN interface - gw receive thread exiting.\n"); - break; + } + }else{ + idx += N_bytes; + } } + }else{ + gw_log->error("Failed to read from TUN interface - gw receive thread exiting.\n"); + gw_log->console("Failed to read from TUN interface - gw receive thread exiting.\n"); + break; } - running = false; - gw_log->info("GW IP receiver thread exiting.\n"); + } + running = false; + gw_log->info("GW IP receiver thread exiting.\n"); } } // namespace srsue diff --git a/srsue/src/upper/nas.cc b/srsue/src/upper/nas.cc index f3b3708af..91b35ce01 100644 --- a/srsue/src/upper/nas.cc +++ b/srsue/src/upper/nas.cc @@ -74,7 +74,12 @@ void nas::attach_request() { } else if (plmn_selection == PLMN_SELECTED) { nas_log->info("Selecting PLMN %s\n", plmn_id_to_c_str(current_plmn).c_str()); rrc->plmn_select(current_plmn); + selecting_plmn = current_plmn; } + } else if (state == EMM_STATE_REGISTERED) { + nas_log->info("NAS state is registered, connecting to same PLMN\n"); + rrc->plmn_select(current_plmn); + selecting_plmn = current_plmn; } else { nas_log->info("Attach request ignored. State = %s\n", emm_state_text[state]); } @@ -97,6 +102,7 @@ void nas::plmn_found(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id, uint16_t tracking_ nas_log->info("Detected known PLMN %s\n", plmn_id_to_c_str(plmn_id).c_str()); if (plmn_id.mcc == home_plmn.mcc && plmn_id.mnc == home_plmn.mnc) { rrc->plmn_select(plmn_id); + selecting_plmn = plmn_id; } return; } @@ -107,6 +113,7 @@ void nas::plmn_found(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id, uint16_t tracking_ tracking_area_code); if (plmn_id.mcc == home_plmn.mcc && plmn_id.mnc == home_plmn.mnc) { rrc->plmn_select(plmn_id); + selecting_plmn = plmn_id; } } @@ -114,6 +121,10 @@ bool nas::is_attached() { return state == EMM_STATE_REGISTERED; } +bool nas::is_attaching() { + return state == EMM_STATE_REGISTERED_INITIATED; +} + void nas::notify_connection_setup() { nas_log->debug("State = %s\n", emm_state_text[state]); if (EMM_STATE_REGISTERED_INITIATED == state) { @@ -317,6 +328,7 @@ void nas::parse_attach_accept(uint32_t lcid, byte_buffer_t *pdu) { // FIXME: Setup the default EPS bearer context state = EMM_STATE_REGISTERED; + current_plmn = selecting_plmn; // Send EPS bearer context accept and attach complete count_ul++; diff --git a/srsue/src/upper/rrc.cc b/srsue/src/upper/rrc.cc index cb7c117a3..3bb3e0017 100644 --- a/srsue/src/upper/rrc.cc +++ b/srsue/src/upper/rrc.cc @@ -31,6 +31,7 @@ #include "upper/rrc.h" #include #include +#include #include "srslte/common/security.h" #include "srslte/common/bcd_helpers.h" @@ -92,16 +93,18 @@ void rrc::init(phy_interface_rrc *phy_, pthread_mutex_init(&mutex, NULL); ue_category = SRSLTE_UE_CATEGORY; - t301 = mac_timers->get_unique_id(); - t310 = mac_timers->get_unique_id(); - t311 = mac_timers->get_unique_id(); - safe_reset_timer = mac_timers->get_unique_id(); + t301 = mac_timers->timer_get_unique_id(); + t310 = mac_timers->timer_get_unique_id(); + t311 = mac_timers->timer_get_unique_id(); transaction_id = 0; // Register logging handler with liblte_rrc liblte_rrc_log_register_handler(this, liblte_rrc_handler); + nof_sib1_trials = 0; + last_win_start = 0; + // Set default values for all layers set_rrc_default(); set_phy_default(); @@ -117,6 +120,14 @@ rrc_state_t rrc::get_state() { return state; } +bool rrc::is_connected() { + return (RRC_STATE_CONNECTED == state); +} + +bool rrc::have_drb() { + return drb_up; +} + void rrc::set_ue_category(int category) { if (category >= 1 && category <= 5) { ue_category = category; @@ -125,311 +136,49 @@ void rrc::set_ue_category(int category) { } } - - -/******************************************************************************* -* -* -* -* PLMN selection, cell selection/reselection and acquisition of SI procedures -* -* -* -*******************************************************************************/ - -/******************************************************************************* -NAS interface -*******************************************************************************/ - -uint16_t rrc::get_mcc() { - if (current_cell) { - if (current_cell->sib1.N_plmn_ids > 0) { - return current_cell->sib1.plmn_id[0].id.mcc; - } - } - return 0; -} - -uint16_t rrc::get_mnc() { - if (current_cell) { - if (current_cell->sib1.N_plmn_ids > 0) { - return current_cell->sib1.plmn_id[0].id.mnc; - } - } - return 0; -} - -void rrc::plmn_search() { - rrc_log->info("Starting PLMN search procedure\n"); - state = RRC_STATE_PLMN_SELECTION; - phy->cell_search_start(); - plmn_select_timeout = 0; -} - -void rrc::plmn_select(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id) { - rrc_log->info("PLMN %s selected\n", plmn_id_to_c_str(plmn_id).c_str()); - - - // Sort cells according to RSRP - - selected_plmn_id = plmn_id; - last_selected_cell = -1; - select_cell_timeout = 0; - - state = RRC_STATE_CELL_SELECTING; - select_next_cell_in_plmn(); -} - -void rrc::select_next_cell_in_plmn() { - for (uint32_t i = last_selected_cell + 1; i < known_cells.size(); i++) { - for (uint32_t j = 0; j < known_cells[i].sib1.N_plmn_ids; j++) { - if (known_cells[i].sib1.plmn_id[j].id.mcc == selected_plmn_id.mcc || - known_cells[i].sib1.plmn_id[j].id.mnc == selected_plmn_id.mnc) { - rrc_log->info("Selecting cell PCI=%d, EARFCN=%d, Cell ID=0x%x\n", - known_cells[i].phy_cell.id, known_cells[i].earfcn, - known_cells[i].sib1.cell_id); - rrc_log->console("Select cell: PCI=%d, EARFCN=%d, Cell ID=0x%x\n", - known_cells[i].phy_cell.id, known_cells[i].earfcn, - known_cells[i].sib1.cell_id); - // Check that cell satisfies S criteria - if (known_cells[i].in_sync) { // %% rsrp > S dbm - // Try to select Cell - if (phy->cell_select(known_cells[i].earfcn, known_cells[i].phy_cell)) - { - last_selected_cell = i; - current_cell = &known_cells[i]; - return; - } else { - rrc_log->warning("Selecting cell EARFCN=%d, Cell ID=0x%x.\n", - known_cells[i].earfcn, known_cells[i].sib1.cell_id); - } - } - } - } - } - rrc_log->info("No more known cells...\n"); -} - -/******************************************************************************* -PHY interface -*******************************************************************************/ - -void rrc::cell_found(uint32_t earfcn, srslte_cell_t phy_cell, float rsrp) { - - // find if cell_id-earfcn combination already exists - for (uint32_t i = 0; i < known_cells.size(); i++) { - if (earfcn == known_cells[i].earfcn && phy_cell.id == known_cells[i].phy_cell.id) { - known_cells[i].rsrp = rsrp; - known_cells[i].in_sync = true; - current_cell = &known_cells[i]; - rrc_log->info("Updating cell EARFCN=%d, PCI=%d, RSRP=%.1f dBm\n", known_cells[i].earfcn, - known_cells[i].phy_cell.id, known_cells[i].rsrp); - - if (!known_cells[i].has_valid_sib1) { - si_acquire_state = SI_ACQUIRE_SIB1; - } else { - for (uint32_t i = 0; i < current_cell->sib1.N_plmn_ids; i++) { - nas->plmn_found(current_cell->sib1.plmn_id[i].id, current_cell->sib1.tracking_area_code); - } - } - return; - } - } - // add to list of known cells - cell_t cell; - cell.phy_cell = phy_cell; - cell.rsrp = rsrp; - cell.earfcn = earfcn; - cell.has_valid_sib1 = false; - cell.has_valid_sib2 = false; - known_cells.push_back(cell); - - // save current cell - current_cell = &known_cells.back(); - - si_acquire_state = SI_ACQUIRE_SIB1; - - rrc_log->info("New Cell: PCI=%d, PRB=%d, Ports=%d, EARFCN=%d, RSRP=%.1f dBm\n", - cell.phy_cell.id, cell.phy_cell.nof_prb, cell.phy_cell.nof_ports, - cell.earfcn, cell.rsrp); -} - -// Detection of physical layer problems (5.3.11.1) -void rrc::out_of_sync() { - current_cell->in_sync = false; - if (!mac_timers->get(t311)->is_running() && !mac_timers->get(t310)->is_running()) { - n310_cnt++; - if (n310_cnt == N310) { - mac_timers->get(t310)->reset(); - mac_timers->get(t310)->run(); - n310_cnt = 0; - rrc_log->info("Detected %d out-of-sync from PHY. Starting T310 timer\n", N310); - } - } -} - -// Recovery of physical layer problems (5.3.11.2) -void rrc::in_sync() { - current_cell->in_sync = true; - if (mac_timers->get(t310)->is_running()) { - n311_cnt++; - if (n311_cnt == N311) { - mac_timers->get(t310)->stop(); - n311_cnt = 0; - rrc_log->info("Detected %d in-sync from PHY. Stopping T310 timer\n", N311); - } - } -} - -/******************************************************************************* -PDCP interface -*******************************************************************************/ -void rrc::write_pdu_bcch_bch(byte_buffer_t *pdu) { - pool->deallocate(pdu); - if (state == RRC_STATE_PLMN_SELECTION) { - // Do we need to do something with BCH? - rrc_log->info_hex(pdu->msg, pdu->N_bytes, "BCCH BCH message received."); - } else { - rrc_log->warning("Received BCCH BCH in incorrect state\n"); - } -} - -void rrc::write_pdu_bcch_dlsch(byte_buffer_t *pdu) { - rrc_log->info_hex(pdu->msg, pdu->N_bytes, "BCCH DLSCH message received."); - rrc_log->info("BCCH DLSCH message Stack latency: %ld us\n", pdu->get_latency_us()); - LIBLTE_RRC_BCCH_DLSCH_MSG_STRUCT dlsch_msg; - srslte_bit_unpack_vector(pdu->msg, bit_buf.msg, pdu->N_bytes * 8); - bit_buf.N_bits = pdu->N_bytes * 8; - pool->deallocate(pdu); - liblte_rrc_unpack_bcch_dlsch_msg((LIBLTE_BIT_MSG_STRUCT *) &bit_buf, &dlsch_msg); - - if (dlsch_msg.N_sibs > 0) { - if (LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_1 == dlsch_msg.sibs[0].sib_type && SI_ACQUIRE_SIB1 == si_acquire_state) { - mac->bcch_stop_rx(); - - // Handle SIB1 - memcpy(¤t_cell->sib1, &dlsch_msg.sibs[0].sib.sib1, sizeof(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_1_STRUCT)); - - rrc_log->info("SIB1 received, CellID=%d, si_window=%d, sib2_period=%d\n", - current_cell->sib1.cell_id & 0xfff, - liblte_rrc_si_window_length_num[current_cell->sib1.si_window_length], - liblte_rrc_si_periodicity_num[current_cell->sib1.sched_info[0].si_periodicity]); - - - // Set TDD Config - if (current_cell->sib1.tdd) { - phy->set_config_tdd(¤t_cell->sib1.tdd_cnfg); - } - - current_cell->has_valid_sib1 = true; - - // Send PLMN and TAC to NAS - std::stringstream ss; - for (uint32_t i = 0; i < current_cell->sib1.N_plmn_ids; i++) { - nas->plmn_found(current_cell->sib1.plmn_id[i].id, current_cell->sib1.tracking_area_code); - } - - // Jump to next state - switch(state) { - case RRC_STATE_CELL_SELECTING: - si_acquire_state = SI_ACQUIRE_SIB2; - break; - case RRC_STATE_PLMN_SELECTION: - si_acquire_state = SI_ACQUIRE_IDLE; - rrc_log->info("SI Acquisition done. Searching next cell...\n"); - usleep(5000); - phy->cell_search_next(); - break; - default: - si_acquire_state = SI_ACQUIRE_IDLE; - } - - } else if (LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2 == dlsch_msg.sibs[0].sib_type && - SI_ACQUIRE_SIB2 == si_acquire_state) { - mac->bcch_stop_rx(); - - // Handle SIB2 - memcpy(¤t_cell->sib2, &dlsch_msg.sibs[0].sib.sib2, sizeof(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT)); - rrc_log->info("SIB2 received\n"); - - apply_sib2_configs(¤t_cell->sib2); - - current_cell->has_valid_sib2 = true; - - // Jump to next state - switch(state) { - case RRC_STATE_CELL_SELECTING: - si_acquire_state = SI_ACQUIRE_IDLE; - state = RRC_STATE_CELL_SELECTED; - break; - default: - si_acquire_state = SI_ACQUIRE_IDLE; - } - } - } -} - - -// Right now, this thread only controls System Information acquisition procedure +/* + * + * RRC State Machine + * + */ void rrc::run_thread() { - uint32_t tti; - uint32_t si_win_start=0, si_win_len=0, last_win_start=0; - uint16_t period; - uint32_t nof_sib1_trials = 0; - const int SIB1_SEARCH_TIMEOUT = 30; while (thread_running) { - switch (si_acquire_state) { - case SI_ACQUIRE_SIB1: - // Instruct MAC to look for SIB1 - tti = mac->get_current_tti(); - si_win_start = sib_start_tti(tti, 2, 5); - if (tti > last_win_start + 10) { - last_win_start = si_win_start; - mac->bcch_start_rx(si_win_start, 1); - rrc_log->debug("Instructed MAC to search for SIB1, win_start=%d, win_len=%d\n", - si_win_start, 1); - nof_sib1_trials++; - if (nof_sib1_trials >= SIB1_SEARCH_TIMEOUT) { - if (state == RRC_STATE_CELL_SELECTING) { - select_next_cell_in_plmn(); - si_acquire_state = SI_ACQUIRE_IDLE; - } else if (state == RRC_STATE_PLMN_SELECTION) { - phy->cell_search_next(); - } - nof_sib1_trials = 0; - } - } - break; - case SI_ACQUIRE_SIB2: - // Instruct MAC to look for SIB2 only when selecting a cell - tti = mac->get_current_tti(); - period = liblte_rrc_si_periodicity_num[current_cell->sib1.sched_info[0].si_periodicity]; - si_win_start = sib_start_tti(tti, period, 0); - if (tti > last_win_start + 10) { - last_win_start = si_win_start; - si_win_len = liblte_rrc_si_window_length_num[current_cell->sib1.si_window_length]; - mac->bcch_start_rx(si_win_start, si_win_len); - rrc_log->debug("Instructed MAC to search for SIB2, win_start=%d, win_len=%d\n", - si_win_start, si_win_len); - } - break; - default: - break; + if (state >= RRC_STATE_IDLE && state < RRC_STATE_CONNECTING) { + run_si_acquisition_procedure(); } + switch(state) { + /* Procedures in IDLE state 36.304 Sec 4 */ case RRC_STATE_IDLE: - if (nas->is_attached()) { - usleep(10000); - rrc_log->info("RRC IDLE: NAS is attached, re-selecting cell...\n"); - plmn_select(selected_plmn_id); + // If camping on the cell, it will receive SI and paging from PLMN + if (phy->sync_status()) { + // If attempting to attach, reselect cell + if (nas->is_attaching()) { + sleep(1); + rrc_log->info("RRC IDLE: NAS is attaching and camping on cell, reselecting...\n"); + plmn_select(selected_plmn_id); + } + // If not camping on a cell + } else { + // If NAS is attached, perform cell reselection on current PLMN + if (nas->is_attached()) { + rrc_log->info("RRC IDLE: NAS is attached, PHY not synchronized. Re-selecting cell...\n"); + plmn_select(selected_plmn_id); + } else if (nas->is_attaching()) { + sleep(1); + rrc_log->info("RRC IDLE: NAS is attaching, searching again PLMN\n"); + plmn_search(); + } + // If not attached, PLMN selection will be triggered from higher layers } break; case RRC_STATE_PLMN_SELECTION: plmn_select_timeout++; if (plmn_select_timeout >= RRC_PLMN_SELECT_TIMEOUT) { rrc_log->info("RRC PLMN Search: timeout expired. Searching again\n"); + phy->cell_search_stop(); sleep(1); rrc_log->console("\nRRC PLMN Search: timeout expired. Searching again\n"); plmn_select_timeout = 0; @@ -473,6 +222,22 @@ void rrc::run_thread() { case RRC_STATE_CONNECTED: // Take measurements, cell reselection, etc break; + case RRC_STATE_LEAVE_CONNECTED: + usleep(60000); + rrc_log->info("Leaving RRC_CONNECTED state\n"); + drb_up = false; + pdcp->reset(); + rlc->reset(); + phy->reset(); + mac->reset(); + set_phy_default(); + set_mac_default(); + mac->pcch_start_rx(); + mac_timers->timer_get(t311)->run(); + mac_timers->timer_get(t310)->stop(); + mac_timers->timer_get(t311)->stop(); + state = RRC_STATE_IDLE; + break; default: break; } @@ -486,36 +251,273 @@ void rrc::run_thread() { - - - - - - - /******************************************************************************* -NAS interface +* +* +* +* System Information Acquisition procedure +* +* +* *******************************************************************************/ -void rrc::write_sdu(uint32_t lcid, byte_buffer_t *sdu) { - rrc_log->info_hex(sdu->msg, sdu->N_bytes, "RX %s SDU", get_rb_name(lcid).c_str()); - switch (state) { - case RRC_STATE_CONNECTING: - send_con_setup_complete(sdu); + +// Determine SI messages scheduling as in 36.331 5.2.3 Acquisition of an SI message +uint32_t rrc::sib_start_tti(uint32_t tti, uint32_t period, uint32_t x) { + return (period * 10 * (1 + tti / (period * 10)) + x) % 10240; // the 1 means next opportunity +} + +void rrc::run_si_acquisition_procedure() +{ + uint32_t tti; + uint32_t si_win_start=0, si_win_len=0; + uint16_t period; + const int SIB1_SEARCH_TIMEOUT = 30; + + switch (si_acquire_state) { + case SI_ACQUIRE_SIB1: + // Instruct MAC to look for SIB1 + tti = mac->get_current_tti(); + si_win_start = sib_start_tti(tti, 2, 5); + if (tti > last_win_start + 10) { + last_win_start = si_win_start; + mac->bcch_start_rx(si_win_start, 1); + rrc_log->debug("Instructed MAC to search for SIB1, win_start=%d, win_len=%d\n", + si_win_start, 1); + nof_sib1_trials++; + if (nof_sib1_trials >= SIB1_SEARCH_TIMEOUT) { + if (state == RRC_STATE_CELL_SELECTING) { + select_next_cell_in_plmn(); + si_acquire_state = SI_ACQUIRE_IDLE; + } else if (state == RRC_STATE_PLMN_SELECTION) { + phy->cell_search_next(); + } + nof_sib1_trials = 0; + } + } break; - case RRC_STATE_CONNECTED: - send_ul_info_transfer(lcid, sdu); + case SI_ACQUIRE_SIB2: + // Instruct MAC to look for SIB2 only when selecting a cell + tti = mac->get_current_tti(); + period = liblte_rrc_si_periodicity_num[current_cell->sib1.sched_info[0].si_periodicity]; + si_win_start = sib_start_tti(tti, period, 0); + if (tti > last_win_start + 10) { + last_win_start = si_win_start; + si_win_len = liblte_rrc_si_window_length_num[current_cell->sib1.si_window_length]; + + mac->bcch_start_rx(si_win_start, si_win_len); + rrc_log->debug("Instructed MAC to search for SIB2, win_start=%d, win_len=%d\n", + si_win_start, si_win_len); + } break; default: - rrc_log->error("SDU received from NAS while RRC state = %s", rrc_state_text[state]); break; } } + + + + + + + + + /******************************************************************************* -MAC interface +* +* +* +* PLMN selection, cell selection/reselection and acquisition of SI procedures +* +* +* *******************************************************************************/ + +uint16_t rrc::get_mcc() { + if (current_cell) { + if (current_cell->sib1.N_plmn_ids > 0) { + return current_cell->sib1.plmn_id[0].id.mcc; + } + } + return 0; +} + +uint16_t rrc::get_mnc() { + if (current_cell) { + if (current_cell->sib1.N_plmn_ids > 0) { + return current_cell->sib1.plmn_id[0].id.mnc; + } + } + return 0; +} + +void rrc::plmn_search() { + rrc_log->info("Starting PLMN search procedure\n"); + state = RRC_STATE_PLMN_SELECTION; + phy->cell_search_start(); + plmn_select_timeout = 0; +} + +void rrc::plmn_select(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id) { + + // If already camping on the selected PLMN, select this cell + if (state == RRC_STATE_IDLE || state == RRC_STATE_CONNECTED || state == RRC_STATE_PLMN_SELECTION) { + if (phy->sync_status() && selected_plmn_id.mcc == plmn_id.mcc && selected_plmn_id.mnc == plmn_id.mnc) { + rrc_log->info("Already camping on selected PLMN, connecting...\n"); + state = RRC_STATE_CELL_SELECTING; + select_cell_timeout = 0; + } else { + rrc_log->info("PLMN %s selected\n", plmn_id_to_c_str(plmn_id).c_str()); + // Sort cells according to RSRP + + selected_plmn_id = plmn_id; + last_selected_cell = -1; + select_cell_timeout = 0; + + state = RRC_STATE_CELL_SELECTING; + select_next_cell_in_plmn(); + } + } else { + rrc_log->warning("Requested PLMN select in incorrect state %s\n", rrc_state_text[state]); + } +} + +void rrc::select_next_cell_in_plmn() { + for (uint32_t i = last_selected_cell + 1; i < known_cells.size(); i++) { + for (uint32_t j = 0; j < known_cells[i].sib1.N_plmn_ids; j++) { + if (known_cells[i].sib1.plmn_id[j].id.mcc == selected_plmn_id.mcc || + known_cells[i].sib1.plmn_id[j].id.mnc == selected_plmn_id.mnc) { + rrc_log->info("Selecting cell PCI=%d, EARFCN=%d, Cell ID=0x%x\n", + known_cells[i].phy_cell.id, known_cells[i].earfcn, + known_cells[i].sib1.cell_id); + rrc_log->console("Select cell: PCI=%d, EARFCN=%d, Cell ID=0x%x\n", + known_cells[i].phy_cell.id, known_cells[i].earfcn, + known_cells[i].sib1.cell_id); + // Check that cell satisfies S criteria + if (known_cells[i].in_sync) { // %% rsrp > S dbm + // Try to select Cell + if (phy->cell_select(known_cells[i].earfcn, known_cells[i].phy_cell)) + { + last_selected_cell = i; + current_cell = &known_cells[i]; + return; + } else { + rrc_log->warning("Selecting cell EARFCN=%d, Cell ID=0x%x.\n", + known_cells[i].earfcn, known_cells[i].sib1.cell_id); + } + } + } + } + } + rrc_log->info("No more known cells...\n"); +} + +void rrc::cell_found(uint32_t earfcn, srslte_cell_t phy_cell, float rsrp) { + + // find if cell_id-earfcn combination already exists + for (uint32_t i = 0; i < known_cells.size(); i++) { + if (earfcn == known_cells[i].earfcn && phy_cell.id == known_cells[i].phy_cell.id) { + known_cells[i].rsrp = rsrp; + known_cells[i].in_sync = true; + current_cell = &known_cells[i]; + rrc_log->info("Updating cell EARFCN=%d, PCI=%d, RSRP=%.1f dBm\n", known_cells[i].earfcn, + known_cells[i].phy_cell.id, known_cells[i].rsrp); + + if (!known_cells[i].has_valid_sib1) { + si_acquire_state = SI_ACQUIRE_SIB1; + } else { + for (uint32_t i = 0; i < current_cell->sib1.N_plmn_ids; i++) { + nas->plmn_found(current_cell->sib1.plmn_id[i].id, current_cell->sib1.tracking_area_code); + } + } + return; + } + } + // add to list of known cells + cell_t cell; + cell.phy_cell = phy_cell; + cell.rsrp = rsrp; + cell.earfcn = earfcn; + cell.has_valid_sib1 = false; + cell.has_valid_sib2 = false; + known_cells.push_back(cell); + + // save current cell + current_cell = &known_cells.back(); + + si_acquire_state = SI_ACQUIRE_SIB1; + + rrc_log->info("New Cell: PCI=%d, PRB=%d, Ports=%d, EARFCN=%d, RSRP=%.1f dBm\n", + cell.phy_cell.id, cell.phy_cell.nof_prb, cell.phy_cell.nof_ports, + cell.earfcn, cell.rsrp); +} + + + + + + + + + +/******************************************************************************* +* +* +* +* Detection of Radio-Link Failures +* +* +* +*******************************************************************************/ + +// Detection of physical layer problems (5.3.11.1) +void rrc::out_of_sync() { + current_cell->in_sync = false; + if (!mac_timers->timer_get(t311)->is_running() && !mac_timers->timer_get(t310)->is_running()) { + n310_cnt++; + if (n310_cnt == N310) { + // attempt resync + phy->sync_reset(); + + mac_timers->timer_get(t310)->reset(); + mac_timers->timer_get(t310)->run(); + n310_cnt = 0; + rrc_log->info("Detected %d out-of-sync from PHY. Starting T310 timer\n", N310); + } + } +} + +// Recovery of physical layer problems (5.3.11.2) +void rrc::in_sync() { + current_cell->in_sync = true; + if (mac_timers->timer_get(t310)->is_running()) { + n311_cnt++; + if (n311_cnt == N311) { + mac_timers->timer_get(t310)->stop(); + n311_cnt = 0; + rrc_log->info("Detected %d in-sync from PHY. Stopping T310 timer\n", N311); + } + } +} + +/* Detection of radio link failure (5.3.11.3) + * Upon T310 expiry, RA problem or RLC max retx + */ +void rrc::radio_link_failure() { + // TODO: Generate and store failure report + + phy->sync_reset(); + rrc_log->warning("Detected Radio-Link Failure\n"); + rrc_log->console("Warning: Detected Radio-Link Failure\n"); + if (state != RRC_STATE_CONNECTED) { + state = RRC_STATE_LEAVE_CONNECTED; + } else { + send_con_restablish_request(); + } +} + /* Reception of PUCCH/SRS release procedure (Section 5.3.13) */ void rrc::release_pucch_srs() { // Apply default configuration for PUCCH (CQI and SR) and SRS (release) @@ -529,95 +531,42 @@ void rrc::ra_problem() { radio_link_failure(); } -/******************************************************************************* -GW interface -*******************************************************************************/ - -bool rrc::is_connected() { - return (RRC_STATE_CONNECTED == state); -} - -bool rrc::have_drb() { - return drb_up; -} - -/******************************************************************************* -PDCP interface -*******************************************************************************/ - -void rrc::write_pdu(uint32_t lcid, byte_buffer_t *pdu) { - rrc_log->info_hex(pdu->msg, pdu->N_bytes, "TX %s PDU", get_rb_name(lcid).c_str()); - rrc_log->info("TX PDU Stack latency: %ld us\n", pdu->get_latency_us()); - - switch (lcid) { - case RB_ID_SRB0: - parse_dl_ccch(pdu); - break; - case RB_ID_SRB1: - case RB_ID_SRB2: - parse_dl_dcch(lcid, pdu); - break; - default: - rrc_log->error("TX PDU with invalid bearer id: %s", lcid); - break; - } -} - -void rrc::write_pdu_pcch(byte_buffer_t *pdu) { - if (pdu->N_bytes > 0 && pdu->N_bytes < SRSLTE_MAX_BUFFER_SIZE_BITS) { - rrc_log->info_hex(pdu->msg, pdu->N_bytes, "PCCH message received %d bytes\n", pdu->N_bytes); - rrc_log->info("PCCH message Stack latency: %ld us\n", pdu->get_latency_us()); - rrc_log->console("PCCH message received %d bytes\n", pdu->N_bytes); - - LIBLTE_RRC_PCCH_MSG_STRUCT pcch_msg; - srslte_bit_unpack_vector(pdu->msg, bit_buf.msg, pdu->N_bytes * 8); - bit_buf.N_bits = pdu->N_bytes * 8; - pool->deallocate(pdu); - liblte_rrc_unpack_pcch_msg((LIBLTE_BIT_MSG_STRUCT *) &bit_buf, &pcch_msg); - - if (pcch_msg.paging_record_list_size > LIBLTE_RRC_MAX_PAGE_REC) { - pcch_msg.paging_record_list_size = LIBLTE_RRC_MAX_PAGE_REC; - } - - LIBLTE_RRC_S_TMSI_STRUCT s_tmsi; - if (!nas->get_s_tmsi(&s_tmsi)) { - rrc_log->info("No S-TMSI present in NAS\n"); - return; - } - - LIBLTE_RRC_S_TMSI_STRUCT *s_tmsi_paged; - for (uint32_t i = 0; i < pcch_msg.paging_record_list_size; i++) { - s_tmsi_paged = &pcch_msg.paging_record_list[i].ue_identity.s_tmsi; - rrc_log->info("Received paging (%d/%d) for UE 0x%x\n", i + 1, pcch_msg.paging_record_list_size, - pcch_msg.paging_record_list[i].ue_identity.s_tmsi); - rrc_log->console("Received paging (%d/%d) for UE 0x%x\n", i + 1, pcch_msg.paging_record_list_size, - pcch_msg.paging_record_list[i].ue_identity.s_tmsi); - if (s_tmsi.mmec == s_tmsi_paged->mmec && s_tmsi.m_tmsi == s_tmsi_paged->m_tmsi) { - rrc_log->info("S-TMSI match in paging message\n"); - rrc_log->console("S-TMSI match in paging message\n"); - mac->pcch_stop_rx(); - if (RRC_STATE_IDLE == state) { - rrc_log->info("RRC in IDLE state - sending connection request.\n"); - state = RRC_STATE_CONNECTING; - send_con_request(); - } - } - } - } -} - -/******************************************************************************* -RLC interface -*******************************************************************************/ - void rrc::max_retx_attempted() { //TODO: Handle the radio link failure rrc_log->warning("Max RLC reTx attempted\n"); - //radio_link_failure(); + radio_link_failure(); } +void rrc::timer_expired(uint32_t timeout_id) { + if (timeout_id == t310) { + rrc_log->info("Timer T310 expired: Radio Link Failure\n"); + radio_link_failure(); + } else if (timeout_id == t311) { + rrc_log->info("Timer T311 expired: Going to RRC IDLE\n"); + state = RRC_STATE_LEAVE_CONNECTED; + } else if (timeout_id == t301) { + rrc_log->info("Timer T301 expired: Going to RRC IDLE\n"); + state = RRC_STATE_LEAVE_CONNECTED; + } else { + rrc_log->error("Timeout from unknown timer id %d\n", timeout_id); + } +} + + + + + + + + /******************************************************************************* -Senders +* +* +* +* Connection Control: Establishment, Reconfiguration, Reestablishment and Release +* +* +* *******************************************************************************/ void rrc::send_con_request() { @@ -706,15 +655,16 @@ void rrc::send_con_restablish_request() { rrc_log->info("Initiating RRC Connection Reestablishment Procedure\n"); rrc_log->console("RRC Connection Reestablishment\n"); - mac_timers->get(t310)->stop(); - mac_timers->get(t311)->reset(); - mac_timers->get(t311)->run(); + mac_timers->timer_get(t310)->stop(); + mac_timers->timer_get(t311)->reset(); + mac_timers->timer_get(t311)->run(); + phy->reset(); set_phy_default(); mac->reset(); + set_mac_default(); // FIXME: Cell selection should be different?? - phy->resync_sfn(); // Wait for cell re-synchronization uint32_t timeout_cnt = 0; @@ -722,9 +672,9 @@ void rrc::send_con_restablish_request() { usleep(10000); timeout_cnt++; } - mac_timers->get(t301)->reset(); - mac_timers->get(t301)->run(); - mac_timers->get(t311)->stop(); + mac_timers->timer_get(t301)->reset(); + mac_timers->timer_get(t301)->run(); + mac_timers->timer_get(t311)->stop(); rrc_log->info("Cell Selection finished. Initiating transmission of RRC Connection Reestablishment Request\n"); // Byte align and pack the message bits for PDCP @@ -747,7 +697,7 @@ void rrc::send_con_restablish_request() { rrc_log->debug("Setting UE contention resolution ID: %d\n", uecri); mac->set_contention_id(uecri); - rrc_log->info("Sending RRC Connection Resetablishment Request on SRB0\n"); + rrc_log->info("Sending RRC Connection Reestablishment Request on SRB0\n"); pdcp->write_sdu(RB_ID_SRB0, pdcp_buf); } @@ -879,6 +829,355 @@ void rrc::send_rrc_con_reconfig_complete(uint32_t lcid, byte_buffer_t *pdu) { pdcp->write_sdu(lcid, pdu); } + +void rrc::handle_rrc_con_reconfig(uint32_t lcid, LIBLTE_RRC_CONNECTION_RECONFIGURATION_STRUCT *reconfig, + byte_buffer_t *pdu) { + uint32_t i; + + if (reconfig->rr_cnfg_ded_present) { + apply_rr_config_dedicated(&reconfig->rr_cnfg_ded); + } else { + printf("received con reconfig no rr confg present\n"); + } + if (reconfig->meas_cnfg_present) { + //TODO: handle meas_cnfg + } + if (reconfig->mob_ctrl_info_present) { + //TODO: handle mob_ctrl_info + } + + send_rrc_con_reconfig_complete(lcid, pdu); + + byte_buffer_t *nas_sdu; + for (i = 0; i < reconfig->N_ded_info_nas; i++) { + nas_sdu = pool_allocate;; + memcpy(nas_sdu->msg, &reconfig->ded_info_nas_list[i].msg, reconfig->ded_info_nas_list[i].N_bytes); + nas_sdu->N_bytes = reconfig->ded_info_nas_list[i].N_bytes; + nas->write_pdu(lcid, nas_sdu); + } +} + + /* Actions upon reception of RRCConnectionRelease 5.3.8.3 */ +void rrc::rrc_connection_release() { + // Save idleModeMobilityControlInfo, etc. + state = RRC_STATE_LEAVE_CONNECTED; + rrc_log->console("Received RRC Connection Release\n"); +} + + + + + + + + +/******************************************************************************* +* +* +* +* Reception of Broadcast messages (MIB and SIBs) +* +* +* +*******************************************************************************/ +void rrc::write_pdu_bcch_bch(byte_buffer_t *pdu) { + pool->deallocate(pdu); + if (state == RRC_STATE_PLMN_SELECTION) { + // Do we need to do something with BCH? + rrc_log->info_hex(pdu->msg, pdu->N_bytes, "BCCH BCH message received."); + } else { + rrc_log->warning("Received BCCH BCH in incorrect state\n"); + } +} + +void rrc::write_pdu_bcch_dlsch(byte_buffer_t *pdu) { + rrc_log->info_hex(pdu->msg, pdu->N_bytes, "BCCH DLSCH message received."); + rrc_log->info("BCCH DLSCH message Stack latency: %ld us\n", pdu->get_latency_us()); + LIBLTE_RRC_BCCH_DLSCH_MSG_STRUCT dlsch_msg; + srslte_bit_unpack_vector(pdu->msg, bit_buf.msg, pdu->N_bytes * 8); + bit_buf.N_bits = pdu->N_bytes * 8; + pool->deallocate(pdu); + liblte_rrc_unpack_bcch_dlsch_msg((LIBLTE_BIT_MSG_STRUCT *) &bit_buf, &dlsch_msg); + + if (dlsch_msg.N_sibs > 0) { + if (LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_1 == dlsch_msg.sibs[0].sib_type && SI_ACQUIRE_SIB1 == si_acquire_state) { + mac->bcch_stop_rx(); + + // Handle SIB1 + memcpy(¤t_cell->sib1, &dlsch_msg.sibs[0].sib.sib1, sizeof(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_1_STRUCT)); + + rrc_log->info("SIB1 received, CellID=%d, si_window=%d, sib2_period=%d\n", + current_cell->sib1.cell_id & 0xfff, + liblte_rrc_si_window_length_num[current_cell->sib1.si_window_length], + liblte_rrc_si_periodicity_num[current_cell->sib1.sched_info[0].si_periodicity]); + + + // Set TDD Config + if (current_cell->sib1.tdd) { + phy->set_config_tdd(¤t_cell->sib1.tdd_cnfg); + } + + current_cell->has_valid_sib1 = true; + + // Send PLMN and TAC to NAS + std::stringstream ss; + for (uint32_t i = 0; i < current_cell->sib1.N_plmn_ids; i++) { + nas->plmn_found(current_cell->sib1.plmn_id[i].id, current_cell->sib1.tracking_area_code); + } + + // Jump to next state + switch(state) { + case RRC_STATE_CELL_SELECTING: + si_acquire_state = SI_ACQUIRE_SIB2; + break; + case RRC_STATE_PLMN_SELECTION: + si_acquire_state = SI_ACQUIRE_IDLE; + rrc_log->info("SI Acquisition done. Searching next cell...\n"); + usleep(5000); + phy->cell_search_next(); + break; + default: + si_acquire_state = SI_ACQUIRE_IDLE; + } + + } else if (LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2 == dlsch_msg.sibs[0].sib_type && + SI_ACQUIRE_SIB2 == si_acquire_state) { + mac->bcch_stop_rx(); + + // Handle SIB2 + memcpy(¤t_cell->sib2, &dlsch_msg.sibs[0].sib.sib2, sizeof(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT)); + rrc_log->info("SIB2 received\n"); + + apply_sib2_configs(¤t_cell->sib2); + + current_cell->has_valid_sib2 = true; + + // Jump to next state + switch(state) { + case RRC_STATE_CELL_SELECTING: + si_acquire_state = SI_ACQUIRE_IDLE; + state = RRC_STATE_CELL_SELECTED; + break; + default: + si_acquire_state = SI_ACQUIRE_IDLE; + } + } + } +} + + + +/******************************************************************************* +* +* +* +* Reception of Paging messages +* +* +* +*******************************************************************************/ +void rrc::write_pdu_pcch(byte_buffer_t *pdu) { + if (pdu->N_bytes > 0 && pdu->N_bytes < SRSLTE_MAX_BUFFER_SIZE_BITS) { + rrc_log->info_hex(pdu->msg, pdu->N_bytes, "PCCH message received %d bytes\n", pdu->N_bytes); + rrc_log->info("PCCH message Stack latency: %ld us\n", pdu->get_latency_us()); + rrc_log->console("PCCH message received %d bytes\n", pdu->N_bytes); + + LIBLTE_RRC_PCCH_MSG_STRUCT pcch_msg; + srslte_bit_unpack_vector(pdu->msg, bit_buf.msg, pdu->N_bytes * 8); + bit_buf.N_bits = pdu->N_bytes * 8; + pool->deallocate(pdu); + liblte_rrc_unpack_pcch_msg((LIBLTE_BIT_MSG_STRUCT *) &bit_buf, &pcch_msg); + + if (pcch_msg.paging_record_list_size > LIBLTE_RRC_MAX_PAGE_REC) { + pcch_msg.paging_record_list_size = LIBLTE_RRC_MAX_PAGE_REC; + } + + LIBLTE_RRC_S_TMSI_STRUCT s_tmsi; + if (!nas->get_s_tmsi(&s_tmsi)) { + rrc_log->info("No S-TMSI present in NAS\n"); + return; + } + + LIBLTE_RRC_S_TMSI_STRUCT *s_tmsi_paged; + for (uint32_t i = 0; i < pcch_msg.paging_record_list_size; i++) { + s_tmsi_paged = &pcch_msg.paging_record_list[i].ue_identity.s_tmsi; + rrc_log->info("Received paging (%d/%d) for UE 0x%x\n", i + 1, pcch_msg.paging_record_list_size, + pcch_msg.paging_record_list[i].ue_identity.s_tmsi); + rrc_log->console("Received paging (%d/%d) for UE 0x%x\n", i + 1, pcch_msg.paging_record_list_size, + pcch_msg.paging_record_list[i].ue_identity.s_tmsi); + if (s_tmsi.mmec == s_tmsi_paged->mmec && s_tmsi.m_tmsi == s_tmsi_paged->m_tmsi) { + rrc_log->info("S-TMSI match in paging message\n"); + rrc_log->console("S-TMSI match in paging message\n"); + mac->pcch_stop_rx(); + if (RRC_STATE_IDLE == state) { + rrc_log->info("RRC in IDLE state - sending connection request.\n"); + state = RRC_STATE_CELL_SELECTING; + } + } + } + } +} + + + + + + + + + + + +/******************************************************************************* +* +* +* +* Packet processing +* +* +* +*******************************************************************************/ +void rrc::write_sdu(uint32_t lcid, byte_buffer_t *sdu) { + rrc_log->info_hex(sdu->msg, sdu->N_bytes, "RX %s SDU", get_rb_name(lcid).c_str()); + switch (state) { + case RRC_STATE_CONNECTING: + send_con_setup_complete(sdu); + break; + case RRC_STATE_CONNECTED: + send_ul_info_transfer(lcid, sdu); + break; + default: + rrc_log->error("SDU received from NAS while RRC state = %s", rrc_state_text[state]); + break; + } +} + +void rrc::write_pdu(uint32_t lcid, byte_buffer_t *pdu) { + rrc_log->info_hex(pdu->msg, pdu->N_bytes, "TX %s PDU", get_rb_name(lcid).c_str()); + rrc_log->info("TX PDU Stack latency: %ld us\n", pdu->get_latency_us()); + + switch (lcid) { + case RB_ID_SRB0: + parse_dl_ccch(pdu); + break; + case RB_ID_SRB1: + case RB_ID_SRB2: + parse_dl_dcch(lcid, pdu); + break; + default: + rrc_log->error("TX PDU with invalid bearer id: %s", lcid); + break; + } +} + +void rrc::parse_dl_ccch(byte_buffer_t *pdu) { + srslte_bit_unpack_vector(pdu->msg, bit_buf.msg, pdu->N_bytes * 8); + bit_buf.N_bits = pdu->N_bytes * 8; + pool->deallocate(pdu); + bzero(&dl_ccch_msg, sizeof(LIBLTE_RRC_DL_CCCH_MSG_STRUCT)); + liblte_rrc_unpack_dl_ccch_msg((LIBLTE_BIT_MSG_STRUCT *) &bit_buf, &dl_ccch_msg); + + rrc_log->info("SRB0 - Received %s\n", + liblte_rrc_dl_ccch_msg_type_text[dl_ccch_msg.msg_type]); + + switch (dl_ccch_msg.msg_type) { + case LIBLTE_RRC_DL_CCCH_MSG_TYPE_RRC_CON_REJ: + rrc_log->info("Connection Reject received. Wait time: %d\n", + dl_ccch_msg.msg.rrc_con_rej.wait_time); + state = RRC_STATE_IDLE; + break; + case LIBLTE_RRC_DL_CCCH_MSG_TYPE_RRC_CON_SETUP: + rrc_log->info("Connection Setup received\n"); + transaction_id = dl_ccch_msg.msg.rrc_con_setup.rrc_transaction_id; + handle_con_setup(&dl_ccch_msg.msg.rrc_con_setup); + rrc_log->info("Notifying NAS of connection setup\n"); + nas->notify_connection_setup(); + break; + case LIBLTE_RRC_DL_CCCH_MSG_TYPE_RRC_CON_REEST: + rrc_log->info("Connection Reestablishment received\n"); + rrc_log->console("Reestablishment OK\n"); + transaction_id = dl_ccch_msg.msg.rrc_con_reest.rrc_transaction_id; + handle_con_reest(&dl_ccch_msg.msg.rrc_con_reest); + break; + /* Reception of RRCConnectionReestablishmentReject 5.3.7.8 */ + case LIBLTE_RRC_DL_CCCH_MSG_TYPE_RRC_CON_REEST_REJ: + rrc_log->info("Connection Reestablishment Reject received\n"); + rrc_log->console("Reestablishment Reject\n"); + state = RRC_STATE_LEAVE_CONNECTED; + break; + default: + break; + } +} + +void rrc::parse_dl_dcch(uint32_t lcid, byte_buffer_t *pdu) { + srslte_bit_unpack_vector(pdu->msg, bit_buf.msg, pdu->N_bytes * 8); + bit_buf.N_bits = pdu->N_bytes * 8; + liblte_rrc_unpack_dl_dcch_msg((LIBLTE_BIT_MSG_STRUCT *) &bit_buf, &dl_dcch_msg); + + rrc_log->info("%s - Received %s\n", + get_rb_name(lcid).c_str(), + liblte_rrc_dl_dcch_msg_type_text[dl_dcch_msg.msg_type]); + + // Reset and reuse pdu buffer if possible + pdu->reset(); + + switch (dl_dcch_msg.msg_type) { + case LIBLTE_RRC_DL_DCCH_MSG_TYPE_DL_INFO_TRANSFER: + memcpy(pdu->msg, dl_dcch_msg.msg.dl_info_transfer.dedicated_info.msg, + dl_dcch_msg.msg.dl_info_transfer.dedicated_info.N_bytes); + pdu->N_bytes = dl_dcch_msg.msg.dl_info_transfer.dedicated_info.N_bytes; + nas->write_pdu(lcid, pdu); + break; + case LIBLTE_RRC_DL_DCCH_MSG_TYPE_SECURITY_MODE_COMMAND: + transaction_id = dl_dcch_msg.msg.security_mode_cmd.rrc_transaction_id; + + cipher_algo = (CIPHERING_ALGORITHM_ID_ENUM) dl_dcch_msg.msg.security_mode_cmd.sec_algs.cipher_alg; + integ_algo = (INTEGRITY_ALGORITHM_ID_ENUM) dl_dcch_msg.msg.security_mode_cmd.sec_algs.int_alg; + + // Configure PDCP for security + usim->generate_as_keys(nas->get_ul_count(), k_rrc_enc, k_rrc_int, k_up_enc, k_up_int, cipher_algo, integ_algo); + pdcp->config_security(lcid, k_rrc_enc, k_rrc_int, cipher_algo, integ_algo); + send_security_mode_complete(lcid, pdu); + break; + case LIBLTE_RRC_DL_DCCH_MSG_TYPE_RRC_CON_RECONFIG: + transaction_id = dl_dcch_msg.msg.rrc_con_reconfig.rrc_transaction_id; + handle_rrc_con_reconfig(lcid, &dl_dcch_msg.msg.rrc_con_reconfig, pdu); + break; + case LIBLTE_RRC_DL_DCCH_MSG_TYPE_UE_CAPABILITY_ENQUIRY: + transaction_id = dl_dcch_msg.msg.ue_cap_enquiry.rrc_transaction_id; + for (uint32_t i = 0; i < dl_dcch_msg.msg.ue_cap_enquiry.N_ue_cap_reqs; i++) { + if (LIBLTE_RRC_RAT_TYPE_EUTRA == dl_dcch_msg.msg.ue_cap_enquiry.ue_capability_request[i]) { + send_rrc_ue_cap_info(lcid, pdu); + break; + } + } + break; + case LIBLTE_RRC_DL_DCCH_MSG_TYPE_RRC_CON_RELEASE: + rrc_connection_release(); + break; + default: + break; + } +} + + + + + + + + + +/******************************************************************************* +* +* +* +* Capabilities Message +* +* +* +*******************************************************************************/ void rrc::enable_capabilities() { bool enable_ul_64 = ue_category >= 5 && current_cell->sib2.rr_config_common_sib.pusch_cnfg.enable_64_qam; rrc_log->info("%s 64QAM PUSCH\n", enable_ul_64 ? "Enabling" : "Disabling"); @@ -963,175 +1262,24 @@ void rrc::send_rrc_ue_cap_info(uint32_t lcid, byte_buffer_t *pdu) { pdcp->write_sdu(lcid, pdu); } -/******************************************************************************* -Parsers -*******************************************************************************/ -void rrc::parse_dl_ccch(byte_buffer_t *pdu) { - srslte_bit_unpack_vector(pdu->msg, bit_buf.msg, pdu->N_bytes * 8); - bit_buf.N_bits = pdu->N_bytes * 8; - pool->deallocate(pdu); - bzero(&dl_ccch_msg, sizeof(LIBLTE_RRC_DL_CCCH_MSG_STRUCT)); - liblte_rrc_unpack_dl_ccch_msg((LIBLTE_BIT_MSG_STRUCT *) &bit_buf, &dl_ccch_msg); - rrc_log->info("SRB0 - Received %s\n", - liblte_rrc_dl_ccch_msg_type_text[dl_ccch_msg.msg_type]); - switch (dl_ccch_msg.msg_type) { - case LIBLTE_RRC_DL_CCCH_MSG_TYPE_RRC_CON_REJ: - rrc_log->info("Connection Reject received. Wait time: %d\n", - dl_ccch_msg.msg.rrc_con_rej.wait_time); - state = RRC_STATE_IDLE; - break; - case LIBLTE_RRC_DL_CCCH_MSG_TYPE_RRC_CON_SETUP: - rrc_log->info("Connection Setup received\n"); - transaction_id = dl_ccch_msg.msg.rrc_con_setup.rrc_transaction_id; - handle_con_setup(&dl_ccch_msg.msg.rrc_con_setup); - rrc_log->info("Notifying NAS of connection setup\n"); - nas->notify_connection_setup(); - break; - case LIBLTE_RRC_DL_CCCH_MSG_TYPE_RRC_CON_REEST: - rrc_log->info("Connection Reestablishment received\n"); - rrc_log->console("Reestablishment OK\n"); - transaction_id = dl_ccch_msg.msg.rrc_con_reest.rrc_transaction_id; - handle_con_reest(&dl_ccch_msg.msg.rrc_con_reest); - break; - case LIBLTE_RRC_DL_CCCH_MSG_TYPE_RRC_CON_REEST_REJ: - rrc_log->info("Connection Reestablishment Reject received\n"); - rrc_log->console("Reestablishment Reject\n"); - usleep(50000); - rrc_connection_release(); - break; - default: - break; - } -} -void rrc::parse_dl_dcch(uint32_t lcid, byte_buffer_t *pdu) { - srslte_bit_unpack_vector(pdu->msg, bit_buf.msg, pdu->N_bytes * 8); - bit_buf.N_bits = pdu->N_bytes * 8; - liblte_rrc_unpack_dl_dcch_msg((LIBLTE_BIT_MSG_STRUCT *) &bit_buf, &dl_dcch_msg); - rrc_log->info("%s - Received %s\n", - get_rb_name(lcid).c_str(), - liblte_rrc_dl_dcch_msg_type_text[dl_dcch_msg.msg_type]); - // Reset and reuse pdu buffer if possible - pdu->reset(); - switch (dl_dcch_msg.msg_type) { - case LIBLTE_RRC_DL_DCCH_MSG_TYPE_DL_INFO_TRANSFER: - memcpy(pdu->msg, dl_dcch_msg.msg.dl_info_transfer.dedicated_info.msg, - dl_dcch_msg.msg.dl_info_transfer.dedicated_info.N_bytes); - pdu->N_bytes = dl_dcch_msg.msg.dl_info_transfer.dedicated_info.N_bytes; - nas->write_pdu(lcid, pdu); - break; - case LIBLTE_RRC_DL_DCCH_MSG_TYPE_SECURITY_MODE_COMMAND: - transaction_id = dl_dcch_msg.msg.security_mode_cmd.rrc_transaction_id; - cipher_algo = (CIPHERING_ALGORITHM_ID_ENUM) dl_dcch_msg.msg.security_mode_cmd.sec_algs.cipher_alg; - integ_algo = (INTEGRITY_ALGORITHM_ID_ENUM) dl_dcch_msg.msg.security_mode_cmd.sec_algs.int_alg; - - // Configure PDCP for security - usim->generate_as_keys(nas->get_ul_count(), k_rrc_enc, k_rrc_int, k_up_enc, k_up_int, cipher_algo, integ_algo); - pdcp->config_security(lcid, k_rrc_enc, k_rrc_int, cipher_algo, integ_algo); - send_security_mode_complete(lcid, pdu); - break; - case LIBLTE_RRC_DL_DCCH_MSG_TYPE_RRC_CON_RECONFIG: - transaction_id = dl_dcch_msg.msg.rrc_con_reconfig.rrc_transaction_id; - handle_rrc_con_reconfig(lcid, &dl_dcch_msg.msg.rrc_con_reconfig, pdu); - break; - case LIBLTE_RRC_DL_DCCH_MSG_TYPE_UE_CAPABILITY_ENQUIRY: - transaction_id = dl_dcch_msg.msg.ue_cap_enquiry.rrc_transaction_id; - for (uint32_t i = 0; i < dl_dcch_msg.msg.ue_cap_enquiry.N_ue_cap_reqs; i++) { - if (LIBLTE_RRC_RAT_TYPE_EUTRA == dl_dcch_msg.msg.ue_cap_enquiry.ue_capability_request[i]) { - send_rrc_ue_cap_info(lcid, pdu); - break; - } - } - break; - case LIBLTE_RRC_DL_DCCH_MSG_TYPE_RRC_CON_RELEASE: - rrc_connection_release(); - break; - default: - break; - } -} /******************************************************************************* -Timer expiration callback +* +* +* +* PHY and MAC Radio Resource configuration +* +* +* *******************************************************************************/ -void rrc::timer_expired(uint32_t timeout_id) { - if (timeout_id == t310) { - rrc_log->info("Timer T310 expired: Radio Link Failure\n"); - radio_link_failure(); - } else if (timeout_id == t311) { - rrc_log->info("Timer T311 expired: Going to RRC IDLE\n"); - rrc_connection_release(); - } else if (timeout_id == t301) { - rrc_log->info("Timer T301 expired: Going to RRC IDLE\n"); - rrc_connection_release(); - } else if (timeout_id == safe_reset_timer) { - reset_ue(); - } else { - rrc_log->error("Timeout from unknown timer id %d\n", timeout_id); - } -} - -/******************************************************************************* -Helpers -*******************************************************************************/ - -void rrc::reset_ue() { - phy->reset(); - mac->reset(); - pdcp->reset(); - rlc->reset(); - mac->pcch_start_rx(); - mac_timers->get(safe_reset_timer)->stop(); - mac_timers->get(safe_reset_timer)->reset(); - rrc_log->console("RRC Connection Released.\n"); -} - -void rrc::rrc_connection_release() { - pthread_mutex_lock(&mutex); - drb_up = false; - state = RRC_STATE_IDLE; - phy->sync_stop(); - set_phy_default(); - set_mac_default(); - mac_timers->get(t311)->run(); - mac_timers->get(t310)->stop(); - mac_timers->get(t311)->stop(); - mac_timers->get(safe_reset_timer)->stop(); - mac_timers->get(safe_reset_timer)->reset(); - mac_timers->get(safe_reset_timer)->run(); - pthread_mutex_unlock(&mutex); -} - -void rrc::test_con_restablishment() { - printf("Testing connection Reestablishment\n"); - send_con_restablish_request(); -} - -/* Detection of radio link failure (5.3.11.3) */ -void rrc::radio_link_failure() { - // TODO: Generate and store failure report - - rrc_log->warning("Detected Radio-Link Failure\n"); - rrc_log->console("Warning: Detected Radio-Link Failure\n"); - if (state != RRC_STATE_CONNECTED) { - rrc_connection_release(); - } else { - send_con_restablish_request(); - } -} - - -// Determine SI messages scheduling as in 36.331 5.2.3 Acquisition of an SI message -uint32_t rrc::sib_start_tti(uint32_t tti, uint32_t period, uint32_t x) { - return (period * 10 * (1 + tti / (period * 10)) + x) % 10240; // the 1 means next opportunity -} void rrc::apply_sib2_configs(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT *sib2) { @@ -1194,15 +1342,15 @@ void rrc::apply_sib2_configs(LIBLTE_RRC_SYS_INFO_BLOCK_TYPE_2_STRUCT *sib2) { liblte_rrc_srs_subfr_config_num[sib2->rr_config_common_sib.srs_ul_cnfg.subfr_cnfg], sib2->rr_config_common_sib.srs_ul_cnfg.ack_nack_simul_tx ? "yes" : "no"); - mac_timers->get(t301)->set(this, liblte_rrc_t301_num[sib2->ue_timers_and_constants.t301]); - mac_timers->get(t310)->set(this, liblte_rrc_t310_num[sib2->ue_timers_and_constants.t310]); - mac_timers->get(t311)->set(this, liblte_rrc_t311_num[sib2->ue_timers_and_constants.t311]); + mac_timers->timer_get(t301)->set(this, liblte_rrc_t301_num[sib2->ue_timers_and_constants.t301]); + mac_timers->timer_get(t310)->set(this, liblte_rrc_t310_num[sib2->ue_timers_and_constants.t310]); + mac_timers->timer_get(t311)->set(this, liblte_rrc_t311_num[sib2->ue_timers_and_constants.t311]); N310 = liblte_rrc_n310_num[sib2->ue_timers_and_constants.n310]; N311 = liblte_rrc_n311_num[sib2->ue_timers_and_constants.n311]; rrc_log->info("Set Constants and Timers: N310=%d, N311=%d, t301=%d, t310=%d, t311=%d\n", - N310, N311, mac_timers->get(t301)->get_timeout(), - mac_timers->get(t310)->get_timeout(), mac_timers->get(t311)->get_timeout()); + N310, N311, mac_timers->timer_get(t301)->get_timeout(), + mac_timers->timer_get(t310)->get_timeout(), mac_timers->timer_get(t311)->get_timeout()); } @@ -1440,7 +1588,7 @@ void rrc::handle_con_setup(LIBLTE_RRC_CONNECTION_SETUP_STRUCT *setup) { /* Reception of RRCConnectionReestablishment by the UE 5.3.7.5 */ void rrc::handle_con_reest(LIBLTE_RRC_CONNECTION_REESTABLISHMENT_STRUCT *setup) { - mac_timers->get(t301)->stop(); + mac_timers->timer_get(t301)->stop(); // TODO: Restablish DRB1. Not done because never was suspended @@ -1453,33 +1601,6 @@ void rrc::handle_con_reest(LIBLTE_RRC_CONNECTION_REESTABLISHMENT_STRUCT *setup) } -void rrc::handle_rrc_con_reconfig(uint32_t lcid, LIBLTE_RRC_CONNECTION_RECONFIGURATION_STRUCT *reconfig, - byte_buffer_t *pdu) { - uint32_t i; - - if (reconfig->rr_cnfg_ded_present) { - apply_rr_config_dedicated(&reconfig->rr_cnfg_ded); - } else { - printf("received con reconfig no rr confg present\n"); - } - if (reconfig->meas_cnfg_present) { - //TODO: handle meas_cnfg - } - if (reconfig->mob_ctrl_info_present) { - //TODO: handle mob_ctrl_info - } - - send_rrc_con_reconfig_complete(lcid, pdu); - - byte_buffer_t *nas_sdu; - for (i = 0; i < reconfig->N_ded_info_nas; i++) { - nas_sdu = pool_allocate;; - memcpy(nas_sdu->msg, &reconfig->ded_info_nas_list[i].msg, reconfig->ded_info_nas_list[i].N_bytes); - nas_sdu->N_bytes = reconfig->ded_info_nas_list[i].N_bytes; - nas->write_pdu(lcid, nas_sdu); - } -} - void rrc::add_srb(LIBLTE_RRC_SRB_TO_ADD_MOD_STRUCT *srb_cnfg) { // Setup PDCP pdcp->add_bearer(srb_cnfg->srb_id, srslte_pdcp_config_t(true)); // Set PDCP config control flag @@ -1588,10 +1709,6 @@ void rrc::release_drb(uint8_t lcid) { // TODO } -/************************** -* DEFAULT VALUES Section 9 -****************************/ - // PHY CONFIG DEDICATED Defaults (3GPP 36.331 v10 9.2.4) void rrc::set_phy_default_pucch_srs() { @@ -1628,9 +1745,8 @@ void rrc::set_mac_default() { void rrc::set_rrc_default() { N310 = 1; N311 = 1; - mac_timers->get(t310)->set(this, 1000); - mac_timers->get(t311)->set(this, 1000); - mac_timers->get(safe_reset_timer)->set(this, 10); + mac_timers->timer_get(t310)->set(this, 1000); + mac_timers->timer_get(t311)->set(this, 1000); } diff --git a/srsue/test/CMakeLists.txt b/srsue/test/CMakeLists.txt index c9949a7e2..217c369ee 100644 --- a/srsue/test/CMakeLists.txt +++ b/srsue/test/CMakeLists.txt @@ -21,3 +21,7 @@ add_subdirectory(phy) add_subdirectory(mac) add_subdirectory(upper) + +add_executable(metrics_test metrics_test.cc ../src/metrics_stdout.cc ../src/metrics_csv.cc) +target_link_libraries(metrics_test srslte_phy srslte_common) +add_test(metrics_test metrics_test -o ${CMAKE_CURRENT_BINARY_DIR}/ue_metrics.csv) diff --git a/srsue/test/mac/mac_test.cc b/srsue/test/mac/mac_test.cc index 368a7f35e..4cb47e9f8 100644 --- a/srsue/test/mac/mac_test.cc +++ b/srsue/test/mac/mac_test.cc @@ -427,22 +427,11 @@ private: int main(int argc, char *argv[]) { - srslte::log_filter mac_log("MAC"), phy_log("PHY"); + srslte::log_filter mac_log("MAC"); rlctest my_rlc; parse_args(&prog_args, argc, argv); - switch (prog_args.verbose) { - case 1: - mac_log.set_level(srslte::LOG_LEVEL_INFO); - phy_log.set_level(srslte::LOG_LEVEL_INFO); - break; - case 2: - mac_log.set_level(srslte::LOG_LEVEL_DEBUG); - phy_log.set_level(srslte::LOG_LEVEL_DEBUG); - break; - } - - // Capture SIGINT to write traces + // Capture SIGINT to write traces if (prog_args.do_trace) { signal(SIGINT, sig_int_handler); //radio.start_trace(); @@ -461,7 +450,26 @@ int main(int argc, char *argv[]) if (!radio.init()) { exit(1); } - phy.init(&radio, &mac, NULL, &phy_log); + + std::vector phy_log; + + srslte::log_filter *mylog = new srslte::log_filter("PHY"); + char tmp[16]; + sprintf(tmp, "PHY%d",0); + phy_log.push_back((void*) mylog); + + switch (prog_args.verbose) { + case 1: + mac_log.set_level(srslte::LOG_LEVEL_INFO); + mylog->set_level(srslte::LOG_LEVEL_INFO); + break; + case 2: + mac_log.set_level(srslte::LOG_LEVEL_DEBUG); + mylog->set_level(srslte::LOG_LEVEL_DEBUG); + break; + } + + phy.init(&radio, &mac, NULL, phy_log); if (prog_args.rf_rx_gain > 0 && prog_args.rf_tx_gain > 0) { radio.set_rx_gain(prog_args.rf_rx_gain); radio.set_tx_gain(prog_args.rf_tx_gain); diff --git a/srsue/test/metrics_test.cc b/srsue/test/metrics_test.cc new file mode 100644 index 000000000..52a5f98f9 --- /dev/null +++ b/srsue/test/metrics_test.cc @@ -0,0 +1,122 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsUE library. + * + * srsUE 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. + * + * srsUE 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 "ue_metrics_interface.h" +#include "srslte/common/metrics_hub.h" +#include "metrics_stdout.h" +#include "metrics_csv.h" + +using namespace srsue; + +namespace srsue { + +char *csv_file_name = NULL; + +// fake classes +class ue_dummy : public ue_metrics_interface +{ +public: + bool get_metrics(ue_metrics_t &m) + { + // fill dummy values + bzero(&m, sizeof(ue_metrics_t)); + m.rf.rf_o = 10; + m.phy.dl.rsrp = -10.0; + m.phy.dl.pathloss = 74; + return true; + } + + bool is_attached() + { + return (rand() % 2 == 0); + } +}; +} + +void usage(char *prog) { + printf("Usage: %s -o csv_output_file\n", prog); +} + +void parse_args(int argc, char **argv) { + int opt; + + while ((opt = getopt(argc, argv, "o")) != -1) { + switch(opt) { + case 'o': + csv_file_name = argv[optind]; + break; + default: + usage(argv[0]); + exit(-1); + } + } + if (!csv_file_name) { + usage(argv[0]); + exit(-1); + } +} + + +int main(int argc, char **argv) +{ + float period = 1.0; + ue_dummy ue; + + if (argc < 3) { + usage(argv[0]); + exit(-1); + } + + parse_args(argc,argv); + + // the default metrics type for stdout output + metrics_stdout metrics_screen; + metrics_screen.set_ue_handle(&ue); + + // the CSV file writer + metrics_csv metrics_file(csv_file_name); + metrics_file.set_ue_handle(&ue); + + // create metrics hub and register metrics for stdout + srslte::metrics_hub metricshub; + metricshub.init(&ue, period); + metricshub.add_listener(&metrics_screen); + metricshub.add_listener(&metrics_file); + + // enable printing + metrics_screen.toggle_print(true); + + std::cout << "Running for 2 seconds .." << std::endl; + usleep(2e6); + + metricshub.stop(); + return 0; +} diff --git a/srsue/test/phy/ue_itf_test_prach.cc b/srsue/test/phy/ue_itf_test_prach.cc index 42e04c495..810278c7c 100644 --- a/srsue/test/phy/ue_itf_test_prach.cc +++ b/srsue/test/phy/ue_itf_test_prach.cc @@ -277,8 +277,8 @@ public: } void new_grant_dl(mac_grant_t grant, tb_action_dl_t *action) { - action->decode_enabled = true; - action->default_ack = false; + action->decode_enabled[0] = true; + action->default_ack[0] = false; if (grant.rnti == 2) { action->generate_ack = false; } else { diff --git a/srsue/test/phy/ue_itf_test_sib1.cc b/srsue/test/phy/ue_itf_test_sib1.cc index 90f8b5b43..23f8566be 100644 --- a/srsue/test/phy/ue_itf_test_sib1.cc +++ b/srsue/test/phy/ue_itf_test_sib1.cc @@ -116,8 +116,8 @@ public: total_dci++; - action->decode_enabled = true; - action->default_ack = false; + action->decode_enabled[0] = true; + action->default_ack[0] = false; action->generate_ack = false; for (uint32_t tb = 0; tb < SRSLTE_MAX_TB; tb++) { action->payload_ptr[tb] = payload[tb]; diff --git a/srsue/ue.conf.example b/srsue/ue.conf.example index 76868008f..30c05069a 100644 --- a/srsue/ue.conf.example +++ b/srsue/ue.conf.example @@ -23,8 +23,8 @@ [rf] dl_earfcn = 3400 freq_offset = 0 -tx_gain = 80 -rx_gain = 50 +tx_gain = 70 +rx_gain = 40 #nof_rx_ant = 1 #device_name = auto @@ -64,7 +64,8 @@ filename = /tmp/ue.pcap # Logging layers: phy, mac, rlc, pdcp, rrc, nas, gw, usim, all # Logging levels: debug, info, warning, error, none # -# filename: File path to use for log output +# filename: File path to use for log output. Can be set to stdout +# to print logs to standard output ##################################################################### [log] all_level = info @@ -129,6 +130,10 @@ enable = false # # pregenerate_signals: Pregenerate uplink signals after attach. Improves CPU performance. # +# metrics_csv_enable: Write UE metrics to CSV file. +# +# metrics_csv_filename: File path to use for CSV metrics. +# ##################################################################### [expert] #ue_category = 4 @@ -148,6 +153,8 @@ enable = false #sss_algorithm = full #estimator_fil_w = 0.1 #pregenerate_signals = false +#metrics_csv_enable = false +#metrics_csv_filename = /tmp/ue_metrics.csv ##################################################################### # Manual RF calibration