diff --git a/lib/examples/pdsch_ue.c b/lib/examples/pdsch_ue.c index 4bf8dc2e0..3b84afb71 100644 --- a/lib/examples/pdsch_ue.c +++ b/lib/examples/pdsch_ue.c @@ -67,6 +67,7 @@ pthread_t plot_thread; sem_t plot_sem; uint32_t plot_sf_idx=0; bool plot_track = true; +bool enable_mbsfn_plot = false; #endif char *output_file_name; #define PRINT_CHANGE_SCHEDULIGN @@ -363,6 +364,12 @@ int main(int argc, char **argv) { parse_args(&prog_args, argc, argv); +#ifndef DISABLE_GRAPHICS + if(prog_args.mbsfn_area_id > -1) { + enable_mbsfn_plot = true; + } +#endif + for (int i = 0; i< SRSLTE_MAX_CODEWORDS; i++) { data[i] = srslte_vec_malloc(sizeof(uint8_t)*1500*8); if (!data[i]) { @@ -981,14 +988,14 @@ void *plot_thread_run(void *arg) { plot_scatter_addToWindowGrid(&pscatequal, (char*)"pdsch_ue", 0, 0); + if(enable_mbsfn_plot) { + plot_scatter_init(&pscatequal_pmch); + plot_scatter_setTitle(&pscatequal_pmch, "PMCH - Equalized Symbols"); + plot_scatter_setXAxisScale(&pscatequal_pmch, -4, 4); + plot_scatter_setYAxisScale(&pscatequal_pmch, -4, 4); + plot_scatter_addToWindowGrid(&pscatequal_pmch, (char*)"pdsch_ue", 0, 1); + } - plot_scatter_init(&pscatequal_pmch); - plot_scatter_setTitle(&pscatequal_pmch, "PMCH - Equalized Symbols"); - plot_scatter_setXAxisScale(&pscatequal_pmch, -4, 4); - plot_scatter_setYAxisScale(&pscatequal_pmch, -4, 4); - - plot_scatter_addToWindowGrid(&pscatequal_pmch, (char*)"pdsch_ue", 0, 1); - if (!prog_args.disable_plots_except_constellation) { plot_real_init(&pce); plot_real_setTitle(&pce, "Channel Response - Magnitude"); @@ -1004,7 +1011,7 @@ void *plot_thread_run(void *arg) { plot_scatter_setXAxisScale(&pscatequal_pdcch, -4, 4); plot_scatter_setYAxisScale(&pscatequal_pdcch, -4, 4); - plot_real_addToWindowGrid(&pce, (char*)"pdsch_ue", 0, 2); + plot_real_addToWindowGrid(&pce, (char*)"pdsch_ue", 0, (enable_mbsfn_plot)?2:1); plot_real_addToWindowGrid(&pscatequal_pdcch, (char*)"pdsch_ue", 1, 0); plot_real_addToWindowGrid(&p_sync, (char*)"pdsch_ue", 1, 1); } @@ -1057,7 +1064,10 @@ void *plot_thread_run(void *arg) { plot_scatter_setNewData(&pscatequal, ue_dl.pdsch.d[0], nof_symbols); - plot_scatter_setNewData(&pscatequal_pmch, ue_dl.pmch.d, nof_symbols_pmch); + if(enable_mbsfn_plot) { + plot_scatter_setNewData(&pscatequal_pmch, ue_dl.pmch.d, nof_symbols_pmch); + } + if (plot_sf_idx == 1) { if (prog_args.net_port_signal > 0) { srslte_netsink_write(&net_sink_signal, &sf_buffer[srslte_ue_sync_sf_len(&ue_sync)/7], diff --git a/lib/include/srslte/radio/radio.h b/lib/include/srslte/radio/radio.h index 641666f93..658bf7367 100644 --- a/lib/include/srslte/radio/radio.h +++ b/lib/include/srslte/radio/radio.h @@ -53,6 +53,7 @@ class radio { radio() : tr_local_time(1024 * 10), tr_usrp_time(1024 * 10), tr_tx_time(1024 * 10), tr_is_eob(1024 * 10) { bzero(&rf_device, sizeof(srslte_rf_t)); bzero(&end_of_burst_time, sizeof(srslte_timestamp_t)); + zeros = (cf_t *) srslte_vec_malloc(burst_preamble_max_samples * sizeof (cf_t)); bzero(zeros, burst_preamble_max_samples * sizeof(cf_t)); burst_preamble_sec = 0; @@ -145,7 +146,7 @@ class radio { bool is_start_of_burst; uint32_t burst_preamble_samples; double burst_preamble_time_rounded; // preamble time rounded to sample time - cf_t zeros[burst_preamble_max_samples]; + cf_t *zeros; double cur_tx_srate; double tx_adv_sec; // Transmission time advance to compensate for antenna->timestamp delay diff --git a/lib/src/phy/ch_estimation/chest_dl.c b/lib/src/phy/ch_estimation/chest_dl.c index 9bf7a84e9..59f54e87e 100644 --- a/lib/src/phy/ch_estimation/chest_dl.c +++ b/lib/src/phy/ch_estimation/chest_dl.c @@ -603,12 +603,12 @@ float chest_estimate_cfo(srslte_chest_dl_t *q) } 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 (q->cfo_estimate_enable && ((1<cfo_estimate_sf_mask)) { + if (q->cfo_estimate_enable && ((1<cfo_estimate_sf_mask) && ch_mode != SRSLTE_SF_MBSFN ) { q->cfo = chest_estimate_cfo(q); } /* Estimate noise */ - if (q->noise_alg == SRSLTE_NOISE_ALG_REFS) { + if (q->noise_alg == SRSLTE_NOISE_ALG_REFS && ch_mode != SRSLTE_SF_MBSFN ) { q->noise_estimate[rxant_id][port_id] = estimate_noise_pilots(q, port_id, ch_mode); } diff --git a/lib/src/phy/phch/test/pmch_test.c b/lib/src/phy/phch/test/pmch_test.c index 448a40c2e..e4871a594 100644 --- a/lib/src/phy/phch/test/pmch_test.c +++ b/lib/src/phy/phch/test/pmch_test.c @@ -259,7 +259,7 @@ int main(int argc, char **argv) { for (i = 0; i < cell.nof_ports; i++) { tx_sf_symbols[i] = srslte_vec_malloc(sizeof(cf_t) * SRSLTE_SF_LEN_PRB(cell.nof_prb)); - + bzero(tx_sf_symbols[i],sizeof(cf_t) * SRSLTE_SF_LEN_PRB(cell.nof_prb)); if (srslte_ofdm_tx_init_mbsfn(&ifft_mbsfn[i], SRSLTE_CP_EXT, tx_slot_symbols[i], tx_sf_symbols[i], cell.nof_prb)) { fprintf(stderr, "Error creating iFFT object\n"); exit(-1); @@ -271,7 +271,7 @@ int main(int argc, char **argv) { for (i = 0; i < nof_rx_antennas; i++) { rx_sf_symbols[i] = srslte_vec_malloc(sizeof(cf_t) * SRSLTE_SF_LEN_PRB(cell.nof_prb)); - + bzero(rx_sf_symbols[i],sizeof(cf_t) * SRSLTE_SF_LEN_PRB(cell.nof_prb)); if (srslte_ofdm_rx_init_mbsfn(&fft_mbsfn[i], SRSLTE_CP_EXT, rx_sf_symbols[i], rx_slot_symbols[i], cell.nof_prb)) { fprintf(stderr, "Error creating iFFT object\n"); exit(-1); diff --git a/lib/src/radio/radio.cc b/lib/src/radio/radio.cc index 117c626bc..9eb7073ef 100644 --- a/lib/src/radio/radio.cc +++ b/lib/src/radio/radio.cc @@ -81,6 +81,9 @@ bool radio::is_init() { void radio::stop() { + if (zeros) { + free(zeros); + } if (is_initialized) { srslte_rf_close(&rf_device); } diff --git a/srsenb/enb.conf.example b/srsenb/enb.conf.example index 935d3fe50..eba0ba830 100644 --- a/srsenb/enb.conf.example +++ b/srsenb/enb.conf.example @@ -34,7 +34,8 @@ n_prb = 50 ##################################################################### # eNB configuration files # -# sib_config: SIB1, SIB2 and SIB3 configuration file +# sib_config: SIB1, SIB2 and SIB3 configuration file +# note: when enabling mbms, use the sib.conf.mbsfn configuration file which includes SIB13 # rr_config: Radio Resources configuration file # drb_config: DRB configuration file ##################################################################### diff --git a/srsenb/hdr/upper/gtpu.h b/srsenb/hdr/upper/gtpu.h index ea2726fbe..1a8d6daaa 100644 --- a/srsenb/hdr/upper/gtpu.h +++ b/srsenb/hdr/upper/gtpu.h @@ -37,6 +37,7 @@ #ifndef SRSENB_GTPU_H #define SRSENB_GTPU_H + namespace srsenb { /**************************************************************************** @@ -64,6 +65,7 @@ typedef struct{ uint32_t teid; }gtpu_header_t; + class gtpu :public gtpu_interface_rrc ,public gtpu_interface_pdcp @@ -71,6 +73,8 @@ class gtpu { public: + gtpu(); + bool init(std::string gtp_bind_addr_, std::string mme_addr_, pdcp_interface_gtpu *pdcp_, srslte::log *gtpu_log_, bool enable_mbsfn = false); void stop(); @@ -82,7 +86,6 @@ public: // gtpu_interface_pdcp void write_pdu(uint16_t rnti, uint32_t lcid, srslte::byte_buffer_t *pdu); - private: static const int THREAD_PRIO = 65; static const int GTPU_PORT = 2152; @@ -90,14 +93,39 @@ private: bool running; bool run_enable; - bool mch_running; - bool mch_run_enable; - bool _enable_mbsfn; + + + bool enable_mbsfn; std::string gtp_bind_addr; std::string mme_addr; srsenb::pdcp_interface_gtpu *pdcp; srslte::log *gtpu_log; - pthread_t mch_thread; + + // Class to create + class mch_thread : public thread { + public: + mch_thread() : initiated(false),running(false),run_enable(false),pool(NULL) {} + bool init(pdcp_interface_gtpu *pdcp_, srslte::log *gtpu_log_); + void stop(); + private: + void run_thread(); + + bool initiated; + bool running; + bool run_enable; + + static const int MCH_THREAD_PRIO = 65; + + pdcp_interface_gtpu *pdcp; + srslte::log *gtpu_log; + int m1u_sd; + int lcid_counter; + + srslte::byte_buffer_pool *pool; + }; + + // MCH thread insteance + mch_thread mchthread; typedef struct{ uint32_t teids_in[SRSENB_N_RADIO_BEARERS]; @@ -109,22 +137,10 @@ private: // Socket file descriptors int snk_fd; int src_fd; - int m1u_sd; - - //Init functions - bool init_m1u(srslte::log *gtpu_log_); //Threading void run_thread(); - void run_mch_thread(); - - int mch_lcid_counter; - static void *mch_thread_routine(void *_this) - { - ((srsenb::gtpu*)_this)->run_mch_thread(); - return _this; - } pthread_mutex_t mutex; /**************************************************************************** diff --git a/srsenb/sib.conf.mbsfn.example b/srsenb/sib.conf.mbsfn.example new file mode 100644 index 000000000..3fe2ddc11 --- /dev/null +++ b/srsenb/sib.conf.mbsfn.example @@ -0,0 +1,153 @@ +sib1 = +{ + intra_freq_reselection = "Allowed"; + q_rx_lev_min = -130; + //p_max = 3; + cell_barred = "Not Barred" + si_window_length = 20; + sched_info = + ( + { + si_periodicity = 16; + si_mapping_info = [13]; // comma-separated array of SIB-indexes (from 3 to 13). + // Leave empty or commented to just scheduler sib2 + } + ); + system_info_value_tag = 0; +}; + +sib2 = +{ + rr_config_common_sib = + { + rach_cnfg = + { + num_ra_preambles = 52; + preamble_init_rx_target_pwr = -108; + pwr_ramping_step = 6; // in dB + preamble_trans_max = 7; + ra_resp_win_size = 10; // in ms + mac_con_res_timer = 64; // in ms + max_harq_msg3_tx = 4; + }; + bcch_cnfg = + { + modification_period_coeff = 16; // in ms + }; + pcch_cnfg = + { + default_paging_cycle = 32; // in rf + nB = "1"; + }; + prach_cnfg = + { + root_sequence_index = 128; + prach_cnfg_info = + { + high_speed_flag = false; + prach_config_index = 3; + prach_freq_offset = 0; + zero_correlation_zone_config = 11; + }; + }; + pdsch_cnfg = + { + p_b = 0; + rs_power = -4; + }; + pusch_cnfg = + { + n_sb = 1; + hopping_mode = "inter-subframe"; + pusch_hopping_offset = 2; + enable_64_qam = false; + ul_rs = + { + cyclic_shift = 0; + group_assignment_pusch = 0; + group_hopping_enabled = false; + sequence_hopping_enabled = false; + }; + }; + pucch_cnfg = + { + delta_pucch_shift = 1; + n_rb_cqi = 1; + n_cs_an = 0; + n1_pucch_an = 2; + }; + ul_pwr_ctrl = + { + p0_nominal_pusch = -108; + alpha = 1.0; + p0_nominal_pucch = -88; + delta_flist_pucch = + { + format_1 = 2; + format_1b = 3; + format_2 = 0; + format_2a = 0; + format_2b = 0; + }; + delta_preamble_msg3 = 4; + }; + ul_cp_length = "Normal"; + }; + + ue_timers_and_constants = + { + t300 = 2000; // in ms + t301 = 100; // in ms + t310 = 1000; // in ms + n310 = 1; + t311 = 1000; // in ms + n311 = 1; + }; + + freqInfo = + { + ul_carrier_freq_present = true; + ul_bw_present = true; + additional_spectrum_emission = 1; + }; + + + + mbsfnSubframeConfigList = + { + radioframeAllocationPeriod = "1"; + subframeAllocationNumFrames = "1"; + radioframeAllocationOffset = 0; + subframeAllocation = 63; + + }; + + mbsfnSubframeConfigListLength = 1; + + time_alignment_timer = "INFINITY"; // use "sf500", "sf750", etc. +}; + +sib13 = +{ + mbsfn_notification_config = + { + mbsfn_notification_repetition_coeff = "2"; + mbsfn_notification_offset = 0; + mbsfn_notification_sf_index = 1; + }; + mbsfn_area_info_list_size = 1; + mbsfn_area_info_list = + { + non_mbsfn_region_length = "2"; + mcch_repetition_period = "64"; + mcch_modification_period = "512"; + signalling_mcs = "2"; + mbsfn_area_id = 1; + notification_indicator = 0; + mcch_offset = 0; + sf_alloc_info = 32; + }; + + +}; + diff --git a/srsenb/src/upper/gtpu.cc b/srsenb/src/upper/gtpu.cc index 8c85763b8..334878941 100644 --- a/srsenb/src/upper/gtpu.cc +++ b/srsenb/src/upper/gtpu.cc @@ -34,6 +34,10 @@ using namespace srslte; namespace srsenb { + gtpu::gtpu():mchthread() + { + } + bool gtpu::init(std::string gtp_bind_addr_, std::string mme_addr_, srsenb::pdcp_interface_gtpu* pdcp_, srslte::log* gtpu_log_, bool enable_mbsfn) { pdcp = pdcp_; @@ -89,127 +93,26 @@ bool gtpu::init(std::string gtp_bind_addr_, std::string mme_addr_, srsenb::pdcp_ return false; } - //Setup M1-u - init_m1u(gtpu_log_); - - _enable_mbsfn = enable_mbsfn; // Setup a thread to receive packets from the src socket start(THREAD_PRIO); - if(_enable_mbsfn){ - mch_lcid_counter = 1; - pthread_create(&mch_thread ,NULL ,mch_thread_routine , this); - } - return true; -} -bool gtpu::init_m1u(srslte::log* gtpu_log_) -{ - struct sockaddr_in bindaddr; - // Set up sink socket - m1u_sd = socket(AF_INET, SOCK_DGRAM, 0); - if (m1u_sd < 0) { - gtpu_log->error("Failed to create M1-U sink socket\n"); - return false; - } - - /* Bind socket */ - bzero((char *)&bindaddr, sizeof(struct sockaddr_in)); - bindaddr.sin_family = AF_INET; - bindaddr.sin_addr.s_addr = htonl(INADDR_ANY); //Multicast sockets require bind to INADDR_ANY - bindaddr.sin_port = htons(GTPU_PORT+1); - size_t addrlen = sizeof(bindaddr); - - if (bind(m1u_sd, (struct sockaddr *) &bindaddr, sizeof(bindaddr)) < 0) { - gtpu_log->error("Failed to bind multicast socket\n"); - return false; + // Start MCH thread if enabled + this->enable_mbsfn = enable_mbsfn; + if(enable_mbsfn) { + mchthread.init(pdcp, gtpu_log); } - - /* Send an ADD MEMBERSHIP message via setsockopt */ - struct ip_mreq mreq; - mreq.imr_multiaddr.s_addr = inet_addr("239.255.0.1"); //Multicast address of the service - mreq.imr_interface.s_addr = inet_addr("127.0.1.200"); //Address of the IF the socket will listen to. - if (setsockopt(m1u_sd, IPPROTO_IP, IP_ADD_MEMBERSHIP, - &mreq, sizeof(mreq)) < 0) { - gtpu_log->error("Register musticast group for M1-U\n"); - return false; - } - gtpu_log->info("M1-U initialized\n"); return true; } -void gtpu::run_mch_thread() -{ - - byte_buffer_t *pdu; - - mch_run_enable = true; - int n; - socklen_t addrlen; - sockaddr_in src_addr; - - bzero((char *)&src_addr, sizeof(src_addr)); - src_addr.sin_family = AF_INET; - src_addr.sin_addr.s_addr = htonl(INADDR_ANY); - src_addr.sin_port = htons(GTPU_PORT+1); - addrlen = sizeof(src_addr); - - pdu = pool->allocate(); - mch_running=true; - - pthread_mutex_lock(&mutex); - uint16_t lcid = mch_lcid_counter; - mch_lcid_counter++; - pthread_mutex_unlock(&mutex); - - while(mch_run_enable) { - - pdu->reset(); - do{ - n = recvfrom(m1u_sd, pdu->msg, SRSENB_MAX_BUFFER_SIZE_BYTES - SRSENB_BUFFER_HEADER_OFFSET, 0, (struct sockaddr *) &src_addr, &addrlen); - } while (n == -1 && errno == EAGAIN); - - pdu->N_bytes = (uint32_t) n; - - - gtpu_header_t header; - gtpu_read_header(pdu, &header); - - uint16_t rnti = 0xFFFD; - - pthread_mutex_lock(&mutex); - bool user_exists = (rnti_bearers.count(rnti) > 0); - pthread_mutex_unlock(&mutex); - - if(!user_exists) { - gtpu_log->error("Unrecognized RNTI for DL PDU: 0x%x - dropping packet\n", rnti); - continue; - } - - if(lcid == 0 || lcid >= SRSENB_N_RADIO_BEARERS) { - gtpu_log->error("Invalid LCID for DL PDU: %d - dropping packet\n", lcid); - continue; - } - - pdcp->write_sdu(rnti, lcid, pdu); - do { - pdu = pool_allocate; - if (!pdu) { - gtpu_log->console("GTPU Buffer pool empty. Trying again...\n"); - usleep(10000); - } - } while(!pdu); - } - mch_running=false; -} - void gtpu::stop() { + + if(enable_mbsfn){ + mchthread.stop(); + } + if (run_enable) { run_enable = false; - if(mch_run_enable) { - mch_run_enable = false; - } - // Wait thread to exit gracefully otherwise might leave a mutex locked int cnt=0; while(running && cnt<100) { @@ -218,16 +121,10 @@ void gtpu::stop() } if (running) { thread_cancel(); - if(mch_running) { - pthread_cancel(mch_thread); - } } wait_thread_finish(); - if(_enable_mbsfn) { - pthread_join(mch_thread, NULL); - } } - + if (snk_fd) { close(snk_fd); } @@ -332,7 +229,6 @@ void gtpu::run_thread() pdu->N_bytes = (uint32_t) n; - gtpu_header_t header; gtpu_read_header(pdu, &header); @@ -366,7 +262,7 @@ void gtpu::run_thread() } } while(!pdu); } - running=false; + running = false; } /**************************************************************************** @@ -446,4 +342,119 @@ void gtpu::rntilcid_to_teidin(uint16_t rnti, uint16_t lcid, uint32_t *teidin) *teidin = (rnti << 16) | lcid; } + +/**************************************************************************** +* Class to run the MCH thread +***************************************************************************/ +bool gtpu::mch_thread::init(pdcp_interface_gtpu *pdcp, srslte::log *gtpu_log) +{ + pool = byte_buffer_pool::get_instance(); + this->pdcp = pdcp; + this->gtpu_log = gtpu_log; + + struct sockaddr_in bindaddr; + + // Set up sink socket + m1u_sd = socket(AF_INET, SOCK_DGRAM, 0); + if (m1u_sd < 0) { + gtpu_log->error("Failed to create M1-U sink socket\n"); + return false; + } + + /* Bind socket */ + bzero((char *)&bindaddr, sizeof(struct sockaddr_in)); + bindaddr.sin_family = AF_INET; + bindaddr.sin_addr.s_addr = htonl(INADDR_ANY); //Multicast sockets require bind to INADDR_ANY + bindaddr.sin_port = htons(GTPU_PORT+1); + size_t addrlen = sizeof(bindaddr); + + if (bind(m1u_sd, (struct sockaddr *) &bindaddr, sizeof(bindaddr)) < 0) { + gtpu_log->error("Failed to bind multicast socket\n"); + return false; + } + + /* Send an ADD MEMBERSHIP message via setsockopt */ + struct ip_mreq mreq; + mreq.imr_multiaddr.s_addr = inet_addr("239.255.0.1"); //Multicast address of the service + mreq.imr_interface.s_addr = inet_addr("127.0.1.200"); //Address of the IF the socket will listen to. + if (setsockopt(m1u_sd, IPPROTO_IP, IP_ADD_MEMBERSHIP, + &mreq, sizeof(mreq)) < 0) { + gtpu_log->error("Register musticast group for M1-U\n"); + return false; + } + gtpu_log->info("M1-U initialized\n"); + + initiated = true; + lcid_counter = 1; + + // Start thread + start(MCH_THREAD_PRIO); + return true; +} + +void gtpu::mch_thread::run_thread() +{ + if (!initiated) { + fprintf(stderr, "Fatal error running mch_thread without initialization\n"); + return; + } + + byte_buffer_t *pdu; + int n; + socklen_t addrlen; + sockaddr_in src_addr; + + bzero((char *)&src_addr, sizeof(src_addr)); + src_addr.sin_family = AF_INET; + src_addr.sin_addr.s_addr = htonl(INADDR_ANY); + src_addr.sin_port = htons(GTPU_PORT+1); + addrlen = sizeof(src_addr); + + run_enable = true; + running=true; + + pdu = pool->allocate(); + + // Warning: Use mutex here if creating multiple services each with a different thread + uint16_t lcid = lcid_counter; + lcid_counter++; + + while(run_enable) { + + pdu->reset(); + do{ + n = recvfrom(m1u_sd, pdu->msg, SRSENB_MAX_BUFFER_SIZE_BYTES - SRSENB_BUFFER_HEADER_OFFSET, 0, (struct sockaddr *) &src_addr, &addrlen); + } while (n == -1 && errno == EAGAIN); + + pdu->N_bytes = (uint32_t) n; + + pdcp->write_sdu(SRSLTE_MRNTI, lcid, pdu); + do { + pdu = pool_allocate; + if (!pdu) { + gtpu_log->console("GTPU Buffer pool empty. Trying again...\n"); + usleep(10000); + } + } while(!pdu); + } + running = false; +} + +void gtpu::mch_thread::stop() +{ + if (run_enable) { + run_enable = false; + // Wait thread to exit gracefully otherwise might leave a mutex locked + int cnt = 0; + while(running && cnt < 100) { + usleep(10000); + cnt++; + } + if (running) { + thread_cancel(); + } + wait_thread_finish(); + } +} + } // namespace srsenb