diff --git a/lib/include/srsran/asn1/rrc_nr_utils.h b/lib/include/srsran/asn1/rrc_nr_utils.h index 8c77e399d..98b3560ac 100644 --- a/lib/include/srsran/asn1/rrc_nr_utils.h +++ b/lib/include/srsran/asn1/rrc_nr_utils.h @@ -94,6 +94,7 @@ bool make_phy_tdd_cfg(const srsran_duplex_config_nr_t& srsran_duplex_config bool make_phy_harq_ack_cfg(const asn1::rrc_nr::phys_cell_group_cfg_s& phys_cell_group_cfg, srsran_harq_ack_cfg_hl_t* srsran_ue_dl_nr_harq_ack_cfg); bool make_phy_coreset_cfg(const asn1::rrc_nr::ctrl_res_set_s& ctrl_res_set, srsran_coreset_t* srsran_coreset); +void make_phy_search_space0_cfg(srsran_search_space_t* in_srsran_search_space); bool make_phy_search_space_cfg(const asn1::rrc_nr::search_space_s& search_space, srsran_search_space_t* srsran_search_space); bool make_phy_csi_report(const asn1::rrc_nr::csi_report_cfg_s& csi_report_cfg, diff --git a/lib/include/srsran/interfaces/ue_nr_interfaces.h b/lib/include/srsran/interfaces/ue_nr_interfaces.h index 8668ce183..c6dc69902 100644 --- a/lib/include/srsran/interfaces/ue_nr_interfaces.h +++ b/lib/include/srsran/interfaces/ue_nr_interfaces.h @@ -197,6 +197,9 @@ public: // RRC informs MAC about new UE identity for contention-free RA virtual bool set_crnti(const uint16_t crnti) = 0; + + // RRC informs MAC to start/stop search for BCCH messages + virtual void bcch_search(bool enabled) = 0; }; struct phy_args_nr_t { diff --git a/lib/src/asn1/rrc_nr_utils.cc b/lib/src/asn1/rrc_nr_utils.cc index f7affbe0e..a452e507a 100644 --- a/lib/src/asn1/rrc_nr_utils.cc +++ b/lib/src/asn1/rrc_nr_utils.cc @@ -503,6 +503,21 @@ bool make_phy_harq_ack_cfg(const phys_cell_group_cfg_s& phys_cell_group_cfg, return true; } +void make_phy_search_space0_cfg(srsran_search_space_t* in_srsran_search_space) +{ + in_srsran_search_space->id = 0; + in_srsran_search_space->coreset_id = 0; + in_srsran_search_space->type = srsran_search_space_type_common_0; + in_srsran_search_space->nof_candidates[0] = 0; + in_srsran_search_space->nof_candidates[1] = 0; + in_srsran_search_space->nof_candidates[2] = 4; + in_srsran_search_space->nof_candidates[3] = 2; + in_srsran_search_space->nof_candidates[4] = 0; + in_srsran_search_space->nof_formats = 1; + in_srsran_search_space->formats[0] = srsran_dci_format_nr_1_0; + in_srsran_search_space->duration = 1; +} + bool make_phy_search_space_cfg(const search_space_s& search_space, srsran_search_space_t* in_srsran_search_space) { srsran_search_space_t srsran_search_space = {}; diff --git a/srsue/hdr/stack/mac_nr/demux_nr.h b/srsue/hdr/stack/mac_nr/demux_nr.h index aae7259e1..fffb26181 100644 --- a/srsue/hdr/stack/mac_nr/demux_nr.h +++ b/srsue/hdr/stack/mac_nr/demux_nr.h @@ -40,6 +40,7 @@ public: void process_pdus(); /// Called by MAC to process received PDUs // HARQ interface + void push_bcch(srsran::unique_byte_buffer_t pdu); void push_pdu(srsran::unique_byte_buffer_t pdu, uint32_t tti); void push_pdu_temp_crnti(srsran::unique_byte_buffer_t pdu, uint32_t tti); uint64_t get_received_crueid(); @@ -55,6 +56,7 @@ private: ///< currently only DCH PDUs supported (add BCH, PCH, etc) srsran::block_queue pdu_queue; + srsran::block_queue bcch_queue; srsran::mac_sch_pdu_nr rx_pdu; srsran::mac_sch_pdu_nr rx_pdu_tcrnti; diff --git a/srsue/hdr/stack/mac_nr/mac_nr.h b/srsue/hdr/stack/mac_nr/mac_nr.h index c6189fe9c..7727337e4 100644 --- a/srsue/hdr/stack/mac_nr/mac_nr.h +++ b/srsue/hdr/stack/mac_nr/mac_nr.h @@ -109,6 +109,7 @@ public: /// RRC void rrc_ra_problem(); void rrc_ra_completed(); + void bcch_search(bool enabled); /// stack interface void process_pdus(); @@ -149,6 +150,9 @@ private: std::atomic started = {false}; + // Boolean to determine if need to decode SI-RNTI + bool search_bcch = false; + ue_rnti rntis; // thread-safe helper to store RNTIs, contention ID, etc bool contention_res_successful; diff --git a/srsue/hdr/stack/mac_nr/mac_nr_interfaces.h b/srsue/hdr/stack/mac_nr/mac_nr_interfaces.h index b894e6509..997b38d49 100644 --- a/srsue/hdr/stack/mac_nr/mac_nr_interfaces.h +++ b/srsue/hdr/stack/mac_nr/mac_nr_interfaces.h @@ -93,6 +93,7 @@ class demux_interface_harq_nr { public: /// Inform demux unit about a newly decoded TB. + virtual void push_bcch(srsran::unique_byte_buffer_t pdu) = 0; virtual void push_pdu(srsran::unique_byte_buffer_t pdu, uint32_t tti) = 0; virtual void push_pdu_temp_crnti(srsran::unique_byte_buffer_t pdu, uint32_t tti) = 0; virtual uint64_t get_received_crueid() = 0; diff --git a/srsue/hdr/stack/rrc_nr/rrc_nr_procedures.h b/srsue/hdr/stack/rrc_nr/rrc_nr_procedures.h index c70dcb3d9..00ed72c15 100644 --- a/srsue/hdr/stack/rrc_nr/rrc_nr_procedures.h +++ b/srsue/hdr/stack/rrc_nr/rrc_nr_procedures.h @@ -25,7 +25,7 @@ namespace srsue { class rrc_nr::cell_selection_proc { public: - enum class state_t { phy_cell_search, phy_cell_select }; + enum class state_t { phy_cell_search, phy_cell_select, sib_acquire }; using cell_selection_complete_ev = srsran::proc_result_t; explicit cell_selection_proc(rrc_nr& parent_); @@ -33,6 +33,7 @@ public: srsran::proc_outcome_t step(); srsran::proc_outcome_t react(const rrc_interface_phy_nr::cell_search_result_t& event); srsran::proc_outcome_t react(const rrc_interface_phy_nr::cell_select_result_t& event); + srsran::proc_outcome_t react(const bool sib1_found); void then(const cell_selection_complete_ev& proc_result) const; diff --git a/srsue/src/phy/nr/cc_worker.cc b/srsue/src/phy/nr/cc_worker.cc index 99ee6f95b..d1139b7fc 100644 --- a/srsue/src/phy/nr/cc_worker.cc +++ b/srsue/src/phy/nr/cc_worker.cc @@ -396,6 +396,7 @@ bool cc_worker::measure_csi() logger.error("PBCH-MIB: NR SFN (%d) does not match current SFN (%d)", mib.sfn, dl_slot_cfg.idx / SRSRAN_NSLOTS_PER_FRAME_NR(cfg.carrier.scs)); + dl_slot_cfg.idx = mib.sfn * SRSRAN_NSLOTS_PER_FRAME_NR(cfg.carrier.scs); } // Log MIB information diff --git a/srsue/src/stack/mac_nr/demux_nr.cc b/srsue/src/stack/mac_nr/demux_nr.cc index a7e5d754a..394854f16 100644 --- a/srsue/src/stack/mac_nr/demux_nr.cc +++ b/srsue/src/stack/mac_nr/demux_nr.cc @@ -38,6 +38,11 @@ void demux_nr::push_pdu(srsran::unique_byte_buffer_t pdu, uint32_t tti) pdu_queue.push(std::move(pdu)); } +void demux_nr::push_bcch(srsran::unique_byte_buffer_t pdu) +{ + bcch_queue.push(std::move(pdu)); +} + /* Demultiplexing of MAC PDU associated with a Temporal C-RNTI. The PDU will * remain in buffer until demultiplex_pending_pdu() is called. * This features is provided to enable the Random Access Procedure to decide @@ -55,6 +60,13 @@ void demux_nr::push_pdu_temp_crnti(srsran::unique_byte_buffer_t pdu, uint32_t tt void demux_nr::process_pdus() { + // Handle first BCCH + while (not bcch_queue.empty()) { + srsran::unique_byte_buffer_t pdu = bcch_queue.wait_pop(); + logger.debug(pdu->msg, pdu->N_bytes, "Handling MAC BCCH PDU (%d B)", pdu->N_bytes); + rlc->write_pdu_bcch_dlsch(pdu->msg, pdu->N_bytes); + } + // Then user PDUs while (not pdu_queue.empty()) { srsran::unique_byte_buffer_t pdu = pdu_queue.wait_pop(); handle_pdu(rx_pdu, std::move(pdu)); diff --git a/srsue/src/stack/mac_nr/dl_harq_nr.cc b/srsue/src/stack/mac_nr/dl_harq_nr.cc index 377269057..68f077fc9 100644 --- a/srsue/src/stack/mac_nr/dl_harq_nr.cc +++ b/srsue/src/stack/mac_nr/dl_harq_nr.cc @@ -229,8 +229,7 @@ void dl_harq_entity_nr::dl_harq_process_nr::tb_decoded(const mac_nr_grant_dl_t& if (acked and result.payload != nullptr) { if (is_bcch) { - logger.warning("Delivering PDU=%d bytes to Dissassemble and Demux unit (BCCH) not implemented", grant.tbs); - reset(); + harq_entity->demux_unit->push_bcch(std::move(result.payload)); } else { if (grant.rnti == harq_entity->mac->get_temp_crnti()) { logger.debug("Delivering PDU=%d bytes to Dissassemble and Demux unit (Temporal C-RNTI) not implemented", diff --git a/srsue/src/stack/mac_nr/mac_nr.cc b/srsue/src/stack/mac_nr/mac_nr.cc index a69a7fad2..d050649b4 100644 --- a/srsue/src/stack/mac_nr/mac_nr.cc +++ b/srsue/src/stack/mac_nr/mac_nr.cc @@ -158,8 +158,7 @@ mac_interface_phy_nr::sched_rnti_t mac_nr::get_ul_sched_rnti_nr(const uint32_t t bool mac_nr::is_si_opportunity() { - // TODO: ask RRC if we need SI - return false; + return search_bcch; } bool mac_nr::is_paging_opportunity() @@ -447,6 +446,11 @@ void mac_nr::set_contention_id(uint64_t ue_identity) rntis.set_contention_id(ue_identity); } +void mac_nr::bcch_search(bool enabled) +{ + search_bcch = enabled; +} + bool mac_nr::set_crnti(const uint16_t c_rnti_) { if (is_valid_crnti(c_rnti_)) { diff --git a/srsue/src/stack/rrc_nr/rrc_nr.cc b/srsue/src/stack/rrc_nr/rrc_nr.cc index b4a9744f2..e8b762e36 100644 --- a/srsue/src/stack/rrc_nr/rrc_nr.cc +++ b/srsue/src/stack/rrc_nr/rrc_nr.cc @@ -391,6 +391,11 @@ void rrc_nr::set_phy_default_config() void rrc_nr::handle_sib1(const sib1_s& sib1) { + if (meas_cells.serving_cell().has_sib1()) { + logger.info("SIB1 already processed"); + return; + } + meas_cells.serving_cell().set_sib1(sib1); logger.info("SIB1 received, CellID=%d", meas_cells.serving_cell().get_cell_id() & 0xfff); @@ -486,6 +491,9 @@ void rrc_nr::handle_sib1(const sib1_s& sib1) logger.warning("Could not set phy config."); return; } + + // Notify cell selector of successful SIB1 reception + cell_selector.trigger(true); } void rrc_nr::write_pdu_pcch(srsran::unique_byte_buffer_t pdu) {} diff --git a/srsue/src/stack/rrc_nr/rrc_nr_procedures.cc b/srsue/src/stack/rrc_nr/rrc_nr_procedures.cc index 8b90b007f..3ee274a3d 100644 --- a/srsue/src/stack/rrc_nr/rrc_nr_procedures.cc +++ b/srsue/src/stack/rrc_nr/rrc_nr_procedures.cc @@ -384,12 +384,12 @@ proc_outcome_t rrc_nr::cell_selection_proc::init() return proc_outcome_t::yield; } -// Skipping SI acquisition procedure proc_outcome_t rrc_nr::cell_selection_proc::step() { switch (state) { case state_t::phy_cell_search: case state_t::phy_cell_select: + case state_t::sib_acquire: // Waits for cell select/search to complete return proc_outcome_t::yield; } @@ -400,84 +400,97 @@ proc_outcome_t rrc_nr::cell_selection_proc::step() proc_outcome_t rrc_nr::cell_selection_proc::handle_cell_search_result(const rrc_interface_phy_nr::cell_search_result_t& result) { - if (result.cell_found) { - // Convert Cell measurement in Text - std::array csi_info_str = {}; - srsran_csi_meas_info_short(&result.measurements, csi_info_str.data(), (uint32_t)csi_info_str.size()); - - // Unpack MIB and convert to text - srsran_mib_nr_t mib = {}; - std::array mib_info_str = {}; - if (srsran_pbch_msg_nr_mib_unpack(&result.pbch_msg, &mib) == SRSASN_SUCCESS) { - // Convert to text - srsran_pbch_msg_nr_mib_info(&mib, mib_info_str.data(), (uint32_t)mib_info_str.size()); - } else { - // It could be the PBCH does not carry MIB - strcpy(mib_info_str.data(), "No MIB found"); - } - - // Logs the PCI, cell measurements and decoded MIB - Info("Cell search found ARFCN=%d PCI=%d %s %s", - result.ssb_arfcn, - result.pci, - csi_info_str.data(), - mib_info_str.data()); - - // Transition to cell selection ignoring the cell search result - state = state_t::phy_cell_select; - - // until cell selection is done, update PHY config to take the last found PCI - rrc_handle.phy_cfg.carrier.pci = result.pci; - - phy_interface_rrc_nr::cell_select_args_t cs_args = {}; - cs_args.carrier = rrc_handle.phy_cfg.carrier; - cs_args.ssb_cfg = rrc_handle.phy_cfg.get_ssb_cfg(); - - { - // Coreset0 configuration - srsran::phy_cfg_nr_t& phy_cfg = rrc_handle.phy_cfg; - - // Get pointA and SSB absolute frequencies - double pointA_abs_freq_Hz = - phy_cfg.carrier.dl_center_frequency_hz - - phy_cfg.carrier.nof_prb * SRSRAN_NRE * SRSRAN_SUBC_SPACING_NR(phy_cfg.carrier.scs) / 2; - double ssb_abs_freq_Hz = phy_cfg.carrier.ssb_center_freq_hz; - // Calculate integer SSB to pointA frequency offset in Hz - uint32_t ssb_pointA_freq_offset_Hz = - (ssb_abs_freq_Hz > pointA_abs_freq_Hz) ? (uint32_t)(ssb_abs_freq_Hz - pointA_abs_freq_Hz) : 0; - - if (srsran_coreset_zero(phy_cfg.carrier.pci, - ssb_pointA_freq_offset_Hz, - phy_cfg.ssb.scs, - phy_cfg.carrier.scs, - 6, - &phy_cfg.pdcch.coreset[0])) { - fprintf(stderr, "Error generating coreset0\n"); - } - phy_cfg.pdcch.coreset_present[0] = true; - } - - // Until SI acquisition is implemented, provide hard-coded SIB for now - uint8_t msg[] = {0x74, 0x81, 0x01, 0x70, 0x10, 0x40, 0x04, 0x02, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x33, 0x60, 0x38, - 0x05, 0x01, 0x00, 0x40, 0x1a, 0x00, 0x00, 0x06, 0x6c, 0x6d, 0x92, 0x21, 0xf3, 0x70, 0x40, 0x20, - 0x00, 0x00, 0x80, 0x80, 0x00, 0x41, 0x06, 0x80, 0xa0, 0x90, 0x9c, 0x20, 0x08, 0x55, 0x19, 0x40, - 0x00, 0x00, 0x33, 0xa1, 0xc6, 0xd9, 0x22, 0x40, 0x00, 0x00, 0x20, 0xb8, 0x94, 0x63, 0xc0, 0x09, - 0x28, 0x44, 0x1b, 0x7e, 0xad, 0x8e, 0x1d, 0x00, 0x9e, 0x2d, 0xa3, 0x0a}; - srsran::unique_byte_buffer_t pdu = srsran::make_byte_buffer(); - memcpy(pdu->msg, msg, sizeof(msg)); - pdu->N_bytes = sizeof(msg); - rrc_handle.write_pdu_bcch_dlsch(std::move(pdu)); - - if (not rrc_handle.phy->start_cell_select(cs_args)) { - Error("Could not set start cell search."); - return proc_outcome_t::error; - } - return proc_outcome_t::yield; - } else { + if (!result.cell_found) { Info("Cell search did not find any cell."); + return proc_outcome_t::error; } - return proc_outcome_t::error; + // Convert Cell measurement in Text + std::array csi_info_str = {}; + srsran_csi_meas_info_short(&result.measurements, csi_info_str.data(), (uint32_t)csi_info_str.size()); + + // Unpack MIB and convert to text + srsran_mib_nr_t mib = {}; + std::array mib_info_str = {}; + if (srsran_pbch_msg_nr_mib_unpack(&result.pbch_msg, &mib) == SRSASN_SUCCESS) { + // Convert to text + srsran_pbch_msg_nr_mib_info(&mib, mib_info_str.data(), (uint32_t)mib_info_str.size()); + } else { + // It could be the PBCH does not carry MIB + strcpy(mib_info_str.data(), "No MIB found"); + Error("No MIB found\n"); + return proc_outcome_t::error; + } + + // Check unsupported settings + if (mib.cell_barred) { + Error("Cell barred"); + return proc_outcome_t::error; + } + if (mib.scs_common != srsran_subcarrier_spacing_15kHz) { + Error("Unsupported SCS %s", srsran_subcarrier_spacing_to_str(mib.scs_common)); + return proc_outcome_t::error; + } + // TODO: calculate SSB offset + if (mib.ssb_offset != 6) { + Error("Unsupported SSB offset %d", mib.ssb_offset); + return proc_outcome_t::error; + } + + // Logs the PCI, cell measurements and decoded MIB + Info("Cell search found ARFCN=%d PCI=%d %s %s", + result.ssb_arfcn, + result.pci, + csi_info_str.data(), + mib_info_str.data()); + + // Apply MIB settings + srsran::phy_cfg_nr_t& phy_cfg = rrc_handle.phy_cfg; + phy_cfg.pdsch.typeA_pos = mib.dmrs_typeA_pos; + phy_cfg.pdsch.scs_cfg = mib.scs_common; + phy_cfg.carrier.pci = result.pci; + + // Get pointA and SSB absolute frequencies + double pointA_abs_freq_Hz = phy_cfg.carrier.dl_center_frequency_hz - + phy_cfg.carrier.nof_prb * SRSRAN_NRE * SRSRAN_SUBC_SPACING_NR(phy_cfg.carrier.scs) / 2; + double ssb_abs_freq_Hz = phy_cfg.carrier.ssb_center_freq_hz; + // Calculate integer SSB to pointA frequency offset in Hz + uint32_t ssb_pointA_freq_offset_Hz = + (ssb_abs_freq_Hz > pointA_abs_freq_Hz) ? (uint32_t)(ssb_abs_freq_Hz - pointA_abs_freq_Hz) : 0; + + // Create coreset0 + if (srsran_coreset_zero(phy_cfg.carrier.pci, + ssb_pointA_freq_offset_Hz, + phy_cfg.ssb.scs, + phy_cfg.carrier.scs, + mib.coreset0_idx, + &phy_cfg.pdcch.coreset[0])) { + Error("Error generating coreset0"); + return proc_outcome_t::error; + } + phy_cfg.pdcch.coreset_present[0] = true; + + // Create SearchSpace0 + make_phy_search_space0_cfg(&phy_cfg.pdcch.search_space[0]); + phy_cfg.pdcch.search_space_present[0] = true; + + // Update PHY configuration + if (not rrc_handle.phy->set_config(phy_cfg)) { + Error("Setting PHY configuration"); + return proc_outcome_t::error; + } + + phy_interface_rrc_nr::cell_select_args_t cs_args = {}; + cs_args.carrier = rrc_handle.phy_cfg.carrier; + cs_args.ssb_cfg = rrc_handle.phy_cfg.get_ssb_cfg(); + + // Transition to cell selection ignoring the cell search result + state = state_t::phy_cell_select; + if (not rrc_handle.phy->start_cell_select(cs_args)) { + Error("Could not set start cell search."); + return proc_outcome_t::error; + } + return proc_outcome_t::yield; } proc_outcome_t rrc_nr::cell_selection_proc::react(const rrc_interface_phy_nr::cell_select_result_t& event) @@ -497,7 +510,24 @@ proc_outcome_t rrc_nr::cell_selection_proc::react(const rrc_interface_phy_nr::ce rrc_search_result = rrc_nr::rrc_cell_search_result_t::same_cell; // PHY is now camping on serving cell - Info("Cell search completed."); + Info("Cell selection completed. Starting SIB1 acquisition"); + + // Transition to cell selection ignoring the cell search result + state = state_t::sib_acquire; + rrc_handle.mac->bcch_search(true); + return proc_outcome_t::yield; +} + +proc_outcome_t rrc_nr::cell_selection_proc::react(const bool sib1_found) +{ + if (state != state_t::sib_acquire) { + Warning("Received unexpected cell select result"); + return proc_outcome_t::yield; + } + + Info("SIB1 acquired successfully"); + rrc_handle.mac->bcch_search(false); + return proc_outcome_t::success; } diff --git a/srsue/src/stack/rrc_nr/test/ue_rrc_nr_test.cc b/srsue/src/stack/rrc_nr/test/ue_rrc_nr_test.cc index d06597c68..68fd9e178 100644 --- a/srsue/src/stack/rrc_nr/test/ue_rrc_nr_test.cc +++ b/srsue/src/stack/rrc_nr/test/ue_rrc_nr_test.cc @@ -41,6 +41,7 @@ class dummy_mac : public mac_interface_rrc_nr int add_tag_config(const srsran::tag_cfg_nr_t& tag_cfg) { return SRSRAN_SUCCESS; } int set_config(const srsran::phr_cfg_nr_t& phr_cfg) { return SRSRAN_SUCCESS; } int remove_tag_config(const uint32_t tag_id) { return SRSRAN_SUCCESS; } + void bcch_search(bool) {} void start_ra_procedure() {}