diff --git a/lib/include/srslte/interfaces/rrc_nr_interface_types.h b/lib/include/srslte/interfaces/rrc_nr_interface_types.h index f2781f548..176f4f563 100644 --- a/lib/include/srslte/interfaces/rrc_nr_interface_types.h +++ b/lib/include/srslte/interfaces/rrc_nr_interface_types.h @@ -30,6 +30,7 @@ struct phy_cfg_nr_t { srslte_prach_cfg_t prach = {}; srslte_ue_dl_nr_pdcch_cfg_t pdcch = {}; srslte_ue_dl_nr_harq_ack_cfg_t harq_ack = {}; + srslte_csi_hl_cfg_t csi = {}; phy_cfg_nr_t() { @@ -514,6 +515,13 @@ struct phy_cfg_nr_t { // nrofPRBs: 1 // nrofSymbols: 2 // startingSymbolIndex: 2 + srslte_pucch_nr_resource_t pucch_res_17 = {}; + pucch_res_17.starting_prb = 1; + pucch_res_17.format = SRSLTE_PUCCH_NR_FORMAT_2; + pucch_res_17.nof_prb = 1; + pucch_res_17.nof_symbols = 2; + pucch_res_17.start_symbol_idx = 2; + // format1: setup (1) // setup // format2: setup (1) @@ -527,6 +535,7 @@ struct phy_cfg_nr_t { } } } + pucch_res_17.max_code_rate = 2; // schedulingRequestResourceToAddModList: 1 item // Item 0 @@ -564,6 +573,34 @@ struct phy_cfg_nr_t { harq_ack.dl_data_to_ul_ack[5] = 12; harq_ack.dl_data_to_ul_ack[6] = 11; harq_ack.nof_dl_data_to_ul_ack = 7; + + // csi-ReportConfigToAddModList: 1 item + // Item 0 + // CSI-ReportConfig + // reportConfigId: 0 + // resourcesForChannelMeasurement: 0 + // csi-IM-ResourcesForInterference: 1 + // reportConfigType: periodic (0) + // periodic + // reportSlotConfig: slots80 (7) + // slots80: 9 + // pucch-CSI-ResourceList: 1 item + // Item 0 + // PUCCH-CSI-Resource + // uplinkBandwidthPartId: 0 + // pucch-Resource: 17 + // reportQuantity: cri-RI-PMI-CQI (1) + // cri-RI-PMI-CQI: NULL + // reportFreqConfiguration + // cqi-FormatIndicator: widebandCQI (0) + // timeRestrictionForChannelMeasurements: notConfigured (1) + // timeRestrictionForInterferenceMeasurements: notConfigured (1) + // groupBasedBeamReporting: disabled (1) + // disabled + // cqi-Table: table2 (1) + // subbandSize: value1 (0) + csi.reports[0].type = SRSLTE_CSI_REPORT_TYPE_PERIODIC; + csi.reports[0].periodic.resource = pucch_res_17; } }; } // namespace srslte diff --git a/lib/include/srslte/interfaces/ue_nr_interfaces.h b/lib/include/srslte/interfaces/ue_nr_interfaces.h index a5285afcf..67a66da52 100644 --- a/lib/include/srslte/interfaces/ue_nr_interfaces.h +++ b/lib/include/srslte/interfaces/ue_nr_interfaces.h @@ -121,7 +121,8 @@ 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; + std::set fixed_sr = {1}; + uint32_t fix_wideband_cqi = 15; // Set to a non-zero value for fixing the wide-band CQI report phy_args_nr_t() { diff --git a/lib/include/srslte/phy/phch/csi.h b/lib/include/srslte/phy/phch/csi.h new file mode 100644 index 000000000..240097a8c --- /dev/null +++ b/lib/include/srslte/phy/phch/csi.h @@ -0,0 +1,69 @@ +/** + * + * \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. + * + */ + +#ifndef SRSLTE_CSI_NR_H +#define SRSLTE_CSI_NR_H + +#include "uci_cfg_nr.h" + +/** + * @brief Fills Uplink Control Information data with triggered reports for the given slot + * @param cfg CSI report configuration + * @param slot_idx Slot index within the radio frame + * @param measurements CSI measurements + * @param[out] uci_data Uplink Control Information data + * @return The number CSI reports for transmission if the provided data is valid, SRSLTE_ERROR code otherwise + */ +SRSLTE_API int srslte_csi_generate_reports(const srslte_csi_hl_cfg_t* cfg, + uint32_t slot_idx, + const srslte_csi_measurements_t measurements[SRSLTE_CSI_MAX_NOF_RESOURCES], + srslte_csi_report_cfg_t report_cfg[SRSLTE_CSI_MAX_NOF_REPORT], + srslte_csi_report_value_t report_value[SRSLTE_CSI_MAX_NOF_REPORT]); + +/** + * @brief Compute number of CSI bits necessary to transmit all the CSI reports for a PUCCH transmission + * @param report_list Provides the CSI report list + * @param nof_reports Number of CSI reports in the list + * @return The number of bits if the provided list is valid, SRSLTE_ERROR code otherwise + */ +SRSLTE_API int srslte_csi_nof_bits(const srslte_csi_report_cfg_t* report_list, uint32_t nof_reports); + +/** + * @brief Pack CSI part 1 bits for a PUCCH transmission + * @param report_list Provides the CSI report list + * @param nof_reports Number of CSI reports in the list + * @param o_csi1 CSI bits + * @param max_o_csi1 Maximum number of CSI bits + * @return number of packed bits if provided data is valid, SRSLTE_ERROR code otherwise + */ +SRSLTE_API int srslte_csi_part1_pack(const srslte_csi_report_cfg_t* report_cfg, + const srslte_csi_report_value_t* report_value, + uint32_t nof_reports, + uint8_t* o_csi1, + uint32_t max_o_csi1); + +/** + * @brief Converts to string a given list of CSI reports + * @param report_cfg Report configuration list + * @param report_value Report value list + * @param nof_reports Number of reports + * @param str String pointer + * @param str_len Maximum string length + * @return Number of used characters + */ +SRSLTE_API uint32_t srslte_csi_str(const srslte_csi_report_cfg_t* report_cfg, + const srslte_csi_report_value_t* report_value, + uint32_t nof_reports, + char* str, + uint32_t str_len); + +#endif // SRSLTE_CSI_NR_H diff --git a/lib/include/srslte/phy/phch/csi_cfg.h b/lib/include/srslte/phy/phch/csi_cfg.h new file mode 100644 index 000000000..48a33699b --- /dev/null +++ b/lib/include/srslte/phy/phch/csi_cfg.h @@ -0,0 +1,165 @@ +/** + * + * \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. + * + */ + +#ifndef SRSLTE_CSI_CFG_H +#define SRSLTE_CSI_CFG_H + +#include "pucch_cfg_nr.h" +#include "srslte/config.h" +#include + +/** + * @brief Maximum number of CSI report configurations defined in TS 38.331 maxNrofCSI-ReportConfigurations + */ +#define SRSLTE_CSI_MAX_NOF_REPORT 48 + +/** + * @brief Maximum number of CSI-RS resources defined in TS 38.331 maxNrofCSI-ResourceConfigurations + */ +#define SRSLTE_CSI_MAX_NOF_RESOURCES 112 +/** + * @brief CSI report types defined in TS 38.331 CSI-ReportConfig + */ +typedef enum SRSLTE_API { + SRSLTE_CSI_REPORT_TYPE_NONE = 0, + SRSLTE_CSI_REPORT_TYPE_PERIODIC, + SRSLTE_CSI_REPORT_TYPE_SEMI_PERSISTENT_ON_PUCCH, + SRSLTE_CSI_REPORT_TYPE_SEMI_PERSISTENT_ON_PUSCH, + SRSLTE_CSI_REPORT_TYPE_APERIODIC, +} srslte_csi_report_type_t; + +/** + * @brief CSI report quantities defined in TS 38.331 CSI-ReportConfig + */ +typedef enum SRSLTE_API { + SRSLTE_CSI_REPORT_QUANTITY_NONE = 0, + SRSLTE_CSI_REPORT_QUANTITY_CRI_RI_PMI_CQI, + SRSLTE_CSI_REPORT_QUANTITY_CRI_RI_I1, + SRSLTE_CSI_REPORT_QUANTITY_CRI_RI_I1_CQI, + SRSLTE_CSI_REPORT_QUANTITY_CRI_RI_CQI, + SRSLTE_CSI_REPORT_QUANTITY_CRI_RSRP, + SRSLTE_CSI_REPORT_QUANTITY_SSB_INDEX_RSRP, + SRSLTE_CSI_REPORT_QUANTITY_CRI_RI_LI_PMI_CQI +} srslte_csi_report_quantity_t; + +/** + * @brief CSI report frequency configuration defined in TS 38.331 CSI-ReportConfig + */ +typedef enum SRSLTE_API { + SRSLTE_CSI_REPORT_FREQ_WIDEBAND = 0, + SRSLTE_CSI_REPORT_FREQ_SUBBAND +} srslte_csi_report_freq_t; + +/** + * @brief CQI table selection + */ +typedef enum SRSLTE_API { + SRSLTE_CSI_CQI_TABLE_1 = 0, + SRSLTE_CSI_CQI_TABLE_2, + SRSLTE_CSI_CQI_TABLE_3, +} srslte_csi_cqi_table_t; + +/** + * @brief CSI periodic report configuration from upper layers + * @remark Described in TS 38.331 CSI-ReportConfig + */ +typedef struct SRSLTE_API { + 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 to use for reporting +} srslte_csi_periodic_report_cfg_t; + +/** + * @brief CSI report configuration from higher layers + */ +typedef struct SRSLTE_API { + uint32_t channel_meas_id; ///< Channel measurement resource identifier + uint32_t interf_meas_id; ///< Interference measurement resource identifier + bool interf_meas_present; ///< Indicates if interference measurement identifier is present + srslte_csi_report_type_t type; ///< CSI report type (none, periodic, semiPersistentOnPUCCH, ...) + union { + void* none; ///< Reserved, no configured + srslte_csi_periodic_report_cfg_t periodic; ///< Used for periodic reporting + // ... add here other types + }; + srslte_csi_report_quantity_t quantity; ///< Report quantity + srslte_csi_cqi_table_t cqi_table; ///< CQI table selection + srslte_csi_report_freq_t freq_cfg; ///< Determine whether it is wideband or subband +} srslte_csi_hl_report_cfg_t; + +/** + * @brief General CSI configuration provided by higher layers + */ +typedef struct SRSLTE_API { + srslte_csi_hl_report_cfg_t reports[SRSLTE_CSI_MAX_NOF_REPORT]; ///< CSI report configuration + // ... add here physical CSI measurement sets +} srslte_csi_hl_cfg_t; + +/** + * @brief Generic measurement structure + */ +typedef struct SRSLTE_API { + uint32_t cri; ///< CSI-RS Resource Indicator + float wideband_rsrp_dBm; ///< Measured NZP-CSI-RS RSRP (Ignore for IM-CSI-RS) + float wideband_epre_dBm; ///< Measured EPRE + float wideband_snr_db; ///< SNR calculated from NZP-CSI-RS RSRP and EPRE (Ignore for IM-CSI-RS) + + // Resource set context + uint32_t nof_ports; ///< Number of antenna ports + uint32_t K_csi_rs; ///< Number of CSI-RS in the corresponding resource set +} srslte_csi_measurements_t; + +/** + * @brief CSI report configuration + */ +typedef struct SRSLTE_API { + srslte_csi_report_type_t type; ///< CSI report type (none, periodic, semiPersistentOnPUCCH, ...) + srslte_csi_report_quantity_t quantity; ///< Report quantity + srslte_pucch_nr_resource_t pucch_resource; ///< PUCCH resource to use for periodic reporting + srslte_csi_report_freq_t freq_cfg; ///< Determine whether it is wideband or subband + + // Resource set context + uint32_t nof_ports; ///< Number of antenna ports + uint32_t K_csi_rs; ///< Number of CSI-RS in the corresponding resource set +} srslte_csi_report_cfg_t; + +/** + * @brief Wideband CSI report values + */ +typedef struct SRSLTE_API { + uint32_t ri; + uint32_t pmi; + uint32_t cqi; +} srslte_csi_report_wideband_cri_ri_pmi_cqi_t; + +/** + * @brief Unified CSI report values + */ +typedef struct SRSLTE_API { + uint32_t cri; ///< CSI-RS Resource Indicator + union { + void* none; + srslte_csi_report_wideband_cri_ri_pmi_cqi_t wideband_cri_ri_pmi_cqi; + }; + bool valid; ///< Used by receiver only +} srslte_csi_report_value_t; + +/** + * @brief Complete report configuration and value + */ +typedef struct SRSLTE_API { + srslte_csi_report_cfg_t cfg[SRSLTE_CSI_MAX_NOF_REPORT]; ///< Configuration ready for encoding + srslte_csi_report_value_t value[SRSLTE_CSI_MAX_NOF_REPORT]; ///< Quantified values + uint32_t nof_reports; ///< Total number of reports to transmit +} srslte_csi_reports_t; + +#endif // SRSLTE_CSI_CFG_H diff --git a/lib/include/srslte/phy/phch/ra_ul_nr.h b/lib/include/srslte/phy/phch/ra_ul_nr.h index eac5d5aae..6b4ec57da 100644 --- a/lib/include/srslte/phy/phch/ra_ul_nr.h +++ b/lib/include/srslte/phy/phch/ra_ul_nr.h @@ -110,4 +110,11 @@ SRSLTE_API int srslte_ra_ul_nr_pucch_resource(const srslte_pucch_nr_hl_cfg_t* pu const srslte_uci_cfg_nr_t* uci_cfg, srslte_pucch_nr_resource_t* resource); +/** + * @brief Computes the number of SR bits + * @param K Number of SR transmission opportunities, including negative + * @return The number of bits according to the number of SRs + */ +SRSLTE_API uint32_t srslte_ra_ul_nr_nof_sr_bits(uint32_t K); + #endif // SRSLTE_RA_UL_NR_H diff --git a/lib/include/srslte/phy/phch/uci_cfg_nr.h b/lib/include/srslte/phy/phch/uci_cfg_nr.h index e0526040b..34c1729a2 100644 --- a/lib/include/srslte/phy/phch/uci_cfg_nr.h +++ b/lib/include/srslte/phy/phch/uci_cfg_nr.h @@ -13,6 +13,7 @@ #ifndef SRSLTE_UCI_CFG_NR_H #define SRSLTE_UCI_CFG_NR_H +#include "csi_cfg.h" #include "srslte/phy/common/phy_common.h" #include #include @@ -50,31 +51,31 @@ */ 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 + srslte_csi_report_cfg_t csi[SRSLTE_CSI_MAX_NOF_REPORT]; ///< CSI report configuration + uint32_t nof_csi; ///< Number of CSI reports /// 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 1_1 - uint32_t sr_resource_id; ///< Scheduling request resource identifier, only valid if o_sr > 0 + 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 positive SR + bool sr_positive_present; ///< Set to true if there is at least one positive SR } srslte_uci_cfg_nr_t; /** * @brief Uplink Control Information (UCI) message packed information */ typedef struct SRSLTE_API { - uint8_t ack[SRSLTE_UCI_NR_MAX_ACK_BITS]; ///< HARQ ACK feedback bits - uint8_t sr[SRSLTE_UCI_NR_MAX_SR_BITS]; ///< Scheduling Request bits - uint8_t csi1[SRSLTE_UCI_NR_MAX_CSI1_BITS]; ///< Channel State Information part 1 - uint8_t csi2[SRSLTE_UCI_NR_MAX_CSI2_BITS]; ///< Channel State Information part 2 - bool valid; ///< Indicates whether the message has been decoded successfully, ignored in the transmitter + uint8_t ack[SRSLTE_UCI_NR_MAX_ACK_BITS]; ///< HARQ ACK feedback bits + uint32_t sr; ///< Number of positive SR + srslte_csi_report_value_t csi[SRSLTE_CSI_MAX_NOF_REPORT]; ///< Packed CSI report values + bool valid; ///< Indicates whether the message has been decoded successfully, ignored in the transmitter } srslte_uci_value_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 adc983910..25c57d987 100644 --- a/lib/include/srslte/phy/ue/ue_ul_nr.h +++ b/lib/include/srslte/phy/ue/ue_ul_nr.h @@ -82,16 +82,14 @@ SRSLTE_API int srslte_ue_ul_nr_pucch_info(const srslte_pucch_nr_resource_t* reso * * @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 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 + * @return the number of SR opportunities if the provided slot index is a 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); + uint32_t sr_resource_id[SRSLTE_PUCCH_MAX_NOF_SR_RESOURCES]); #endif // SRSLTE_UE_UL_DATA_H diff --git a/lib/include/srslte/srslte.h b/lib/include/srslte/srslte.h index 3f05b6195..8150d6ba6 100644 --- a/lib/include/srslte/srslte.h +++ b/lib/include/srslte/srslte.h @@ -81,6 +81,7 @@ extern "C" { #include "srslte/phy/fec/softbuffer.h" #include "srslte/phy/phch/cqi.h" +#include "srslte/phy/phch/csi.h" #include "srslte/phy/phch/dci.h" #include "srslte/phy/phch/dci_nr.h" #include "srslte/phy/phch/pbch.h" diff --git a/lib/src/phy/phch/csi.c b/lib/src/phy/phch/csi.c new file mode 100644 index 000000000..73da3a352 --- /dev/null +++ b/lib/src/phy/phch/csi.c @@ -0,0 +1,218 @@ +/** + * + * \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 "srslte/phy/phch/csi.h" +#include "srslte/phy/utils/bit.h" +#include "srslte/phy/utils/debug.h" +#include + +#define CSI_WIDEBAND_CSI_NOF_BITS 4 + +/// Implements SNRI to CQI conversion +uint32_t csi_snri_db_to_cqi(srslte_csi_cqi_table_t table, float snri_db) +{ + return 15; +} + +// Implements CSI report triggers +static bool csi_report_trigger(const srslte_csi_hl_report_cfg_t* cfg, uint32_t slot_idx) +{ + switch (cfg->type) { + case SRSLTE_CSI_REPORT_TYPE_PERIODIC: + return (slot_idx + cfg->periodic.period - cfg->periodic.offset) % cfg->periodic.period == 0; + default:; // Do nothing + } + return false; +} + +static void csi_wideband_cri_ri_pmi_cqi_quantify(const srslte_csi_hl_report_cfg_t* cfg, + const srslte_csi_measurements_t* channel_meas, + const srslte_csi_measurements_t* interf_meas, + srslte_csi_report_cfg_t* report_cfg, + srslte_csi_report_value_t* report_value) +{ + // Take SNR by default + float wideband_sinr_db = channel_meas->wideband_snr_db; + + // If interference is provided, use the channel RSRP and interference EPRE to calculate the SINR + if (interf_meas != NULL) { + wideband_sinr_db = channel_meas->wideband_rsrp_dBm - interf_meas->wideband_epre_dBm; + } + + // Fill report configuration + report_cfg->type = cfg->type; + report_cfg->quantity = SRSLTE_CSI_REPORT_QUANTITY_CRI_RI_PMI_CQI; + report_cfg->freq_cfg = SRSLTE_CSI_REPORT_FREQ_WIDEBAND; + report_cfg->nof_ports = channel_meas->nof_ports; + report_cfg->K_csi_rs = channel_meas->K_csi_rs; + + // Save PUCCH resource only if periodic type + if (cfg->type == SRSLTE_CSI_REPORT_TYPE_PERIODIC) { + report_cfg->pucch_resource = cfg->periodic.resource; + } + + // Fill quantified values + report_value->wideband_cri_ri_pmi_cqi.cqi = csi_snri_db_to_cqi(cfg->cqi_table, wideband_sinr_db); + report_value->wideband_cri_ri_pmi_cqi.ri = 0; + report_value->wideband_cri_ri_pmi_cqi.pmi = 0; +} + +static uint32_t csi_wideband_cri_ri_pmi_cqi_nof_bits(const srslte_csi_report_cfg_t* cfg) +{ + // Avoid K_csi_rs invalid value + if (cfg->K_csi_rs == 0) { + ERROR("Invalid K_csi_rs=%d", cfg->K_csi_rs); + return 0; + } + + // Compute number of bits for CRI + uint32_t nof_bits_cri = (uint32_t)ceilf(log2f((float)cfg->K_csi_rs)); + + switch (cfg->nof_ports) { + case 1: + return SRSLTE_CSI_REPORT_FREQ_WIDEBAND + nof_bits_cri; + default: + ERROR("Invalid or not implemented number of ports (%d)", cfg->nof_ports); + } + return 0; +} + +static int csi_wideband_cri_ri_pmi_cqi_pack(const srslte_csi_report_cfg_t* cfg, + const srslte_csi_report_value_t* value, + uint8_t* o_csi1) +{ + // Avoid K_csi_rs invalid value + if (cfg->K_csi_rs == 0) { + ERROR("Invalid K_csi_rs=%d", cfg->K_csi_rs); + return SRSLTE_ERROR; + } + + // Write wideband CQI + srslte_bit_unpack(value->wideband_cri_ri_pmi_cqi.cqi, &o_csi1, CSI_WIDEBAND_CSI_NOF_BITS); + + // Compute number of bits for CRI and write + uint32_t nof_bits_cri = (uint32_t)ceilf(log2f((float)cfg->K_csi_rs)); + srslte_bit_unpack(value->cri, &o_csi1, nof_bits_cri); + + return nof_bits_cri + CSI_WIDEBAND_CSI_NOF_BITS; +} + +int srslte_csi_generate_reports(const srslte_csi_hl_cfg_t* cfg, + uint32_t slot_idx, + const srslte_csi_measurements_t measurements[SRSLTE_CSI_MAX_NOF_RESOURCES], + srslte_csi_report_cfg_t report_cfg[SRSLTE_CSI_MAX_NOF_REPORT], + srslte_csi_report_value_t report_value[SRSLTE_CSI_MAX_NOF_REPORT]) +{ + uint32_t count = 0; + + // Check inputs + if (cfg == NULL || measurements == NULL || report_cfg == NULL || report_value == NULL) { + return SRSLTE_ERROR_INVALID_INPUTS; + } + + // Iterate every possible configured CSI report + for (uint32_t i = 0; i < SRSLTE_CSI_MAX_NOF_REPORT; i++) { + // Skip if report is not configured or triggered + if (!csi_report_trigger(&cfg->reports[i], slot_idx)) { + continue; + } + + // Select channel measurement + if (cfg->reports->channel_meas_id >= SRSLTE_CSI_MAX_NOF_RESOURCES) { + ERROR("Channel measurement ID (%d) is out of range", cfg->reports->channel_meas_id); + return SRSLTE_ERROR; + } + const srslte_csi_measurements_t* channel_meas = &measurements[cfg->reports->channel_meas_id]; + + // Select interference measurement + const srslte_csi_measurements_t* interf_meas = NULL; + if (cfg->reports->interf_meas_present) { + if (cfg->reports->interf_meas_id >= SRSLTE_CSI_MAX_NOF_RESOURCES) { + ERROR("Interference measurement ID (%d) is out of range", cfg->reports->interf_meas_id); + return SRSLTE_ERROR; + } + interf_meas = &measurements[cfg->reports->interf_meas_id]; + } + + // Quantify measurements according to frequency and quantity configuration + if (cfg->reports->freq_cfg == SRSLTE_CSI_REPORT_FREQ_WIDEBAND && + cfg->reports->quantity == SRSLTE_CSI_REPORT_QUANTITY_CRI_RI_PMI_CQI) { + csi_wideband_cri_ri_pmi_cqi_quantify( + &cfg->reports[i], channel_meas, interf_meas, &report_cfg[count], &report_value[count]); + count++; + } else { + ; // Ignore other types + } + } + + return (int)count; +} + +int srslte_csi_nof_bits(const srslte_csi_report_cfg_t* report_list, uint32_t nof_reports) +{ + uint32_t count = 0; + + // Check input pointer + if (report_list == NULL) { + return SRSLTE_ERROR_INVALID_INPUTS; + } + + // Iterate all report configurations + for (uint32_t i = 0; i < nof_reports; i++) { + const srslte_csi_report_cfg_t* report = &report_list[i]; + if (report->quantity && report->quantity == SRSLTE_CSI_REPORT_QUANTITY_CRI_RI_PMI_CQI) { + count += csi_wideband_cri_ri_pmi_cqi_nof_bits(report); + } + } + + return (int)count; +} + +int srslte_csi_part1_pack(const srslte_csi_report_cfg_t* report_cfg, + const srslte_csi_report_value_t* report_value, + uint32_t nof_reports, + uint8_t* o_csi1, + uint32_t max_o_csi1) +{ + uint32_t count = 0; + + if (report_cfg == NULL || report_value == NULL || o_csi1 == NULL) { + return SRSLTE_ERROR_INVALID_INPUTS; + } + + int n = srslte_csi_nof_bits(report_cfg, nof_reports); + if (n > (int)max_o_csi1) { + ERROR("The maximum number of CSI bits (%d) is not enough to accommodate %d bits", max_o_csi1, n); + return SRSLTE_ERROR; + } + + for (uint32_t i = 0; i < nof_reports && count < max_o_csi1; i++) { + if (report_cfg[i].freq_cfg == SRSLTE_CSI_REPORT_FREQ_WIDEBAND && + report_cfg[i].quantity == SRSLTE_CSI_REPORT_QUANTITY_CRI_RI_PMI_CQI) { + count += csi_wideband_cri_ri_pmi_cqi_pack(&report_cfg[i], &report_value[i], &o_csi1[count]); + } else { + ERROR("CSI frequency (%d) and quantity (%d) combination is not implemented", + report_cfg[i].freq_cfg, + report_cfg[i].quantity); + } + } + + return (int)count; +} + +uint32_t srslte_csi_str(const srslte_csi_report_cfg_t* report_cfg, + const srslte_csi_report_value_t* report_value, + uint32_t nof_reports, + char* str, + uint32_t str_len) +{ + return srslte_print_check(str, str_len, 0, "cqi=%s", report_value->wideband_cri_ri_pmi_cqi.cqi); +} \ No newline at end of file diff --git a/lib/src/phy/phch/ra_ul_nr.c b/lib/src/phy/phch/ra_ul_nr.c index 65cfa5117..45042f5b4 100644 --- a/lib/src/phy/phch/ra_ul_nr.c +++ b/lib/src/phy/phch/ra_ul_nr.c @@ -14,6 +14,7 @@ #include "ra_helper.h" #include "srslte/phy/ch_estimation/dmrs_pucch.h" #include "srslte/phy/common/phy_common.h" +#include "srslte/phy/phch/csi.h" #include "srslte/phy/utils/debug.h" #include "srslte/phy/utils/vector.h" @@ -372,7 +373,7 @@ int srslte_ra_ul_nr_pucch_format_2_3_min_prb(const srslte_pucch_nr_resource_t* r } // Compute total number of UCI bits - uint32_t O_total = uci_cfg->o_ack + uci_cfg->o_sr + uci_cfg->o_csi1 + uci_cfg->o_csi2; + uint32_t O_total = uci_cfg->o_ack + uci_cfg->o_sr + srslte_csi_nof_bits(uci_cfg->csi, uci_cfg->nof_csi); // Add CRC bits if any O_total += srslte_uci_nr_crc_len(O_total); @@ -456,8 +457,12 @@ int srslte_ra_ul_nr_pucch_resource(const srslte_pucch_nr_hl_cfg_t* pucch_cfg, 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) { + // Use SR PUCCH resource + // - At least one positive SR + // - up to 2 HARQ-ACK + // - No CSI report + if (uci_cfg->sr_positive_present > 0 && uci_cfg->o_ack <= SRSLTE_PUCCH_NR_FORMAT1_MAX_NOF_BITS && + uci_cfg->nof_csi == 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); @@ -476,6 +481,14 @@ int srslte_ra_ul_nr_pucch_resource(const srslte_pucch_nr_hl_cfg_t* pucch_cfg, return SRSLTE_SUCCESS; } + // Use format 2, 3 or 4 resource from higher layers + // - K SR opportunities + // - More than 2 HARQ-ACK + // - No CSI report + if (uci_cfg->o_sr > 0 && uci_cfg->o_ack > SRSLTE_PUCCH_NR_FORMAT1_MAX_NOF_BITS && uci_cfg->nof_csi == 0) { + return ra_ul_nr_pucch_resource_hl(pucch_cfg, O_uci, uci_cfg->pucch_resource_id, resource); + } + // 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. @@ -485,3 +498,11 @@ int srslte_ra_ul_nr_pucch_resource(const srslte_pucch_nr_hl_cfg_t* pucch_cfg, } return ra_ul_nr_pucch_resource_hl(pucch_cfg, O_uci, uci_cfg->pucch_resource_id, resource); } + +uint32_t srslte_ra_ul_nr_nof_sr_bits(uint32_t K) +{ + if (K > 0) { + return (uint32_t)ceilf(log2f((float)K + 1.0f)); + } + return 0; +} \ No newline at end of file diff --git a/lib/src/phy/phch/uci_nr.c b/lib/src/phy/phch/uci_nr.c index 3eaec68e1..e74c2502d 100644 --- a/lib/src/phy/phch/uci_nr.c +++ b/lib/src/phy/phch/uci_nr.c @@ -13,6 +13,7 @@ #include "srslte/phy/phch/uci_nr.h" #include "srslte/phy/fec/block/block.h" #include "srslte/phy/fec/polar/polar_chanalloc.h" +#include "srslte/phy/phch/csi.h" #include "srslte/phy/phch/uci_cfg.h" #include "srslte/phy/utils/bit.h" #include "srslte/phy/utils/vector.h" @@ -154,7 +155,8 @@ static int uci_nr_pack_ack_sr(const srslte_uci_cfg_nr_t* cfg, const srslte_uci_v A += cfg->o_ack; // Append SR bits - srslte_vec_u8_copy(&sequence[A], value->sr, cfg->o_sr); + uint8_t* bits = &sequence[A]; + srslte_bit_unpack(value->sr, &bits, cfg->o_sr); A += cfg->o_sr; if (SRSLTE_DEBUG_ENABLED && srslte_verbose >= SRSLTE_VERBOSE_INFO && !handler_registered) { @@ -165,7 +167,7 @@ static int uci_nr_pack_ack_sr(const srslte_uci_cfg_nr_t* cfg, const srslte_uci_v return A; } -static int uci_nr_unpack_ack_sr(const srslte_uci_cfg_nr_t* cfg, const uint8_t* sequence, srslte_uci_value_nr_t* value) +static int uci_nr_unpack_ack_sr(const srslte_uci_cfg_nr_t* cfg, uint8_t* sequence, srslte_uci_value_nr_t* value) { int A = 0; @@ -174,7 +176,8 @@ static int uci_nr_unpack_ack_sr(const srslte_uci_cfg_nr_t* cfg, const uint8_t* s A += cfg->o_ack; // Append SR bits - srslte_vec_u8_copy(value->sr, &sequence[A], cfg->o_sr); + uint8_t* bits = &sequence[A]; + value->sr = srslte_bit_pack(&bits, cfg->o_sr); A += cfg->o_sr; if (SRSLTE_DEBUG_ENABLED && srslte_verbose >= SRSLTE_VERBOSE_INFO && !handler_registered) { @@ -187,15 +190,16 @@ static int uci_nr_unpack_ack_sr(const srslte_uci_cfg_nr_t* cfg, const uint8_t* s static int uci_nr_A(const srslte_uci_cfg_nr_t* cfg) { + int o_csi = srslte_csi_nof_bits(cfg->csi, cfg->nof_csi); + // 6.3.1.1.1 HARQ-ACK/SR only UCI bit sequence generation - if (cfg->o_csi1 == 0 && cfg->o_csi2 == 0) { + if (o_csi == 0) { return cfg->o_ack + cfg->o_sr; } // 6.3.1.1.2 CSI only if (cfg->o_ack == 0 && cfg->o_sr == 0) { - ERROR("CSI only are not implemented"); - return SRSLTE_ERROR; + return o_csi; } // 6.3.1.1.3 HARQ-ACK/SR and CSI @@ -205,15 +209,16 @@ static int uci_nr_A(const srslte_uci_cfg_nr_t* cfg) static int uci_nr_packing(const srslte_uci_cfg_nr_t* cfg, const srslte_uci_value_nr_t* value, uint8_t* sequence) { + int o_csi = srslte_csi_nof_bits(cfg->csi, cfg->nof_csi); + // 6.3.1.1.1 HARQ-ACK/SR only UCI bit sequence generation - if (cfg->o_csi1 == 0 && cfg->o_csi2 == 0) { + if (o_csi == 0) { return uci_nr_pack_ack_sr(cfg, value, sequence); } // 6.3.1.1.2 CSI only if (cfg->o_ack == 0 && cfg->o_sr == 0) { - ERROR("CSI only are not implemented"); - return SRSLTE_ERROR; + return srslte_csi_part1_pack(cfg->csi, value->csi, cfg->nof_csi, sequence, SRSLTE_UCI_NR_MAX_NOF_BITS); } // 6.3.1.1.3 HARQ-ACK/SR and CSI @@ -221,10 +226,12 @@ static int uci_nr_packing(const srslte_uci_cfg_nr_t* cfg, const srslte_uci_value return SRSLTE_ERROR; } -static int uci_nr_unpacking(const srslte_uci_cfg_nr_t* cfg, const uint8_t* sequence, srslte_uci_value_nr_t* value) +static int uci_nr_unpacking(const srslte_uci_cfg_nr_t* cfg, uint8_t* sequence, srslte_uci_value_nr_t* value) { + int o_csi = srslte_csi_nof_bits(cfg->csi, cfg->nof_csi); + // 6.3.1.1.1 HARQ-ACK/SR only UCI bit sequence generation - if (cfg->o_csi1 == 0 && cfg->o_csi2 == 0) { + if (o_csi) { return uci_nr_unpack_ack_sr(cfg, sequence, value); } @@ -737,10 +744,10 @@ int srslte_uci_nr_pucch_format_2_3_4_E(const srslte_pucch_nr_resource_t* resourc static int uci_nr_pucch_E_uci(const srslte_pucch_nr_resource_t* pucch_cfg, const srslte_uci_cfg_nr_t* uci_cfg, uint32_t E_tot) { - if (uci_cfg->o_csi1 != 0 && uci_cfg->o_csi2) { - ERROR("Simultaneous CSI part 1 and CSI part 2 is not implemented"); - return SRSLTE_ERROR; - } + // if (uci_cfg->o_csi1 != 0 && uci_cfg->o_csi2) { + // ERROR("Simultaneous CSI part 1 and CSI part 2 is not implemented"); + // return SRSLTE_ERROR; + // } return E_tot; } @@ -791,7 +798,7 @@ uint32_t srslte_uci_nr_total_bits(const srslte_uci_cfg_nr_t* uci_cfg) return 0; } - return uci_cfg->o_ack + uci_cfg->o_csi1 + uci_cfg->o_csi2 + uci_cfg->o_sr; + return uci_cfg->o_ack + srslte_csi_nof_bits(uci_cfg->csi, uci_cfg->nof_csi); } uint32_t srslte_uci_nr_info(const srslte_uci_data_nr_t* uci_data, char* str, uint32_t str_len) @@ -806,22 +813,12 @@ uint32_t srslte_uci_nr_info(const srslte_uci_data_nr_t* uci_data, char* str, uin len = srslte_print_check(str, str_len, len, ", ack=%s", str2); } - if (uci_data->cfg.o_csi1 > 0) { - char str2[10]; - srslte_vec_sprint_bin(str2, 10, uci_data->value.csi1, uci_data->cfg.o_csi1); - len = srslte_print_check(str, str_len, len, ", csi1=%s", str2); - } - - if (uci_data->cfg.o_csi2 > 0) { - char str2[10]; - srslte_vec_sprint_bin(str2, 10, uci_data->value.csi2, uci_data->cfg.o_csi2); - len = srslte_print_check(str, str_len, len, ", csi2=%s", str2); + if (uci_data->cfg.nof_csi > 0) { + len += srslte_csi_str(uci_data->cfg.csi, uci_data->value.csi, uci_data->cfg.nof_csi, &str[len], str_len - len); } if (uci_data->cfg.o_sr > 0) { - char str2[10]; - srslte_vec_sprint_bin(str2, 10, uci_data->value.sr, uci_data->cfg.o_sr); - len = srslte_print_check(str, str_len, len, ", sr=%s", str2); + len = srslte_print_check(str, str_len, len, ", sr=%d", uci_data->value.sr); } return len; diff --git a/lib/src/phy/ue/ue_ul_nr.c b/lib/src/phy/ue/ue_ul_nr.c index 74341c636..b44252551 100644 --- a/lib/src/phy/ue/ue_ul_nr.c +++ b/lib/src/phy/ue/ue_ul_nr.c @@ -149,7 +149,7 @@ static int ue_ul_nr_encode_pucch_format1(srslte_ue_ul_nr_t* q, // 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) { + if (nof_bits == 0 && uci_data->cfg.o_sr > 0 && uci_data->value.sr > 0) { b[0] = 0; nof_bits = 1; } @@ -253,9 +253,10 @@ int srslte_ue_ul_nr_pucch_info(const srslte_pucch_nr_resource_t* resource, 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) + uint32_t sr_resource_id[SRSLTE_PUCCH_MAX_NOF_SR_RESOURCES]) { + int count = 0; + // Check inputs if (sr_resources == NULL) { return SRSLTE_ERROR_INVALID_INPUTS; @@ -270,20 +271,15 @@ int srslte_ue_ul_nr_sr_send_slot(const srslte_pucch_nr_sr_resource_t sr_resource 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; + sr_resource_id[count] = i; } - return 1; + count++; } } // If the program reached this point is because there is no SR transmission opportunity - return SRSLTE_SUCCESS; + return count; } \ No newline at end of file diff --git a/srsue/hdr/phy/nr/state.h b/srsue/hdr/phy/nr/state.h index e7975d0e6..2a8acac02 100644 --- a/srsue/hdr/phy/nr/state.h +++ b/srsue/hdr/phy/nr/state.h @@ -50,6 +50,9 @@ private: /// Pending scheduling request identifiers std::set pending_sr_id; + /// CSI-RS measurements + std::array csi_measurements = {}; + public: mac_interface_phy_nr* stack = nullptr; srslte_carrier_nr_t carrier = {}; @@ -64,6 +67,10 @@ public: carrier.id = 500; carrier.nof_prb = 100; carrier.max_mimo_layers = 1; + + // Hard-coded values, this should be set when the measurements take place + csi_measurements[0].K_csi_rs = 1; + csi_measurements[1].K_csi_rs = 4; } /** @@ -253,24 +260,39 @@ public: // 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; + // Calculate all SR opportunities in the given TTI + uint32_t sr_resource_id[SRSLTE_PUCCH_MAX_NOF_SR_RESOURCES] = {}; + int sr_count_all = srslte_ue_ul_nr_sr_send_slot(cfg.pucch.sr_resources, tti, sr_resource_id); + uint32_t sr_count_positive = 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; + // Iterate all opportunities + for (uint32_t i = 0; i < sr_count_all; i++) { + // Extract SR identifier + uint32_t sr_id = cfg.pucch.sr_resources[sr_resource_id[i]].sr_id; - // Remove pending SR - pending_sr_id.erase(sr_id); + // Check if the SR resource ID is pending + if (pending_sr_id.count(sr_id) > 0) { + // Count it as present + sr_count_positive++; - // Only one SR is supported - return; + // Erase pending SR + pending_sr_id.erase(sr_id); } } + + // Configure SR fields in UCI data + uci_data.cfg.sr_resource_id = sr_resource_id[0]; + uci_data.cfg.o_sr = srslte_ra_ul_nr_nof_sr_bits(sr_count_all); + uci_data.cfg.sr_positive_present = sr_count_positive > 0; + uci_data.value.sr = sr_count_positive; + } + + void get_periodic_csi(const uint32_t& tti, srslte_uci_data_nr_t& uci_data) + { + int n = srslte_csi_generate_reports(&cfg.csi, tti, csi_measurements.data(), uci_data.cfg.csi, uci_data.value.csi); + if (n > SRSLTE_SUCCESS) { + uci_data.cfg.nof_csi = n; + } } }; } // namespace nr diff --git a/srsue/src/phy/nr/cc_worker.cc b/srsue/src/phy/nr/cc_worker.cc index 5b48a98cf..4f5ba9236 100644 --- a/srsue/src/phy/nr/cc_worker.cc +++ b/srsue/src/phy/nr/cc_worker.cc @@ -271,6 +271,9 @@ bool cc_worker::work_ul() // Add SR to UCI data if available phy->get_pending_sr(ul_slot_cfg.idx, uci_data); + // Add CSI reports to UCI data if available + phy->get_periodic_csi(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 = {};