From 8c92f3fddc09564531abafd7392107def76256d5 Mon Sep 17 00:00:00 2001 From: Ismael Gomez Date: Fri, 29 Jun 2018 11:25:22 +0200 Subject: [PATCH 1/9] Improvements and fixes on srsENB scheduler (#228) --- .../srslte/interfaces/sched_interface.h | 5 +- lib/include/srslte/phy/phch/prach.h | 6 +- lib/src/phy/phch/prach.c | 6 + srsenb/hdr/mac/scheduler.h | 4 +- srsenb/hdr/mac/scheduler_harq.h | 5 +- srsenb/hdr/mac/scheduler_metric.h | 8 +- srsenb/sib.conf.example | 2 +- srsenb/src/mac/scheduler.cc | 96 +++++++++++----- srsenb/src/mac/scheduler_metric.cc | 107 ++++++++++++++---- srsenb/src/metrics_stdout.cc | 23 ++-- srsenb/src/upper/gtpu.cc | 1 + srsenb/src/upper/rrc.cc | 7 +- 12 files changed, 200 insertions(+), 70 deletions(-) diff --git a/lib/include/srslte/interfaces/sched_interface.h b/lib/include/srslte/interfaces/sched_interface.h index 56bf99182..5cd8f5f4d 100644 --- a/lib/include/srslte/interfaces/sched_interface.h +++ b/lib/include/srslte/interfaces/sched_interface.h @@ -80,7 +80,10 @@ public: uint32_t maxharq_msg3tx; uint32_t n1pucch_an; uint32_t delta_pucch_shift; - + + // If non-negative, statically allocate N prbs at the edges of the uplink for PUCCH + int nrb_pucch; + uint32_t nrb_cqi; uint32_t ncs_an; diff --git a/lib/include/srslte/phy/phch/prach.h b/lib/include/srslte/phy/phch/prach.h index 087c52957..27c59d394 100644 --- a/lib/include/srslte/phy/phch/prach.h +++ b/lib/include/srslte/phy/phch/prach.h @@ -127,7 +127,11 @@ SRSLTE_API srslte_prach_sfn_t srslte_prach_get_sfn(uint32_t config_idx); SRSLTE_API bool srslte_prach_tti_opportunity(srslte_prach_t *p, uint32_t current_tti, - int allowed_subframe); + int allowed_subframe); + +SRSLTE_API bool srslte_prach_tti_opportunity_config(uint32_t config_idx, + uint32_t current_tti, + int allowed_subframe); SRSLTE_API void srslte_prach_sf_config(uint32_t config_idx, srslte_prach_sf_config_t *sf_config); diff --git a/lib/src/phy/phch/prach.c b/lib/src/phy/phch/prach.c index b5d51ba0b..0aca3bf19 100644 --- a/lib/src/phy/phch/prach.c +++ b/lib/src/phy/phch/prach.c @@ -193,6 +193,11 @@ srslte_prach_sfn_t srslte_prach_get_sfn(uint32_t config_idx) { */ bool srslte_prach_tti_opportunity(srslte_prach_t *p, uint32_t current_tti, int allowed_subframe) { uint32_t config_idx = p->config_idx; + return srslte_prach_tti_opportunity_config(config_idx,current_tti,allowed_subframe); +} + +bool srslte_prach_tti_opportunity_config(uint32_t config_idx, uint32_t current_tti, int allowed_subframe) +{ // Get SFN and sf_idx from the PRACH configuration index srslte_prach_sfn_t prach_sfn = srslte_prach_get_sfn(config_idx); @@ -213,6 +218,7 @@ bool srslte_prach_tti_opportunity(srslte_prach_t *p, uint32_t current_tti, int a } } return false; + } void srslte_prach_sf_config(uint32_t config_idx, srslte_prach_sf_config_t *sf_config) { diff --git a/srsenb/hdr/mac/scheduler.h b/srsenb/hdr/mac/scheduler.h index d964726d9..20d711451 100644 --- a/srsenb/hdr/mac/scheduler.h +++ b/srsenb/hdr/mac/scheduler.h @@ -66,9 +66,10 @@ public: public: /* Virtual methods for user metric calculation */ + virtual void reset_allocation(uint32_t nof_rb_) = 0; virtual void new_tti(std::map &ue_db, uint32_t nof_rb, uint32_t tti) = 0; virtual ul_harq_proc* get_user_allocation(sched_ue *user) = 0; - virtual void update_allocation(ul_harq_proc::ul_alloc_t alloc) = 0; + virtual bool update_allocation(ul_harq_proc::ul_alloc_t alloc) = 0; }; @@ -120,7 +121,6 @@ public: int dl_sched(uint32_t tti, dl_sched_res_t *sched_result); int ul_sched(uint32_t tti, ul_sched_res_t *sched_result); - /* Custom TPC functions */ void tpc_inc(uint16_t rnti); diff --git a/srsenb/hdr/mac/scheduler_harq.h b/srsenb/hdr/mac/scheduler_harq.h index 7002653e3..5ac38459d 100644 --- a/srsenb/hdr/mac/scheduler_harq.h +++ b/srsenb/hdr/mac/scheduler_harq.h @@ -93,10 +93,11 @@ class ul_harq_proc : public harq_proc { public: - typedef struct { + struct ul_alloc_t { uint32_t RB_start; uint32_t L; - } ul_alloc_t; + inline void set(uint32_t start, uint32_t len) {RB_start = start; L = len;} + }; void new_tx(uint32_t tti, int mcs, int tbs); diff --git a/srsenb/hdr/mac/scheduler_metric.h b/srsenb/hdr/mac/scheduler_metric.h index 9c40eda5c..f4335fd68 100644 --- a/srsenb/hdr/mac/scheduler_metric.h +++ b/srsenb/hdr/mac/scheduler_metric.h @@ -64,20 +64,22 @@ class ul_metric_rr : public sched::metric_ul public: void new_tti(std::map &ue_db, uint32_t nof_rb, uint32_t tti); ul_harq_proc* get_user_allocation(sched_ue *user); - void update_allocation(ul_harq_proc::ul_alloc_t alloc); + bool update_allocation(ul_harq_proc::ul_alloc_t alloc); + void reset_allocation(uint32_t nof_rb_); private: const static int MAX_PRB = 100; bool new_allocation(uint32_t L, ul_harq_proc::ul_alloc_t *alloc); bool allocation_is_valid(ul_harq_proc::ul_alloc_t alloc); - ul_harq_proc* apply_user_allocation(sched_ue *user); + ul_harq_proc* apply_user_allocation(sched_ue *user, bool retx_only); + ul_harq_proc* allocate_user_newtx_prbs(sched_ue* user); + ul_harq_proc* allocate_user_retx_prbs(sched_ue *user); bool used_rb[MAX_PRB]; uint32_t current_tti; uint32_t nof_rb; - uint32_t available_rb; }; diff --git a/srsenb/sib.conf.example b/srsenb/sib.conf.example index 02ad7c776..1616c546f 100644 --- a/srsenb/sib.conf.example +++ b/srsenb/sib.conf.example @@ -46,7 +46,7 @@ sib2 = { high_speed_flag = false; prach_config_index = 3; - prach_freq_offset = 0; + prach_freq_offset = 2; zero_correlation_zone_config = 11; }; }; diff --git a/srsenb/src/mac/scheduler.cc b/srsenb/src/mac/scheduler.cc index 2c3dee85a..932255b34 100644 --- a/srsenb/src/mac/scheduler.cc +++ b/srsenb/src/mac/scheduler.cc @@ -792,6 +792,7 @@ int sched::dl_sched(uint32_t tti, sched_interface::dl_sched_res_t* sched_result) // Uplink sched int sched::ul_sched(uint32_t tti, srsenb::sched_interface::ul_sched_res_t* sched_result) { + typedef std::map::iterator it_t; if (!configured) { return 0; } @@ -816,66 +817,103 @@ int sched::ul_sched(uint32_t tti, srsenb::sched_interface::ul_sched_res_t* sched // current_cfi is set in dl_sched() bzero(sched_result, sizeof(sched_interface::ul_sched_res_t)); + ul_metric->reset_allocation(cfg.cell.nof_prb); // Get HARQ process for this TTI - for(std::map::iterator iter=ue_db.begin(); iter!=ue_db.end(); ++iter) { + for(it_t iter=ue_db.begin(); iter!=ue_db.end(); ++iter) { sched_ue *user = (sched_ue*) &iter->second; uint16_t rnti = (uint16_t) iter->first; user->has_pucch = false; ul_harq_proc *h = user->get_ul_harq(current_tti); - + /* Indicate PHICH acknowledgment if needed */ if (h->has_pending_ack()) { sched_result->phich[nof_phich_elems].phich = h->get_ack(0)?ul_sched_phich_t::ACK:ul_sched_phich_t::NACK; sched_result->phich[nof_phich_elems].rnti = rnti; nof_phich_elems++; } - } + } - ul_metric->new_tti(ue_db, cfg.cell.nof_prb, current_tti); - // Update available allocation if there's a pending RAR if (pending_msg3[tti%10].enabled) { - ul_harq_proc::ul_alloc_t msg3 = {pending_msg3[tti%10].n_prb, pending_msg3[tti%10].L}; - ul_metric->update_allocation(msg3); + ul_harq_proc::ul_alloc_t msg3 = {pending_msg3[tti%10].n_prb, pending_msg3[tti%10].L}; + if(ul_metric->update_allocation(msg3)) { + log_h->debug("SCHED: Allocated msg3 RBs within (%d,%d)\n", msg3.RB_start, msg3.RB_start + msg3.L); + } + else { + log_h->warning("SCHED: Could not allocate msg3 within (%d,%d)\n", msg3.RB_start, msg3.RB_start + msg3.L); + } } - // Allocate PUCCH resources - for(std::map::iterator iter=ue_db.begin(); iter!=ue_db.end(); ++iter) { - sched_ue *user = (sched_ue*) &iter->second; - uint16_t rnti = (uint16_t) iter->first; - uint32_t prb_idx[2] = {0, 0}; - if (user->get_pucch_sched(current_tti, prb_idx)) { - user->has_pucch = true; - // allocate PUCCH - for (int i=0;i<2;i++) { - ul_harq_proc::ul_alloc_t pucch = {prb_idx[i], 1}; - ul_metric->update_allocation(pucch); + // Allocate PUCCH resources + if (cfg.nrb_pucch >= 0) { + ul_harq_proc::ul_alloc_t pucch = {0, (uint32_t) cfg.nrb_pucch}; + if(!ul_metric->update_allocation(pucch)) { + log_h->warning("SCHED: Failed to allocate PUCCH\n"); + } + pucch.RB_start = cfg.cell.nof_prb-cfg.nrb_pucch; + pucch.L = (uint32_t) cfg.nrb_pucch; + if(!ul_metric->update_allocation(pucch)) { + log_h->warning("SCHED: Failed to allocate PUCCH\n"); + } + for(it_t iter=ue_db.begin(); iter!=ue_db.end(); ++iter) { + sched_ue *user = (sched_ue *) &iter->second; + uint16_t rnti = (uint16_t) iter->first; + uint32_t prb_idx[2] = {0, 0}; + if(user->get_pucch_sched(current_tti, prb_idx)) { + user->has_pucch = true; + } + } + } else { + for(it_t iter=ue_db.begin(); iter!=ue_db.end(); ++iter) { + sched_ue *user = (sched_ue*) &iter->second; + uint16_t rnti = (uint16_t) iter->first; + uint32_t prb_idx[2] = {0, 0}; + if (user->get_pucch_sched(current_tti, prb_idx)) { + user->has_pucch = true; + // allocate PUCCH + for (int i=0;i<2;i++) { + ul_harq_proc::ul_alloc_t pucch = {prb_idx[i], 1}; + ul_metric->update_allocation(pucch); + } } } } - + + // reserve PRBs for PRACH + if(srslte_prach_tti_opportunity_config(cfg.prach_config, tti, -1)) { + ul_harq_proc::ul_alloc_t prach = {cfg.prach_freq_offset, 6}; + if(!ul_metric->update_allocation(prach)) { + log_h->warning("SCHED: Failed to allocate PRACH RBs within (%d,%d)\n", prach.RB_start, prach.RB_start + prach.L); + } + else { + log_h->debug("SCHED: Allocated PRACH RBs within (%d,%d)\n", prach.RB_start, prach.RB_start + prach.L); + } + } + + ul_metric->new_tti(ue_db, cfg.cell.nof_prb, current_tti); + // Now allocate PUSCH - for(std::map::iterator iter=ue_db.begin(); iter!=ue_db.end(); ++iter) { + for(it_t iter=ue_db.begin(); iter!=ue_db.end(); ++iter) { sched_ue *user = (sched_ue*) &iter->second; uint16_t rnti = (uint16_t) iter->first; - ul_harq_proc *h = NULL; - + ul_harq_proc *h = NULL; + // Check if there are pending Msg3 transmissions bool is_rar = false; if (pending_msg3[tti%10].enabled && pending_msg3[tti%10].rnti == rnti) { - h = user->get_ul_harq(tti); + h = user->get_ul_harq(tti); if (h) { - ul_harq_proc::ul_alloc_t alloc; - alloc.L = pending_msg3[tti%10].L; - alloc.RB_start = pending_msg3[tti%10].n_prb; + ul_harq_proc::ul_alloc_t alloc; + alloc.L = pending_msg3[tti%10].L; + alloc.RB_start = pending_msg3[tti%10].n_prb; h->set_alloc(alloc); - h->set_rar_mcs(pending_msg3[tti%10].mcs); + h->set_rar_mcs(pending_msg3[tti%10].mcs); is_rar = true; - pending_msg3[tti%10].enabled = false; + pending_msg3[tti%10].enabled = false; } else { Warning("No HARQ pid available for transmission of Msg3\n"); } @@ -950,7 +988,7 @@ int sched::ul_sched(uint32_t tti, srsenb::sched_interface::ul_sched_res_t* sched } // Update pending data counters after this TTI - for(std::map::iterator iter=ue_db.begin(); iter!=ue_db.end(); ++iter) { + for(it_t iter=ue_db.begin(); iter!=ue_db.end(); ++iter) { sched_ue *user = (sched_ue *) &iter->second; uint16_t rnti = (uint16_t) iter->first; diff --git a/srsenb/src/mac/scheduler_metric.cc b/srsenb/src/mac/scheduler_metric.cc index ff12d6641..517590c6d 100644 --- a/srsenb/src/mac/scheduler_metric.cc +++ b/srsenb/src/mac/scheduler_metric.cc @@ -208,28 +208,50 @@ dl_harq_proc* dl_metric_rr::get_user_allocation(sched_ue *user) * * Uplink Metric * - *****************************************************************/ + *****************************************************************/ + +void ul_metric_rr::reset_allocation(uint32_t nof_rb_) +{ + nof_rb = nof_rb_; + bzero(used_rb, nof_rb*sizeof(bool)); +} void ul_metric_rr::new_tti(std::map &ue_db, uint32_t nof_rb_, uint32_t tti) { + typedef std::map::iterator it_t; current_tti = tti; - nof_rb = nof_rb_; - available_rb = nof_rb_; - bzero(used_rb, nof_rb*sizeof(bool)); - + if(ue_db.size()==0) return; + for(it_t it = ue_db.begin(); it != ue_db.end(); ++it) { + it->second.ul_next_alloc = NULL; + } + // give priority in a time-domain RR basis - uint32_t priority_idx = (current_tti+ue_db.size()/2) % ue_db.size(); // make DL and UL interleaved - std::map::iterator iter = ue_db.begin(); + uint32_t priority_idx = (current_tti+(uint32_t)ue_db.size()/2) % (uint32_t)ue_db.size(); // make DL and UL interleaved + + // allocate reTxs first + it_t iter = ue_db.begin(); + for(uint32_t ue_count = 0 ; ue_count < ue_db.size() ; ++iter, ++ue_count) { + if(iter==ue_db.end()) { + iter = ue_db.begin(); // wrap around + } + sched_ue *user = (sched_ue *) &iter->second; + user->ul_next_alloc = allocate_user_retx_prbs(user); + } + + // give priority in a time-domain RR basis + iter = ue_db.begin(); std::advance(iter,priority_idx); for(uint32_t ue_count = 0 ; ue_count < ue_db.size() ; ++iter, ++ue_count) { if(iter==ue_db.end()) { iter = ue_db.begin(); // wrap around } sched_ue *user = (sched_ue*) &iter->second; - user->ul_next_alloc = apply_user_allocation(user); + if (!user->ul_next_alloc) { + user->ul_next_alloc = allocate_user_newtx_prbs(user); + } } } @@ -266,8 +288,8 @@ bool ul_metric_rr::new_allocation(uint32_t L, ul_harq_proc::ul_alloc_t* alloc) } } } - if (!alloc->L) { - return 0; + if (alloc->L==0) { + return false; } // Make sure L is allowed by SC-FDMA modulation @@ -277,21 +299,64 @@ bool ul_metric_rr::new_allocation(uint32_t L, ul_harq_proc::ul_alloc_t* alloc) return alloc->L == L; } -void ul_metric_rr::update_allocation(ul_harq_proc::ul_alloc_t alloc) +bool ul_metric_rr::update_allocation(ul_harq_proc::ul_alloc_t alloc) { - if (alloc.L > available_rb) { - return; + if(allocation_is_valid(alloc)) { + for (uint32_t n=alloc.RB_start;n nof_rb) { - return; + return false; +} + +ul_harq_proc* ul_metric_rr::allocate_user_retx_prbs(sched_ue *user) +{ + ul_harq_proc *h = user->get_ul_harq(current_tti); + + // if there are procedures and we have space + if(!h->is_empty(0)) { + ul_harq_proc::ul_alloc_t alloc = h->get_alloc(); + + // If can schedule the same mask, do it + if (update_allocation(alloc)) { + return h; + } + + // If not, try to find another mask in the current tti + if (new_allocation(alloc.L, &alloc)) { + if(not update_allocation(alloc)) { + printf("SCHED: Computed UL allocation is not valid!\n"); + } + h->set_alloc(alloc); + return h; + } } - for (uint32_t n=alloc.RB_start;nget_pending_ul_new_data(current_tti); + ul_harq_proc *h = user->get_ul_harq(current_tti); + + // find an empty PID + if (h->is_empty(0) and pending_data) { + uint32_t pending_rb = user->get_required_prb_ul(pending_data); + ul_harq_proc::ul_alloc_t alloc; + new_allocation(pending_rb, &alloc); + if (alloc.L) { + if(!update_allocation(alloc)) { + printf("SCHED: Computed UL allocation is not valid!\n"); + } + h->set_alloc(alloc); + return h; + } } - available_rb -= alloc.L; + return NULL; } -ul_harq_proc* ul_metric_rr::apply_user_allocation(sched_ue *user) { +ul_harq_proc* ul_metric_rr::apply_user_allocation(sched_ue *user, bool retx_only) { // Time-domain RR scheduling uint32_t pending_data = user->get_pending_ul_new_data(current_tti); ul_harq_proc *h = user->get_ul_harq(current_tti); @@ -314,6 +379,10 @@ ul_harq_proc* ul_metric_rr::apply_user_allocation(sched_ue *user) { } } + if (retx_only) { + return NULL; + } + // If could not schedule the reTx, or there wasn't any pending retx, find an empty PID if (h->is_empty(0)) { // Allocate resources based on pending data diff --git a/srsenb/src/metrics_stdout.cc b/srsenb/src/metrics_stdout.cc index ca9137a24..e80d7c158 100644 --- a/srsenb/src/metrics_stdout.cc +++ b/srsenb/src/metrics_stdout.cc @@ -111,8 +111,8 @@ void metrics_stdout::print_metrics() { n_reports = 0; cout << endl; - cout << "------DL-------------------------------UL--------------------------------" << endl; - cout << "rnti cqi ri mcs brate bler snr phr mcs brate bler bsr" << endl; + cout << "------DL------------------------------UL----------------------------------" << endl; + cout << "rnti cqi ri mcs brate bler snr phr mcs brate bler bsr" << endl; } if (metrics.rrc.n_ues > 0) { @@ -126,13 +126,9 @@ void metrics_stdout::print_metrics() cout << std::hex << metrics.mac[i].rnti << " "; cout << float_to_string(metrics.mac[i].dl_cqi, 2); - cout << float_to_string(metrics.mac[i].dl_ri, 3); + cout << float_to_string(metrics.mac[i].dl_ri, 1); cout << float_to_string(metrics.phy[i].dl.mcs, 2); - if (metrics.mac[i].tx_brate > 0 && metrics_report_period) { - cout << float_to_eng_string((float) metrics.mac[i].tx_brate/metrics_report_period, 2); - } else { - cout << float_to_string(0, 2); - } + cout << float_to_eng_string((float) metrics.mac[i].tx_brate/metrics_report_period, 2); if (metrics.mac[i].tx_pkts > 0 && metrics.mac[i].tx_errors) { cout << float_to_string((float) 100*metrics.mac[i].tx_errors/metrics.mac[i].tx_pkts, 1) << "%"; } else { @@ -144,7 +140,7 @@ void metrics_stdout::print_metrics() if (metrics.mac[i].rx_brate > 0 && metrics_report_period) { cout << float_to_eng_string((float) metrics.mac[i].rx_brate/metrics_report_period, 2); } else { - cout << float_to_string(0, 2); + cout << " " << float_to_string(0, 2); } if (metrics.mac[i].rx_pkts > 0 && metrics.mac[i].rx_errors > 0) { cout << float_to_string((float) 100*metrics.mac[i].rx_errors/metrics.mac[i].rx_pkts, 1) << "%"; @@ -174,7 +170,14 @@ void metrics_stdout::print_disconnect() std::string metrics_stdout::float_to_string(float f, int digits) { std::ostringstream os; - const int precision = (f == 0.0) ? digits-1 : digits - log10(fabs(f))-2*DBL_EPSILON; + int precision; + if(isnan(f) or abs(f) < 0.0001) { + f = 0.0; + precision = digits-1; + } + else { + precision = digits - (int)(log10(fabs(f))-2*DBL_EPSILON); + } os << std::setw(6) << std::fixed << std::setprecision(precision) << f; return os.str(); } diff --git a/srsenb/src/upper/gtpu.cc b/srsenb/src/upper/gtpu.cc index 6e487a715..13f47ee2c 100644 --- a/srsenb/src/upper/gtpu.cc +++ b/srsenb/src/upper/gtpu.cc @@ -89,6 +89,7 @@ bool gtpu::init(std::string gtp_bind_addr_, std::string mme_addr_, srsenb::pdcp_ 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.c_str(), GTPU_PORT); + gtpu_log->console("Failed to bind on address %s, port %d\n", gtp_bind_addr.c_str(), GTPU_PORT); return false; } diff --git a/srsenb/src/upper/rrc.cc b/srsenb/src/upper/rrc.cc index 2b5ad1d4e..770685165 100644 --- a/srsenb/src/upper/rrc.cc +++ b/srsenb/src/upper/rrc.cc @@ -637,8 +637,12 @@ void rrc::config_mac() } sched_cfg.si_window_ms = liblte_rrc_si_window_length_num[cfg.sibs[0].sib.sib1.si_window_length]; sched_cfg.prach_rar_window = liblte_rrc_ra_response_window_size_num[cfg.sibs[1].sib.sib2.rr_config_common_sib.rach_cnfg.ra_resp_win_size]; + sched_cfg.prach_freq_offset = cfg.sibs[1].sib.sib2.rr_config_common_sib.prach_cnfg.prach_cnfg_info.prach_freq_offset; sched_cfg.maxharq_msg3tx = cfg.sibs[1].sib.sib2.rr_config_common_sib.rach_cnfg.max_harq_msg3_tx; + sched_cfg.nrb_pucch = SRSLTE_MAX(cfg.sr_cfg.nof_prb, cfg.cqi_cfg.nof_prb); + rrc_log->info("Allocating %d PRBs for PUCCH\n", sched_cfg.nrb_pucch); + // Copy Cell configuration memcpy(&sched_cfg.cell, &cfg.cell, sizeof(srslte_cell_t)); @@ -804,8 +808,7 @@ void rrc::run_thread() break; } } else { - printf("Discarting rnti=0x%xn", p.rnti); - rrc_log->warning("Discarting PDU for removed rnti=0x%x\n", p.rnti); + rrc_log->warning("Discarding PDU for removed rnti=0x%x\n", p.rnti); } pthread_mutex_unlock(&user_mutex); } From 3dc5a40caf6354e8f389d107490dc9c3dfa3183a Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Fri, 29 Jun 2018 14:53:00 +0200 Subject: [PATCH 2/9] handle config parsing error gracefully and fix op/opc selection issue --- srsue/src/main.cc | 20 ++++++++++---------- srsue/src/upper/usim.cc | 5 ++--- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/srsue/src/main.cc b/srsue/src/main.cc index f1026f6b7..f71f9ac6f 100644 --- a/srsue/src/main.cc +++ b/srsue/src/main.cc @@ -363,8 +363,14 @@ void parse_args(all_args_t *args, int argc, char *argv[]) { exit(1); } - bpo::store(bpo::parse_config_file(conf, common), vm); - bpo::notify(vm); + // parse config file and handle errors gracefully + try { + bpo::store(bpo::parse_config_file(conf, common), vm); + bpo::notify(vm); + } catch (const boost::program_options::error& e) { + cerr << e.what() << endl; + exit(1); + } //Check conflicting OP/OPc options and which is being used if (vm.count("usim.op") && !vm["usim.op"].defaulted() && @@ -373,14 +379,8 @@ void parse_args(all_args_t *args, int argc, char *argv[]) { cout << "Conflicting options OP and OPc. Please configure either one or the other." << endl; exit(1); } - else - { - if(vm["usim.op"].defaulted()){ - args->usim.using_op = true; - } - else{ - args->usim.using_op = false; - } + else { + args->usim.using_op = vm.count("usim.op"); } // Apply all_level to any unset layers diff --git a/srsue/src/upper/usim.cc b/srsue/src/upper/usim.cc index dedbc8794..f13469517 100644 --- a/srsue/src/upper/usim.cc +++ b/srsue/src/upper/usim.cc @@ -53,8 +53,7 @@ int usim::init(usim_args_t *args, srslte::log *usim_log_) usim_log->console("Invalid length for K: %zu should be %d\n", args->k.length(), 32); } - if(args->using_op) - { + if(args->using_op) { if(32 == args->op.length()) { str_to_hex(args->op, op); compute_opc(k,op,opc); @@ -63,7 +62,7 @@ int usim::init(usim_args_t *args, srslte::log *usim_log_) usim_log->console("Invalid length for OP: %zu should be %d\n", args->op.length(), 32); } } - else{ + else { if(32 == args->opc.length()) { str_to_hex(args->opc, opc); } else { From 05ede38ea665e148fb523912e282b25801d42d9e Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Fri, 29 Jun 2018 15:31:34 +0200 Subject: [PATCH 3/9] remove obsolte config.h --- lib/include/srslte/common/config.h | 57 ------------------------------ 1 file changed, 57 deletions(-) delete mode 100644 lib/include/srslte/common/config.h diff --git a/lib/include/srslte/common/config.h b/lib/include/srslte/common/config.h deleted file mode 100644 index ed95631cd..000000000 --- a/lib/include/srslte/common/config.h +++ /dev/null @@ -1,57 +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 SRSLTE_CONFIG_H -#define SRSLTE_CONFIG_H - -// Generic helper definitions for shared library support -#if defined _WIN32 || defined __CYGWIN__ - #define SRSAPPS_IMPORT __declspec(dllimport) - #define SRSAPPS_EXPORT __declspec(dllexport) - #define SRSAPPS_LOCAL -#else - #if __GNUC__ >= 4 - #define SRSAPPS_IMPORT __attribute__ ((visibility ("default"))) - #define SRSAPPS_EXPORT __attribute__ ((visibility ("default"))) - #else - #define SRSAPPS_IMPORT - #define SRSAPPS_EXPORT - #define SRSAPPS_LOCAL - #endif -#endif - -// Define SRSAPPS_API -// is used for the public API symbols. -#ifdef SRSAPPS_DLL_EXPORTS // defined if we are building the SRSAPPS DLL (instead of using it) - #define SRSAPPS_EXPORT -#else - #define SRSAPPS_IMPORT -#endif - -// cf_t definition -typedef _Complex float cf_t; - -#endif // SRSLTE_CONFIG_H From a7574d288af45b9180f4d553459345d1a8895bee Mon Sep 17 00:00:00 2001 From: Ismael Gomez Date: Fri, 29 Jun 2018 16:58:28 +0200 Subject: [PATCH 4/9] Set a reasonable default rs_power --- srsenb/sib.conf.example | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/srsenb/sib.conf.example b/srsenb/sib.conf.example index 1616c546f..631f32e03 100644 --- a/srsenb/sib.conf.example +++ b/srsenb/sib.conf.example @@ -53,7 +53,7 @@ sib2 = pdsch_cnfg = { p_b = 0; - rs_power = 20; + rs_power = -10; }; pusch_cnfg = { From 115244657fc01062023f4e9642db89572135d521 Mon Sep 17 00:00:00 2001 From: Ismael Gomez Date: Fri, 29 Jun 2018 16:58:38 +0200 Subject: [PATCH 5/9] Set GTPU socket to non-blocking --- srsenb/src/upper/gtpu.cc | 4 ---- 1 file changed, 4 deletions(-) diff --git a/srsenb/src/upper/gtpu.cc b/srsenb/src/upper/gtpu.cc index 13f47ee2c..8c85763b8 100644 --- a/srsenb/src/upper/gtpu.cc +++ b/srsenb/src/upper/gtpu.cc @@ -51,10 +51,6 @@ bool gtpu::init(std::string gtp_bind_addr_, std::string mme_addr_, srsenb::pdcp_ gtpu_log->error("Failed to create sink socket\n"); return false; } - 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) From e837788ad497b855fdfb9aa5a0d9bae2cb409fd1 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Mon, 2 Jul 2018 10:20:40 +0200 Subject: [PATCH 6/9] Added initial Generic DL Phy test --- lib/test/CMakeLists.txt | 1 + lib/test/phy/CMakeLists.txt | 27 +++ lib/test/phy/phy_dl_test.c | 377 ++++++++++++++++++++++++++++++++++++ 3 files changed, 405 insertions(+) create mode 100644 lib/test/phy/CMakeLists.txt create mode 100644 lib/test/phy/phy_dl_test.c diff --git a/lib/test/CMakeLists.txt b/lib/test/CMakeLists.txt index 72e9e9100..90ed8e928 100644 --- a/lib/test/CMakeLists.txt +++ b/lib/test/CMakeLists.txt @@ -20,4 +20,5 @@ add_subdirectory(asn1) add_subdirectory(common) +add_subdirectory(phy) add_subdirectory(upper) diff --git a/lib/test/phy/CMakeLists.txt b/lib/test/phy/CMakeLists.txt new file mode 100644 index 000000000..209ba1b0d --- /dev/null +++ b/lib/test/phy/CMakeLists.txt @@ -0,0 +1,27 @@ +# +# Copyright 2013-2017 Software Radio Systems Limited +# +# This file is part of srsLTE +# +# 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/. +# + +####################################################################### +# PHY TESTS +####################################################################### +add_executable(phy_dl_test phy_dl_test.c) +target_link_libraries(phy_dl_test srslte_phy srslte_common srslte_phy ${SEC_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT}) +add_test(phy_dl_test phy_dl_test) + diff --git a/lib/test/phy/phy_dl_test.c b/lib/test/phy/phy_dl_test.c new file mode 100644 index 000000000..8c400c3b4 --- /dev/null +++ b/lib/test/phy/phy_dl_test.c @@ -0,0 +1,377 @@ +/** + * + * \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 "srslte/srslte.h" + +srslte_cell_t cell = { + .nof_prb = 100, + .nof_ports = 1, + .id = 1, + .cp = SRSLTE_CP_NORM, + .phich_resources = SRSLTE_PHICH_R_1, + .phich_length = SRSLTE_PHICH_NORM +}; + +uint32_t tm = 0; +srslte_mimo_type_t mimo_type = SRSLTE_MIMO_TYPE_SINGLE_ANTENNA; +uint32_t sf_idx = 5; +uint32_t cfi = 3; +uint32_t nof_rx_ant = 1; +uint32_t nof_subframes = 10; +uint16_t rnti = 0x1234; +bool print_dci_table; + +void usage(char *prog) { + printf("Usage: %s [cfpndvs]\n", prog); + printf("\t-c cell id [Default %d]\n", cell.id); + printf("\t-f cfi [Default %d]\n", cfi); + printf("\t-p cell.nof_prb [Default %d]\n", cell.nof_prb); + printf("\t-s number of subframes to simulate [Default %d]\n", nof_subframes); + printf("\t-d Print DCI table [Default %s]\n", print_dci_table ? "yes" : "no"); + printf("\t-x MIMO Type: single, diversity, cdd, multiplex [Default %s]\n", srslte_mimotype2str(mimo_type)); + printf("\t-v [set srslte_verbose to debug, default none]\n"); +} + +void parse_args(int argc, char **argv) { + int opt; + while ((opt = getopt(argc, argv, "cfpndvsx")) != -1) { + switch (opt) { + case 'x': + if (srslte_str2mimotype(argv[optind], &mimo_type)) { + fprintf(stderr, "'%s' is not a valid MIMO type\n", argv[optind]); + usage(argv[0]); + exit(SRSLTE_ERROR); + } + if (mimo_type == SRSLTE_MIMO_TYPE_SINGLE_ANTENNA) { + cell.nof_ports = 1; + nof_rx_ant = 1; + tm = 0; + } else { + cell.nof_ports = 2; + nof_rx_ant = 2; + if (mimo_type == SRSLTE_MIMO_TYPE_TX_DIVERSITY) { + tm = 2; + } + } + break; + case 'f': + cfi = (uint32_t) atoi(argv[optind]); + break; + case 'p': + cell.nof_prb = (uint32_t) atoi(argv[optind]); + break; + case 'c': + cell.id = (uint32_t) atoi(argv[optind]); + break; + case 's': + nof_subframes = (uint32_t) atoi(argv[optind]); + break; + case 'd': + print_dci_table = true; + break; + case 'v': + srslte_verbose++; + break; + default: + usage(argv[0]); + exit(-1); + } + } +} + +int prbset_num = 1, last_prbset_num = 1; +int prbset_orig = 0; + +unsigned int +reverse(register unsigned int x) { + x = (((x & 0xaaaaaaaa) >> 1) | ((x & 0x55555555) << 1)); + x = (((x & 0xcccccccc) >> 2) | ((x & 0x33333333) << 2)); + x = (((x & 0xf0f0f0f0) >> 4) | ((x & 0x0f0f0f0f) << 4)); + x = (((x & 0xff00ff00) >> 8) | ((x & 0x00ff00ff) << 8)); + return ((x >> 16) | (x << 16)); + +} + +uint32_t prbset_to_bitmask() { + uint32_t mask = 0; + int nb = (int) ceilf((float) cell.nof_prb / srslte_ra_type0_P(cell.nof_prb)); + for (int i = 0; i < nb; i++) { + if (i >= prbset_orig && i < prbset_orig + prbset_num) { + mask = mask | (0x1 << i); + } + } + return reverse(mask) >> (32 - nb); +} + +int main(int argc, char **argv) { + srslte_enb_dl_t enb_dl = {}; + srslte_ue_dl_t ue_dl = {}; + srslte_softbuffer_tx_t *softbuffer_tx[SRSLTE_MAX_TB] = {}; + srslte_softbuffer_rx_t *softbuffer_rx[SRSLTE_MAX_TB] = {}; + uint8_t *data_tx[SRSLTE_MAX_TB] = {}; + uint8_t *data_rx[SRSLTE_MAX_TB] = {}; + uint32_t count_failures = 0; + + int ret = -1; + + parse_args(argc, argv); + + cf_t *signal_buffer[SRSLTE_MAX_PORTS] = {NULL}; + + /* + * Allocate Memory + */ + for (int i = 0; i < cell.nof_ports; i++) { + signal_buffer[i] = srslte_vec_malloc(sizeof(cf_t) * SRSLTE_SF_LEN_PRB(cell.nof_prb)); + if (!signal_buffer[i]) { + fprintf(stderr, "Error allocating buffer\n"); + goto quit; + } + } + + for (int i = 0; i < SRSLTE_MAX_TB; i++) { + softbuffer_tx[i] = (srslte_softbuffer_tx_t *) calloc(sizeof(srslte_softbuffer_tx_t), 1); + if (!softbuffer_tx[i]) { + fprintf(stderr, "Error allocating softbuffer_tx\n"); + goto quit; + } + + if (srslte_softbuffer_tx_init(softbuffer_tx[i], cell.nof_prb)) { + fprintf(stderr, "Error initiating softbuffer_tx\n"); + goto quit; + } + + softbuffer_rx[i] = (srslte_softbuffer_rx_t *) calloc(sizeof(srslte_softbuffer_rx_t), 1); + if (!softbuffer_rx[i]) { + fprintf(stderr, "Error allocating softbuffer_rx\n"); + goto quit; + } + + if (srslte_softbuffer_rx_init(softbuffer_rx[i], cell.nof_prb)) { + fprintf(stderr, "Error initiating softbuffer_rx\n"); + goto quit; + } + + data_tx[i] = srslte_vec_malloc(sizeof(uint8_t) * 150000); + if (!data_tx[i]) { + fprintf(stderr, "Error allocating data tx\n"); + goto quit; + } + + data_rx[i] = srslte_vec_malloc(sizeof(uint8_t) * 150000); + if (!data_rx[i]) { + fprintf(stderr, "Error allocating data tx\n"); + goto quit; + } + } + + /* + * Initialise eNb + */ + if (srslte_enb_dl_init(&enb_dl, signal_buffer, cell.nof_prb)) { + fprintf(stderr, "Error initiating eNb downlink\n"); + goto quit; + } + + if (srslte_enb_dl_set_cell(&enb_dl, cell)) { + fprintf(stderr, "Error setting eNb DL cell\n"); + goto quit; + } + + srslte_enb_dl_set_cfi(&enb_dl, cfi); + srslte_enb_dl_set_power_allocation(&enb_dl, 0.0f, 0.0f); /* Default: none */ + + /* + * Initialise UE + */ + if (srslte_ue_dl_init(&ue_dl, signal_buffer, cell.nof_prb, nof_rx_ant)) { + fprintf(stderr, "Error initiating UE downlink\n"); + goto quit; + } + + if (srslte_ue_dl_set_cell(&ue_dl, cell)) { + fprintf(stderr, "Error setting UE downlink cell\n"); + goto quit; + } + + srslte_ue_dl_set_rnti(&ue_dl, rnti); + + /* + * Loop + */ + for (uint32_t sf_idx = 0; sf_idx < nof_subframes; sf_idx++) { + bool acks[SRSLTE_MAX_TB] = {}; + + /* Run eNodeB */ + srslte_enb_dl_clear_sf(&enb_dl); + + srslte_enb_dl_put_base(&enb_dl, sf_idx); + + srslte_ra_dl_dci_t dci = {}; + srslte_dci_format_t dci_format = SRSLTE_DCI_FORMAT1A; + srslte_ra_dl_grant_t grant = {}; + + /* Pupulate TB Common */ + dci.harq_process = 0; + + /* Pupulate TB0 */ + dci.mcs_idx = 0; + dci.ndi = 0; + dci.rv_idx = 0; + dci.tb_en[0] = true; + + if (mimo_type == SRSLTE_MIMO_TYPE_CDD || mimo_type == SRSLTE_MIMO_TYPE_SPATIAL_MULTIPLEX) { + dci_format = SRSLTE_DCI_FORMAT2B; + + /* Pupulate TB1 */ + dci.mcs_idx_1 = 0; + dci.ndi_1 = 0; + dci.rv_idx_1 = 0; + dci.tb_en[1] = true; + + /* Pupulate Allocation */ + dci.alloc_type = SRSLTE_RA_ALLOC_TYPE0; + dci.alloc_type = SRSLTE_RA_ALLOC_TYPE0; + dci.type0_alloc.rbg_bitmask = prbset_to_bitmask(); + } else { + dci_format = SRSLTE_DCI_FORMAT1A; + dci.alloc_type = SRSLTE_RA_ALLOC_TYPE2; + dci.type2_alloc.riv = 0; + dci.type2_alloc.L_crb = 4; + dci.type2_alloc.RB_start = 0; + dci.type2_alloc.n_prb1a = 1; + dci.type2_alloc.n_gap = 0; + dci.type2_alloc.mode = 0; + } + + dci.dci_is_1a = (dci_format == SRSLTE_DCI_FORMAT1A); + dci.dci_is_1c = (dci_format == SRSLTE_DCI_FORMAT1C); + + srslte_ra_dl_dci_to_grant(&dci, cell.nof_prb, rnti, &grant); + + srslte_dci_location_t location = { + .ncce = 0, + .L = 2 + }; + + for (int t = 0; t < SRSLTE_RA_DL_GRANT_NOF_TB(&grant); t++) { + for (int i = 0; i < grant.mcs->tbs; i++) { + data_tx[t][i] = (uint8_t) (rand() & 0xff); + } + } + + if (srslte_enb_dl_put_pdcch_dl(&enb_dl, + &dci, + dci_format, + location, + rnti, + sf_idx % 10) < 0) { + fprintf(stderr, "Error putting PDCCH\n"); + goto quit; + } + + if (srslte_enb_dl_put_pdsch(&enb_dl, + &grant, + softbuffer_tx, + rnti, + (int[SRSLTE_MAX_CODEWORDS]) {dci.rv_idx, dci.rv_idx_1}, + sf_idx % 10, + data_tx, + mimo_type) < 0) { + fprintf(stderr, "Error putting PDSCH\n"); + goto quit; + } + + srslte_enb_dl_gen_signal(&enb_dl); + + /* Run UE */ + int n = srslte_ue_dl_decode(&ue_dl, data_rx, tm, sf_idx, acks); + if (n < 0) { + fprintf(stderr, "Error decoding PDSCH\n"); + goto quit; + } + + for (int i = 0; i < SRSLTE_RA_DL_GRANT_NOF_TB(&grant); i++) { + if (!acks[i]) { + INFO("UE Failed decoding subframe %d\n", sf_idx); + count_failures++; + } + } + } + + printf("Finished! The UE failed decoding %d of %d.\n", count_failures, nof_subframes); + if (!count_failures) { + ret = SRSLTE_SUCCESS; + } + + quit: + srslte_enb_dl_free(&enb_dl); + srslte_ue_dl_free(&ue_dl); + + for ( + int i = 0; + i < cell. + nof_ports; + i++) { + if (signal_buffer[i]) { + free(signal_buffer[i]); + } + } + + for ( + int i = 0; + i < SRSLTE_MAX_TB; i++) { + if (softbuffer_tx[i]) { + srslte_softbuffer_tx_free(softbuffer_tx[i]); + free(softbuffer_tx[i]); + } + + if (softbuffer_rx[i]) { + srslte_softbuffer_rx_free(softbuffer_rx[i]); + free(softbuffer_rx[i]); + } + + if (data_tx[i]) { + free(data_tx[i]); + } + + if (data_rx[i]) { + free(data_rx[i]); + } + } + + if (ret) { + printf("Error\n"); + } else { + printf("Ok\n"); + } + srslte_dft_exit(); + exit(ret); +} From 0321a967f2785143a809f11b514003fe97b2f698 Mon Sep 17 00:00:00 2001 From: Ismael Gomez Date: Mon, 2 Jul 2018 16:14:37 +0200 Subject: [PATCH 7/9] Search SIB in all opportunities --- srsue/src/upper/rrc.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/srsue/src/upper/rrc.cc b/srsue/src/upper/rrc.cc index a8d858da7..57cadb288 100644 --- a/srsue/src/upper/rrc.cc +++ b/srsue/src/upper/rrc.cc @@ -783,7 +783,7 @@ bool rrc::si_acquire(uint32_t sib_index) si_win_len = liblte_rrc_si_window_length_num[sib1->si_window_length]; if (last_win_start == 0 || - (srslte_tti_interval(tti, last_win_start) > period*10 && srslte_tti_interval(tti, last_win_start) < 1000)) + (srslte_tti_interval(tti, last_win_start) > period*5 && srslte_tti_interval(tti, last_win_start) < 1000)) { last_win_start = si_win_start; instruct_phy = true; From 50589108c620d824b1e3b0c1bb7669a20c2a277e Mon Sep 17 00:00:00 2001 From: jctallon <40573586+jctallon@users.noreply.github.com> Date: Mon, 2 Jul 2018 17:51:09 +0200 Subject: [PATCH 8/9] Mbms fixes (#225) * fixing the threading structure for mbms in the gtpu fixing some leaks in pmch tests fixing stack overflow caused by radio objext * adding sib.conf.mbsfn.example * creating a different thread_mch object for the gtpu * Make mch_thread an isolated class * excluding mbsfn subframes from noise estimation and cfo estimation * fixing pdsch ue plotting to only show pmch constellation when mbsfn is activated. --- lib/examples/pdsch_ue.c | 28 ++- lib/include/srslte/radio/radio.h | 3 +- lib/src/phy/ch_estimation/chest_dl.c | 4 +- lib/src/phy/phch/test/pmch_test.c | 4 +- lib/src/radio/radio.cc | 3 + srsenb/enb.conf.example | 3 +- srsenb/hdr/upper/gtpu.h | 50 ++++-- srsenb/sib.conf.mbsfn.example | 153 ++++++++++++++++ srsenb/src/upper/gtpu.cc | 249 ++++++++++++++------------- 9 files changed, 346 insertions(+), 151 deletions(-) create mode 100644 srsenb/sib.conf.mbsfn.example 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 From 2c1608f6f14c83861412a28c431c6b4ca6134ed8 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Mon, 2 Jul 2018 18:15:56 +0200 Subject: [PATCH 9/9] Fixed UCI short CQI decoder. Fixed possible interleaver segfault. PUSCH Unit test tidied up. --- lib/src/phy/fec/rm_turbo.c | 9 +- lib/src/phy/fec/turbocoder.c | 15 +- lib/src/phy/phch/test/pusch_test.c | 392 ++++++++++++++++------------- lib/src/phy/phch/uci.c | 2 +- 4 files changed, 236 insertions(+), 182 deletions(-) diff --git a/lib/src/phy/fec/rm_turbo.c b/lib/src/phy/fec/rm_turbo.c index b1cc95a8c..b327500c8 100644 --- a/lib/src/phy/fec/rm_turbo.c +++ b/lib/src/phy/fec/rm_turbo.c @@ -252,9 +252,12 @@ void srslte_rm_turbo_gentables() { } void srslte_rm_turbo_free_tables () { - for (int i = 0; i < SRSLTE_NOF_TC_CB_SIZES; i++) { - srslte_bit_interleaver_free(&bit_interleavers_systematic_bits[i]); - srslte_bit_interleaver_free(&bit_interleavers_parity_bits[i]); + if (rm_turbo_tables_generated) { + for (int i = 0; i < SRSLTE_NOF_TC_CB_SIZES; i++) { + srslte_bit_interleaver_free(&bit_interleavers_systematic_bits[i]); + srslte_bit_interleaver_free(&bit_interleavers_parity_bits[i]); + } + rm_turbo_tables_generated = false; } } diff --git a/lib/src/phy/fec/turbocoder.c b/lib/src/phy/fec/turbocoder.c index 64f05b5e8..69f40dd46 100644 --- a/lib/src/phy/fec/turbocoder.c +++ b/lib/src/phy/fec/turbocoder.c @@ -60,12 +60,15 @@ int srslte_tcod_init(srslte_tcod_t *h, uint32_t max_long_cb) { } void srslte_tcod_free(srslte_tcod_t *h) { - h->max_long_cb = 0; - if (h->temp) { - free(h->temp); - } - for (int i = 0; i < 188; i++) { - srslte_bit_interleaver_free(&tcod_interleavers[i]); + if (table_initiated) { + h->max_long_cb = 0; + if (h->temp) { + free(h->temp); + } + for (int i = 0; i < 188; i++) { + srslte_bit_interleaver_free(&tcod_interleavers[i]); + } + table_initiated = false; } } diff --git a/lib/src/phy/phch/test/pusch_test.c b/lib/src/phy/phch/test/pusch_test.c index 4e377b42a..38be7b70c 100644 --- a/lib/src/phy/phch/test/pusch_test.c +++ b/lib/src/phy/phch/test/pusch_test.c @@ -27,28 +27,27 @@ #include #include #include -#include #include #include #include "srslte/srslte.h" -srslte_cell_t cell = { - .nof_prb = 6, // nof_prb - .nof_ports = 1, // nof_ports - .id = 0, // cell_id - .cp = SRSLTE_CP_NORM, // cyclic prefix - .phich_length = SRSLTE_PHICH_NORM, // PHICH length - .phich_resources = SRSLTE_PHICH_R_1_6 // PHICH resources +static srslte_cell_t cell = { + .nof_prb = 6, // nof_prb + .nof_ports = 1, // nof_ports + .id = 0, // cell_id + .cp = SRSLTE_CP_NORM, // cyclic prefix + .phich_length = SRSLTE_PHICH_NORM, // PHICH length + .phich_resources = SRSLTE_PHICH_R_1_6 // PHICH resources }; -srslte_uci_cfg_t uci_cfg = { +static srslte_uci_cfg_t uci_cfg = { .I_offset_cqi = 6, .I_offset_ri = 2, .I_offset_ack = 9, }; -srslte_uci_data_t uci_data_tx = { +static srslte_uci_data_t uci_data_tx = { .uci_cqi = {0}, .uci_cqi_len = 0, .uci_ri = 0, @@ -64,14 +63,14 @@ srslte_uci_data_t uci_data_tx = { uint32_t cfi = 2; uint32_t tbs = 0; -uint32_t subframe = 1; +uint32_t subframe = 10; srslte_mod_t modulation = SRSLTE_MOD_QPSK; uint32_t rv_idx = 0; -uint32_t L_prb = 2; -uint32_t n_prb = 0; -int freq_hop = -1; -int riv = -1; -uint32_t mcs_idx = 0; +uint32_t L_prb = 2; +uint32_t n_prb = 0; +int freq_hop = -1; +int riv = -1; +uint32_t mcs_idx = 0; srslte_cqi_value_t cqi_value; void usage(char *prog) { @@ -95,56 +94,52 @@ void usage(char *prog) { printf("\t\t-p I_offset_ack (0-15) [Default %d]\n", uci_cfg.I_offset_ack); printf("\n\tCQI/RI/ACK Reporting contents:\n"); - printf("\t\t-p uci_cqi (zeros, ones, random) [Default zeros]\n"); - printf("\t\t-p uci_cqi_len (0-64) [Default %d]\n", uci_data_tx.uci_cqi_len); + printf("\t\t-p uci_cqi (none, wideband) [Default none]\n"); printf("\t\t-p uci_ri (0-1) (zeros, ones, random) [Default none]\n"); printf("\t\t-p uci_ack (0-1) [Default none]\n"); printf("\t\t-p uci_ack_2 (0-1) [Default none]\n"); printf("\n\tOther parameters:\n"); - printf("\t\t-s subframe [Default %d]\n", subframe); + printf("\t\t-s number of subframes [Default %d]\n", subframe); printf("\t-v [set srslte_verbose to debug, default none]\n"); } -void parse_extensive_param (char *param, char *arg) { +void parse_extensive_param(char *param, char *arg) { int ext_code = SRSLTE_SUCCESS; if (!strcmp(param, "I_offset_cqi")) { - uci_cfg.I_offset_cqi = (uint32_t) atoi(arg); + uci_cfg.I_offset_cqi = (uint32_t) strtol(arg, NULL, 10); if (uci_cfg.I_offset_cqi > 15) { ext_code = SRSLTE_ERROR; } } else if (!strcmp(param, "I_offset_ri")) { - uci_cfg.I_offset_ri = (uint32_t) atoi(arg); + uci_cfg.I_offset_ri = (uint32_t) strtol(arg, NULL, 10); if (uci_cfg.I_offset_ri > 15) { ext_code = SRSLTE_ERROR; } } else if (!strcmp(param, "I_offset_ack")) { - uci_cfg.I_offset_ack = (uint32_t) atoi(arg); + uci_cfg.I_offset_ack = (uint32_t) strtol(arg, NULL, 10); if (uci_cfg.I_offset_ack > 15) { ext_code = SRSLTE_ERROR; } } else if (!strcmp(param, "uci_cqi")) { if (!strcmp(arg, "wideband")) { cqi_value.type = SRSLTE_CQI_TYPE_WIDEBAND; - cqi_value.wideband.wideband_cqi = (uint8_t) (rand() & 0x03); - uci_data_tx.uci_cqi_len = (uint32_t) srslte_cqi_value_unpack(uci_data_tx.uci_cqi, &cqi_value); + cqi_value.wideband.wideband_cqi = (uint8_t) (random() & 0x0f); + uci_data_tx.uci_cqi_len = (uint32_t) srslte_cqi_value_pack(&cqi_value, uci_data_tx.uci_cqi); + } else if (!strcmp(arg, "none")) { + uci_data_tx.uci_cqi_len = 0; } else { ext_code = SRSLTE_ERROR; } - } else if (!strcmp(param, "uci_cqi_len")) { - uci_data_tx.uci_cqi_len = (uint32_t) atol(arg); - if (uci_data_tx.uci_cqi_len >= SRSLTE_CQI_MAX_BITS) { - ext_code = SRSLTE_ERROR; - } } else if (!strcmp(param, "uci_ri")) { - uci_data_tx.uci_ri = (uint8_t) atol(arg); + uci_data_tx.uci_ri = (uint8_t) strtol(arg, NULL, 10); if (uci_data_tx.uci_ri > 1) { ext_code = SRSLTE_ERROR; } else { uci_data_tx.uci_ri_len = 1; } } else if (!strcmp(param, "uci_ack")) { - uci_data_tx.uci_ack = (uint8_t) atol(arg); + uci_data_tx.uci_ack = (uint8_t) strtol(arg, NULL, 10); if (uci_data_tx.uci_ack > 1) { ext_code = SRSLTE_ERROR; } else { @@ -154,7 +149,7 @@ void parse_extensive_param (char *param, char *arg) { } } } else if (!strcmp(param, "uci_ack_2")) { - uci_data_tx.uci_ack_2 = (uint8_t) atol(arg); + uci_data_tx.uci_ack_2 = (uint8_t) strtol(arg, NULL, 10); if (uci_data_tx.uci_ack_2 > 1) { ext_code = SRSLTE_ERROR; } else { @@ -175,45 +170,48 @@ void parse_extensive_param (char *param, char *arg) { void parse_args(int argc, char **argv) { int opt; - while ((opt = getopt(argc, argv, "msLNRFrncpv")) != -1) { - switch(opt) { - case 'm': - mcs_idx = atoi(argv[optind]); - break; - case 's': - subframe = atoi(argv[optind]); - break; - case 'L': - L_prb = atoi(argv[optind]); - break; - case 'N': - n_prb = atoi(argv[optind]); - break; - case 'R': - riv = atoi(argv[optind]); - break; - case 'F': - freq_hop = atoi(argv[optind]); - break; - case 'r': - rv_idx = atoi(argv[optind]); - break; - case 'n': - cell.nof_prb = atoi(argv[optind]); - break; - case 'c': - cell.id = atoi(argv[optind]); - break; - case 'p': - parse_extensive_param(argv[optind], argv[optind + 1]); - optind++; - break; - case 'v': - srslte_verbose++; - break; - default: - usage(argv[0]); - exit(-1); + while ((opt = getopt(argc, argv, "msLNRFrncpvf")) != -1) { + switch (opt) { + case 'm': + mcs_idx = (uint32_t) strtol(argv[optind], NULL, 10); + break; + case 's': + subframe = (uint32_t) strtol(argv[optind], NULL, 10); + break; + case 'f': + cfi = (uint32_t) strtol(argv[optind], NULL, 10); + break; + case 'L': + L_prb = (uint32_t) strtol(argv[optind], NULL, 10); + break; + case 'N': + n_prb = (uint32_t) strtol(argv[optind], NULL, 10); + break; + case 'R': + riv = (int) strtol(argv[optind], NULL, 10); + break; + case 'F': + freq_hop = (int) strtol(argv[optind], NULL, 10); + break; + case 'r': + rv_idx = (uint32_t) strtol(argv[optind], NULL, 10); + break; + case 'n': + cell.nof_prb = (uint32_t) strtol(argv[optind], NULL, 10); + break; + case 'c': + cell.id = (uint32_t) strtol(argv[optind], NULL, 10); + break; + case 'p': + parse_extensive_param(argv[optind], argv[optind + 1]); + optind++; + break; + case 'v': + srslte_verbose++; + break; + default: + usage(argv[0]); + exit(-1); } } } @@ -222,15 +220,16 @@ int main(int argc, char **argv) { srslte_pusch_t pusch_tx; srslte_pusch_t pusch_rx; uint8_t *data = NULL; + uint8_t *data_rx = NULL; cf_t *sf_symbols = NULL; - cf_t *ce = NULL; + cf_t *ce = NULL; int ret = -1; struct timeval t[3]; - srslte_pusch_cfg_t cfg; + srslte_pusch_cfg_t cfg; srslte_softbuffer_tx_t softbuffer_tx; - srslte_softbuffer_rx_t softbuffer_rx; - - parse_args(argc,argv); + srslte_softbuffer_rx_t softbuffer_rx; + + parse_args(argc, argv); bzero(&cfg, sizeof(srslte_pusch_cfg_t)); @@ -239,24 +238,24 @@ int main(int argc, char **argv) { srslte_ra_ul_dci_t dci; dci.freq_hop_fl = freq_hop; if (riv < 0) { - dci.type2_alloc.L_crb = L_prb; - dci.type2_alloc.RB_start = n_prb; + dci.type2_alloc.L_crb = L_prb; + dci.type2_alloc.RB_start = n_prb; } else { - dci.type2_alloc.riv = riv; + dci.type2_alloc.riv = (uint32_t) riv; } dci.mcs_idx = mcs_idx; - - srslte_ra_ul_grant_t grant; + + srslte_ra_ul_grant_t grant; if (srslte_ra_ul_dci_to_grant(&dci, cell.nof_prb, 0, &grant)) { fprintf(stderr, "Error computing resource allocation\n"); return ret; } - - srslte_pusch_hopping_cfg_t ul_hopping; - ul_hopping.n_sb = 1; + + srslte_pusch_hopping_cfg_t ul_hopping; + ul_hopping.n_sb = 1; ul_hopping.hopping_offset = 0; - ul_hopping.hop_mode = SRSLTE_PUSCH_HOP_MODE_INTER_SF; - + ul_hopping.hop_mode = 1; + if (srslte_pusch_init_ue(&pusch_tx, cell.nof_prb)) { fprintf(stderr, "Error creating PUSCH object\n"); goto quit; @@ -274,139 +273,188 @@ int main(int argc, char **argv) { goto quit; } - /* Configure PUSCH */ - - if (srslte_pusch_cfg(&pusch_tx, &cfg, &grant, &uci_cfg, &ul_hopping, NULL, subframe, 0, 0)) { - fprintf(stderr, "Error configuring PDSCH\n"); - exit(-1); - } - if (srslte_pusch_cfg(&pusch_rx, &cfg, &grant, &uci_cfg, &ul_hopping, NULL, subframe, 0, 0)) { - fprintf(stderr, "Error configuring PDSCH\n"); - exit(-1); - } - - uint16_t rnti = 1234; + uint16_t rnti = 1234; srslte_pusch_set_rnti(&pusch_tx, rnti); srslte_pusch_set_rnti(&pusch_rx, rnti); srslte_uci_data_t uci_data_rx; memcpy(&uci_data_rx, &uci_data_tx, sizeof(srslte_uci_data_t)); - - uint32_t nof_re = SRSLTE_NRE*cell.nof_prb*2*SRSLTE_CP_NSYMB(cell.cp); + + uint32_t nof_re = SRSLTE_NRE * cell.nof_prb * 2 * SRSLTE_CP_NSYMB(cell.cp); sf_symbols = srslte_vec_malloc(sizeof(cf_t) * nof_re); if (!sf_symbols) { perror("malloc"); exit(-1); } - - data = srslte_vec_malloc(sizeof(uint8_t) * (cfg.grant.mcs.tbs+24)); + + data = srslte_vec_malloc(sizeof(uint8_t) * 150000); if (!data) { perror("malloc"); exit(-1); } - - for (uint32_t i=0;i 0) { - cfg.rv = rv_idx; - if (srslte_pusch_encode(&pusch_tx, &cfg, &softbuffer_tx, data, uci_data_tx, rnti, sf_symbols)) { - fprintf(stderr, "Error encoding TB\n"); - exit(-1); - } - } ce = srslte_vec_malloc(sizeof(cf_t) * SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp)); if (!ce) { perror("srslte_vec_malloc"); goto quit; } - for (int j=0;j 1) { - if (uci_data_tx.uci_ack_2 != uci_data_rx.uci_ack_2) { - printf("UCI ACK 2 bit error: %d != %d\n", uci_data_tx.uci_ack_2, uci_data_rx.uci_ack_2); - ret = SRSLTE_ERROR; + + if (srslte_pusch_cfg(&pusch_rx, &cfg, &grant, &uci_cfg, &ul_hopping, NULL, (uint32_t) n % 10, 0, 0)) { + fprintf(stderr, "Error configuring PDSCH\n"); + exit(-1); } - } - if (uci_data_tx.uci_ri_len) { - if (uci_data_tx.uci_ri != uci_data_rx.uci_ri) { - printf("UCI RI bit error: %d != %d\n", uci_data_tx.uci_ri, uci_data_rx.uci_ri); - ret = SRSLTE_ERROR; + + srslte_softbuffer_tx_reset(&softbuffer_tx); + srslte_softbuffer_rx_reset(&softbuffer_rx); + + for (uint32_t i = 0; i < cfg.grant.mcs.tbs / 8; i++) { + data[i] = (uint8_t) (random() & 0xff); } - } - if (uci_data_tx.uci_cqi_len) { - if (memcmp(uci_data_tx.uci_cqi, uci_data_rx.uci_cqi, uci_data_tx.uci_cqi_len)) { - printf("cqi_tx="); - srslte_vec_fprint_b(stdout, uci_data_tx.uci_cqi, uci_data_tx.uci_cqi_len); - printf("cqi_rx="); - srslte_vec_fprint_b(stdout, uci_data_rx.uci_cqi, uci_data_rx.uci_cqi_len); - ret = SRSLTE_ERROR; + + for (uint32_t i = 0; i < uci_data_tx.uci_cqi_len; i++) { + uci_data_tx.uci_cqi[i] = (uint8_t) (random() & 0x1); + } + + if (uci_data_tx.uci_ack_len > 0) { + uci_data_tx.uci_ack = (uint8_t) (random() & 0x1); + } + + if (uci_data_tx.uci_ack_len > 1) { + uci_data_tx.uci_ack_2 = (uint8_t) (random() & 0x1); } + + if (srslte_pusch_encode(&pusch_tx, &cfg, &softbuffer_tx, data, uci_data_tx, rnti, sf_symbols)) { + fprintf(stderr, "Error encoding TB\n"); + exit(-1); + } + if (rv_idx > 0) { + cfg.rv = rv_idx; + if (srslte_pusch_encode(&pusch_tx, &cfg, &softbuffer_tx, data, uci_data_tx, rnti, sf_symbols)) { + fprintf(stderr, "Error encoding TB\n"); + exit(-1); + } + } + + gettimeofday(&t[1], NULL); + int r = srslte_pusch_decode(&pusch_rx, + &cfg, + &softbuffer_rx, + sf_symbols, + ce, + 0, + rnti, + data_rx, + (uci_data_tx.uci_cqi_len) ? &cqi_value : NULL, + &uci_data_rx); + gettimeofday(&t[2], NULL); + if (r) { + printf("Error returned while decoding\n"); + goto quit; + } + + if (memcmp(data_rx, data, (size_t) cfg.grant.mcs.tbs / 8) != 0) { + printf("Unmatched data detected\n"); + goto quit; + } else { + INFO("Rx Data is Ok\n"); + } + + if (uci_data_tx.uci_ack_len) { + if (uci_data_tx.uci_ack != uci_data_rx.uci_ack) { + printf("UCI ACK bit error: %d != %d\n", uci_data_tx.uci_ack, uci_data_rx.uci_ack); + ret = SRSLTE_ERROR; + } else { + INFO("Rx ACK is Ok\n"); + } + } + + if (uci_data_tx.uci_ack_len > 1) { + if (uci_data_tx.uci_ack_2 != uci_data_rx.uci_ack_2) { + printf("UCI ACK 2 bit error: %d != %d\n", uci_data_tx.uci_ack_2, uci_data_rx.uci_ack_2); + ret = SRSLTE_ERROR; + } else { + INFO("Rx ACK2 is Ok\n"); + } + } + + if (uci_data_tx.uci_ri_len) { + if (uci_data_tx.uci_ri != uci_data_rx.uci_ri) { + printf("UCI RI bit error: %d != %d\n", uci_data_tx.uci_ri, uci_data_rx.uci_ri); + ret = SRSLTE_ERROR; + } else { + INFO("Rx RI is Ok\n"); + } + } + + if (uci_data_tx.uci_cqi_len) { + if (memcmp(uci_data_tx.uci_cqi, uci_data_rx.uci_cqi, uci_data_tx.uci_cqi_len) != 0) { + printf("CQI Decode failed at subframe %d\n", n); + printf("cqi_tx="); + srslte_vec_fprint_b(stdout, uci_data_tx.uci_cqi, uci_data_tx.uci_cqi_len); + printf("cqi_rx="); + srslte_vec_fprint_b(stdout, uci_data_rx.uci_cqi, uci_data_rx.uci_cqi_len); + ret = SRSLTE_ERROR; + } else { + INFO("Rx CQI is Ok\n"); + } + } + + if (ret) { + goto quit; + } + + get_time_interval(t); + printf("DECODED OK in %d:%d (TBS: %d bits, TX: %.2f Mbps, Processing: %.2f Mbps)\n", (int) t[0].tv_sec, + (int) t[0].tv_usec, + cfg.grant.mcs.tbs, + (float) cfg.grant.mcs.tbs / 1000, + (float) cfg.grant.mcs.tbs / t[0].tv_usec); + } -quit: + quit: srslte_pusch_free(&pusch_tx); srslte_pusch_free(&pusch_rx); srslte_softbuffer_tx_free(&softbuffer_tx); srslte_softbuffer_rx_free(&softbuffer_rx); - + if (sf_symbols) { free(sf_symbols); } if (data) { free(data); } + if (data_rx) { + free(data_rx); + } if (ce) { free(ce); } diff --git a/lib/src/phy/phch/uci.c b/lib/src/phy/phch/uci.c index 1b7b43ecb..9d783a93d 100644 --- a/lib/src/phy/phch/uci.c +++ b/lib/src/phy/phch/uci.c @@ -331,7 +331,7 @@ int decode_cqi_short(srslte_uci_cqi_pusch_t *q, int16_t *q_bits, uint32_t Q, uin for (uint32_t w=0;w<(1<cqi_table_s[nof_bits-1][w*32], q_bits, 32); + int32_t corr = srslte_vec_dot_prod_sss(&q->cqi_table_s[nof_bits-1][w*32], q_bits, SRSLTE_MIN(32, Q)); if (corr > max_corr) { max_corr = corr; max_w = w;