diff --git a/lib/include/srslte/interfaces/rrc_nr_interface_types.h b/lib/include/srslte/interfaces/rrc_nr_interface_types.h index aeca76ead..f2781f548 100644 --- a/lib/include/srslte/interfaces/rrc_nr_interface_types.h +++ b/lib/include/srslte/interfaces/rrc_nr_interface_types.h @@ -498,6 +498,13 @@ struct phy_cfg_nr_t { // nrofSymbols: 14 // startingSymbolIndex: 0 // timeDomainOCC: 2 + pucch.sr_resources[1].resource.format = SRSLTE_PUCCH_NR_FORMAT_1; + pucch.sr_resources[1].resource.starting_prb = 0; + pucch.sr_resources[1].resource.initial_cyclic_shift = 8; + pucch.sr_resources[1].resource.nof_symbols = 14; + pucch.sr_resources[1].resource.start_symbol_idx = 0; + pucch.sr_resources[1].resource.time_domain_occ = 2; + // Item 17 // PUCCH-Resource // pucch-ResourceId: 17 @@ -529,6 +536,10 @@ struct phy_cfg_nr_t { // periodicityAndOffset: sl40 (10) // sl40: 8 // resource: 16 + pucch.sr_resources[1].sr_id = 0; + pucch.sr_resources[1].period = 40; + pucch.sr_resources[1].offset = 8; + pucch.sr_resources[1].configured = true; // dl-DataToUL-ACK: 7 items // Item 0 diff --git a/lib/include/srslte/interfaces/ue_nr_interfaces.h b/lib/include/srslte/interfaces/ue_nr_interfaces.h index 1324f7b69..a5285afcf 100644 --- a/lib/include/srslte/interfaces/ue_nr_interfaces.h +++ b/lib/include/srslte/interfaces/ue_nr_interfaces.h @@ -17,6 +17,7 @@ #include "srslte/interfaces/mac_interface_types.h" #include "srslte/interfaces/rrc_nr_interface_types.h" #include +#include #include namespace srsue { @@ -120,6 +121,7 @@ struct phy_args_nr_t { srslte::phy_log_args_t log; srslte_ue_dl_nr_args_t dl; srslte_ue_ul_nr_args_t ul; + std::set fixed_sr; phy_args_nr_t() { @@ -131,6 +133,8 @@ struct phy_args_nr_t { ul.nof_max_prb = 100; ul.pusch.measure_time = true; ul.pusch.sch.disable_simd = false; + + // fixed_sr.insert(0); // Enable SR_id = 0 by default for testing purposes } }; @@ -156,6 +160,9 @@ public: const int preamble_index, 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; }; class phy_interface_rrc_nr diff --git a/lib/include/srslte/phy/phch/pucch_cfg_nr.h b/lib/include/srslte/phy/phch/pucch_cfg_nr.h index 68a234d64..7ce80551e 100644 --- a/lib/include/srslte/phy/phch/pucch_cfg_nr.h +++ b/lib/include/srslte/phy/phch/pucch_cfg_nr.h @@ -77,6 +77,11 @@ */ #define SRSLTE_PUCCH_NR_MAX_NOF_SETS 4 +/** + * Maximum number of SR resources (TS 38.331 maxNrofSR-Resources) + */ +#define SRSLTE_PUCCH_MAX_NOF_SR_RESOURCES 8 + typedef enum SRSLTE_API { SRSLTE_PUCCH_NR_FORMAT_0 = 0, SRSLTE_PUCCH_NR_FORMAT_1, @@ -142,10 +147,24 @@ typedef struct SRSLTE_API { uint32_t max_payload_size; ///< Maximum payload size, set to 0 if not present } srslte_pucch_nr_resource_set_t; +/** + * @brief Scheduling Request resource described in TS 38.331 SchedulingRequestResourceConfig + * @note Every SR configuration corresponds to one or more logical channels (resources) + */ +typedef struct SRSLTE_API { + uint32_t sr_id; ///< Scheduling Request identifier + uint32_t period; ///< Period in slots + uint32_t offset; ///< Offset from beginning of the period in slots + srslte_pucch_nr_resource_t resource; ///< PUCCH resource + bool configured; ///< Set to true if higher layers added this value, otherwise set to false +} srslte_pucch_nr_sr_resource_t; + typedef struct SRSLTE_API { srslte_pucch_nr_common_cfg_t common; ///< NR-PUCCH configuration common for all formats and resources srslte_pucch_nr_resource_set_t sets[SRSLTE_PUCCH_NR_MAX_NOF_SETS]; ///< Resource sets, indexed by pucch-ResourceSetId bool enabled; ///< Set to true if any set is enabled + srslte_pucch_nr_sr_resource_t + sr_resources[SRSLTE_PUCCH_MAX_NOF_SR_RESOURCES]; ///< SR resources, indexed by identifier } srslte_pucch_nr_hl_cfg_t; /** diff --git a/lib/include/srslte/phy/phch/uci_cfg_nr.h b/lib/include/srslte/phy/phch/uci_cfg_nr.h index 28919b913..e0526040b 100644 --- a/lib/include/srslte/phy/phch/uci_cfg_nr.h +++ b/lib/include/srslte/phy/phch/uci_cfg_nr.h @@ -50,19 +50,20 @@ */ typedef struct SRSLTE_API { /// Common Parameters - uint32_t o_ack; ///< Number of HARQ-ACK bits - uint32_t o_sr; ///< Number of SR bits - uint32_t o_csi1; ///< Number of CSI1 report number of bits - uint32_t o_csi2; ///< Number of CSI2 report number of bits + uint32_t o_ack; ///< Number of HARQ-ACK bits + uint32_t o_sr; ///< Number of SR bits + uint32_t o_csi1; ///< Number of CSI1 report number of bits + uint32_t o_csi2; ///< Number of CSI2 report number of bits /// PUSCH only parameters srslte_mod_t modulation; ///< Modulation /// PUCCH only parameters - uint16_t rnti; ///< RNTI - uint32_t pucch_resource_id; ///< PUCCH resource indicator field in the DCI format 1_0 or DCI format 1_1 - uint32_t n_cce_0; ///< index of a first CCE for the PDCCH reception - uint32_t N_cce; ///< number of CCEs in a CORESET of a PDCCH reception with DCI format 1_0 or DCI format 1_1 + uint16_t rnti; ///< RNTI + uint32_t pucch_resource_id; ///< PUCCH resource indicator field in the DCI format 1_0 or DCI format 1_1 + uint32_t n_cce_0; ///< index of a first CCE for the PDCCH reception + uint32_t N_cce; ///< number of CCEs in a CORESET of a PDCCH reception with DCI format 1_0 or 1_1 + uint32_t sr_resource_id; ///< Scheduling request resource identifier, only valid if o_sr > 0 } srslte_uci_cfg_nr_t; /** diff --git a/lib/include/srslte/phy/ue/ue_ul_nr.h b/lib/include/srslte/phy/ue/ue_ul_nr.h index d5f592ed5..8de5865de 100644 --- a/lib/include/srslte/phy/ue/ue_ul_nr.h +++ b/lib/include/srslte/phy/ue/ue_ul_nr.h @@ -75,4 +75,23 @@ SRSLTE_API int srslte_ue_ul_nr_pucch_info(const srslte_pucch_nr_resource_t* reso char* str, uint32_t str_len); +/** + * @brief Decides whether the provided slot index within the radio frame is a SR transmission opportunity + * + * @remark Implemented according to TS 38.213 9.2.4 UE procedure for reporting SR + * + * @param sr_resources Provides the SR configuration from the upper layers + * @param slot_idx Slot index in the radio frame + * @param sr_id Scheduling Request logic channel identifier + * @param[out] sr_resource_id Optional SR resource index (or identifier) + * + * @return 1 if the provided slot index is a SR transmission opportunity, SRSLTE_SUCCESS if it is not an SR transmission + * opportunity, SRSLTE_ERROR code if provided parameters are invalid + */ +SRSLTE_API int +srslte_ue_ul_nr_sr_send_slot(const srslte_pucch_nr_sr_resource_t sr_resources[SRSLTE_PUCCH_MAX_NOF_SR_RESOURCES], + uint32_t slot_idx, + uint32_t sr_id, + uint32_t* sr_resource_id); + #endif // SRSLTE_UE_UL_DATA_H diff --git a/lib/src/phy/phch/ra_ul_nr.c b/lib/src/phy/phch/ra_ul_nr.c index 3bc453717..65cfa5117 100644 --- a/lib/src/phy/phch/ra_ul_nr.c +++ b/lib/src/phy/phch/ra_ul_nr.c @@ -450,12 +450,32 @@ int srslte_ra_ul_nr_pucch_resource(const srslte_pucch_nr_hl_cfg_t* pucch_cfg, const srslte_uci_cfg_nr_t* uci_cfg, srslte_pucch_nr_resource_t* resource) { - if (pucch_cfg == NULL || uci_cfg == NULL) { + if (pucch_cfg == NULL || uci_cfg == NULL || resource == NULL) { return SRSLTE_ERROR_INVALID_INPUTS; } uint32_t O_uci = srslte_uci_nr_total_bits(uci_cfg); + // Scheduling request has preference see 9.2.5.1 UE procedure for multiplexing HARQ-ACK or CSI and SR in a PUCCH + if (uci_cfg->o_sr > 0) { + uint32_t sr_resource_id = uci_cfg->sr_resource_id; + if (sr_resource_id >= SRSLTE_PUCCH_MAX_NOF_SR_RESOURCES) { + ERROR("SR resource ID (%d) exceeds the maximum ID (%d)", sr_resource_id, SRSLTE_PUCCH_MAX_NOF_SR_RESOURCES); + return SRSLTE_ERROR; + } + + if (!pucch_cfg->sr_resources[sr_resource_id].configured) { + ERROR("SR resource ID (%d) is not configured", sr_resource_id); + return SRSLTE_ERROR; + } + + // Set PUCCH resource + *resource = pucch_cfg->sr_resources[sr_resource_id].resource; + + // No more logic is required in this case + return SRSLTE_SUCCESS; + } + // If a UE does not have dedicated PUCCH resource configuration, provided by PUCCH-ResourceSet in PUCCH-Config, // a PUCCH resource set is provided by pucch-ResourceCommon through an index to a row of Table 9.2.1-1 for size // transmission of HARQ-ACK information on PUCCH in an initial UL BWP of N BWP PRBs. diff --git a/lib/src/phy/ue/ue_ul_nr.c b/lib/src/phy/ue/ue_ul_nr.c index 0a21950f5..74341c636 100644 --- a/lib/src/phy/ue/ue_ul_nr.c +++ b/lib/src/phy/ue/ue_ul_nr.c @@ -139,8 +139,20 @@ static int ue_ul_nr_encode_pucch_format1(srslte_ue_ul_nr_t* q, const srslte_uci_data_nr_t* uci_data) { uint8_t b[SRSLTE_PUCCH_NR_FORMAT1_MAX_NOF_BITS] = {}; - b[0] = uci_data->value.ack[0]; - uint32_t nof_bits = 1; + + // Set ACK bits + uint32_t nof_bits = SRSLTE_MIN(SRSLTE_PUCCH_NR_FORMAT1_MAX_NOF_BITS, uci_data->cfg.o_ack); + for (uint32_t i = 0; i < nof_bits; i++) { + b[i] = uci_data->value.ack[i]; + } + + // Set SR bits + // For a positive SR transmission using PUCCH format 1, the UE transmits the PUCCH as described in [4, TS + // 38.211] by setting b ( 0 ) = 0 . + if (nof_bits == 0 && uci_data->cfg.o_sr > 0 && uci_data->value.sr[0] != 0) { + b[0] = 0; + nof_bits = 1; + } if (srslte_dmrs_pucch_format1_put(&q->pucch, &q->carrier, cfg, slot, resource, q->sf_symbols[0])) { return SRSLTE_ERROR; @@ -238,3 +250,40 @@ int srslte_ue_ul_nr_pucch_info(const srslte_pucch_nr_resource_t* resource, return len; } + +int srslte_ue_ul_nr_sr_send_slot(const srslte_pucch_nr_sr_resource_t sr_resources[SRSLTE_PUCCH_MAX_NOF_SR_RESOURCES], + uint32_t slot_idx, + uint32_t sr_id, + uint32_t* sr_resource_id) +{ + // Check inputs + if (sr_resources == NULL) { + return SRSLTE_ERROR_INVALID_INPUTS; + } + + // Iterate over all SR resources + for (uint32_t i = 0; i < SRSLTE_PUCCH_MAX_NOF_SR_RESOURCES; i++) { + const srslte_pucch_nr_sr_resource_t* res = &sr_resources[i]; + + // Skip if resource is not provided + if (!res->configured) { + continue; + } + + // Skip if SR identifier does not match + if (sr_id != res->sr_id) { + continue; + } + + // Check periodicity and offset condition + if ((slot_idx + res->period - res->offset) % res->period == 0) { + if (sr_resource_id != NULL) { + *sr_resource_id = i; + } + return 1; + } + } + + // If the program reached this point is because there is no SR transmission opportunity + return SRSLTE_SUCCESS; +} \ No newline at end of file diff --git a/srsue/hdr/phy/nr/state.h b/srsue/hdr/phy/nr/state.h index 614540363..e7975d0e6 100644 --- a/srsue/hdr/phy/nr/state.h +++ b/srsue/hdr/phy/nr/state.h @@ -47,6 +47,9 @@ private: srslte::circular_array pending_ack = {}; mutable std::mutex pending_ack_mutex; + /// Pending scheduling request identifiers + std::set pending_sr_id; + public: mac_interface_phy_nr* stack = nullptr; srslte_carrier_nr_t carrier = {}; @@ -240,6 +243,35 @@ public: return true; } + + void reset() { pending_sr_id.clear(); } + + void set_pending_sr(uint32_t value) { pending_sr_id.insert(value); } + + void get_pending_sr(const uint32_t& tti, srslte_uci_data_nr_t& uci_data) + { + // Append fixed SR + pending_sr_id.insert(args.fixed_sr.begin(), args.fixed_sr.end()); + + // Iterate all SR IDs + for (const uint32_t& sr_id : pending_sr_id) { + uint32_t sr_resource_id = 0; + + // Check if there is an SR transmission opportunity for the given SR identifier in any SR logic channel + if (srslte_ue_ul_nr_sr_send_slot(cfg.pucch.sr_resources, tti, sr_id, &sr_resource_id) > SRSLTE_SUCCESS) { + // Set UCI data + uci_data.cfg.o_sr = 1; + uci_data.cfg.sr_resource_id = sr_resource_id; + uci_data.value.sr[0] = 1; + + // Remove pending SR + pending_sr_id.erase(sr_id); + + // Only one SR is supported + return; + } + } + } }; } // namespace nr } // namespace srsue diff --git a/srsue/hdr/phy/nr/worker_pool.h b/srsue/hdr/phy/nr/worker_pool.h index 9dc9f38ca..4528d7332 100644 --- a/srsue/hdr/phy/nr/worker_pool.h +++ b/srsue/hdr/phy/nr/worker_pool.h @@ -41,6 +41,7 @@ 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, srslte_rnti_type_t rnti_type); bool set_config(const srslte::phy_cfg_nr_t& cfg); + void sr_send(uint32_t sr_id); }; } // namespace nr diff --git a/srsue/hdr/phy/phy.h b/srsue/hdr/phy/phy.h index 764d6c486..ba9facef5 100644 --- a/srsue/hdr/phy/phy.h +++ b/srsue/hdr/phy/phy.h @@ -66,9 +66,7 @@ private: srslte::block_queue > cmd_queue; }; -class phy final : public ue_lte_phy_base, - public ue_nr_phy_base, - public srslte::thread +class phy final : public ue_lte_phy_base, public ue_nr_phy_base, public srslte::thread { public: explicit phy(srslog::sink& log_sink) : @@ -184,6 +182,7 @@ 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; private: void run_thread() final; diff --git a/srsue/hdr/phy/vnf_phy_nr.h b/srsue/hdr/phy/vnf_phy_nr.h index b44fe3005..2dea24f40 100644 --- a/srsue/hdr/phy/vnf_phy_nr.h +++ b/srsue/hdr/phy/vnf_phy_nr.h @@ -59,6 +59,7 @@ 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; private: std::unique_ptr vnf; diff --git a/srsue/src/phy/nr/cc_worker.cc b/srsue/src/phy/nr/cc_worker.cc index c0f6065e8..5b48a98cf 100644 --- a/srsue/src/phy/nr/cc_worker.cc +++ b/srsue/src/phy/nr/cc_worker.cc @@ -259,7 +259,7 @@ bool cc_worker::work_ul() srslte_sch_cfg_nr_t pusch_cfg = {}; bool has_pusch_grant = phy->get_ul_pending_grant(ul_slot_cfg.idx, pusch_cfg, pid); - // If PDSCH UL AKC is available, load into UCI + // If PDSCH UL ACK is available, load into UCI if (has_ul_ack) { pdsch_ack.use_pusch = has_pusch_grant; if (srslte_ue_dl_nr_gen_ack(&phy->cfg.harq_ack, &pdsch_ack, &uci_data) < SRSLTE_SUCCESS) { @@ -268,6 +268,9 @@ bool cc_worker::work_ul() } } + // Add SR to UCI data if available + phy->get_pending_sr(ul_slot_cfg.idx, uci_data); + if (has_pusch_grant) { // Notify MAC about PUSCH found grant mac_interface_phy_nr::tb_action_ul_t ul_action = {}; diff --git a/srsue/src/phy/nr/state.cc b/srsue/src/phy/nr/state.cc deleted file mode 100644 index 6010f6d94..000000000 --- a/srsue/src/phy/nr/state.cc +++ /dev/null @@ -1,17 +0,0 @@ -/** - * - * \section COPYRIGHT - * - * Copyright 2013-2020 Software Radio Systems Limited - * - * By using this file, you agree to the terms and conditions set - * forth in the LICENSE file which can be found at the top level of - * the distribution. - * - */ - -#include "srsue/hdr/phy/nr/state.h" - -namespace srsue { -namespace nr {} -} // namespace srsue \ No newline at end of file diff --git a/srsue/src/phy/nr/worker_pool.cc b/srsue/src/phy/nr/worker_pool.cc index 9043c5a41..0731bb48f 100644 --- a/srsue/src/phy/nr/worker_pool.cc +++ b/srsue/src/phy/nr/worker_pool.cc @@ -134,5 +134,10 @@ bool worker_pool::set_config(const srslte::phy_cfg_nr_t& cfg) phy_state.cfg = cfg; return true; } + +void worker_pool::sr_send(uint32_t sr_id) +{ + phy_state.set_pending_sr(sr_id); +} } // namespace nr } // namespace srsue diff --git a/srsue/src/phy/phy.cc b/srsue/src/phy/phy.cc index 9a431e951..92923f658 100644 --- a/srsue/src/phy/phy.cc +++ b/srsue/src/phy/phy.cc @@ -644,4 +644,8 @@ bool phy::set_config(const srslte::phy_cfg_nr_t& cfg) return nr_workers.set_config(cfg); } +void phy::sr_send(uint32_t sr_id) +{ + nr_workers.sr_send(sr_id); +} } // namespace srsue diff --git a/srsue/src/phy/vnf_phy_nr.cc b/srsue/src/phy/vnf_phy_nr.cc index 3e37a0126..f18d6df1f 100644 --- a/srsue/src/phy/vnf_phy_nr.cc +++ b/srsue/src/phy/vnf_phy_nr.cc @@ -73,5 +73,6 @@ bool vnf_phy_nr::set_config(const srslte::phy_cfg_nr_t& cfg) { return false; } +void vnf_phy_nr::sr_send(uint32_t sr_id) {} } // namespace srsue \ No newline at end of file diff --git a/srsue/test/mac_nr/proc_ra_nr_test.cc b/srsue/test/mac_nr/proc_ra_nr_test.cc index 21f25a094..4ccb778af 100644 --- a/srsue/test/mac_nr/proc_ra_nr_test.cc +++ b/srsue/test/mac_nr/proc_ra_nr_test.cc @@ -23,14 +23,14 @@ public: void send_prach(const uint32_t prach_occasion_, const int preamble_index_, const float preamble_received_target_power_, - const float ta_base_sec_ = 0.0f) + const float ta_base_sec_ = 0.0f) override { prach_occasion = prach_occasion_; preamble_index = preamble_index_; preamble_received_target_power = preamble_received_target_power_; } - int tx_request(const tx_request_t& request) { return 0; } - int set_ul_grant(std::array, uint16_t rnti, srslte_rnti_type_t rnti_type) + int tx_request(const tx_request_t& request) override { return 0; } + int set_ul_grant(std::array, uint16_t rnti, srslte_rnti_type_t rnti_type) override { return 0; } @@ -41,6 +41,7 @@ public: *preamble_index_ = preamble_index; *preamble_received_target_power_ = preamble_received_target_power; } + void sr_send(uint32_t sr_id) override {} private: uint32_t prach_occasion;