Initial NR CSI reports

master
Xavier Arteaga 4 years ago committed by Xavier Arteaga
parent 202c4d7566
commit 4679e9f871

@ -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

@ -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<uint32_t> fixed_sr;
std::set<uint32_t> 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()
{

@ -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

@ -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 <stdint.h>
/**
* @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

@ -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

@ -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 <stdbool.h>
#include <stdint.h>
@ -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;
/**

@ -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

@ -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"

@ -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 <math.h>
#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);
}

@ -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;
}

@ -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;

@ -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;
}

@ -50,6 +50,9 @@ private:
/// Pending scheduling request identifiers
std::set<uint32_t> pending_sr_id;
/// CSI-RS measurements
std::array<srslte_csi_measurements_t, SRSLTE_CSI_MAX_NOF_RESOURCES> 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

@ -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 = {};

Loading…
Cancel
Save