/** * * \section COPYRIGHT * * Copyright 2013-2017 Software Radio Systems Limited * * \section LICENSE * * This file is part of srsLTE. * * srsUE is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of * the License, or (at your option) any later version. * * srsUE is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * A copy of the GNU Affero General Public License can be found in * the LICENSE file in the top-level directory of this distribution * and at http://www.gnu.org/licenses/. * */ #include #include #include #include #include #include #include #include "srslte/common/threads.h" #include "srslte/common/log.h" #include "phy/phy.h" #define Error(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->error_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) #define Warning(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->warning_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) #define Info(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->info_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) #define Debug(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->debug_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) using namespace std; namespace srsenb { phy::phy() : workers_pool(MAX_WORKERS), workers(MAX_WORKERS), workers_common(txrx::MUTEX_X_WORKER*MAX_WORKERS) { } void phy::parse_config(phy_cfg_t* cfg) { // PRACH configuration prach_cfg.config_idx = cfg->prach_cnfg.prach_cnfg_info.prach_config_index; prach_cfg.hs_flag = cfg->prach_cnfg.prach_cnfg_info.high_speed_flag; prach_cfg.root_seq_idx = cfg->prach_cnfg.root_sequence_index; prach_cfg.zero_corr_zone = cfg->prach_cnfg.prach_cnfg_info.zero_correlation_zone_config; prach_cfg.freq_offset = cfg->prach_cnfg.prach_cnfg_info.prach_freq_offset; // PUSCH DMRS configuration workers_common.pusch_cfg.cyclic_shift = cfg->pusch_cnfg.ul_rs.cyclic_shift; workers_common.pusch_cfg.delta_ss = cfg->pusch_cnfg.ul_rs.group_assignment_pusch; workers_common.pusch_cfg.group_hopping_en = cfg->pusch_cnfg.ul_rs.group_hopping_enabled; workers_common.pusch_cfg.sequence_hopping_en = cfg->pusch_cnfg.ul_rs.sequence_hopping_enabled; // PUSCH hopping configuration workers_common.hopping_cfg.hop_mode = cfg->pusch_cnfg.hopping_mode == LIBLTE_RRC_HOPPING_MODE_INTRA_AND_INTER_SUBFRAME ? srslte_pusch_hopping_cfg_t::SRSLTE_PUSCH_HOP_MODE_INTRA_SF : srslte_pusch_hopping_cfg_t::SRSLTE_PUSCH_HOP_MODE_INTER_SF; ; workers_common.hopping_cfg.n_sb = cfg->pusch_cnfg.n_sb; workers_common.hopping_cfg.hopping_offset = cfg->pusch_cnfg.pusch_hopping_offset; // PUCCH configuration workers_common.pucch_cfg.delta_pucch_shift = liblte_rrc_delta_pucch_shift_num[cfg->pucch_cnfg.delta_pucch_shift%LIBLTE_RRC_DELTA_PUCCH_SHIFT_N_ITEMS]; workers_common.pucch_cfg.N_cs = cfg->pucch_cnfg.n_cs_an; workers_common.pucch_cfg.n_rb_2 = cfg->pucch_cnfg.n_rb_cqi; workers_common.pucch_cfg.srs_configured = false; workers_common.pucch_cfg.n1_pucch_an = cfg->pucch_cnfg.n1_pucch_an;; } bool phy::init(phy_args_t *args, phy_cfg_t *cfg, srslte::radio* radio_handler_, mac_interface_phy *mac, srslte::log* log_h) { std::vector log_vec; for (int i=0;inof_phy_threads;i++) { log_vec[i] = (void*) 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; 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(); workers_common.stop(); workers_pool.stop(); prach.stop(); } uint32_t phy::tti_to_SFN(uint32_t tti) { return tti/10; } uint32_t phy::tti_to_subf(uint32_t tti) { return tti%10; } /***** MAC->PHY interface **********/ int phy::add_rnti(uint16_t rnti) { if (rnti >= SRSLTE_CRNTI_START && rnti <= SRSLTE_CRNTI_END) { workers_common.ack_add_rnti(rnti); } for (uint32_t i=0;i= SRSLTE_CRNTI_START && rnti <= SRSLTE_CRNTI_END) { workers_common.ack_rem_rnti(rnti); } for (uint32_t i=0;iPHY interface **********/ void phy::set_config_dedicated(uint16_t rnti, LIBLTE_RRC_PHYSICAL_CONFIG_DEDICATED_STRUCT* dedicated) { // Parse RRC config srslte_uci_cfg_t uci_cfg; srslte_pucch_sched_t pucch_sched; /* PUSCH UCI configuration */ bzero(&uci_cfg, sizeof(srslte_uci_cfg_t)); uci_cfg.I_offset_ack = dedicated->pusch_cnfg_ded.beta_offset_ack_idx; uci_cfg.I_offset_cqi = dedicated->pusch_cnfg_ded.beta_offset_cqi_idx; uci_cfg.I_offset_ri = dedicated->pusch_cnfg_ded.beta_offset_ri_idx; /* PUCCH Scheduling configuration */ bzero(&pucch_sched, sizeof(srslte_pucch_sched_t)); pucch_sched.n_pucch_2 = dedicated->cqi_report_cnfg.report_periodic.pucch_resource_idx; pucch_sched.n_pucch_sr = dedicated->sched_request_cnfg.sr_pucch_resource_idx; for (uint32_t i=0;isched_request_cnfg.sr_cnfg_idx, dedicated->cqi_report_cnfg.report_periodic_setup_present, dedicated->cqi_report_cnfg.report_periodic.pmi_cnfg_idx, dedicated->cqi_report_cnfg.report_periodic.simult_ack_nack_and_cqi); } } // Start GUI void phy::start_plot() { ((phch_worker) workers[0]).start_plot(); } }