diff --git a/cmake/modules/FindSKIQ.cmake b/cmake/modules/FindSKIQ.cmake index 9835842fe..74bf873ea 100644 --- a/cmake/modules/FindSKIQ.cmake +++ b/cmake/modules/FindSKIQ.cmake @@ -66,7 +66,18 @@ FIND_LIBRARY( /usr/local/lib32 ) -set(SKIQ_LIBRARIES ${SKIQ_LIBRARY} ${SKIQ_LIBRARY_GLIB} ${SKIQ_LIBRARY_USB}) +FIND_LIBRARY( + SKIQ_LIBRARY_TIRPC + NAMES libtirpc.so.3 + PATHS /usr/local/lib + /usr/lib64 + /usr/lib/epiq + /usr/lib/x86_64-linux-gnu + /usr/local/lib64 + /usr/local/lib32 +) + +set(SKIQ_LIBRARIES ${SKIQ_LIBRARY} ${SKIQ_LIBRARY_GLIB} ${SKIQ_LIBRARY_USB} ${SKIQ_LIBRARY_TIRPC}) message(STATUS "SKIQ LIBRARIES " ${SKIQ_LIBRARIES}) message(STATUS "SKIQ INCLUDE DIRS " ${SKIQ_INCLUDE_DIRS}) diff --git a/lib/include/srsran/common/nas_pcap.h b/lib/include/srsran/common/nas_pcap.h index 3bec3e3ef..c9cefe4f7 100644 --- a/lib/include/srsran/common/nas_pcap.h +++ b/lib/include/srsran/common/nas_pcap.h @@ -31,22 +31,17 @@ namespace srsran { class nas_pcap { public: - nas_pcap() - { - enable_write = false; - ue_id = 0; - pcap_file = NULL; - } + nas_pcap(); void enable(); uint32_t open(std::string filename_, uint32_t ue_id = 0, srsran_rat_t rat_type = srsran_rat_t::lte); void close(); void write_nas(uint8_t* pdu, uint32_t pdu_len_bytes); private: - bool enable_write; + bool enable_write = false; std::string filename; - FILE* pcap_file; - uint32_t ue_id; + FILE* pcap_file = nullptr; + uint32_t ue_id = 0; void pack_and_write(uint8_t* pdu, uint32_t pdu_len_bytes); }; diff --git a/lib/include/srsran/interfaces/ue_phy_interfaces.h b/lib/include/srsran/interfaces/ue_phy_interfaces.h index 23f915bf9..6cb3a6463 100644 --- a/lib/include/srsran/interfaces/ue_phy_interfaces.h +++ b/lib/include/srsran/interfaces/ue_phy_interfaces.h @@ -45,6 +45,7 @@ struct phy_args_t { std::map ul_earfcn_map; // Map linking DL EARFCN and UL EARFCN int force_N_id_2 = -1; // Cell identity within the identity group (PSS) to filter. + int force_N_id_1 = -1; // Cell identity group (SSS) to filter. float dl_freq = -1.0f; float ul_freq = -1.0f; diff --git a/lib/src/common/nas_pcap.cc b/lib/src/common/nas_pcap.cc index 6c2031b86..fc94f901c 100644 --- a/lib/src/common/nas_pcap.cc +++ b/lib/src/common/nas_pcap.cc @@ -22,10 +22,22 @@ #include "srsran/common/nas_pcap.h" #include "srsran/common/pcap.h" #include "srsran/srsran.h" +#include "srsran/support/emergency_handlers.h" #include namespace srsran { +/// Try to flush the contents of the pcap class before the application is killed. +static void emergency_cleanup_handler(void* data) +{ + reinterpret_cast(data)->close(); +} + +nas_pcap::nas_pcap() +{ + add_emergency_cleanup_handler(emergency_cleanup_handler, this); +} + void nas_pcap::enable() { enable_write = true; @@ -51,6 +63,7 @@ void nas_pcap::close() { fprintf(stdout, "Saving NAS PCAP file (DLT=%d) to %s \n", NAS_LTE_DLT, filename.c_str()); DLT_PCAP_Close(pcap_file); + pcap_file = nullptr; } void nas_pcap::write_nas(uint8_t* pdu, uint32_t pdu_len_bytes) diff --git a/lib/src/phy/rf/rf_uhd_imp.cc b/lib/src/phy/rf/rf_uhd_imp.cc index d0d232be6..4530d4db9 100644 --- a/lib/src/phy/rf/rf_uhd_imp.cc +++ b/lib/src/phy/rf/rf_uhd_imp.cc @@ -150,6 +150,7 @@ struct rf_uhd_handler_t { uint32_t nof_tx_channels = 0; std::array tx_freq = {}; std::array rx_freq = {}; + double cur_rx_gain_ch0 = 0; std::mutex tx_gain_mutex; std::array, SRSRAN_MAX_CHANNELS> tx_gain_db = {}; @@ -1111,6 +1112,9 @@ int rf_uhd_set_rx_gain_ch(void* h, uint32_t ch, double gain) if (handler->uhd->set_rx_gain(ch, gain) != UHD_ERROR_NONE) { return SRSRAN_ERROR; } + if (ch == 0) { + handler->cur_rx_gain_ch0 = gain; + } return SRSRAN_SUCCESS; } @@ -1155,13 +1159,7 @@ int rf_uhd_set_tx_gain_ch(void* h, uint32_t ch, double gain) double rf_uhd_get_rx_gain(void* h) { rf_uhd_handler_t* handler = (rf_uhd_handler_t*)h; - double gain = 0.0; - - if (handler->uhd->get_rx_gain(gain) != UHD_ERROR_NONE) { - return SRSRAN_ERROR; - } - - return gain; + return handler->cur_rx_gain_ch0; } double rf_uhd_get_tx_gain(void* h) diff --git a/lib/src/phy/sync/sync.c b/lib/src/phy/sync/sync.c index 022185cb1..c80163c25 100644 --- a/lib/src/phy/sync/sync.c +++ b/lib/src/phy/sync/sync.c @@ -330,7 +330,7 @@ int srsran_sync_set_N_id_1(srsran_sync_t* q, uint32_t N_id_1) generate_freq_sss(q, N_id_1); return SRSRAN_SUCCESS; } else { - ERROR("Invalid N_id_2=%d", N_id_1); + ERROR("Invalid N_id_1=%d", N_id_1); return SRSRAN_ERROR_INVALID_INPUTS; } } diff --git a/lib/src/phy/ue/test/CMakeLists.txt b/lib/src/phy/ue/test/CMakeLists.txt index 3a3d53804..48327a4b9 100644 --- a/lib/src/phy/ue/test/CMakeLists.txt +++ b/lib/src/phy/ue/test/CMakeLists.txt @@ -69,4 +69,5 @@ endforeach () #add_test(ue_dl_nr_pci500_rb52_n4_ra_L2_ncce0 ue_dl_nr_file_test -f ${CMAKE_CURRENT_SOURCE_DIR}/ue_dl_nr_pci500_rb52_n4_ra_L2_ncce0.dat -i 1 -P 52 -n 4 -R 7f) add_test(ue_dl_nr_pci500_rb52_si_coreset0_idx6 ue_dl_nr_file_test -f ${CMAKE_CURRENT_SOURCE_DIR}/ue_dl_nr_pci500_rb52_si_coreset0_idx6_s15.36e6.dat -S -i 500 -P 52 -n 0 -R ffff -T si -c 6 -s common0 -A 368500 -a 368410) #add_test(ue_dl_nr_pci500_rb52_si_coreset0_idx7 ue_dl_nr_file_test -f ${CMAKE_CURRENT_SOURCE_DIR}/ue_dl_nr_pci500_rb52_si_coreset0_idx7_s15.36e6.dat -S -i 500 -P 52 -n 0 -R ffff -T si -c 7 -s common0 -A 161200 -a 161290) -#add_test(ue_dl_nr_pci500_rb52_pdsch ue_dl_nr_file_test -f ${CMAKE_CURRENT_SOURCE_DIR}/ue_dl_nr_pci500_rb52_rnti0x100_s15.36e6.dat -S -i 500 -P 52 -n 0 -R ffff -T si -o 2 -s common3) \ No newline at end of file +#add_test(ue_dl_nr_pci500_rb52_pdsch ue_dl_nr_file_test -f ${CMAKE_CURRENT_SOURCE_DIR}/ue_dl_nr_pci500_rb52_rnti0x100_s15.36e6.dat -S -i 500 -P 52 -n 0 -R ffff -T si -o 2 -s common3) +add_test(ue_dl_nr_pci500_rb52_rar ue_dl_nr_file_test -f ${CMAKE_CURRENT_SOURCE_DIR}/ue_dl_nr_pci500_rb52_rar_s15.36e6.dat -i 500 -P 52 -n 5 -R f -T ra -c 6 -S -s common1 -A 368500 -a 368410) diff --git a/lib/src/phy/ue/test/ue_dl_nr_file_test.cc b/lib/src/phy/ue/test/ue_dl_nr_file_test.cc index 8ad1db77b..1889179a1 100644 --- a/lib/src/phy/ue/test/ue_dl_nr_file_test.cc +++ b/lib/src/phy/ue/test/ue_dl_nr_file_test.cc @@ -203,6 +203,13 @@ static int work_ue_dl(srsran_ue_dl_nr_t* ue_dl, srsran_slot_cfg_t* slot) // Convert DCI to PDSCH transmission srsran_sch_cfg_nr_t pdsch_cfg = {}; + if (rnti_type == srsran_rnti_type_ra) { + pdsch_hl_cfg.common_time_ra[0].k = 0; + pdsch_hl_cfg.common_time_ra[0].mapping_type = srsran_sch_mapping_type_A; + pdsch_hl_cfg.common_time_ra[0].sliv = + srsran_ra_type2_to_riv(SRSRAN_NSYMB_PER_SLOT_NR - 1, 1, SRSRAN_NSYMB_PER_SLOT_NR); + pdsch_hl_cfg.nof_common_time_ra = 1; + } if (srsran_ra_dl_dci_to_grant_nr(&carrier, slot, &pdsch_hl_cfg, &dci_dl_rx, &pdsch_cfg, &pdsch_cfg.grant) < SRSRAN_SUCCESS) { ERROR("Error decoding PDSCH search"); @@ -323,7 +330,7 @@ int main(int argc, char** argv) srsran_coreset_t* coreset = NULL; // Configure CORESET - if (rnti_type == srsran_rnti_type_si) { + if (rnti_type == srsran_rnti_type_si || rnti_type == srsran_rnti_type_ra) { // configure to use coreset0 coreset = &pdcch_cfg.coreset[0]; pdcch_cfg.coreset_present[0] = true; @@ -355,7 +362,7 @@ int main(int argc, char** argv) pdsch_hl_cfg.typeA_pos = srsran_dmrs_sch_typeA_pos_2; // set coreset0 bandwidth - dci_cfg.coreset0_bw = srsran_coreset_get_bw(coreset); + dci_cfg.coreset0_bw = srsran_coreset_get_bw(coreset); } else { // configure to use coreset1 coreset = &pdcch_cfg.coreset[1]; @@ -377,7 +384,7 @@ int main(int argc, char** argv) srsran_search_space_t* search_space = &pdcch_cfg.search_space[0]; pdcch_cfg.search_space_present[0] = true; search_space->id = 0; - search_space->coreset_id = (rnti_type == srsran_rnti_type_si) ? 0 : 1; + search_space->coreset_id = (rnti_type == srsran_rnti_type_si || rnti_type == srsran_rnti_type_ra) ? 0 : 1; search_space->type = ss_type; search_space->formats[0] = srsran_dci_format_nr_0_0; search_space->formats[1] = srsran_dci_format_nr_1_0; diff --git a/lib/src/phy/ue/test/ue_dl_nr_pci500_rb52_rar_s15.36e6.dat b/lib/src/phy/ue/test/ue_dl_nr_pci500_rb52_rar_s15.36e6.dat new file mode 100644 index 000000000..3b96f8307 Binary files /dev/null and b/lib/src/phy/ue/test/ue_dl_nr_pci500_rb52_rar_s15.36e6.dat differ diff --git a/srsenb/hdr/stack/upper/gtpu.h b/srsenb/hdr/stack/upper/gtpu.h index b25d1ad34..10072dafb 100644 --- a/srsenb/hdr/stack/upper/gtpu.h +++ b/srsenb/hdr/stack/upper/gtpu.h @@ -58,7 +58,7 @@ class gtpu_tunnel_manager public: // A UE should have <= 3 DRBs active, and each DRB should have two tunnels active at the same time at most - const static size_t MAX_TUNNELS_PER_UE = 6; + const static size_t MAX_TUNNELS_PER_UE = 10; enum class tunnel_state { pdcp_active, buffering, forward_to, forwarded_from, inactive }; diff --git a/srsue/hdr/phy/phy.h b/srsue/hdr/phy/phy.h index dc78705ad..19b5c6aa3 100644 --- a/srsue/hdr/phy/phy.h +++ b/srsue/hdr/phy/phy.h @@ -199,6 +199,9 @@ private: // Tracks the current selected cell (last call to cell_select) srsran_cell_t selected_cell = {}; + // Tracks the current selected EARFCN (last call to cell_select) + uint32_t selected_earfcn = 0; + static void set_default_args(phy_args_t& args); bool check_args(const phy_args_t& args); }; diff --git a/srsue/hdr/phy/phy_common.h b/srsue/hdr/phy/phy_common.h index 4d83ce738..51d0dd250 100644 --- a/srsue/hdr/phy/phy_common.h +++ b/srsue/hdr/phy/phy_common.h @@ -333,7 +333,9 @@ private: std::array avg_rsrp_neigh = {}; static constexpr uint32_t pcell_report_period = 20; - uint32_t rssi_read_cnt = 0; + + static constexpr uint32_t update_rxgain_period = 10; + uint32_t update_rxgain_cnt = 0; rsrp_insync_itf* insync_itf = nullptr; diff --git a/srsue/hdr/phy/search.h b/srsue/hdr/phy/search.h index b065e36cc..c3602d26b 100644 --- a/srsue/hdr/phy/search.h +++ b/srsue/hdr/phy/search.h @@ -45,7 +45,7 @@ public: explicit search(srslog::basic_logger& logger) : logger(logger) {} ~search(); - void init(srsran::rf_buffer_t& buffer_, uint32_t nof_rx_channels, search_callback* parent, int force_N_id_2_); + void init(srsran::rf_buffer_t& buffer_, uint32_t nof_rx_channels, search_callback* parent, int force_N_id_2_, int force_N_id_1_); void reset(); float get_last_cfo(); void set_agc_enable(bool enable); @@ -59,6 +59,7 @@ private: srsran_ue_cellsearch_t cs = {}; srsran_ue_mib_sync_t ue_mib_sync = {}; int force_N_id_2 = 0; + int force_N_id_1 = 0; }; }; // namespace srsue diff --git a/srsue/src/main.cc b/srsue/src/main.cc index 8310219cd..8a5b6e3e2 100644 --- a/srsue/src/main.cc +++ b/srsue/src/main.cc @@ -418,6 +418,10 @@ static int parse_args(all_args_t* args, int argc, char* argv[]) bpo::value(&args->phy.force_N_id_2)->default_value(-1), "Force using a specific PSS (set to -1 to allow all PSSs).") + ("phy.force_N_id_1", + bpo::value(&args->phy.force_N_id_1)->default_value(-1), + "Force using a specific SSS (set to -1 to allow all SSSs).") + // PHY NR args ("phy.nr.store_pdsch_ko", bpo::value(&args->phy.nr_store_pdsch_ko)->default_value(false), diff --git a/srsue/src/phy/phy.cc b/srsue/src/phy/phy.cc index 1c99219f7..5e6133200 100644 --- a/srsue/src/phy/phy.cc +++ b/srsue/src/phy/phy.cc @@ -253,8 +253,7 @@ void phy::set_cells_to_meas(uint32_t earfcn, const std::set& pci) // measurements to avoid a concurrency issue cmd_worker.add_cmd([this, earfcn, pci]() { // Check if the EARFCN matches with serving cell - uint32_t pcell_earfcn = 0; - sfsync.get_current_cell(nullptr, &pcell_earfcn); + uint32_t pcell_earfcn = selected_earfcn; bool available = (pcell_earfcn == earfcn); // Find if there is secondary serving cell configured with the specified EARFCN @@ -312,6 +311,10 @@ bool phy::cell_select(phy_cell_t cell) // Indicate workers that cell selection is in progress common.cell_is_selecting = true; + // Update EARCN before starting the background task to make sure is taken into account when finding carriers to + // measure inter-frequency neighbours (see set_cells_to_meas) + selected_earfcn = cell.earfcn; + cmd_worker_cell.add_cmd([this, cell]() { // Wait SYNC transitions to IDLE sfsync.wait_idle(); diff --git a/srsue/src/phy/phy_common.cc b/srsue/src/phy/phy_common.cc index 6dd982892..a48d580a8 100644 --- a/srsue/src/phy/phy_common.cc +++ b/srsue/src/phy/phy_common.cc @@ -682,9 +682,9 @@ void phy_common::update_measurements(uint32_t cc_idx, return; } - // Only worker 0 reads the RSSI sensor + // Only worker 0 updates RX gain offset every 10 ms if (rssi_power_buffer) { - if (!rssi_read_cnt) { + if (!update_rxgain_cnt) { // Average RSSI over all symbols in antenna port 0 (make sure SF length is non-zero) float rssi_dbm = SRSRAN_SF_LEN_PRB(cell.nof_prb) > 0 ? (srsran_convert_power_to_dB( @@ -697,9 +697,9 @@ void phy_common::update_measurements(uint32_t cc_idx, rx_gain_offset = get_radio()->get_rx_gain() + args->rx_gain_offset; } - rssi_read_cnt++; - if (rssi_read_cnt >= 1000) { - rssi_read_cnt = 0; + update_rxgain_cnt++; + if (update_rxgain_cnt >= update_rxgain_period) { + update_rxgain_cnt = 0; } } diff --git a/srsue/src/phy/search.cc b/srsue/src/phy/search.cc index 32006da29..f12edb2e0 100644 --- a/srsue/src/phy/search.cc +++ b/srsue/src/phy/search.cc @@ -55,7 +55,7 @@ search::~search() srsran_ue_cellsearch_free(&cs); } -void search::init(srsran::rf_buffer_t& buffer_, uint32_t nof_rx_channels, search_callback* parent, int force_N_id_2_) +void search::init(srsran::rf_buffer_t& buffer_, uint32_t nof_rx_channels, search_callback* parent, int force_N_id_2_, int force_N_id_1_) { p = parent; @@ -74,6 +74,7 @@ void search::init(srsran::rf_buffer_t& buffer_, uint32_t nof_rx_channels, search p->set_ue_sync_opts(&cs.ue_sync, 0); force_N_id_2 = force_N_id_2_; + force_N_id_1 = force_N_id_1_; } void search::set_cp_en(bool enable) @@ -120,7 +121,7 @@ search::ret_code search::run(srsran_cell_t* cell_, std::array= 0 && force_N_id_2 < 3) { + if (force_N_id_2 >= 0 && force_N_id_2 < SRSRAN_NOF_NID_2) { ret = srsran_ue_cellsearch_scan_N_id_2(&cs, force_N_id_2, &found_cells[force_N_id_2]); max_peak_cell = force_N_id_2; } else { @@ -134,6 +135,38 @@ search::ret_code search::run(srsran_cell_t* cell_, std::array= 0 && force_N_id_1 < SRSRAN_NOF_NID_1) { + /* Note that srsran_ue_cellsearch_scan_N_id_2 only finds the strongest cell for a given N_id_2/PSS within the search + * window. A cell with the desired SSS can be occluded by other cells with the same PSS, if their PSS is stronger and + * within the same search window. + */ + bool N_id_1_found = false; + if (force_N_id_2 >= 0 && force_N_id_2 < SRSRAN_NOF_NID_2) { + // N_id_2 (PSS) was forced, so there is only one search result to check + if (found_cells[max_peak_cell].cell_id / SRSRAN_NOF_NID_2 == (uint32_t)force_N_id_1) { + N_id_1_found = true; + } + } else { + // Go through the results for all N_id_2 (PSS); pick strongest with matching N_id_1 (SSS) + float max_peak_value = -1.0; + for (uint32_t N_id_2 = 0; N_id_2 < SRSRAN_NOF_NID_2; N_id_2++) { + if (found_cells[N_id_2].cell_id / SRSRAN_NOF_NID_2 == (uint32_t)force_N_id_1) { + if (found_cells[N_id_2].peak > max_peak_value) { + N_id_1_found = true; + max_peak_value = found_cells[N_id_2].peak; + max_peak_cell = N_id_2; + } + } + } + } + if (!N_id_1_found) { + Info("SYNC: Could not find any cell with preselected SSS (force_N_id_1=%d)", force_N_id_1); + return CELL_NOT_FOUND; + } + } + // Save result new_cell.id = found_cells[max_peak_cell].cell_id; new_cell.cp = found_cells[max_peak_cell].cp; @@ -203,4 +236,4 @@ search::ret_code search::run(srsran_cell_t* cell_, std::arrayargs->force_N_id_2); + search_p.init(sf_buffer, nof_rf_channels, this, worker_com->args->force_N_id_2, worker_com->args->force_N_id_1); search_p.set_cp_en(worker_com->args->detect_cp); // Initialize SFN synchronizer, it uses only pcell buffer sfn_p.init(&ue_sync, worker_com->args, sf_buffer, sf_buffer.size()); diff --git a/srsue/src/stack/rrc/rrc_procedures.cc b/srsue/src/stack/rrc/rrc_procedures.cc index 677c4aefc..0749c8fe9 100644 --- a/srsue/src/stack/rrc/rrc_procedures.cc +++ b/srsue/src/stack/rrc/rrc_procedures.cc @@ -1744,12 +1744,6 @@ srsran::proc_outcome_t rrc::ho_proc::init(const asn1::rrc::rrc_conn_recfg_s& rrc // perform the measurement related actions as specified in 5.5.6.1; rrc_ptr->measurements->ho_reest_actions(ho_src_cell.earfcn, target_earfcn); - // if the RRCConnectionReconfiguration message includes the measConfig: - if (not rrc_ptr->measurements->parse_meas_config(&recfg_r8, true, ho_src_cell.earfcn)) { - Error("Parsing measurementConfig. TODO: Send ReconfigurationReject"); - return proc_outcome_t::yield; // wait for t304 expiry - } - // Note: We delay the enqueuing of RRC Reconf Complete message to avoid that the message goes in an UL grant // directed at the old RNTI. rrc_ptr->task_sched.defer_callback(4, [this]() { @@ -1785,6 +1779,12 @@ srsran::proc_outcome_t rrc::ho_proc::react(ra_completed_ev ev) if (ev.success) { Info("Random Access completed. Applying final configuration and finishing procedure"); + // if the RRCConnectionReconfiguration message includes the measConfig: + if (not rrc_ptr->measurements->parse_meas_config(&recfg_r8, true, ho_src_cell.earfcn)) { + Error("Parsing measurementConfig. TODO: Send ReconfigurationReject"); + return proc_outcome_t::yield; // wait for t304 expiry + } + // TS 36.331, sec. 5.3.5.4, last "1>" rrc_ptr->t304.stop(); rrc_ptr->apply_rr_config_dedicated_on_ho_complete(recfg_r8.rr_cfg_ded); diff --git a/srsue/ue.conf.example b/srsue/ue.conf.example index 67ad68634..59f36dacd 100644 --- a/srsue/ue.conf.example +++ b/srsue/ue.conf.example @@ -343,6 +343,9 @@ enable = false # nof_in_sync_events: Number of PHY in-sync events before sending an in-sync event to RRC # nof_out_of_sync_events: Number of PHY out-sync events before sending an out-sync event to RRC # +# force_N_id_2: Force using a specific PSS (set to -1 to allow all PSSs). +# force_N_id_1: Force using a specific SSS (set to -1 to allow all SSSs). +# ##################################################################### [phy] #rx_gain_offset = 62 @@ -374,6 +377,9 @@ enable = false #nof_in_sync_events = 10 #nof_out_of_sync_events = 20 +#force_N_id_2 = 1 +#force_N_id_1 = 10 + ##################################################################### # PHY NR specific configuration options #