diff --git a/srsue/hdr/phy/phy.h b/srsue/hdr/phy/phy.h index e6641eda5..25d8578e8 100644 --- a/srsue/hdr/phy/phy.h +++ b/srsue/hdr/phy/phy.h @@ -22,7 +22,6 @@ #ifndef SRSUE_PHY_H #define SRSUE_PHY_H -#include "async_scell_recv.h" #include "phy_common.h" #include "phy_metrics.h" #include "prach.h" @@ -32,6 +31,7 @@ #include "srslte/interfaces/ue_interfaces.h" #include "srslte/radio/radio.h" #include "srslte/srslte.h" +#include "srsue/hdr/phy/scell/async_scell_recv.h" #include "srsue/hdr/phy/ue_lte_phy_base.h" #include "sync.h" @@ -151,13 +151,13 @@ private: srslte::log *log_phy_lib_h; srsue::stack_interface_phy_lte* stack; - srslte::thread_pool workers_pool; - std::vector workers; - phy_common common; - sync sfsync; - async_scell_recv_vector scell_sync; - uint32_t scell_earfcn[SRSLTE_MAX_CARRIERS - 1]; - prach prach_buffer; + srslte::thread_pool workers_pool; + std::vector workers; + phy_common common; + sync sfsync; + scell::async_recv_vector scell_sync; + uint32_t scell_earfcn[SRSLTE_MAX_CARRIERS - 1]; + prach prach_buffer; srslte_prach_cfg_t prach_cfg; srslte_tdd_config_t tdd_config; diff --git a/srsue/hdr/phy/async_scell_recv.h b/srsue/hdr/phy/scell/async_scell_recv.h similarity index 95% rename from srsue/hdr/phy/async_scell_recv.h rename to srsue/hdr/phy/scell/async_scell_recv.h index 0733c3158..9b6a0dd38 100644 --- a/srsue/hdr/phy/async_scell_recv.h +++ b/srsue/hdr/phy/scell/async_scell_recv.h @@ -24,8 +24,6 @@ #include -#include "prach.h" -#include "phy_common.h" #include "srslte/common/log.h" #include "srslte/common/thread_pool.h" #include "srslte/common/threads.h" @@ -33,6 +31,8 @@ #include "srslte/interfaces/ue_interfaces.h" #include "srslte/radio/radio.h" #include "srslte/srslte.h" +#include "srsue/hdr/phy/phy_common.h" +#include "srsue/hdr/phy/prach.h" #include #include @@ -43,6 +43,7 @@ #include namespace srsue { +namespace scell { class async_scell_recv : private thread { @@ -195,9 +196,10 @@ protected: void run_thread() override; }; -typedef std::unique_ptr async_scell_recv_ptr; -typedef std::vector async_scell_recv_vector; +typedef std::unique_ptr async_recv_ptr; +typedef std::vector async_recv_vector; +} // namespace scell } // namespace srsue #endif // SRSUE_ASYNCH_SCELL_RECV_H diff --git a/srsue/hdr/phy/scell/intra_measure.h b/srsue/hdr/phy/scell/intra_measure.h new file mode 100644 index 000000000..115560d54 --- /dev/null +++ b/srsue/hdr/phy/scell/intra_measure.h @@ -0,0 +1,78 @@ +/* + * 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/. + * + */ +#ifndef SRSUE_INTRA_MEASURE_H +#define SRSUE_INTRA_MEASURE_H + +#include +#include +#include + +#include + +namespace srsue { +namespace scell { + +// Class to perform intra-frequency measurements +class intra_measure : public thread +{ +public: + intra_measure(); + ~intra_measure(); + void init(phy_common* common, rrc_interface_phy_lte* rrc, srslte::log* log_h); + void stop(); + void add_cell(int pci); + void rem_cell(int pci); + void set_primay_cell(uint32_t earfcn, srslte_cell_t cell); + void clear_cells(); + int get_offset(uint32_t pci); + void write(uint32_t tti, cf_t* data, uint32_t nsamples); + +private: + void run_thread(); + const static int INTRA_FREQ_MEAS_PRIO = DEFAULT_PRIORITY + 5; + + scell_recv scell; + rrc_interface_phy_lte* rrc; + srslte::log* log_h; + phy_common* common; + uint32_t current_earfcn; + uint32_t current_sflen; + srslte_cell_t primary_cell; + std::vector active_pci; + + srslte::tti_sync_cv tti_sync; + + cf_t* search_buffer; + + scell_recv::cell_info_t info[scell_recv::MAX_CELLS]; + + bool running; + bool receive_enabled; + bool receiving; + uint32_t measure_tti; + uint32_t receive_cnt; + srslte_ringbuffer_t ring_buffer; +}; + +} // namespace scell +} // namespace srsue + +#endif // SRSUE_INTRA_MEASURE_H diff --git a/srsue/hdr/phy/scell/measure.h b/srsue/hdr/phy/scell/measure.h new file mode 100644 index 000000000..310b21dcd --- /dev/null +++ b/srsue/hdr/phy/scell/measure.h @@ -0,0 +1,74 @@ +/* + * 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/. + * + */ + +#ifndef SRSUE_MEASURE_RECV_H +#define SRSUE_MEASURE_RECV_H + +#include + +#include "srsue/hdr/phy/phy_common.h" + +namespace srsue { +namespace scell { +// Class to perform cell measurements +class measure +{ + + // TODO: This class could early stop once the variance between the last N measurements is below 3GPP requirements + +public: + typedef enum { IDLE, MEASURE_OK, ERROR } ret_code; + + ~measure(); + void init(cf_t* buffer[SRSLTE_MAX_PORTS], + srslte::log* log_h, + uint32_t nof_rx_antennas, + phy_common* worker_com, + uint32_t nof_subframes = RSRP_MEASURE_NOF_FRAMES); + void reset(); + void set_cell(srslte_cell_t cell); + ret_code run_subframe(uint32_t sf_idx); + ret_code run_multiple_subframes(cf_t* buffer, uint32_t offset, uint32_t sf_idx, uint32_t nof_sf); + float rssi(); + float rsrp(); + float rsrq(); + float snr(); + uint32_t frame_st_idx(); + void set_rx_gain_offset(float rx_gain_offset); + +private: + srslte::log* log_h; + srslte_ue_dl_t ue_dl; + srslte_ue_dl_cfg_t ue_dl_cfg; + cf_t* buffer[SRSLTE_MAX_PORTS]; + uint32_t cnt; + uint32_t nof_subframes; + uint32_t current_prb; + float rx_gain_offset; + float mean_rsrp, mean_rsrq, mean_snr, mean_rssi; + uint32_t final_offset; + const static int RSRP_MEASURE_NOF_FRAMES = 5; +}; + +} // namespace scell +} // namespace srsue + +#endif // SRSUE_MEASURE_RECV_H diff --git a/srsue/hdr/phy/scell/scell_recv.h b/srsue/hdr/phy/scell/scell_recv.h new file mode 100644 index 000000000..486b4b96d --- /dev/null +++ b/srsue/hdr/phy/scell/scell_recv.h @@ -0,0 +1,69 @@ +/* + * 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/. + * + */ + +#ifndef SRSUE_SCELL_RECV_H +#define SRSUE_SCELL_RECV_H + +#include +#include + +#include + +namespace srsue { +namespace scell { + +// Class to receive secondary cell +class scell_recv +{ +public: + const static int MAX_CELLS = 8; + typedef struct { + uint32_t pci; + float rsrp; + float rsrq; + uint32_t offset; + } cell_info_t; + void init(srslte::log* log_h, bool sic_pss_enabled, uint32_t max_sf_window, phy_common* worker_com); + void deinit(); + void reset(); + int find_cells(cf_t* input_buffer, + float rx_gain_offset, + srslte_cell_t current_cell, + uint32_t nof_sf, + cell_info_t found_cells[MAX_CELLS]); + +private: + // 36.133 9.1.2.1 for band 7 + constexpr static float ABSOLUTE_RSRP_THRESHOLD_DBM = -125; + + cf_t* sf_buffer[SRSLTE_MAX_PORTS]; + srslte::log* log_h; + srslte_sync_t sync_find; + + bool sic_pss_enabled; + uint32_t current_fft_sz; + measure measure_p; +}; + +} // namespace scell +} // namespace srsue + +#endif // SRSUE_SCELL_RECV_H diff --git a/srsue/hdr/phy/sync.h b/srsue/hdr/phy/sync.h index 4474758dc..da6e7fd30 100644 --- a/srsue/hdr/phy/sync.h +++ b/srsue/hdr/phy/sync.h @@ -26,7 +26,6 @@ #include #include -#include "async_scell_recv.h" #include "phy_common.h" #include "prach.h" #include "sf_worker.h" @@ -36,6 +35,9 @@ #include "srslte/common/tti_sync_cv.h" #include "srslte/interfaces/ue_interfaces.h" #include "srslte/srslte.h" +#include "srsue/hdr/phy/scell/async_scell_recv.h" + +#include namespace srsue { @@ -47,16 +49,16 @@ public: sync(); ~sync(); - void init(radio_interface_phy* radio_, - stack_interface_phy_lte* _stack, - prach* prach_buffer, - srslte::thread_pool* _workers_pool, - phy_common* _worker_com, - srslte::log* _log_h, - srslte::log* _log_phy_lib_h, - async_scell_recv_vector* scell_sync_, - uint32_t prio, - int sync_cpu_affinity = -1); + void init(radio_interface_phy* radio_, + stack_interface_phy_lte* _stack, + prach* prach_buffer, + srslte::thread_pool* _workers_pool, + phy_common* _worker_com, + srslte::log* _log_h, + srslte::log* _log_phy_lib_h, + scell::async_recv_vector* scell_sync_, + uint32_t prio, + int sync_cpu_affinity = -1); void stop(); void radio_overflow(); @@ -138,116 +140,10 @@ private: srslte_ue_mib_t ue_mib; }; - // Class to perform cell measurements - class measure { - - // TODO: This class could early stop once the variance between the last N measurements is below 3GPP requirements - - public: - typedef enum {IDLE, MEASURE_OK, ERROR} ret_code; - - ~measure(); - void init(cf_t* buffer[SRSLTE_MAX_PORTS], - srslte::log* log_h, - uint32_t nof_rx_antennas, - phy_common* worker_com, - uint32_t nof_subframes = RSRP_MEASURE_NOF_FRAMES); - void reset(); - void set_cell(srslte_cell_t cell); - ret_code run_subframe(uint32_t sf_idx); - ret_code run_multiple_subframes(cf_t *buffer, uint32_t offset, uint32_t sf_idx, uint32_t nof_sf); - float rssi(); - float rsrp(); - float rsrq(); - float snr(); - uint32_t frame_st_idx(); - void set_rx_gain_offset(float rx_gain_offset); - private: - srslte::log* log_h; - srslte_ue_dl_t ue_dl; - srslte_ue_dl_cfg_t ue_dl_cfg; - cf_t *buffer[SRSLTE_MAX_PORTS]; - uint32_t cnt; - uint32_t nof_subframes; - uint32_t current_prb; - float rx_gain_offset; - float mean_rsrp, mean_rsrq, mean_snr, mean_rssi; - uint32_t final_offset; - const static int RSRP_MEASURE_NOF_FRAMES = 5; - }; - - // Class to receive secondary cell - class scell_recv { - public: - const static int MAX_CELLS = 8; - typedef struct { - uint32_t pci; - float rsrp; - float rsrq; - uint32_t offset; - } cell_info_t; - void init(srslte::log* log_h, bool sic_pss_enabled, uint32_t max_sf_window, phy_common* worker_com); - void deinit(); - void reset(); - int find_cells(cf_t *input_buffer, float rx_gain_offset, srslte_cell_t current_cell, uint32_t nof_sf, cell_info_t found_cells[MAX_CELLS]); - private: - - cf_t *sf_buffer[SRSLTE_MAX_PORTS]; - srslte::log *log_h; - srslte_sync_t sync_find; - - bool sic_pss_enabled; - uint32_t current_fft_sz; - measure measure_p; - }; - /* TODO: Intra-freq measurements can be improved by capturing 200 ms length signal and run cell search + * measurements offline using sync object and finding multiple cells for each N_id_2 */ - // Class to perform intra-frequency measurements - class intra_measure : public thread { - public: - intra_measure(); - ~intra_measure(); - void init(phy_common* common, rrc_interface_phy_lte* rrc, srslte::log* log_h); - void stop(); - void add_cell(int pci); - void rem_cell(int pci); - void set_primay_cell(uint32_t earfcn, srslte_cell_t cell); - void clear_cells(); - int get_offset(uint32_t pci); - void write(uint32_t tti, cf_t *data, uint32_t nsamples); - private: - void run_thread(); - const static int INTRA_FREQ_MEAS_PRIO = DEFAULT_PRIORITY + 5; - - scell_recv scell; - rrc_interface_phy_lte* rrc; - srslte::log *log_h; - phy_common* common; - uint32_t current_earfcn; - uint32_t current_sflen; - srslte_cell_t primary_cell; - std::vector active_pci; - - srslte::tti_sync_cv tti_sync; - - cf_t *search_buffer; - - scell_recv::cell_info_t info[scell_recv::MAX_CELLS]; - - bool running; - bool receive_enabled; - bool receiving; - uint32_t measure_tti; - uint32_t receive_cnt; - srslte_ringbuffer_t ring_buffer; - }; - - // 36.133 9.1.2.1 for band 7 - constexpr static float ABSOLUTE_RSRP_THRESHOLD_DBM = -125; - std::vector earfcn; void reset(); @@ -267,22 +163,22 @@ private: // Objects for internal use search search_p; sfn_sync sfn_p; - intra_measure intra_freq_meas; + scell::intra_measure intra_freq_meas; uint32_t current_sflen; int next_offset; // Sample offset triggered by Time aligment commands int next_radio_offset[SRSLTE_MAX_RADIOS]; // Sample offset triggered by SFO compensation // Pointers to other classes - stack_interface_phy_lte* stack; - srslte::log* log_h; - srslte::log* log_phy_lib_h; - srslte::thread_pool* workers_pool; - radio_interface_phy* radio_h; - phy_common* worker_com; - prach* prach_buffer; - async_scell_recv_vector* scell_sync; - srslte::channel_ptr channel_emulator = nullptr; + stack_interface_phy_lte* stack; + srslte::log* log_h; + srslte::log* log_phy_lib_h; + srslte::thread_pool* workers_pool; + radio_interface_phy* radio_h; + phy_common* worker_com; + prach* prach_buffer; + scell::async_recv_vector* scell_sync; + srslte::channel_ptr channel_emulator = nullptr; // Object for synchronization of the primary cell srslte_ue_sync_t ue_sync; diff --git a/srsue/src/phy/CMakeLists.txt b/srsue/src/phy/CMakeLists.txt index aa577a8b4..31321a244 100644 --- a/srsue/src/phy/CMakeLists.txt +++ b/srsue/src/phy/CMakeLists.txt @@ -18,7 +18,7 @@ # and at http://www.gnu.org/licenses/. # -file(GLOB SOURCES "*.cc") +file(GLOB_RECURSE SOURCES "*.cc") add_library(srsue_phy STATIC ${SOURCES}) if(ENABLE_GUI AND SRSGUI_FOUND) diff --git a/srsue/src/phy/phy.cc b/srsue/src/phy/phy.cc index 22c9bbb79..974db62a7 100644 --- a/srsue/src/phy/phy.cc +++ b/srsue/src/phy/phy.cc @@ -198,7 +198,7 @@ void phy::run_thread() // Load Asynchronous SCell objects for (int i = 0; i < (int)args.nof_radios - 1; i++) { - auto t = async_scell_recv_ptr(new async_scell_recv()); + auto t = scell::async_recv_ptr(new scell::async_scell_recv()); t->init(radio, &common, log_h); scell_sync.push_back(std::move(t)); } diff --git a/srsue/src/phy/async_scell_recv.cc b/srsue/src/phy/scell/async_scell_recv.cc similarity index 99% rename from srsue/src/phy/async_scell_recv.cc rename to srsue/src/phy/scell/async_scell_recv.cc index 1d2eaae6b..39ead977b 100644 --- a/srsue/src/phy/async_scell_recv.cc +++ b/srsue/src/phy/scell/async_scell_recv.cc @@ -19,7 +19,7 @@ * */ -#include "srsue/hdr/phy/async_scell_recv.h" +#include "srsue/hdr/phy/scell/async_scell_recv.h" #include "srsue/hdr/phy/phy_common.h" #include #include @@ -44,6 +44,7 @@ #endif namespace srsue { +namespace scell { async_scell_recv::async_scell_recv() : thread("ASYNC_SCELL_RECV") { @@ -617,4 +618,5 @@ void async_scell_recv::read_sf(cf_t** dst, srslte_timestamp_t* timestamp, int* n pthread_mutex_unlock(&mutex_buffer); } +} // namespace scell } // namespace srsue diff --git a/srsue/src/phy/scell/intra_measure.cc b/srsue/src/phy/scell/intra_measure.cc new file mode 100644 index 000000000..e1fffbca9 --- /dev/null +++ b/srsue/src/phy/scell/intra_measure.cc @@ -0,0 +1,199 @@ +/* + * 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 "srsue/hdr/phy/scell/intra_measure.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__) + +namespace srsue { +namespace scell { + +intra_measure::intra_measure() : scell(), thread("SYNC_INTRA_MEASURE") +{ + + rrc = nullptr; + common = nullptr; + search_buffer = nullptr; + log_h = nullptr; + + current_earfcn = 0; + current_sflen = 0; + measure_tti = 0; + receive_cnt = 0; + + running = false; + receive_enabled = false; + receiving = false; + + ZERO_OBJECT(info); + ZERO_OBJECT(ring_buffer); + ZERO_OBJECT(primary_cell); +} + +intra_measure::~intra_measure() +{ + srslte_ringbuffer_free(&ring_buffer); + scell.deinit(); + free(search_buffer); +} + +void intra_measure::init(phy_common* common, rrc_interface_phy_lte* rrc, srslte::log* log_h) +{ + this->rrc = rrc; + this->log_h = log_h; + this->common = common; + receive_enabled = false; + + // Start scell + scell.init(log_h, common->args->sic_pss_enabled, common->args->intra_freq_meas_len_ms, common); + + search_buffer = + (cf_t*)srslte_vec_malloc(common->args->intra_freq_meas_len_ms * SRSLTE_SF_LEN_PRB(SRSLTE_MAX_PRB) * sizeof(cf_t)); + + if (srslte_ringbuffer_init( + &ring_buffer, sizeof(cf_t) * common->args->intra_freq_meas_len_ms * 2 * SRSLTE_SF_LEN_PRB(SRSLTE_MAX_PRB))) { + return; + } + + running = true; + start(INTRA_FREQ_MEAS_PRIO); +} + +void intra_measure::stop() +{ + running = false; + srslte_ringbuffer_stop(&ring_buffer); + tti_sync.increase(); + wait_thread_finish(); +} + +void intra_measure::set_primay_cell(uint32_t earfcn, srslte_cell_t cell) +{ + this->current_earfcn = earfcn; + current_sflen = (uint32_t)SRSLTE_SF_LEN_PRB(cell.nof_prb); + this->primary_cell = cell; +} + +void intra_measure::clear_cells() +{ + active_pci.clear(); + receive_enabled = false; + receiving = false; + receive_cnt = 0; + srslte_ringbuffer_reset(&ring_buffer); +} + +void intra_measure::add_cell(int pci) +{ + if (std::find(active_pci.begin(), active_pci.end(), pci) == active_pci.end()) { + active_pci.push_back(pci); + receive_enabled = true; + Info("INTRA: Starting intra-frequency measurement for pci=%d\n", pci); + } else { + Debug("INTRA: Requested to start already existing intra-frequency measurement for PCI=%d\n", pci); + } +} + +int intra_measure::get_offset(uint32_t pci) +{ + for (auto& i : info) { + if (i.pci == pci) { + return i.offset; + } + } + return -1; +} + +void intra_measure::rem_cell(int pci) +{ + auto newEnd = std::remove(active_pci.begin(), active_pci.end(), pci); + + if (newEnd != active_pci.end()) { + active_pci.erase(newEnd, active_pci.end()); + if (active_pci.empty()) { + receive_enabled = false; + } + Info("INTRA: Stopping intra-frequency measurement for pci=%d. Number of cells: %zu\n", pci, active_pci.size()); + } else { + Warning("INTRA: Requested to stop non-existing intra-frequency measurement for PCI=%d\n", pci); + } +} + +void intra_measure::write(uint32_t tti, cf_t* data, uint32_t nsamples) +{ + if (receive_enabled) { + if ((tti % common->args->intra_freq_meas_period_ms) == 0) { + receiving = true; + receive_cnt = 0; + measure_tti = tti; + srslte_ringbuffer_reset(&ring_buffer); + } + if (receiving) { + if (srslte_ringbuffer_write(&ring_buffer, data, nsamples * sizeof(cf_t)) < (int)(nsamples * sizeof(cf_t))) { + Warning("Error writting to ringbuffer\n"); + receiving = false; + } else { + receive_cnt++; + if (receive_cnt == common->args->intra_freq_meas_len_ms) { + tti_sync.increase(); + receiving = false; + } + } + } + } +} + +void intra_measure::run_thread() +{ + while (running) { + if (running) { + tti_sync.wait(); + } + + if (running) { + + // Read data from buffer and find cells in it + srslte_ringbuffer_read( + &ring_buffer, search_buffer, common->args->intra_freq_meas_len_ms * current_sflen * sizeof(cf_t)); + int found_cells = scell.find_cells( + search_buffer, common->rx_gain_offset, primary_cell, common->args->intra_freq_meas_len_ms, info); + receiving = false; + + for (int i = 0; i < found_cells; i++) { + rrc->new_phy_meas(info[i].rsrp, info[i].rsrq, measure_tti, current_earfcn, info[i].pci); + } + // Look for other cells not found automatically + } + } +} + +} // namespace scell +} // namespace srsue diff --git a/srsue/src/phy/scell/measure.cc b/srsue/src/phy/scell/measure.cc new file mode 100644 index 000000000..67b302f5a --- /dev/null +++ b/srsue/src/phy/scell/measure.cc @@ -0,0 +1,223 @@ +/* + * 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 "srsue/hdr/phy/scell/measure.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__) + +namespace srsue { +namespace scell { +void measure::init(cf_t* buffer[SRSLTE_MAX_PORTS], + srslte::log* log_h, + uint32_t nof_rx_antennas, + phy_common* worker_com, + uint32_t nof_subframes) + +{ + this->log_h = log_h; + this->nof_subframes = nof_subframes; + for (int i = 0; i < SRSLTE_MAX_PORTS; i++) { + this->buffer[i] = buffer[i]; + } + + if (srslte_ue_dl_init(&ue_dl, this->buffer, SRSLTE_MAX_PRB, nof_rx_antennas)) { + Error("SYNC: Initiating ue_dl_measure\n"); + return; + } + worker_com->set_ue_dl_cfg(&ue_dl_cfg); + reset(); +} + +measure::~measure() +{ + srslte_ue_dl_free(&ue_dl); +} + +void measure::reset() +{ + cnt = 0; + mean_rsrp = 0; + mean_rsrq = 0; + mean_snr = 0; + mean_rssi = 0; +} + +void measure::set_cell(srslte_cell_t cell) +{ + current_prb = cell.nof_prb; + if (srslte_ue_dl_set_cell(&ue_dl, cell)) { + Error("SYNC: Setting cell: initiating ue_dl_measure\n"); + } + reset(); +} + +float measure::rssi() +{ + return 10 * log10(mean_rssi); +} + +float measure::rsrp() +{ + return 10 * log10(mean_rsrp) + 30 - rx_gain_offset; +} + +float measure::rsrq() +{ + return 10 * log10(mean_rsrq); +} + +float measure::snr() +{ + return mean_snr; +} + +uint32_t measure::frame_st_idx() +{ + return final_offset; +} + +void measure::set_rx_gain_offset(float rx_gain_offset) +{ + this->rx_gain_offset = rx_gain_offset; +} + +measure::ret_code measure::run_multiple_subframes(cf_t* input_buffer, uint32_t offset, uint32_t sf_idx, uint32_t max_sf) +{ + uint32_t sf_len = (uint32_t)SRSLTE_SF_LEN_PRB(current_prb); + + ret_code ret = IDLE; + + int sf_start = offset - sf_len / 2; + while (sf_start < 0 && sf_idx < max_sf) { + Info("INTRA: sf_start=%d, sf_idx=%d\n", sf_start, sf_idx); + sf_start += sf_len; + sf_idx++; + } + +#ifdef FINE_TUNE_OFFSET_WITH_RS + float max_rsrp = -200; + int best_test_sf_start = 0; + int test_sf_start = 0; + bool found_best = false; + + // Fine-tune sf_start using RS + for (uint32_t n = 0; n < 5; n++) { + + test_sf_start = sf_start - 2 + n; + if (test_sf_start >= 0) { + + cf_t* buf_m[SRSLTE_MAX_PORTS]; + buf_m[0] = &input_buffer[test_sf_start]; + + uint32_t cfi; + if (srslte_ue_dl_decode_fft_estimate_noguru(&ue_dl, buf_m, sf_idx, &cfi)) { + Error("MEAS: Measuring RSRP: Estimating channel\n"); + return ERROR; + } + + float rsrp = srslte_chest_dl_get_rsrp(&ue_dl.chest); + if (rsrp > max_rsrp) { + max_rsrp = rsrp; + best_test_sf_start = test_sf_start; + found_best = true; + } + } + } + + Debug("INTRA: fine-tuning sf_start: %d, found_best=%d, rem_sf=%d\n", sf_start, found_best, nof_sf); + + sf_start = found_best ? best_test_sf_start : sf_start; +#endif + + if (sf_start >= 0 && sf_start < (int)(sf_len * max_sf)) { + + uint32_t nof_sf = (sf_len * max_sf - sf_start) / sf_len; + + final_offset = (uint32_t)sf_start; + + for (uint32_t i = 0; i < nof_sf; i++) { + memcpy(buffer[0], &input_buffer[sf_start + i * sf_len], sizeof(cf_t) * sf_len); + ret = run_subframe((sf_idx + i) % 10); + if (ret != IDLE) { + return ret; + } + } + if (ret != ERROR) { + return MEASURE_OK; + } + } else { + Error("INTRA: not running because sf_start=%d, offset=%d, sf_len*max_sf=%d*%d\n", sf_start, offset, sf_len, max_sf); + ret = ERROR; + } + return ret; +} + +measure::ret_code measure::run_subframe(uint32_t sf_idx) +{ + srslte_dl_sf_cfg_t sf_cfg; + ZERO_OBJECT(sf_cfg); + sf_cfg.tti = sf_idx; + + if (srslte_ue_dl_decode_fft_estimate(&ue_dl, &sf_cfg, &ue_dl_cfg)) { + log_h->error("SYNC: Measuring RSRP: Estimating channel\n"); + return ERROR; + } + + float rsrp = ue_dl.chest_res.rsrp; + float rsrq = ue_dl.chest_res.rsrq; + float snr = ue_dl.chest_res.snr_db; + float rssi = srslte_vec_avg_power_cf(buffer[0], (uint32_t)SRSLTE_SF_LEN_PRB(current_prb)); + + if (cnt == 0) { + mean_rsrp = rsrp; + mean_rsrq = rsrq; + mean_snr = snr; + mean_rssi = rssi; + } else { + mean_rsrp = SRSLTE_VEC_CMA(rsrp, mean_rsrp, cnt); + mean_rsrq = SRSLTE_VEC_CMA(rsrq, mean_rsrq, cnt); + mean_snr = SRSLTE_VEC_CMA(snr, mean_snr, cnt); + mean_rssi = SRSLTE_VEC_CMA(rssi, mean_rssi, cnt); + } + cnt++; + + log_h->debug( + "SYNC: Measuring RSRP %d/%d, sf_idx=%d, RSRP=%.1f dBm, SNR=%.1f dB\n", cnt, nof_subframes, sf_idx, rsrp, snr); + + if (cnt >= nof_subframes) { + return MEASURE_OK; + } else { + return IDLE; + } +} +} // namespace scell +} // namespace srsue diff --git a/srsue/src/phy/scell/scell_recv.cc b/srsue/src/phy/scell/scell_recv.cc new file mode 100644 index 000000000..ac2c00da2 --- /dev/null +++ b/srsue/src/phy/scell/scell_recv.cc @@ -0,0 +1,245 @@ +/* + * 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 "srsue/hdr/phy/scell/scell_recv.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__) + +namespace srsue { +namespace scell { + +/********** + * Secondary cell receiver + */ + +void scell_recv::init(srslte::log* _log_h, bool _sic_pss_enabled, uint32_t max_sf_window, phy_common* worker_com) +{ + log_h = _log_h; + sic_pss_enabled = _sic_pss_enabled; + + // and a separate ue_sync instance + + uint32_t max_fft_sz = srslte_symbol_sz(100); + uint32_t max_sf_size = SRSLTE_SF_LEN(max_fft_sz); + + sf_buffer[0] = (cf_t*)srslte_vec_malloc(sizeof(cf_t) * max_sf_size); + if (!sf_buffer[0]) { + ERROR("Error allocating %d samples for scell\n", max_sf_size); + return; + } + measure_p.init(sf_buffer, log_h, 1, worker_com, max_sf_window); + + // do this different we don't need all this search window. + if (srslte_sync_init(&sync_find, max_sf_window * max_sf_size, 5 * max_sf_size, max_fft_sz)) { + ERROR("Error initiating sync_find\n"); + return; + } + srslte_sync_set_sss_algorithm(&sync_find, SSS_FULL); + srslte_sync_cp_en(&sync_find, false); + srslte_sync_set_cfo_pss_enable(&sync_find, true); + srslte_sync_set_threshold(&sync_find, 1.7); + srslte_sync_set_em_alpha(&sync_find, 0.3); + + // Configure FIND object behaviour (this configuration is always the same) + srslte_sync_set_cfo_ema_alpha(&sync_find, 1.0); + srslte_sync_set_cfo_i_enable(&sync_find, false); + srslte_sync_set_cfo_pss_enable(&sync_find, true); + srslte_sync_set_pss_filt_enable(&sync_find, true); + srslte_sync_set_sss_eq_enable(&sync_find, true); + + sync_find.pss.chest_on_filter = true; + sync_find.sss_channel_equalize = false; + + reset(); +} + +void scell_recv::deinit() +{ + srslte_sync_free(&sync_find); + free(sf_buffer[0]); +} + +void scell_recv::reset() +{ + current_fft_sz = 0; + measure_p.reset(); +} + +int scell_recv::find_cells( + cf_t* input_buffer, float rx_gain_offset, srslte_cell_t cell, uint32_t nof_sf, cell_info_t cells[MAX_CELLS]) +{ + uint32_t fft_sz = srslte_symbol_sz(cell.nof_prb); + uint32_t sf_len = SRSLTE_SF_LEN(fft_sz); + + if (fft_sz != current_fft_sz) { + if (srslte_sync_resize(&sync_find, nof_sf * sf_len, 5 * sf_len, fft_sz)) { + ERROR("Error resizing sync nof_sf=%d, sf_len=%d, fft_sz=%d\n", nof_sf, sf_len, fft_sz); + return SRSLTE_ERROR; + } + current_fft_sz = fft_sz; + } + + int nof_cells = 0; + uint32_t peak_idx = 0; + uint32_t sf_idx = 0; + int cell_id = 0; + + srslte_cell_t found_cell; + found_cell = cell; + + measure_p.set_rx_gain_offset(rx_gain_offset); + + for (uint32_t n_id_2 = 0; n_id_2 < 3; n_id_2++) { + + found_cell.id = 10000; + + if (n_id_2 != (cell.id % 3) || sic_pss_enabled) { + srslte_sync_set_N_id_2(&sync_find, n_id_2); + + srslte_sync_find_ret_t sync_res; + + do { + srslte_sync_reset(&sync_find); + srslte_sync_cfo_reset(&sync_find); + + sync_res = SRSLTE_SYNC_NOFOUND; + cell_id = 0; + float max_peak = -1; + uint32_t max_sf5 = 0; + uint32_t max_sf_idx = 0; + + for (uint32_t sf5_cnt = 0; sf5_cnt < nof_sf / 5; sf5_cnt++) { + sync_res = srslte_sync_find(&sync_find, input_buffer, sf5_cnt * 5 * sf_len, &peak_idx); + Debug("INTRA: n_id_2=%d, cnt=%d/%d, sync_res=%d, sf_idx=%d, peak_idx=%d, peak_value=%f\n", + n_id_2, + sf5_cnt, + nof_sf / 5, + sync_res, + srslte_sync_get_sf_idx(&sync_find), + peak_idx, + sync_find.peak_value); + + if (sync_find.peak_value > max_peak && sync_res == SRSLTE_SYNC_FOUND) { + max_sf5 = sf5_cnt; + max_sf_idx = srslte_sync_get_sf_idx(&sync_find); + cell_id = srslte_sync_get_cell_id(&sync_find); + } + } + + switch (sync_res) { + case SRSLTE_SYNC_ERROR: + return SRSLTE_ERROR; + ERROR("Error finding correlation peak\n"); + return SRSLTE_ERROR; + case SRSLTE_SYNC_FOUND: + + sf_idx = (10 - max_sf_idx - 5 * (max_sf5 % 2)) % 10; + + if (cell_id >= 0) { + // We found the same cell as before, look another N_id_2 + if ((uint32_t)cell_id == found_cell.id || (uint32_t)cell_id == cell.id) { + Debug("INTRA: n_id_2=%d, PCI=%d, found_cell.id=%d, cell.id=%d\n", + n_id_2, + cell_id, + found_cell.id, + cell.id); + sync_res = SRSLTE_SYNC_NOFOUND; + } else { + // We found a new cell ID + found_cell.id = (uint32_t)cell_id; + found_cell.nof_ports = 1; // Use port 0 only for measurement + measure_p.set_cell(found_cell); + + // Correct CFO + /* + srslte_cfo_correct(&sync_find.cfo_corr_frame, + input_buffer, + input_cfo_corrected, + -srslte_sync_get_cfo(&sync_find)/sync_find.fft_size); + */ + + switch (measure_p.run_multiple_subframes(input_buffer, peak_idx, sf_idx, nof_sf)) { + default: + // Consider a cell to be detectable 8.1.2.2.1.1 from 36.133. Currently only using first condition + if (measure_p.rsrp() > ABSOLUTE_RSRP_THRESHOLD_DBM) { + cells[nof_cells].pci = found_cell.id; + cells[nof_cells].rsrp = measure_p.rsrp(); + cells[nof_cells].rsrq = measure_p.rsrq(); + cells[nof_cells].offset = measure_p.frame_st_idx(); + + Info("INTRA: Found neighbour cell %d: PCI=%03d, RSRP=%5.1f dBm, peak_idx=%5d, peak_value=%3.2f, " + "sf=%d, max_sf=%d, n_id_2=%d, CFO=%6.1f Hz\n", + nof_cells, + cell_id, + measure_p.rsrp(), + measure_p.frame_st_idx(), + sync_find.peak_value, + sf_idx, + max_sf5, + n_id_2, + 15000 * srslte_sync_get_cfo(&sync_find)); + + nof_cells++; + + /* + if (sic_pss_enabled) { + srslte_pss_sic(&sync_find.pss, &input_buffer[sf5_cnt * 5 * sf_len + sf_len / 2 - fft_sz]); + }*/ + } else { + Info("INTRA: Found neighbour cell but RSRP=%.1f dBm is below threshold (%.1f dBm)\n", + measure_p.rsrp(), + ABSOLUTE_RSRP_THRESHOLD_DBM); + } + break; + case measure::ERROR: + Error("INTRA: Measuring neighbour cell\n"); + return SRSLTE_ERROR; + } + } + } else { + sync_res = SRSLTE_SYNC_NOFOUND; + } + break; + case SRSLTE_SYNC_FOUND_NOSPACE: + /* If a peak was found but there is not enough space for SSS/CP detection, discard a few samples */ + break; + default: + break; + } + } while (sync_res == SRSLTE_SYNC_FOUND && sic_pss_enabled && nof_cells < MAX_CELLS); + } + } + return nof_cells; +} + +} // namespace scell +} // namespace srsue diff --git a/srsue/src/phy/sync.cc b/srsue/src/phy/sync.cc index 3aa80841e..5a7e78a12 100644 --- a/srsue/src/phy/sync.cc +++ b/srsue/src/phy/sync.cc @@ -60,16 +60,16 @@ sync::sync() : thread("SYNC") worker_com = NULL; } -void sync::init(radio_interface_phy* _radio, - stack_interface_phy_lte* _stack, - prach* _prach_buffer, - srslte::thread_pool* _workers_pool, - phy_common* _worker_com, - srslte::log* _log_h, - srslte::log* _log_phy_lib_h, - async_scell_recv_vector* scell_sync_, - uint32_t prio, - int sync_cpu_affinity) +void sync::init(radio_interface_phy* _radio, + stack_interface_phy_lte* _stack, + prach* _prach_buffer, + srslte::thread_pool* _workers_pool, + phy_common* _worker_com, + srslte::log* _log_h, + srslte::log* _log_phy_lib_h, + scell::async_recv_vector* scell_sync_, + uint32_t prio, + int sync_cpu_affinity) { radio_h = _radio; log_h = _log_h; @@ -1250,388 +1250,6 @@ sync::sfn_sync::decode_mib(srslte_cell_t* cell, uint32_t* tti_cnt, cf_t* ext_buf return IDLE; } -/********* - * Measurement class - */ -void sync::measure::init(cf_t* buffer[SRSLTE_MAX_PORTS], - srslte::log* log_h, - uint32_t nof_rx_antennas, - phy_common* worker_com, - uint32_t nof_subframes) - -{ - this->log_h = log_h; - this->nof_subframes = nof_subframes; - for (int i=0;ibuffer[i] = buffer[i]; - } - - if (srslte_ue_dl_init(&ue_dl, this->buffer, SRSLTE_MAX_PRB, nof_rx_antennas)) { - Error("SYNC: Initiating ue_dl_measure\n"); - return; - } - worker_com->set_ue_dl_cfg(&ue_dl_cfg); - reset(); -} - -sync::measure::~measure() -{ - srslte_ue_dl_free(&ue_dl); -} - -void sync::measure::reset() -{ - cnt = 0; - mean_rsrp = 0; - mean_rsrq = 0; - mean_snr = 0; - mean_rssi = 0; -} - -void sync::measure::set_cell(srslte_cell_t cell) -{ - current_prb = cell.nof_prb; - if (srslte_ue_dl_set_cell(&ue_dl, cell)) { - Error("SYNC: Setting cell: initiating ue_dl_measure\n"); - } - reset(); -} - -float sync::measure::rssi() -{ - return 10*log10(mean_rssi); -} - -float sync::measure::rsrp() -{ - return 10*log10(mean_rsrp) + 30 - rx_gain_offset; -} - -float sync::measure::rsrq() -{ - return 10*log10(mean_rsrq); -} - -float sync::measure::snr() -{ - return mean_snr; -} - -uint32_t sync::measure::frame_st_idx() -{ - return final_offset; -} - -void sync::measure::set_rx_gain_offset(float rx_gain_offset) -{ - this->rx_gain_offset = rx_gain_offset; -} - -sync::measure::ret_code -sync::measure::run_multiple_subframes(cf_t* input_buffer, uint32_t offset, uint32_t sf_idx, uint32_t max_sf) -{ - uint32_t sf_len = SRSLTE_SF_LEN_PRB(current_prb); - - ret_code ret = IDLE; - - int sf_start = offset-sf_len/2; - while (sf_start < 0 && sf_idx < max_sf) { - Info("INTRA: sf_start=%d, sf_idx=%d\n", sf_start, sf_idx); - sf_start += sf_len; - sf_idx ++; - } - -#ifdef FINE_TUNE_OFFSET_WITH_RS - float max_rsrp = -200; - int best_test_sf_start = 0; - int test_sf_start = 0; - bool found_best = false; - - // Fine-tune sf_start using RS - for (uint32_t n=0;n<5;n++) { - - test_sf_start = sf_start-2+n; - if (test_sf_start >= 0) { - - cf_t *buf_m[SRSLTE_MAX_PORTS]; - buf_m[0] = &input_buffer[test_sf_start]; - - uint32_t cfi; - if (srslte_ue_dl_decode_fft_estimate_noguru(&ue_dl, buf_m, sf_idx, &cfi)) { - Error("MEAS: Measuring RSRP: Estimating channel\n"); - return ERROR; - } - - float rsrp = srslte_chest_dl_get_rsrp(&ue_dl.chest); - if (rsrp > max_rsrp) { - max_rsrp = rsrp; - best_test_sf_start = test_sf_start; - found_best = true; - } - } - } - - Debug("INTRA: fine-tuning sf_start: %d, found_best=%d, rem_sf=%d\n", sf_start, found_best, nof_sf); - - sf_start = found_best?best_test_sf_start:sf_start; -#endif - - if (sf_start >= 0 && sf_start < (int) (sf_len*max_sf)) { - - uint32_t nof_sf = (sf_len*max_sf - sf_start)/sf_len; - - final_offset = sf_start; - - for (uint32_t i=0;ierror("SYNC: Measuring RSRP: Estimating channel\n"); - return ERROR; - } - - float rsrp = ue_dl.chest_res.rsrp; - float rsrq = ue_dl.chest_res.rsrq; - float snr = ue_dl.chest_res.snr_db; - float rssi = srslte_vec_avg_power_cf(buffer[0], SRSLTE_SF_LEN_PRB(current_prb)); - - if (cnt == 0) { - mean_rsrp = rsrp; - mean_rsrq = rsrq; - mean_snr = snr; - mean_rssi = rssi; - } else { - mean_rsrp = SRSLTE_VEC_CMA(rsrp, mean_rsrp, cnt); - mean_rsrq = SRSLTE_VEC_CMA(rsrq, mean_rsrq, cnt); - mean_snr = SRSLTE_VEC_CMA(snr, mean_snr, cnt); - mean_rssi = SRSLTE_VEC_CMA(rssi, mean_rssi, cnt); - } - cnt++; - - log_h->debug("SYNC: Measuring RSRP %d/%d, sf_idx=%d, RSRP=%.1f dBm, SNR=%.1f dB\n", - cnt, nof_subframes, sf_idx, rsrp, snr); - - if (cnt >= nof_subframes) { - return MEASURE_OK; - } else { - return IDLE; - } -} - - - - - - -/********** - * Secondary cell receiver - */ - -void sync::scell_recv::init(srslte::log* log_h, bool sic_pss_enabled, uint32_t max_sf_window, phy_common* worker_com) -{ - this->log_h = log_h; - this->sic_pss_enabled = sic_pss_enabled; - - // and a separate ue_sync instance - - uint32_t max_fft_sz = srslte_symbol_sz(100); - uint32_t max_sf_size = SRSLTE_SF_LEN(max_fft_sz); - - sf_buffer[0] = (cf_t*) srslte_vec_malloc(sizeof(cf_t)*max_sf_size); - if (!sf_buffer[0]) { - ERROR("Error allocating %d samples for scell\n", max_sf_size); - return; - } - measure_p.init(sf_buffer, log_h, 1, worker_com, max_sf_window); - - //do this different we don't need all this search window. - if(srslte_sync_init(&sync_find, max_sf_window*max_sf_size, 5*max_sf_size, max_fft_sz)) { - ERROR("Error initiating sync_find\n"); - return; - } - srslte_sync_set_sss_algorithm(&sync_find, SSS_FULL); - srslte_sync_cp_en(&sync_find, false); - srslte_sync_set_cfo_pss_enable(&sync_find, true); - srslte_sync_set_threshold(&sync_find, 1.7); - srslte_sync_set_em_alpha(&sync_find, 0.3); - - // Configure FIND object behaviour (this configuration is always the same) - srslte_sync_set_cfo_ema_alpha(&sync_find, 1.0); - srslte_sync_set_cfo_i_enable(&sync_find, false); - srslte_sync_set_cfo_pss_enable(&sync_find, true); - srslte_sync_set_pss_filt_enable(&sync_find, true); - srslte_sync_set_sss_eq_enable(&sync_find, true); - - sync_find.pss.chest_on_filter = true; - sync_find.sss_channel_equalize = false; - - reset(); -} - -void sync::scell_recv::deinit() -{ - srslte_sync_free(&sync_find); - free(sf_buffer[0]); -} - -void sync::scell_recv::reset() -{ - current_fft_sz = 0; - measure_p.reset(); -} - -int sync::scell_recv::find_cells( - cf_t* input_buffer, float rx_gain_offset, srslte_cell_t cell, uint32_t nof_sf, cell_info_t cells[MAX_CELLS]) -{ - uint32_t fft_sz = srslte_symbol_sz(cell.nof_prb); - uint32_t sf_len = SRSLTE_SF_LEN(fft_sz); - - if (fft_sz != current_fft_sz) { - if (srslte_sync_resize(&sync_find, nof_sf*sf_len, 5*sf_len, fft_sz)) { - ERROR("Error resizing sync nof_sf=%d, sf_len=%d, fft_sz=%d\n", nof_sf, sf_len, fft_sz); - return SRSLTE_ERROR; - } - current_fft_sz = fft_sz; - } - - int nof_cells = 0; - uint32_t peak_idx = 0; - uint32_t sf_idx = 0; - int cell_id = 0; - - srslte_cell_t found_cell; - found_cell = cell; - - measure_p.set_rx_gain_offset(rx_gain_offset); - - for (uint32_t n_id_2=0;n_id_2<3;n_id_2++) { - - found_cell.id = 10000; - - if (n_id_2 != (cell.id%3) || sic_pss_enabled) { - srslte_sync_set_N_id_2(&sync_find, n_id_2); - - srslte_sync_find_ret_t sync_res; - - do { - srslte_sync_reset(&sync_find); - srslte_sync_cfo_reset(&sync_find); - - sync_res = SRSLTE_SYNC_NOFOUND; - cell_id = 0; - float max_peak = -1; - uint32_t max_sf5 = 0; - uint32_t max_sf_idx = 0; - - for (uint32_t sf5_cnt=0;sf5_cnt max_peak && sync_res == SRSLTE_SYNC_FOUND) { - max_sf5 = sf5_cnt; - max_sf_idx = srslte_sync_get_sf_idx(&sync_find); - cell_id = srslte_sync_get_cell_id(&sync_find); - } - } - - switch(sync_res) { - case SRSLTE_SYNC_ERROR: - return SRSLTE_ERROR; - ERROR("Error finding correlation peak\n"); - return SRSLTE_ERROR; - case SRSLTE_SYNC_FOUND: - - sf_idx = (10-max_sf_idx - 5*(max_sf5%2))%10; - - if (cell_id >= 0) { - // We found the same cell as before, look another N_id_2 - if ((uint32_t) cell_id == found_cell.id || (uint32_t) cell_id == cell.id) { - Debug("INTRA: n_id_2=%d, PCI=%d, found_cell.id=%d, cell.id=%d\n", n_id_2, cell_id, found_cell.id, cell.id); - sync_res = SRSLTE_SYNC_NOFOUND; - } else { - // We found a new cell ID - found_cell.id = cell_id; - found_cell.nof_ports = 1; // Use port 0 only for measurement - measure_p.set_cell(found_cell); - - // Correct CFO - /* - srslte_cfo_correct(&sync_find.cfo_corr_frame, - input_buffer, - input_cfo_corrected, - -srslte_sync_get_cfo(&sync_find)/sync_find.fft_size); - */ - - switch(measure_p.run_multiple_subframes(input_buffer, peak_idx, sf_idx, nof_sf)) - { - default: - // Consider a cell to be detectable 8.1.2.2.1.1 from 36.133. Currently only using first condition - if (measure_p.rsrp() > ABSOLUTE_RSRP_THRESHOLD_DBM) { - cells[nof_cells].pci = found_cell.id; - cells[nof_cells].rsrp = measure_p.rsrp(); - cells[nof_cells].rsrq = measure_p.rsrq(); - cells[nof_cells].offset = measure_p.frame_st_idx(); - - Info( - "INTRA: Found neighbour cell %d: PCI=%03d, RSRP=%5.1f dBm, peak_idx=%5d, peak_value=%3.2f, sf=%d, max_sf=%d, n_id_2=%d, CFO=%6.1f Hz\n", - nof_cells, cell_id, measure_p.rsrp(), measure_p.frame_st_idx(), sync_find.peak_value, - sf_idx, max_sf5, n_id_2, 15000 * srslte_sync_get_cfo(&sync_find)); - - nof_cells++; - - /* - if (sic_pss_enabled) { - srslte_pss_sic(&sync_find.pss, &input_buffer[sf5_cnt * 5 * sf_len + sf_len / 2 - fft_sz]); - }*/ - } else { - Info("INTRA: Found neighbour cell but RSRP=%.1f dBm is below threshold (%.1f dBm)\n", - measure_p.rsrp(), ABSOLUTE_RSRP_THRESHOLD_DBM); - } - break; - case measure::ERROR: - Error("INTRA: Measuring neighbour cell\n"); - return SRSLTE_ERROR; - } - } - } else { - sync_res = SRSLTE_SYNC_NOFOUND; - } - break; - case SRSLTE_SYNC_FOUND_NOSPACE: - /* If a peak was found but there is not enough space for SSS/CP detection, discard a few samples */ - break; - default: - break; - } - } while (sync_res == SRSLTE_SYNC_FOUND && sic_pss_enabled && nof_cells < MAX_CELLS); - } - } - return nof_cells; -} - - - /********** * PHY measurements * @@ -1669,159 +1287,4 @@ int sync::meas_stop(uint32_t earfcn, int pci) return -1; } -sync::intra_measure::intra_measure() : scell(), thread("SYNC_INTRA_MEASURE") -{ - - rrc = NULL; - common = NULL; - search_buffer = NULL; - log_h = NULL; - - current_earfcn = 0; - current_sflen = 0; - measure_tti = 0; - receive_cnt = 0; - - running = false; - receive_enabled = false; - receiving = false; - - ZERO_OBJECT(info); - ZERO_OBJECT(ring_buffer); - ZERO_OBJECT(primary_cell); -} - -sync::intra_measure::~intra_measure() -{ - srslte_ringbuffer_free(&ring_buffer); - scell.deinit(); - free(search_buffer); -} - -void sync::intra_measure::init(phy_common* common, rrc_interface_phy_lte* rrc, srslte::log* log_h) -{ - this->rrc = rrc; - this->log_h = log_h; - this->common = common; - receive_enabled = false; - - // Start scell - scell.init(log_h, common->args->sic_pss_enabled, common->args->intra_freq_meas_len_ms, common); - - search_buffer = (cf_t*) srslte_vec_malloc(common->args->intra_freq_meas_len_ms*SRSLTE_SF_LEN_PRB(SRSLTE_MAX_PRB)*sizeof(cf_t)); - - if (srslte_ringbuffer_init(&ring_buffer, sizeof(cf_t)*common->args->intra_freq_meas_len_ms*2*SRSLTE_SF_LEN_PRB(SRSLTE_MAX_PRB))) { - return; - } - - running = true; - start(INTRA_FREQ_MEAS_PRIO); -} - -void sync::intra_measure::stop() -{ - running = false; - srslte_ringbuffer_stop(&ring_buffer); - tti_sync.increase(); - wait_thread_finish(); -} - -void sync::intra_measure::set_primay_cell(uint32_t earfcn, srslte_cell_t cell) -{ - this->current_earfcn = earfcn; - current_sflen = SRSLTE_SF_LEN_PRB(cell.nof_prb); - this->primary_cell = cell; -} - -void sync::intra_measure::clear_cells() -{ - active_pci.clear(); - receive_enabled = false; - receiving = false; - receive_cnt = 0; - srslte_ringbuffer_reset(&ring_buffer); -} - -void sync::intra_measure::add_cell(int pci) -{ - if (std::find(active_pci.begin(), active_pci.end(), pci) == active_pci.end()) { - active_pci.push_back(pci); - receive_enabled = true; - Info("INTRA: Starting intra-frequency measurement for pci=%d\n", pci); - } else { - Debug("INTRA: Requested to start already existing intra-frequency measurement for PCI=%d\n", pci); - } -} - -int sync::intra_measure::get_offset(uint32_t pci) -{ - for (int i=0;i::iterator newEnd = std::remove(active_pci.begin(), active_pci.end(), pci); - - if (newEnd != active_pci.end()) { - active_pci.erase(newEnd, active_pci.end()); - if (active_pci.size() == 0) { - receive_enabled = false; - } - Info("INTRA: Stopping intra-frequency measurement for pci=%d. Number of cells: %zu\n", pci, active_pci.size()); - } else { - Warning("INTRA: Requested to stop non-existing intra-frequency measurement for PCI=%d\n", pci); - } -} - -void sync::intra_measure::write(uint32_t tti, cf_t* data, uint32_t nsamples) -{ - if (receive_enabled) { - if ((tti%common->args->intra_freq_meas_period_ms) == 0) { - receiving = true; - receive_cnt = 0; - measure_tti = tti; - srslte_ringbuffer_reset(&ring_buffer); - } - if (receiving == true) { - if (srslte_ringbuffer_write(&ring_buffer, data, nsamples*sizeof(cf_t)) < (int) (nsamples*sizeof(cf_t))) { - Warning("Error writting to ringbuffer\n"); - receiving = false; - } else { - receive_cnt++; - if (receive_cnt == common->args->intra_freq_meas_len_ms) { - tti_sync.increase(); - receiving = false; - } - } - } - } -} - -void sync::intra_measure::run_thread() -{ - while(running) { - if (running) { - tti_sync.wait(); - } - - if (running) { - - // Read data from buffer and find cells in it - srslte_ringbuffer_read(&ring_buffer, search_buffer, common->args->intra_freq_meas_len_ms*current_sflen*sizeof(cf_t)); - int found_cells = scell.find_cells(search_buffer, common->rx_gain_offset, primary_cell, common->args->intra_freq_meas_len_ms, info); - receiving = false; - - for (int i=0;inew_phy_meas(info[i].rsrp, info[i].rsrq, measure_tti, current_earfcn, info[i].pci); - } - // Look for other cells not found automatically - } - } -} - }