diff --git a/lib/include/srsran/interfaces/ue_nr_interfaces.h b/lib/include/srsran/interfaces/ue_nr_interfaces.h index 0ffdf884f..fa86613f4 100644 --- a/lib/include/srsran/interfaces/ue_nr_interfaces.h +++ b/lib/include/srsran/interfaces/ue_nr_interfaces.h @@ -93,6 +93,14 @@ public: * @param ul_carrier_id The UL carrier used for Msg1 transmission (0 for NUL carrier, and 1 for SUL carrier). */ virtual void prach_sent(uint32_t tti, uint32_t s_id, uint32_t t_id, uint32_t f_id, uint32_t ul_carrier_id) = 0; + + /** + * @brief Indicate a valid SR transmission occasion on the valid PUCCH resource for SR configured; and the SR + * transmission occasion does not overlap with a measurement gap; and the PUCCH resource for the SR transmission + * occasion does not overlap with a UL-SCH resource; + * @param tti The TTI from the PHY viewpoint at which the SR occasion was sent over-the-air (not to the radio). + */ + virtual bool sr_opportunity(uint32_t tti, uint32_t sr_id, bool meas_gap, bool ul_sch_tx) = 0; }; class mac_interface_rrc_nr @@ -163,8 +171,17 @@ public: const float preamble_received_target_power, const float ta_base_sec = 0.0f) = 0; - /// Instruct PHY to transmit SR for a given identifier - virtual void sr_send(uint32_t sr_id) = 0; + /** + * @brief Query PHY if there is a valid PUCCH SR resource configured for a given SR identifier + * @param sr_id SR identifier + * @return True if there is a valid PUCCH resource configured + */ + virtual bool has_valid_sr_resource(uint32_t sr_id) = 0; + + /** + * @brief Clear any configured downlink assignments and uplink grants + */ + virtual void clear_pending_grants() = 0; }; class phy_interface_rrc_nr diff --git a/srsue/hdr/phy/nr/state.h b/srsue/hdr/phy/nr/state.h index 90a70fd42..3144298d7 100644 --- a/srsue/hdr/phy/nr/state.h +++ b/srsue/hdr/phy/nr/state.h @@ -259,7 +259,26 @@ public: void reset() { pending_sr_id.clear(); } - void set_pending_sr(uint32_t value) { pending_sr_id.insert(value); } + bool has_valid_sr_resource(uint32_t sr_id) + { + for (const srsran_pucch_nr_sr_resource_t& r : cfg.pucch.sr_resources) { + if (r.configured && r.sr_id == sr_id) { + return true; + } + } + return false; + } + + void clear_pending_grants() + { + // Scope mutex to protect read/write the list + std::lock_guard lock(pending_ul_grant_mutex); + + // Clear all PDSCH assignments and PUSCH grants + pending_dl_grant = {}; + pending_ul_grant = {}; + pending_ack = {}; + } void get_pending_sr(const uint32_t& tti, srsran_uci_data_nr_t& uci_data) { diff --git a/srsue/hdr/phy/nr/worker_pool.h b/srsue/hdr/phy/nr/worker_pool.h index 55eb3f9c3..7f435ceba 100644 --- a/srsue/hdr/phy/nr/worker_pool.h +++ b/srsue/hdr/phy/nr/worker_pool.h @@ -40,7 +40,8 @@ public: void send_prach(uint32_t prach_occasion, uint32_t preamble_index, int preamble_received_target_power); int set_ul_grant(std::array array, uint16_t rnti, srsran_rnti_type_t rnti_type); bool set_config(const srsran::phy_cfg_nr_t& cfg); - void sr_send(uint32_t sr_id); + bool has_valid_sr_resource(uint32_t sr_id); + void clear_pending_grants(); }; } // namespace nr diff --git a/srsue/hdr/phy/phy.h b/srsue/hdr/phy/phy.h index a7643929d..3632073da 100644 --- a/srsue/hdr/phy/phy.h +++ b/srsue/hdr/phy/phy.h @@ -176,7 +176,8 @@ public: const float ta_base_sec = 0.0f) final; int tx_request(const tx_request_t& request) final; void set_earfcn(std::vector earfcns) final; - void sr_send(uint32_t sr_id) final; + bool has_valid_sr_resource(uint32_t sr_id) final; + void clear_pending_grants() final; private: void run_thread() final; diff --git a/srsue/hdr/phy/vnf_phy_nr.h b/srsue/hdr/phy/vnf_phy_nr.h index c81f667f4..fd685264d 100644 --- a/srsue/hdr/phy/vnf_phy_nr.h +++ b/srsue/hdr/phy/vnf_phy_nr.h @@ -57,7 +57,8 @@ public: const int prach_occasion, const float target_power_dbm, const float ta_base_sec = 0.0f) override{}; - void sr_send(uint32_t sr_id) override; + bool has_valid_sr_resource(uint32_t sr_id) override; + void clear_pending_grants() override; private: std::unique_ptr vnf; diff --git a/srsue/hdr/stack/mac_nr/mac_nr.h b/srsue/hdr/stack/mac_nr/mac_nr.h index cb58f5d04..d5ea4e899 100644 --- a/srsue/hdr/stack/mac_nr/mac_nr.h +++ b/srsue/hdr/stack/mac_nr/mac_nr.h @@ -29,8 +29,7 @@ namespace srsue { class rlc_interface_mac; -struct mac_nr_args_t { -}; +struct mac_nr_args_t {}; class mac_nr final : public mac_interface_phy_nr, public mac_interface_rrc_nr, @@ -63,6 +62,7 @@ public: const uint32_t t_id, const uint32_t f_id, const uint32_t ul_carrier_id); + bool sr_opportunity(uint32_t tti, uint32_t sr_id, bool meas_gap, bool ul_sch_tx); /// Stack interface void timer_expired(uint32_t timer_id); @@ -92,10 +92,6 @@ public: static bool is_in_window(uint32_t tti, int* start, int* len); - // PHY Interface - void prach_sent(const uint32_t tti); - void tb_decoded_ok(const uint8_t cc_idx, const uint32_t tti); - private: void write_pcap(const uint32_t cc_idx, mac_nr_grant_dl_t& grant); // If PCAPs are enabled for this MAC void handle_pdu(srsran::unique_byte_buffer_t pdu); @@ -107,8 +103,8 @@ private: bool is_si_opportunity(); bool is_paging_opportunity(); - bool has_crnti(); - bool is_valid_crnti(const uint16_t crnti); + bool has_crnti(); + bool is_valid_crnti(const uint16_t crnti); /// Interaction with rest of the stack phy_interface_mac_nr* phy = nullptr; @@ -135,8 +131,8 @@ private: /// Tx buffer srsran::unique_byte_buffer_t ul_harq_buffer = nullptr; // store PDU generated from MUX - srsran::unique_byte_buffer_t rlc_buffer = nullptr; - srsran_softbuffer_tx_t softbuffer_tx = {}; /// UL HARQ (temporal) + srsran::unique_byte_buffer_t rlc_buffer = nullptr; + srsran_softbuffer_tx_t softbuffer_tx = {}; /// UL HARQ (temporal) srsran::task_multiqueue::queue_handle stack_task_dispatch_queue; diff --git a/srsue/hdr/stack/mac_nr/proc_sr_nr.h b/srsue/hdr/stack/mac_nr/proc_sr_nr.h index 12dee8275..e88bc1165 100644 --- a/srsue/hdr/stack/mac_nr/proc_sr_nr.h +++ b/srsue/hdr/stack/mac_nr/proc_sr_nr.h @@ -35,10 +35,9 @@ public: int32_t set_config(const srsran::sr_cfg_nr_t& cfg); void reset(); void start(); + bool sr_opportunity(uint32_t tti, uint32_t sr_id, bool meas_gap, bool ul_sch_tx); private: - bool need_tx(uint32_t tti); - int sr_counter = 0; bool is_pending_sr = 0; diff --git a/srsue/hdr/stack/ue_stack_lte.h b/srsue/hdr/stack/ue_stack_lte.h index c0778aa1f..8ab5b03be 100644 --- a/srsue/hdr/stack/ue_stack_lte.h +++ b/srsue/hdr/stack/ue_stack_lte.h @@ -143,6 +143,11 @@ public: mac_nr.prach_sent(tti, s_id, t_id, f_id, ul_carrier_id); } + bool sr_opportunity(uint32_t tti, uint32_t sr_id, bool meas_gap, bool ul_sch_tx) final + { + return mac_nr.sr_opportunity(tti, sr_id, meas_gap, ul_sch_tx); + } + // Interface for GW void write_sdu(uint32_t lcid, srsran::unique_byte_buffer_t sdu) final; diff --git a/srsue/hdr/stack/ue_stack_nr.h b/srsue/hdr/stack/ue_stack_nr.h index 093f6d1cf..84e10467c 100644 --- a/srsue/hdr/stack/ue_stack_nr.h +++ b/srsue/hdr/stack/ue_stack_nr.h @@ -89,6 +89,10 @@ public: { mac->prach_sent(tti, s_id, t_id, f_id, ul_carrier_id); } + bool sr_opportunity(uint32_t tti, uint32_t sr_id, bool meas_gap, bool ul_sch_tx) + { + return mac->sr_opportunity(tti, sr_id, meas_gap, ul_sch_tx); + } // Interface for GW void write_sdu(uint32_t lcid, srsran::unique_byte_buffer_t sdu) final; diff --git a/srsue/src/phy/nr/worker_pool.cc b/srsue/src/phy/nr/worker_pool.cc index 7bf9c7c3e..606153250 100644 --- a/srsue/src/phy/nr/worker_pool.cc +++ b/srsue/src/phy/nr/worker_pool.cc @@ -134,9 +134,15 @@ bool worker_pool::set_config(const srsran::phy_cfg_nr_t& cfg) return true; } -void worker_pool::sr_send(uint32_t sr_id) +bool worker_pool::has_valid_sr_resource(uint32_t sr_id) { - phy_state.set_pending_sr(sr_id); + return phy_state.has_valid_sr_resource(sr_id); } + +void worker_pool::clear_pending_grants() +{ + phy_state.clear_pending_grants(); +} + } // namespace nr } // namespace srsue diff --git a/srsue/src/phy/phy.cc b/srsue/src/phy/phy.cc index b5e3449cc..e7c5454f5 100644 --- a/srsue/src/phy/phy.cc +++ b/srsue/src/phy/phy.cc @@ -621,8 +621,14 @@ bool phy::set_config(const srsran::phy_cfg_nr_t& cfg) return nr_workers.set_config(cfg); } -void phy::sr_send(uint32_t sr_id) +bool phy::has_valid_sr_resource(uint32_t sr_id) { - nr_workers.sr_send(sr_id); + return nr_workers.has_valid_sr_resource(sr_id); } + +void phy::clear_pending_grants() +{ + nr_workers.clear_pending_grants(); +} + } // namespace srsue diff --git a/srsue/src/phy/vnf_phy_nr.cc b/srsue/src/phy/vnf_phy_nr.cc index 81ef31ea3..b19e2ce4d 100644 --- a/srsue/src/phy/vnf_phy_nr.cc +++ b/srsue/src/phy/vnf_phy_nr.cc @@ -72,6 +72,11 @@ bool vnf_phy_nr::set_config(const srsran::phy_cfg_nr_t& cfg) { return false; } -void vnf_phy_nr::sr_send(uint32_t sr_id) {} +bool vnf_phy_nr::has_valid_sr_resource(uint32_t sr_id) +{ + return false; +} + +void vnf_phy_nr::clear_pending_grants() {} } // namespace srsue \ No newline at end of file diff --git a/srsue/src/stack/mac_nr/mac_nr.cc b/srsue/src/stack/mac_nr/mac_nr.cc index d752af8c0..d2a96bb71 100644 --- a/srsue/src/stack/mac_nr/mac_nr.cc +++ b/srsue/src/stack/mac_nr/mac_nr.cc @@ -181,6 +181,11 @@ void mac_nr::prach_sent(const uint32_t tti, proc_ra.prach_sent(tti, s_id, t_id, f_id, ul_carrier_id); } +bool mac_nr::sr_opportunity(uint32_t tti, uint32_t sr_id, bool meas_gap, bool ul_sch_tx) +{ + return proc_sr.sr_opportunity(tti, sr_id, meas_gap, ul_sch_tx); +} + // This function handles all PCAP writing for a decoded DL TB void mac_nr::write_pcap(const uint32_t cc_idx, mac_nr_grant_dl_t& grant) { diff --git a/srsue/src/stack/mac_nr/proc_sr_nr.cc b/srsue/src/stack/mac_nr/proc_sr_nr.cc index e40e1a8ac..7a1f8921f 100644 --- a/srsue/src/stack/mac_nr/proc_sr_nr.cc +++ b/srsue/src/stack/mac_nr/proc_sr_nr.cc @@ -35,19 +35,6 @@ void proc_sr_nr::reset() is_pending_sr = false; } -bool proc_sr_nr::need_tx(uint32_t tti) -{ - int last_tx_tti = 0; // FIXME: phy->sr_last_tx_tti(); - logger.debug("SR: need_tx(): last_tx_tti=%d, tti=%d", last_tx_tti, tti); - if (last_tx_tti >= 0) { - // TODO: implement prohibit timer - if (TTI_SUB(last_tx_tti, tti) >= 8) { - return true; - } - } - return false; -} - int32_t proc_sr_nr::set_config(const srsran::sr_cfg_nr_t& cfg_) { // disable by default @@ -80,38 +67,81 @@ int32_t proc_sr_nr::set_config(const srsran::sr_cfg_nr_t& cfg_) void proc_sr_nr::step(uint32_t tti) { - if (initiated) { - if (is_pending_sr) { - if (cfg.enabled) { - if (sr_counter < cfg.item[0].trans_max) { - if (sr_counter == 0 || need_tx(tti)) { - sr_counter++; - logger.info("SR: Signalling PHY sr_counter=%d", sr_counter); - phy->sr_send(0); // @xavierarteaga what is the ID you expect here? - } - } else { - if (need_tx(tti)) { - logger.info("SR: Releasing PUCCH/SRS resources, sr_counter=%d, sr-TransMax=%d", - sr_counter, - cfg.item[0].trans_max); - srsran::console("Scheduling request failed: releasing RRC connection...\n"); - rrc->release_pucch_srs(); - // TODO: - // - clear any configured downlink assignments and uplink grants; - // - clear any PUSCH resources for semi-persistent CSI reporting; - ra->start_by_mac(); - reset(); - } - } - } else { - logger.info("SR: PUCCH not configured. Starting RA procedure"); - ra->start_by_mac(); - reset(); - } - } + if (!initiated) { + return; + } + + // As long as at least one SR is pending, the MAC entity shall for each pending SR: + if (!is_pending_sr) { + return; + } + + // 1> if the MAC entity has no valid PUCCH resource configured for the pending SR: + if (!cfg.enabled || not phy->has_valid_sr_resource(0)) { + // 2> initiate a Random Access procedure (see clause 5.1) on the SpCell and cancel the pending SR. + logger.info("SR: PUCCH not configured. Starting RA procedure"); + ra->start_by_mac(); + reset(); + return; + } + + // Handle + if (sr_counter >= cfg.item[0].trans_max) { + logger.info( + "SR: Releasing PUCCH/SRS resources, sr_counter=%d, sr-TransMax=%d", sr_counter, cfg.item[0].trans_max); + srsran::console("Scheduling request failed: releasing RRC connection...\n"); + rrc->release_pucch_srs(); + + // 4> clear any configured downlink assignments and uplink grants; + phy->clear_pending_grants(); + + // 4> clear any PUSCH resources for semi-persistent CSI reporting; + // ... TODO + + ra->start_by_mac(); + reset(); } } +bool proc_sr_nr::sr_opportunity(uint32_t tti, uint32_t sr_id, bool meas_gap, bool ul_sch_tx) +{ + // 2> when the MAC entity has an SR transmission occasion on the valid PUCCH resource for SR configured; and + if (!initiated || !cfg.enabled || !is_pending_sr) { + return false; + } + + // 2> if sr-ProhibitTimer is not running at the time of the SR transmission occasion; and + // ... TODO + + // 2> if the PUCCH resource for the SR transmission occasion does not overlap with a measurement gap; and + if (meas_gap) { + return false; + } + + // 2> if the PUCCH resource for the SR transmission occasion does not overlap with a UL-SCH resource: + if (ul_sch_tx) { + return false; + } + + // 3> if SR_COUNTER < sr-TransMax: + if (sr_counter < cfg.item[0].trans_max) { // + // 4> increment SR_COUNTER by 1; + sr_counter += 1; + + // 4> start the sr-ProhibitTimer. + // ... TODO + + // 4> instruct the physical layer to signal the SR on one valid PUCCH resource for SR; + logger.info("SR: Signalling PHY sr_counter=%d", sr_counter); + return true; + } + + // 3> else: + // step will execute + + return false; +} + void proc_sr_nr::start() { if (initiated) { diff --git a/srsue/test/mac_nr/mac_nr_test.cc b/srsue/test/mac_nr/mac_nr_test.cc index 55ac58980..de8dc5f63 100644 --- a/srsue/test/mac_nr/mac_nr_test.cc +++ b/srsue/test/mac_nr/mac_nr_test.cc @@ -47,7 +47,8 @@ public: *preamble_index_ = preamble_index; *preamble_received_target_power_ = preamble_received_target_power; } - void sr_send(uint32_t sr_id) override {} + bool has_valid_sr_resource(uint32_t sr_id) override { return false; } + void clear_pending_grants() override {} private: uint32_t prach_occasion = 0; diff --git a/srsue/test/mac_nr/proc_ra_nr_test.cc b/srsue/test/mac_nr/proc_ra_nr_test.cc index 96b6fd409..9f7bf79fb 100644 --- a/srsue/test/mac_nr/proc_ra_nr_test.cc +++ b/srsue/test/mac_nr/proc_ra_nr_test.cc @@ -41,7 +41,8 @@ public: *preamble_index_ = preamble_index; *preamble_received_target_power_ = preamble_received_target_power; } - void sr_send(uint32_t sr_id) override {} + bool has_valid_sr_resource(uint32_t sr_id) override { return false; } + void clear_pending_grants() override {} private: uint32_t prach_occasion = 0;