/* * Copyright 2013-2019 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/. * */ #include #include #include #include #include #include #include #include "srslte/common/threads.h" #include "srslte/common/log.h" #include "srsenb/hdr/phy/phy.h" #define Error(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->error(fmt, ##__VA_ARGS__) #define Warning(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->warning(fmt, ##__VA_ARGS__) #define Info(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->info(fmt, ##__VA_ARGS__) #define Debug(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->debug(fmt, ##__VA_ARGS__) using namespace std; using namespace asn1::rrc; namespace srsenb { phy::phy() : workers_pool(MAX_WORKERS), workers(MAX_WORKERS), workers_common(MAX_WORKERS), nof_workers(0) { radio_handler = NULL; bzero(&prach_cfg, sizeof(prach_cfg)); } void phy::parse_config(phy_cfg_t* cfg) { // PRACH configuration ZERO_OBJECT(prach_cfg); prach_cfg.config_idx = cfg->prach_cnfg.prach_cfg_info.prach_cfg_idx; prach_cfg.hs_flag = cfg->prach_cnfg.prach_cfg_info.high_speed_flag; prach_cfg.root_seq_idx = cfg->prach_cnfg.root_seq_idx; prach_cfg.zero_corr_zone = cfg->prach_cnfg.prach_cfg_info.zero_correlation_zone_cfg; prach_cfg.freq_offset = cfg->prach_cnfg.prach_cfg_info.prach_freq_offset; // Uplink Physical common configuration ZERO_OBJECT(workers_common.ul_cfg_com); // DMRS workers_common.ul_cfg_com.dmrs.cyclic_shift = cfg->pusch_cnfg.ul_ref_sigs_pusch.cyclic_shift; workers_common.ul_cfg_com.dmrs.delta_ss = cfg->pusch_cnfg.ul_ref_sigs_pusch.group_assign_pusch; workers_common.ul_cfg_com.dmrs.group_hopping_en = cfg->pusch_cnfg.ul_ref_sigs_pusch.group_hop_enabled; workers_common.ul_cfg_com.dmrs.sequence_hopping_en = cfg->pusch_cnfg.ul_ref_sigs_pusch.seq_hop_enabled; // Hopping workers_common.ul_cfg_com.hopping.hop_mode = cfg->pusch_cnfg.pusch_cfg_basic.hop_mode == asn1::rrc::pusch_cfg_common_s::pusch_cfg_basic_s_::hop_mode_e_::intra_and_inter_sub_frame ? srslte_pusch_hopping_cfg_t::SRSLTE_PUSCH_HOP_MODE_INTRA_SF : srslte_pusch_hopping_cfg_t::SRSLTE_PUSCH_HOP_MODE_INTER_SF; ; workers_common.ul_cfg_com.hopping.n_sb = cfg->pusch_cnfg.pusch_cfg_basic.n_sb; workers_common.ul_cfg_com.hopping.hopping_offset = cfg->pusch_cnfg.pusch_cfg_basic.pusch_hop_offset; workers_common.ul_cfg_com.pusch.max_nof_iterations = workers_common.params.pusch_max_its; workers_common.ul_cfg_com.pusch.csi_enable = false; workers_common.ul_cfg_com.pusch.meas_time_en = true; // PUCCH workers_common.ul_cfg_com.pucch.delta_pucch_shift = cfg->pucch_cnfg.delta_pucch_shift.to_number(); workers_common.ul_cfg_com.pucch.N_cs = cfg->pucch_cnfg.n_cs_an; workers_common.ul_cfg_com.pucch.n_rb_2 = cfg->pucch_cnfg.n_rb_cqi; workers_common.ul_cfg_com.pucch.N_pucch_1 = cfg->pucch_cnfg.n1_pucch_an; workers_common.ul_cfg_com.pucch.threshold_format1 = 0.8; // PDSCH configuration ZERO_OBJECT(workers_common.dl_cfg_com); workers_common.dl_cfg_com.tm = SRSLTE_TM1; workers_common.dl_cfg_com.pdsch.rs_power = cfg->pdsch_cnfg.ref_sig_pwr; workers_common.dl_cfg_com.pdsch.p_b = cfg->pdsch_cnfg.p_b; workers_common.dl_cfg_com.pdsch.meas_time_en = true; } bool phy::init(phy_args_t *args, phy_cfg_t *cfg, srslte::radio* radio_handler_, mac_interface_phy *mac, srslte::log_filter* log_h) { std::vector log_vec; this->log_h = log_h; for (int i=0;inof_phy_threads;i++) { log_vec.push_back(log_h); } init(args, cfg, radio_handler_, mac, log_vec); return true; } bool phy::init(phy_args_t *args, phy_cfg_t *cfg, srslte::radio* radio_handler_, mac_interface_phy *mac, std::vector log_vec) { mlockall(MCL_CURRENT | MCL_FUTURE); radio_handler = radio_handler_; nof_workers = args->nof_phy_threads; this->log_h = (srslte::log*)log_vec[0]; workers_common.params = *args; workers_common.init(&cfg->cell, radio_handler, mac); parse_config(cfg); // Add workers to workers pool and start threads for (uint32_t i=0;icell, &prach_cfg, mac, (srslte::log*) log_vec[0], PRACH_WORKER_THREAD_PRIO); prach.set_max_prach_offset_us(args->max_prach_offset_us); // Warning this must be initialized after all workers have been added to the pool tx_rx.init(radio_handler, &workers_pool, &workers_common, &prach, (srslte::log*) log_vec[0], SF_RECV_THREAD_PRIO); return true; } void phy::stop() { tx_rx.stop(); for (uint32_t i=0;iPHY interface **********/ int phy::add_rnti(uint16_t rnti, bool is_temporal) { if (SRSLTE_RNTI_ISUSER(rnti)) { workers_common.ue_db_add_rnti(rnti); } for (uint32_t i=0;iPHY interface **********/ void phy::set_config_dedicated(uint16_t rnti, phys_cfg_ded_s* dedicated) { for (uint32_t i=0;imbsfn_sf_cfg_list_present) { if (sib2->mbsfn_sf_cfg_list.size() == 0) { Warning("SIB2 does not have any MBSFN config although it was set as present\n"); } else { if (sib2->mbsfn_sf_cfg_list.size() > 1) { Warning("SIB2 has %d MBSFN subframe configs - only 1 supported\n", sib2->mbsfn_sf_cfg_list.size()); } phy_rrc_config.mbsfn.mbsfn_subfr_cnfg = sib2->mbsfn_sf_cfg_list[0]; } } phy_rrc_config.mbsfn.mbsfn_notification_cnfg = sib13->notif_cfg_r9; if (sib13->mbsfn_area_info_list_r9.size() > 0) { if (sib13->mbsfn_area_info_list_r9.size() > 1) { Warning("SIB13 has %d MBSFN area info elements - only 1 supported\n", sib13->mbsfn_area_info_list_r9.size()); } phy_rrc_config.mbsfn.mbsfn_area_info = sib13->mbsfn_area_info_list_r9[0]; } phy_rrc_config.mbsfn.mcch = mcch; workers_common.configure_mbsfn(&phy_rrc_config.mbsfn); } // Start GUI void phy::start_plot() { ((sf_worker)workers[0]).start_plot(); } }