Merge remote-tracking branch 'origin/uci_csi_on_pusch' into integration_2026_w05 (!3766)

UE support to send CSI report on PUSCH

Earlier work on UCI on PUSCH implemented only ACK/NACK. This MR extends that
to send CSI report too.

This branch is verified with MATLAB implementation for multiplexing CSI part 1
and part 2 on PUSCH. It is also verified with srsRAN gNB which successfully
decodes CSI part 1 on PUSCH.
This commit is contained in:
Jaroslava Fiedlerova
2026-01-26 16:21:31 +01:00
11 changed files with 450 additions and 317 deletions
@@ -260,6 +260,13 @@ typedef struct
} nfapi_nr_ue_pusch_data_t;
typedef struct csi_payload {
uint64_t part1_payload;
uint64_t part2_payload;
int p1_bits;
int p2_bits;
} nfapi_nr_ue_csi_payload_t;
typedef struct
{
// payloads with fixed array size
@@ -267,10 +274,7 @@ typedef struct
// vector without L1 implementation
uint16_t harq_ack_bit_length;
uint64_t harq_payload;
uint16_t csi_part1_bit_length;
uint64_t csi_part1_payload;
uint16_t csi_part2_bit_length;
uint64_t csi_part2_payload;
nfapi_nr_ue_csi_payload_t csi_payload;
uint8_t alpha_scaling; // 0 = 0.5, 1 = 0.65, 2 = 0.8, 3 = 1
uint8_t beta_offset_harq_ack;
uint8_t beta_offset_csi1;
@@ -152,6 +152,10 @@ typedef struct {
uint16_t E_uci_ACK; // number of coded HARQ-ACK bits
uint16_t Q_dash_ACK_rvd; // number of coded HARQ-ACK symbols reserved
uint16_t E_uci_ACK_rvd; // number of coded HARQ-ACK bits reserved
uint16_t Q_dash_CSI1; // number of coded CSI part 1 symbols
uint16_t E_uci_CSI1; // number of coded CSI part 1 bits
uint16_t Q_dash_CSI2; // number of coded CSI part 2 symbols
uint16_t E_uci_CSI2; // number of coded CSI part 2 bits
uint32_t G_ulsch; // bit capacity of ULSCH
} rate_match_info_uci_t;
+239 -136
View File
@@ -517,6 +517,51 @@ static void map_symbols(const nr_phy_pxsch_params_t p,
}
}
// Function to lookup beta offset value from Table 9.3-2 in TS 38.213
static double get_beta_offset_csi(const uint8_t beta_offset_idx)
{
static const double beta_offset_values[19] = {1.125,
1.250,
1.375,
1.625,
1.750,
2.000,
2.250,
2.500,
2.875,
3.125,
3.500,
4.000,
5.000,
6.250,
8.000,
10.000,
12.625,
15.875,
20.000};
if (beta_offset_idx >= sizeofArray(beta_offset_values)) {
LOG_E(PHY, "Invalid beta_offset_index %d, using default value\n", beta_offset_idx);
return beta_offset_values[9];
}
return beta_offset_values[beta_offset_idx];
}
static uint32_t get_d_factor_re(const uint32_t a, const uint32_t b)
{
uint32_t d_factor_re;
if (a >= b) {
d_factor_re = 1;
} else {
d_factor_re = floor((double)b / a);
if (d_factor_re == 0) {
d_factor_re = 1;
}
}
return d_factor_re;
}
// Function to lookup beta offset value from Table 9.3-1 in TS 38.213
static double get_beta_offset_harq_ack(uint8_t beta_offset_index)
{
@@ -586,13 +631,19 @@ static int get_crc_uci(const uint16_t ouci)
return L;
}
static uint16_t get_Qd(const uint16_t oack, double beta, double alpha, const uint32_t sumKr, const uint32_t s1, const uint32_t s2)
static uint16_t get_Qd(const uint16_t oack,
double beta,
double alpha,
const uint32_t sumKr,
const uint32_t s1,
const uint32_t s2,
const uint32_t sub)
{
if (oack == 0)
return 0;
uint16_t first_term = ceil(((double)oack + get_crc_uci(oack)) * (double)beta * s1 / sumKr);
uint16_t second_term = ceil(alpha * s2);
uint16_t second_term = ceil(alpha * s2) - sub;
return (first_term < second_term) ? first_term : second_term;
}
@@ -661,26 +712,41 @@ static rate_match_info_uci_t calc_rate_match_info_uci(const nfapi_nr_ue_pusch_pd
rate_match_info_uci_t rminfo = {0};
// get the number of coded HARQ-ACK symbols and bits, TS 38.212 section 6.3.2.4.1.1
rminfo.Q_dash_ACK = get_Qd(oack, beta, alpha, sumKr, s1, s2);
rminfo.Q_dash_ACK = get_Qd(oack, beta, alpha, sumKr, s1, s2, 0);
rminfo.E_uci_ACK = rminfo.Q_dash_ACK * nlqm;
if (oack_rvd > 0) {
rminfo.Q_dash_ACK_rvd = get_Qd(oack_rvd, beta, alpha, sumKr, s1, s2);
rminfo.Q_dash_ACK_rvd = get_Qd(oack_rvd, beta, alpha, sumKr, s1, s2, 0);
rminfo.E_uci_ACK_rvd = rminfo.Q_dash_ACK_rvd * nlqm;
}
// get beta offset for csi
const double beta_csi1 = get_beta_offset_csi(pusch_pdu->pusch_uci.beta_offset_csi1);
// get the number of coded CSI part 1 symbols and bits, TS 38.212 section 6.3.2.4.1.2
const uint16_t ocsi1 = pusch_pdu->pusch_uci.csi_payload.p1_bits;
rminfo.Q_dash_CSI1 = get_Qd(ocsi1, beta_csi1, alpha, sumKr, s1, s1, rminfo.Q_dash_ACK);
rminfo.E_uci_CSI1 = rminfo.Q_dash_CSI1 * nlqm;
// get the number of coded CSI part 2 symbols and bits, TS 38.212 section 6.3.2.4.1.3
const double beta_csi2 = get_beta_offset_csi(pusch_pdu->pusch_uci.beta_offset_csi2);
const uint16_t ocsi2 = pusch_pdu->pusch_uci.csi_payload.p2_bits;
rminfo.Q_dash_CSI2 = get_Qd(ocsi2, beta_csi2, alpha, sumKr, s1, s1, rminfo.Q_dash_ACK + rminfo.Q_dash_CSI1);
rminfo.E_uci_CSI2 = rminfo.Q_dash_CSI2 * nlqm;
rminfo.G_ulsch = *G - (rminfo.E_uci_CSI1 + rminfo.E_uci_CSI2);
if (oack_rvd == 0) {
rminfo.G_ulsch = *G - rminfo.E_uci_ACK;
} else {
rminfo.G_ulsch = *G;
rminfo.G_ulsch -= rminfo.E_uci_ACK;
}
*G = rminfo.G_ulsch;
LOG_D(PHY, "[UCI_RATE_MATCH] sumKr=%u, s1=%u, s2=%u, Final G_ulsch (output G): %u\n", sumKr, s1, s2, *G);
LOG_D(PHY,
"[UCI_RATE_MATCH] rate matching info returned: E_uci_ACK=%u, E_uci_ACK_rvd=%u, G_ulsch=%u\n",
"[UCI_RATE_MATCH] rate matching info returned: E_uci_ACK=%u, E_uci_ACK_rvd=%u, E_uci_CSI1=%u, E_uci_CSI2=%u, G_ulsch=%u\n",
rminfo.E_uci_ACK,
rminfo.E_uci_ACK_rvd,
rminfo.E_uci_CSI1,
rminfo.E_uci_CSI2,
rminfo.G_ulsch);
return rminfo;
@@ -747,115 +813,93 @@ static void get_first_uci_symbol(const uint8_t start_symbol,
*dmrs_p1 -= start_symbol;
}
/*
* This function builds the initial template by reserving positions for HARQ-ACK.
*/
static void build_template_reserve_ack(uci_on_pusch_bit_type_t *template,
const nfapi_nr_ue_pusch_pdu_t *pusch_pdu,
uint32_t G_ack_rvd,
uint8_t l1_c,
const uint32_t *m_uci_current,
const uint32_t *m_ulsch_initial,
uint32_t positions_by_sym[][MAX_UCI_CODED_BITS],
uint32_t *count_by_sym)
static inline bool skip_mapping_current_uci(const uci_on_pusch_bit_type_t template, const uci_on_pusch_bit_type_t uci_type_to_map)
{
const uint8_t n_symbols = pusch_pdu->nr_of_symbols;
const uint32_t nlqm = pusch_pdu->qam_mod_order * pusch_pdu->nrOfLayers;
bool ret = false;
switch (uci_type_to_map) {
case BIT_TYPE_ACK_RESERVED:
case BIT_TYPE_ACK:
// ACK bits get the highest priority. Don't skip
ret = false;
break;
memset(count_by_sym, 0, n_symbols * sizeof(uint32_t));
case BIT_TYPE_CSI1:
// Skip if already occupied by ACK and reserved ACK. Template is initialized with ULSCH
ret = (template != BIT_TYPE_ULSCH);
break;
uint32_t symbol_start_bit_idx[14] = {0};
for (uint8_t s = 1; s < n_symbols; s++) {
symbol_start_bit_idx[s] = symbol_start_bit_idx[s - 1] + (m_ulsch_initial[s - 1] * nlqm);
}
case BIT_TYPE_CSI2:
// Skip if already occupied by ACK but not reserved ACK
ret = (template != BIT_TYPE_ACK_RESERVED && template != BIT_TYPE_ULSCH);
break;
// Reserve Positions using RE-level D-Factor Distribution
uint32_t total_reserved = 0;
for (uint8_t sym = l1_c; sym < n_symbols && total_reserved < G_ack_rvd; sym++) {
const uint32_t uci_re_on_sym = m_uci_current[sym];
if (uci_re_on_sym > 0) {
const uint32_t remaining_to_reserve = G_ack_rvd - total_reserved;
uint32_t d_factor_re;
const uint32_t num_re_to_select = ceil((double)remaining_to_reserve / nlqm);
if (num_re_to_select >= uci_re_on_sym) {
d_factor_re = 1;
} else {
d_factor_re = floor((double)uci_re_on_sym / num_re_to_select);
if (d_factor_re == 0) {
d_factor_re = 1;
}
}
for (uint32_t re_offset = 0; re_offset < uci_re_on_sym && total_reserved < G_ack_rvd; re_offset += d_factor_re) {
for (uint32_t bit_in_re = 0; bit_in_re < nlqm; bit_in_re++) {
if (total_reserved >= G_ack_rvd) {
break;
}
uint32_t bit_offset_in_sym = (re_offset * nlqm) + bit_in_re;
uint32_t cw_idx = symbol_start_bit_idx[sym] + bit_offset_in_sym;
template[cw_idx] = BIT_TYPE_ACK_RESERVED;
positions_by_sym[sym][count_by_sym[sym]] = cw_idx;
count_by_sym[sym]++;
total_reserved++;
}
}
}
default:
AssertFatal(0, "Mapping called with incorrect UCI type\n");
}
return ret;
}
/*
* This function maps the HARQ-ACK bits when O_ACK > 2
*/
static void map_non_overlapped_ack(uci_on_pusch_bit_type_t *template,
const nfapi_nr_ue_pusch_pdu_t *pusch_pdu,
uint16_t G_ack,
uint8_t l1_c,
const uint32_t *m_uci_current,
const uint32_t *m_ulsch_initial)
{
const uint8_t n_symbols = pusch_pdu->nr_of_symbols;
const uint32_t nlqm = pusch_pdu->qam_mod_order * pusch_pdu->nrOfLayers;
struct map_uci_common_arg {
uci_on_pusch_bit_type_t *template;
uci_on_pusch_bit_type_t uci_type_to_map;
uint32_t n_symbols;
uint32_t nlqm;
uint16_t G_uci;
uint8_t l1_c;
uint32_t *m_uci_current;
uint32_t *m_ulsch_initial;
uint32_t (*resv_ack_pos_symb)[MAX_UCI_CODED_BITS];
uint32_t *resv_ack_count_symb;
};
uint32_t symbol_start_bit_idx[14] = {0};
for (uint8_t s = 1; s < n_symbols; s++) {
symbol_start_bit_idx[s] = symbol_start_bit_idx[s - 1] + (m_ulsch_initial[s - 1] * nlqm);
static void map_uci_common(struct map_uci_common_arg p)
{
DevAssert((p.resv_ack_count_symb && p.resv_ack_pos_symb && (p.uci_type_to_map == BIT_TYPE_ACK_RESERVED))
|| (!p.resv_ack_count_symb && !p.resv_ack_pos_symb && (p.uci_type_to_map != BIT_TYPE_ACK_RESERVED)));
uint32_t symbol_start_bit_idx[NR_SYMBOLS_PER_SLOT] = {0};
for (uint8_t s = 1; s < p.n_symbols; s++) {
symbol_start_bit_idx[s] = symbol_start_bit_idx[s - 1] + (p.m_ulsch_initial[s - 1] * p.nlqm);
}
if (p.uci_type_to_map == BIT_TYPE_ACK_RESERVED)
memset(p.resv_ack_count_symb, 0, sizeof(*p.resv_ack_count_symb) * NR_SYMBOLS_PER_SLOT);
uint32_t total_placed = 0;
for (uint8_t sym = l1_c; sym < n_symbols && total_placed < G_ack; sym++) {
const uint32_t uci_re_on_sym = m_uci_current[sym];
for (uint8_t sym = p.l1_c; sym < p.n_symbols && total_placed < p.G_uci; sym++) {
const uint32_t uci_re_on_sym = p.m_uci_current[sym];
if (uci_re_on_sym > 0) {
const uint32_t remaining_to_place = G_ack - total_placed;
uint32_t d_factor_re;
const uint32_t num_re_to_select = ceil((double)remaining_to_place / nlqm);
if (uci_re_on_sym <= 0) {
continue;
}
if (num_re_to_select >= uci_re_on_sym) {
d_factor_re = 1;
} else {
d_factor_re = floor((double)uci_re_on_sym / num_re_to_select);
if (d_factor_re == 0) {
d_factor_re = 1;
}
const uint32_t remaining_to_place = p.G_uci - total_placed;
const uint32_t num_re_to_select = ceil((double)remaining_to_place / p.nlqm);
uint32_t d_factor_re = get_d_factor_re(num_re_to_select, uci_re_on_sym);
uint32_t re_offset = 0;
uint32_t *cur_sym_resv_ack_pos = p.resv_ack_pos_symb[sym];
while (re_offset < uci_re_on_sym && total_placed < p.G_uci) {
uci_on_pusch_bit_type_t cur_template = p.template[symbol_start_bit_idx[sym] + (re_offset * p.nlqm)];
if (skip_mapping_current_uci(cur_template, p.uci_type_to_map)) {
re_offset++;
continue; // if RE already allocated to UCI or reserved for ACK
}
for (uint32_t re_offset = 0; re_offset < uci_re_on_sym && total_placed < G_ack; re_offset += d_factor_re) {
for (uint32_t bit_in_re = 0; bit_in_re < nlqm; bit_in_re++) {
if (total_placed >= G_ack) {
break;
}
uint32_t bit_offset_in_sym = (re_offset * nlqm) + bit_in_re;
uint32_t cw_idx = symbol_start_bit_idx[sym] + bit_offset_in_sym;
template[cw_idx] = BIT_TYPE_ACK;
total_placed++;
for (uint32_t bit_in_re = 0; bit_in_re < p.nlqm; bit_in_re++) {
if (total_placed >= p.G_uci) {
break;
}
uint32_t bit_offset_in_sym = (re_offset * p.nlqm) + bit_in_re;
uint32_t cw_idx = symbol_start_bit_idx[sym] + bit_offset_in_sym;
p.template[cw_idx] = p.uci_type_to_map;
if (p.uci_type_to_map == BIT_TYPE_ACK_RESERVED) {
cur_sym_resv_ack_pos[p.resv_ack_count_symb[sym]++] = cw_idx;
}
total_placed++;
}
re_offset += d_factor_re;
}
}
}
@@ -877,21 +921,13 @@ static void map_overlapped_ack(uci_on_pusch_bit_type_t *template,
if (num_reserved_bits_on_sym > 0) {
const uint32_t num_ack_remaining = G_ack - ack_bits_marked;
uint32_t d_factor;
// This d-factor is calculated for stepping through the list of *reserved bits*.
if (num_ack_remaining >= num_reserved_bits_on_sym) {
d_factor = 1;
} else {
d_factor = floor((double)num_reserved_bits_on_sym / num_ack_remaining);
if (d_factor == 0) {
d_factor = 1;
}
}
const uint32_t d_factor_re = get_d_factor_re(num_ack_remaining, num_reserved_bits_on_sym);
const uint32_t *reserved_indices_on_this_sym = positions_by_sym[sym_iter];
for (uint32_t i = 0; i < num_reserved_bits_on_sym && ack_bits_marked < G_ack; i += d_factor) {
for (uint32_t i = 0; i < num_reserved_bits_on_sym && ack_bits_marked < G_ack; i += d_factor_re) {
uint32_t pos_to_mark = reserved_indices_on_this_sym[i];
template[pos_to_mark] = BIT_TYPE_ACK_ULSCH;
@@ -909,11 +945,17 @@ static void apply_template_to_codeword(uint8_t *codeword,
uint32_t codeword_len,
const uint8_t *ulsch_bits,
const uint64_t *cack,
const uint64_t *csi1,
const uint64_t *csi2,
uint16_t G_ack,
uint32_t G_csi1,
uint32_t G_csi2,
uint32_t G_ulsch)
{
uint32_t ulsch_idx = 0;
uint32_t ack_idx = 0;
uint32_t csi1_idx = 0;
uint32_t csi2_idx = 0;
for (uint32_t i = 0; i < codeword_len; i++) {
switch (template[i]) {
@@ -935,6 +977,24 @@ static void apply_template_to_codeword(uint8_t *codeword,
}
break;
case BIT_TYPE_CSI1:
if (G_csi1 > 0 && csi1_idx < G_csi1) {
uint32_t word_idx = csi1_idx / 64;
uint32_t bit_in_word_idx = csi1_idx % 64;
codeword[i] = (csi1[word_idx] >> bit_in_word_idx) & 1;
csi1_idx++;
}
break;
case BIT_TYPE_CSI2:
if (G_csi2 > 0 && csi2_idx < G_csi2) {
uint32_t word_idx = csi2_idx / 64;
uint32_t bit_in_word_idx = csi2_idx % 64;
codeword[i] = (csi2[word_idx] >> bit_in_word_idx) & 1;
csi2_idx++;
}
break;
case BIT_TYPE_ACK_RESERVED:
case BIT_TYPE_ULSCH:
default:
@@ -957,10 +1017,14 @@ static uci_on_pusch_bit_type_t *nr_data_control_mapping(const nfapi_nr_ue_pusch_
unsigned int G_ulsch,
uint16_t G_ack,
uint32_t G_ack_rvd,
uint32_t G_csi1,
uint32_t G_csi2,
uint8_t *codeword,
uint32_t codeword_len,
const uint8_t *ulsch_bits,
const uint64_t *cack)
const uint64_t *cack,
const uint64_t *csi1,
const uint64_t *csi2)
{
if (!pusch_pdu || !codeword || codeword_len == 0 || !template)
return NULL;
@@ -989,24 +1053,40 @@ static uci_on_pusch_bit_type_t *nr_data_control_mapping(const nfapi_nr_ue_pusch_
uint32_t positions_by_sym[NR_NUMBER_OF_SYMBOLS_PER_SLOT][MAX_UCI_CODED_BITS] = {0};
uint32_t count_by_sym[NR_NUMBER_OF_SYMBOLS_PER_SLOT] = {0};
struct map_uci_common_arg map_arg = {.template = template,
.n_symbols = pusch_pdu->nr_of_symbols,
.nlqm = pusch_pdu->qam_mod_order * pusch_pdu->nrOfLayers,
.l1_c = l1_c,
.m_uci_current = m_uci_current,
.m_ulsch_initial = m_ulsch_initial};
if (G_ack_rvd > 0) {
build_template_reserve_ack(template,
pusch_pdu,
G_ack_rvd,
l1_c,
m_uci_current,
m_ulsch_initial,
positions_by_sym,
count_by_sym);
map_arg.uci_type_to_map = BIT_TYPE_ACK_RESERVED;
map_arg.G_uci = G_ack_rvd;
map_arg.resv_ack_pos_symb = positions_by_sym;
map_arg.resv_ack_count_symb = count_by_sym;
map_uci_common(map_arg);
} else if (G_ack > 0) {
map_non_overlapped_ack(template, pusch_pdu, G_ack, l1_c, m_uci_current, m_ulsch_initial);
map_arg.uci_type_to_map = BIT_TYPE_ACK;
map_arg.G_uci = G_ack;
map_uci_common(map_arg);
}
// CSI part 1
map_arg.uci_type_to_map = BIT_TYPE_CSI1;
map_arg.G_uci = G_csi1;
map_arg.resv_ack_pos_symb = NULL;
map_arg.resv_ack_count_symb = NULL;
map_uci_common(map_arg);
// CSI part 2
map_arg.uci_type_to_map = BIT_TYPE_CSI2;
map_arg.G_uci = G_csi2;
map_uci_common(map_arg);
if (G_ack > 0 && G_ack_rvd > 0) {
map_overlapped_ack(template, G_ack, l1_c, n_symbols, positions_by_sym, count_by_sym);
}
apply_template_to_codeword(codeword, template, codeword_len, ulsch_bits, cack, G_ack, G_ulsch);
apply_template_to_codeword(codeword, template, codeword_len, ulsch_bits, cack, csi1, csi2, G_ack, G_csi1, G_csi2, G_ulsch);
return template;
}
@@ -1106,7 +1186,8 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE,
return;
}
if (pusch_pdu->pusch_uci.harq_ack_bit_length != 0) {
bool uci_present = (pusch_pdu->pusch_uci.harq_ack_bit_length != 0) || (pusch_pdu->pusch_uci.csi_payload.p1_bits != 0);
if (uci_present) {
rm_info = calc_rate_match_info_uci(pusch_pdu, harq_process_ul_ue, nl_qm, &G[pusch_id]);
}
@@ -1123,12 +1204,10 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE,
int N_PRB_oh = 0; // higher layer (RRC) parameter xOverhead in PUSCH-ServingCellConfig
if (pusch_pdu->pusch_uci.harq_ack_bit_length != 0) {
LOG_D(PHY, "[UCI_ON_PUSCH] Original HARQ-ACK bit length: %u\n", pusch_pdu->pusch_uci.harq_ack_bit_length);
LOG_D(PHY, "[UCI_ON_PUSCH] Initial G: %u\n", G_initial_total_pusch_bits);
// b is the block of bits transmitted on the physical channel after payload coding
uint64_t b[16] = {0}; // limit to 1024-bit encoded length
// b is the block of bits transmitted on the physical channel after payload coding
uint64_t b_ack[16] = {0}; // limit to 1024-bit encoded length
if (pusch_pdu->pusch_uci.harq_ack_bit_length != 0) {
if (pucch_pdu == NULL) {
LOG_E(PHY, "nr_ue_ulsch_procedures: pucch_pdu is NULL but HARQ-ACK is present. Cannot proceed with UCI encoding.\n");
stop_meas_nr_ue_phy(UE, PUSCH_PROC_STATS);
@@ -1141,7 +1220,7 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE,
true,
rm_info.E_uci_ACK,
mod_order,
&b[0]);
&b_ack[0]);
LOG_D(PHY,
"[UCI_ON_PUSCH] G_ulsch=%u (updated G[pusch_id]), G_ack=%u (M_bit), G_ack_rvd=%u, total_len=%u "
@@ -1150,7 +1229,31 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE,
rm_info.E_uci_ACK,
rm_info.E_uci_ACK_rvd,
G_initial_total_pusch_bits);
}
uint64_t b_csi1[16] = {0}; // limit to 1024-bit encoded length
uint64_t b_csi2[16] = {0}; // limit to 1024-bit encoded length
if (pusch_pdu->pusch_uci.csi_payload.p1_bits != 0) {
nr_uci_encoding(pusch_pdu->pusch_uci.csi_payload.part1_payload,
pusch_pdu->pusch_uci.csi_payload.p1_bits,
pucch_pdu->prb_size,
true,
rm_info.E_uci_CSI1,
mod_order,
&b_csi1[0]);
// Process CSI Part 2 if any
if (pusch_pdu->pusch_uci.csi_payload.p2_bits > 0)
nr_uci_encoding(pusch_pdu->pusch_uci.csi_payload.part2_payload,
pusch_pdu->pusch_uci.csi_payload.p2_bits,
pucch_pdu->prb_size,
true,
rm_info.E_uci_CSI2,
mod_order,
&b_csi2[0]);
}
if (uci_present) {
uint8_t temp_codeword[G_initial_total_pusch_bits];
start_meas_nr_ue_phy(UE, UCI_ON_PUSCH_MAPPING);
nr_data_control_mapping(pusch_pdu,
@@ -1158,18 +1261,19 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE,
G[pusch_id],
rm_info.E_uci_ACK,
rm_info.E_uci_ACK_rvd,
rm_info.E_uci_CSI1,
rm_info.E_uci_CSI2,
temp_codeword,
G_initial_total_pusch_bits,
harq_process_ul_ue->f,
b);
b_ack,
b_csi1,
b_csi2);
stop_meas_nr_ue_phy(UE, UCI_ON_PUSCH_MAPPING);
memcpy(harq_process_ul_ue->f, temp_codeword, G_initial_total_pusch_bits);
uci_mapping_template = template_buffer;
}
AssertFatal(pusch_pdu->pusch_uci.csi_part1_bit_length == 0 && pusch_pdu->pusch_uci.csi_part2_bit_length == 0,
"UCI (CSI) on PUSCH not supported at PHY\n");
uint16_t start_rb = pusch_pdu->rb_start;
uint16_t start_sc = frame_parms->first_carrier_offset + (start_rb + pusch_pdu->bwp_start) * NR_NB_SC_PER_RB;
@@ -1202,9 +1306,8 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE,
/////////////////////////ULSCH scrambling/////////////////////////
uint32_t available_bits;
bool is_uci_on_pusch = (pusch_pdu->pusch_uci.harq_ack_bit_length != 0);
if (is_uci_on_pusch) {
if (uci_present) {
// UCI on PUSCH is present, so available bits are the total codeword length
available_bits = G_initial_total_pusch_bits;
} else {
@@ -1221,7 +1324,7 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE,
available_bits,
pusch_pdu->data_scrambling_id,
rnti,
is_uci_on_pusch,
uci_present,
uci_mapping_template,
scrambled_output);
if (UE->phy_sim_test_buf) {
+8 -10
View File
@@ -257,15 +257,15 @@ static void prepare_ue_pusch_pdu_from_matlab_vector(const bool uci_on_pusch,
p_vec_bits += var.A;
copy_bytes_to_packed_bits(p_vec_bits, var.oack, false, pb);
pusch_config_pdu->pusch_uci.csi_part1_bit_length = var.ocsi1;
pb = (uint8_t *)&pusch_config_pdu->pusch_uci.csi_part1_payload;
memset(pb, 0, sizeof(pusch_config_pdu->pusch_uci.csi_part1_payload));
pusch_config_pdu->pusch_uci.csi_payload.p1_bits = var.ocsi1;
pb = (uint8_t *)&pusch_config_pdu->pusch_uci.csi_payload.part1_payload;
memset(pb, 0, sizeof(pusch_config_pdu->pusch_uci.csi_payload.part1_payload));
p_vec_bits += var.oack;
copy_bytes_to_packed_bits(p_vec_bits, var.ocsi1, false, pb);
pusch_config_pdu->pusch_uci.csi_part2_bit_length = var.ocsi2;
pb = (uint8_t *)&pusch_config_pdu->pusch_uci.csi_part2_payload;
memset(pb, 0, sizeof(pusch_config_pdu->pusch_uci.csi_part2_payload));
pusch_config_pdu->pusch_uci.csi_payload.p2_bits = var.ocsi2;
pb = (uint8_t *)&pusch_config_pdu->pusch_uci.csi_payload.part2_payload;
memset(pb, 0, sizeof(pusch_config_pdu->pusch_uci.csi_payload.part2_payload));
p_vec_bits += var.ocsi1;
copy_bytes_to_packed_bits(p_vec_bits, var.ocsi2, false, pb);
}
@@ -1349,9 +1349,7 @@ int main(int argc, char *argv[])
.beta_offset_harq_ack = 11,
.harq_ack_bit_length = 3,
.harq_payload = 3,
//.csi_part1_bit_length = 4,
//.csi_part1_payload = 15
};
.csi_payload = {.p1_bits = 4, .part1_payload = 15, .p2_bits = 4, .part2_payload = 15}};
pusch_config_pdu->pusch_uci = pusch_uci;
prepare_ue_pusch_pdu_from_matlab_vector(uci_on_pusch, uci_ulsch_matlab_vec, pusch_config_pdu, cw_buf);
}
@@ -1603,7 +1601,6 @@ int main(int argc, char *argv[])
}
}
}
round++;
if (uci_on_pusch && uci_ulsch_matlab_vec && (errors_scrambling[round] == 0)) {
ret = 0;
printf("*************\n");
@@ -1611,6 +1608,7 @@ int main(int argc, char *argv[])
printf("*************\n");
break;
}
round++;
} // round
if (n_trials == 1 && errors_scrambling[0] > 0) {
@@ -1,5 +1,5 @@
% ulsim command for same pusch config
% ./nr_ulsim -m 27 -u 1 -R 51 -r 51 -s 300 -o uci_on_pusch_7.bin
% ./nr_ulsim -m 27 -u 1 -R 51 -r 51 -s 300 -ouci_on_pusch_oack3_ocsi14_ocsi20.bin
carrier = nrCarrierConfig;
carrier.NSizeGrid = 51;
@@ -32,7 +32,7 @@ pusch.DMRS.SequenceHopping = 0;
pusch.BetaOffsetACK = 20;
pusch.BetaOffsetCSI1 = 6.25;
pusch.BetaOffsetCSI2 = 1;
pusch.BetaOffsetCSI2 = 6.25;
pusch.UCIScaling = 1;
A = 37896;
@@ -41,17 +41,17 @@ rv = 0;
modulation = pusch.Modulation;
nlayers = pusch.NumLayers; % Number of layers for decoding
oack = 7;
ocsi1 = 0;
ocsi2 = 0;
oack = 3;
ocsi1 = 4;
ocsi2 = 4;
cbsInfo = nrULSCHInfo(pusch, rate, A, oack, ocsi1, ocsi2); % Get ULSCH information
ack = randi([0 1],oack,1);
csi1 = randi([0 1],ocsi1,1);
csi2 = randi([0 1],ocsi2,1);
cack = nrUCIEncode(ack,cbsInfo.GACK,pusch.Modulation);
ccsi1 = [];
ccsi2 = [];
ccsi1 = nrUCIEncode(csi1,cbsInfo.GCSI1,pusch.Modulation);
ccsi2 = nrUCIEncode(csi2,cbsInfo.GCSI2,pusch.Modulation);
tb_data = randi([0 1],A,1);
% Transport block CRC attachment
@@ -73,7 +73,8 @@ culsch = chIn;
cw_scr = nrPUSCHScramble(cw,pusch.NID,pusch.RNTI);
% Write to bin file
fid = fopen('uci_on_pusch_7.bin', 'wb');
file_name = sprintf('uci_on_pusch_oack%d_ocsi1%d_ocsi2%d.bin', oack, ocsi1, ocsi2);
fid = fopen(file_name, 'wb');
to_write = [A,oack,ocsi1,ocsi2,length(cw),length(cw_scr)];
fwrite(fid, to_write, 'uint32'); % Write the data to the binary file
fwrite(fid, tb_data, "uint8");
@@ -3399,11 +3399,11 @@ uint16_t get_ssb_start_symbol(const long band, NR_SubcarrierSpacing_t scs, int i
}
}
void csi_period_offset(NR_CSI_ReportConfig_t *csirep,
struct NR_CSI_ResourcePeriodicityAndOffset *periodicityAndOffset,
int *period, int *offset) {
void csi_period_offset(const NR_CSI_ReportConfig_t *csirep,
const struct NR_CSI_ResourcePeriodicityAndOffset *periodicityAndOffset,
int *period,
int *offset)
{
if(periodicityAndOffset != NULL) {
NR_CSI_ResourcePeriodicityAndOffset_PR p_and_o = periodicityAndOffset->present;
@@ -285,9 +285,10 @@ unsigned int get_N_RA_RB(const unsigned int delta_f_RA_PRACH, const unsigned int
void find_period_offset_SR(const NR_SchedulingRequestResourceConfig_t *SchedulingReqRec, int *period, int *offset);
void csi_period_offset(NR_CSI_ReportConfig_t *csirep,
struct NR_CSI_ResourcePeriodicityAndOffset *periodicityAndOffset,
int *period, int *offset);
void csi_period_offset(const NR_CSI_ReportConfig_t *csirep,
const struct NR_CSI_ResourcePeriodicityAndOffset *periodicityAndOffset,
int *period,
int *offset);
bool set_dl_ptrs_values(NR_PTRS_DownlinkConfig_t *ptrs_config,
uint16_t rbSize, uint8_t mcsIndex, uint8_t mcsTable,
+1 -10
View File
@@ -310,10 +310,8 @@ typedef struct {
NR_PUCCH_Resource_t *pucch_resource;
uint32_t ack_payload;
uint8_t sr_payload;
uint64_t csi_part1_payload;
uint64_t csi_part2_payload;
nfapi_nr_ue_csi_payload_t csi_payload;
int n_sr;
int n_csi;
int n_harq;
int n_CCE;
int N_CCE;
@@ -490,13 +488,6 @@ typedef struct {
A_SEQUENCE_OF(NR_SearchSpace_t) list_SS;
} NR_BWP_PDCCH_t;
typedef struct csi_payload {
uint64_t part1_payload;
uint64_t part2_payload;
int p1_bits;
int p2_bits;
} csi_payload_t;
typedef enum {
WIDEBAND_ON_PUCCH,
SUBBAND_ON_PUCCH,
+10 -5
View File
@@ -124,7 +124,7 @@ void release_mac_configuration(NR_UE_MAC_INST_t *mac,
void nr_ue_ul_scheduler(NR_UE_MAC_INST_t *mac, nr_uplink_indication_t *ul_info);
void nr_ue_dl_scheduler(NR_UE_MAC_INST_t *mac, nr_downlink_indication_t *dl_info);
csi_payload_t nr_ue_aperiodic_csi_reporting(NR_UE_MAC_INST_t *mac, dci_field_t csi_request, int tda, long *K2);
nfapi_nr_ue_csi_payload_t nr_ue_aperiodic_csi_reporting(NR_UE_MAC_INST_t *mac, dci_field_t csi_request, int tda, long *K2);
nr_dci_format_t nr_ue_process_dci_indication_pdu(NR_UE_MAC_INST_t *mac, frame_t frame, int slot, fapi_nr_dci_indication_pdu_t *dci);
@@ -137,12 +137,17 @@ bool trigger_periodic_scheduling_request(NR_UE_MAC_INST_t *mac,
frame_t frame,
int slot);
int nr_get_csi_measurements(NR_UE_MAC_INST_t *mac, frame_t frame, int slot, PUCCH_sched_t *pucch);
int nr_get_csi_measurements(NR_UE_MAC_INST_t *mac,
frame_t frame,
int slot,
nfapi_nr_ue_csi_payload_t *csi_payload,
NR_PUCCH_Resource_t **csi_pucch,
bool csi_on_pusch);
csi_payload_t nr_get_csi_payload(NR_UE_MAC_INST_t *mac,
nfapi_nr_ue_csi_payload_t nr_get_csi_payload(NR_UE_MAC_INST_t *mac,
int csi_report_id,
CSI_mapping_t mapping_type,
NR_CSI_MeasConfig_t *csi_MeasConfig);
const NR_CSI_MeasConfig_t *csi_MeasConfig);
/* \brief Get payload (MAC PDU) from UE PHY
@param dl_info pointer to dl indication
@@ -330,7 +335,7 @@ int nr_config_pusch_pdu(NR_UE_MAC_INST_t *mac,
NR_tda_info_t *tda_info,
nfapi_nr_ue_pusch_pdu_t *pusch_config_pdu,
dci_pdu_rel15_t *dci,
csi_payload_t *csi_report,
nfapi_nr_ue_csi_payload_t *csi_report,
RAR_grant_t *rar_grant,
rnti_t rnti,
int ss_type,
+105 -98
View File
@@ -632,7 +632,7 @@ static int nr_ue_process_dci_ul_01(NR_UE_MAC_INST_t *mac,
/* CSI_REQUEST */
long csi_K2 = -1;
csi_payload_t csi_report = {0};
nfapi_nr_ue_csi_payload_t csi_report = {0};
if (dci->csi_request.nbits > 0 && dci->csi_request.val > 0)
csi_report = nr_ue_aperiodic_csi_reporting(mac, dci->csi_request, dci->time_domain_assignment.val, &csi_K2);
@@ -1609,7 +1609,7 @@ int nr_ue_configure_pucch(NR_UE_MAC_INST_t *mac,
pucch_pdu->second_hop_prb = pucchres->secondHopPRB!= NULL ? *pucchres->secondHopPRB : 0;
pucch_pdu->prb_size = 1; // format 0 or 1
int n_uci = pucch->n_sr + pucch->n_harq + pucch->n_csi;
int n_uci = pucch->n_sr + pucch->n_harq + pucch->csi_payload.p1_bits;
if (n_uci > (sizeof(uint64_t) * 8)) {
LOG_E(NR_MAC, "PUCCH number of UCI bits exceeds payload size\n");
return -1;
@@ -1651,14 +1651,15 @@ int nr_ue_configure_pucch(NR_UE_MAC_INST_t *mac,
pucch_pdu->dmrs_scrambling_id = id0 != NULL ? *id0 : mac->physCellId;
pucch_pdu->prb_size = compute_pucch_prb_size(2,
pucchres->format.choice.format2->nrofPRBs,
pucch->n_csi,
pucch->csi_payload.p1_bits,
pucch->n_harq,
pucch->n_sr,
pucch_Config->format2->choice.setup->maxCodeRate,
2,
pucchres->format.choice.format2->nrofSymbols,
8);
pucch_pdu->payload = (pucch->csi_part1_payload << (pucch->n_harq + pucch->n_sr)) | (pucch->sr_payload << pucch->n_harq) | pucch->ack_payload;
pucch_pdu->payload = (pucch->csi_payload.part1_payload << (pucch->n_harq + pucch->n_sr))
| (pucch->sr_payload << pucch->n_harq) | pucch->ack_payload;
break;
case NR_PUCCH_Resource__format_PR_format3 :
pucch_pdu->format_type = 3;
@@ -1686,14 +1687,15 @@ int nr_ue_configure_pucch(NR_UE_MAC_INST_t *mac,
}
pucch_pdu->prb_size = compute_pucch_prb_size(3,
pucchres->format.choice.format3->nrofPRBs,
pucch->n_csi,
pucch->csi_payload.p1_bits,
pucch->n_harq,
pucch->n_sr,
pucch_Config->format3->choice.setup->maxCodeRate,
2 - pucch_pdu->pi_2bpsk,
pucchres->format.choice.format3->nrofSymbols - f3_dmrs_symbols,
12);
pucch_pdu->payload = (pucch->csi_part1_payload << (pucch->n_harq + pucch->n_sr)) | (pucch->sr_payload << pucch->n_harq) | pucch->ack_payload;
pucch_pdu->payload = (pucch->csi_payload.part1_payload << (pucch->n_harq + pucch->n_sr))
| (pucch->sr_payload << pucch->n_harq) | pucch->ack_payload;
break;
case NR_PUCCH_Resource__format_PR_format4 :
pucch_pdu->format_type = 4;
@@ -1711,7 +1713,8 @@ int nr_ue_configure_pucch(NR_UE_MAC_INST_t *mac,
pucch_pdu->pi_2bpsk = pucchfmt->pi2BPSK!= NULL ? 1 : 0;
pucch_pdu->add_dmrs_flag = pucchfmt->additionalDMRS!= NULL ? 1 : 0;
}
pucch_pdu->payload = (pucch->csi_part1_payload << (pucch->n_harq + pucch->n_sr)) | (pucch->sr_payload << pucch->n_harq) | pucch->ack_payload;
pucch_pdu->payload = (pucch->csi_payload.part1_payload << (pucch->n_harq + pucch->n_sr))
| (pucch->sr_payload << pucch->n_harq) | pucch->ack_payload;
break;
default :
LOG_E(NR_MAC, "Undefined PUCCH format \n");
@@ -2152,8 +2155,8 @@ void merge_resources(PUCCH_sched_t *res, int num_res, NR_PUCCH_Config_t *pucch_C
case NR_PUCCH_Resource__format_PR_format2:
case NR_PUCCH_Resource__format_PR_format4:
case NR_PUCCH_Resource__format_PR_format3:
if (res[i + 1].n_csi > 0) {
AssertFatal(res[i].n_csi == 0, "Multiplexing multiple CSI report in a single PUCCH not supported yet\n");
if (res[i + 1].csi_payload.p1_bits > 0) {
AssertFatal(res[i].csi_payload.p1_bits == 0, "Multiplexing multiple CSI report in a single PUCCH not supported yet\n");
AssertFatal(res[i].n_harq > 0 && res[i + 1].n_harq == 0,
"There is CSI in next F2 or above resource, since there is no CSI in current one, we expect HARQ in "
"there and not in next\n");
@@ -2166,8 +2169,8 @@ void merge_resources(PUCCH_sched_t *res, int num_res, NR_PUCCH_Config_t *pucch_C
res[i].n_sr = res[i + 1].n_sr;
res[i].sr_payload = res[i + 1].sr_payload;
}
res[i].n_csi = res[i + 1].n_csi;
res[i].csi_part1_payload = res[i + 1].csi_part1_payload;
res[i].csi_payload.p1_bits = res[i + 1].csi_payload.p1_bits;
res[i].csi_payload.part1_payload = res[i + 1].csi_payload.part1_payload;
res[i + 1] = res[i];
res[i] = empty;
} else {
@@ -2188,8 +2191,8 @@ void merge_resources(PUCCH_sched_t *res, int num_res, NR_PUCCH_Config_t *pucch_C
res[i] = empty;
}
}
} else if (res[i].n_csi > 0) {
AssertFatal(res[i + 1].n_csi == 0, "Multiplexing multiple CSI report in a single PUCCH not supported yet\n");
} else if (res[i].csi_payload.p1_bits > 0) {
AssertFatal(res[i + 1].csi_payload.p1_bits == 0, "Multiplexing multiple CSI report in a single PUCCH not supported yet\n");
AssertFatal(res[i + 1].n_harq > 0 && res[i].n_harq == 0,
"There is CSI in next F2 or above resource, since there is no CSI in current one, we expect HARQ in "
"there and not in next\n");
@@ -2202,8 +2205,8 @@ void merge_resources(PUCCH_sched_t *res, int num_res, NR_PUCCH_Config_t *pucch_C
res[i + 1].n_sr = res[i].n_sr;
res[i + 1].sr_payload = res[i].sr_payload;
}
res[i + 1].n_csi = res[i].n_csi;
res[i + 1].csi_part1_payload = res[i].csi_part1_payload;
res[i + 1].csi_payload.p1_bits = res[i].csi_payload.p1_bits;
res[i + 1].csi_payload.part1_payload = res[i].csi_payload.part1_payload;
res[i] = empty;
} else {
if (res[i + 1].n_sr > 0) {
@@ -2597,68 +2600,72 @@ int compute_csi_priority(NR_UE_MAC_INST_t *mac, NR_CSI_ReportConfig_t *csirep)
return 2 * Ncells * Ms * y + Ncells * Ms * k + Ms * c + s;
}
int nr_get_csi_measurements(NR_UE_MAC_INST_t *mac, frame_t frame, int slot, PUCCH_sched_t *pucch)
int nr_get_csi_measurements(NR_UE_MAC_INST_t *mac,
frame_t frame,
int slot,
nfapi_nr_ue_csi_payload_t *csi_payload,
NR_PUCCH_Resource_t **csi_pucch,
bool csi_on_pusch)
{
NR_UE_UL_BWP_t *current_UL_BWP = mac->current_UL_BWP;
NR_PUCCH_Config_t *pucch_Config = current_UL_BWP ? current_UL_BWP->pucch_Config : NULL;
if (!mac->sc_info.csi_MeasConfig || !pucch_Config)
return 0;
int num_csi = 0;
NR_CSI_MeasConfig_t *csi_measconfig = mac->sc_info.csi_MeasConfig;
if (mac->sc_info.csi_MeasConfig) {
NR_CSI_MeasConfig_t *csi_measconfig = mac->sc_info.csi_MeasConfig;
int csi_priority = INT_MAX;
for (int csi_report_id = 0; csi_report_id < csi_measconfig->csi_ReportConfigToAddModList->list.count; csi_report_id++) {
NR_CSI_ReportConfig_t *csirep = csi_measconfig->csi_ReportConfigToAddModList->list.array[csi_report_id];
int csi_priority = INT_MAX;
for (int csi_report_id = 0; csi_report_id < csi_measconfig->csi_ReportConfigToAddModList->list.count; csi_report_id++) {
NR_CSI_ReportConfig_t *csirep = csi_measconfig->csi_ReportConfigToAddModList->list.array[csi_report_id];
AssertFatal(csirep->reportConfigType.present == NR_CSI_ReportConfig__reportConfigType_PR_aperiodic
|| csirep->reportConfigType.present == NR_CSI_ReportConfig__reportConfigType_PR_periodic,
"Not supported CSI report type\n");
if(csirep->reportConfigType.present == NR_CSI_ReportConfig__reportConfigType_PR_periodic) {
int period, offset;
csi_period_offset(csirep, NULL, &period, &offset);
const int n_slots_frame = mac->frame_structure.numb_slots_frame;
if (((n_slots_frame*frame + slot - offset)%period) == 0 && pucch_Config) {
int csi_res_id = -1;
for (int i = 0; i < csirep->reportConfigType.choice.periodic->pucch_CSI_ResourceList.list.count; i++) {
const NR_PUCCH_CSI_Resource_t *pucchcsires =
csirep->reportConfigType.choice.periodic->pucch_CSI_ResourceList.list.array[i];
if (pucchcsires->uplinkBandwidthPartId == current_UL_BWP->bwp_id) {
csi_res_id = pucchcsires->pucch_Resource;
break;
}
}
if (csi_res_id < 0) {
// This CSI Report ID is not associated with current active BWP
continue;
}
NR_PUCCH_Resource_t *csi_pucch = find_pucch_resource_from_list(pucch_Config->resourceToAddModList, csi_res_id);
AssertFatal(csi_pucch != NULL, "Couldn't find PUCCH Resource ID for SR in PUCCH resource list\n");
LOG_D(NR_MAC, "Preparing CSI report in frame %d slot %d CSI report ID %d\n", frame, slot, csi_report_id);
int temp_priority = compute_csi_priority(mac, csirep);
if (num_csi > 0) {
// need to verify if we can multiplex multiple CSI report
if (pucch_Config->multi_CSI_PUCCH_ResourceList) {
AssertFatal(false, "Multiplexing multiple CSI report in a single PUCCH not supported yet\n");
} else if (temp_priority < csi_priority) {
// we discard previous report
csi_priority = temp_priority;
num_csi = 1;
csi_payload_t csi = nr_get_csi_payload(mac, csi_report_id, WIDEBAND_ON_PUCCH, csi_measconfig);
pucch->n_csi = csi.p1_bits;
pucch->csi_part1_payload = csi.part1_payload;
pucch->pucch_resource = csi_pucch;
} else
continue;
} else {
num_csi = 1;
csi_priority = temp_priority;
csi_payload_t csi = nr_get_csi_payload(mac, csi_report_id, WIDEBAND_ON_PUCCH, csi_measconfig);
pucch->n_csi = csi.p1_bits;
pucch->csi_part1_payload = csi.part1_payload;
pucch->pucch_resource = csi_pucch;
}
}
// Aperiodic CSI measurements handled in nr_ue_aperiodic_csi_reporting function
if (csirep->reportConfigType.present != NR_CSI_ReportConfig__reportConfigType_PR_periodic)
continue;
int period, offset;
csi_period_offset(csirep, NULL, &period, &offset);
const int n_slots_frame = mac->frame_structure.numb_slots_frame;
// Check if current slot falls in the report period
if (((n_slots_frame * frame + slot - offset) % period) != 0)
continue;
int csi_res_id = -1;
for (int i = 0; i < csirep->reportConfigType.choice.periodic->pucch_CSI_ResourceList.list.count; i++) {
const NR_PUCCH_CSI_Resource_t *pucchcsires = csirep->reportConfigType.choice.periodic->pucch_CSI_ResourceList.list.array[i];
if (pucchcsires->uplinkBandwidthPartId == current_UL_BWP->bwp_id) {
csi_res_id = pucchcsires->pucch_Resource;
break;
}
else
AssertFatal(csirep->reportConfigType.present == NR_CSI_ReportConfig__reportConfigType_PR_aperiodic,
"Not supported CSI report type\n");
}
if (csi_res_id < 0) {
// This CSI Report ID is not associated with current active BWP
continue;
}
*csi_pucch = find_pucch_resource_from_list(pucch_Config->resourceToAddModList, csi_res_id);
AssertFatal(*csi_pucch != NULL, "Couldn't find PUCCH Resource ID for CSI in PUCCH resource list\n");
LOG_D(NR_MAC, "Preparing CSI report in frame %d slot %d CSI report ID %d\n", frame, slot, csi_report_id);
int temp_priority = compute_csi_priority(mac, csirep);
if (num_csi > 0) {
// need to verify if we can multiplex multiple CSI report
if (pucch_Config->multi_CSI_PUCCH_ResourceList) {
AssertFatal(false, "Multiplexing multiple CSI report in a single PUCCH not supported yet\n");
} else if (temp_priority < csi_priority) {
// we discard previous report
csi_priority = temp_priority;
num_csi = 1;
*csi_payload = nr_get_csi_payload(mac, csi_report_id, csi_on_pusch ? ON_PUSCH : WIDEBAND_ON_PUCCH, csi_measconfig);
} else
continue;
} else {
num_csi = 1;
csi_priority = temp_priority;
*csi_payload = nr_get_csi_payload(mac, csi_report_id, csi_on_pusch ? ON_PUSCH : WIDEBAND_ON_PUCCH, csi_measconfig);
}
}
return num_csi;
@@ -2696,10 +2703,10 @@ static int compare_ssb_sinr(const void *a, const void *b)
return mb->ssb_sinr_dB - ma->ssb_sinr_dB;
}
static csi_payload_t get_ssb_sinr_payload(NR_UE_MAC_INST_t *mac,
struct NR_CSI_ReportConfig *csi_reportconfig,
NR_CSI_ResourceConfigId_t csi_ResourceConfigId,
NR_CSI_MeasConfig_t *csi_MeasConfig)
static nfapi_nr_ue_csi_payload_t get_ssb_sinr_payload(NR_UE_MAC_INST_t *mac,
const struct NR_CSI_ReportConfig *csi_reportconfig,
const NR_CSI_ResourceConfigId_t csi_ResourceConfigId,
const NR_CSI_MeasConfig_t *csi_MeasConfig)
{
int nb_ssb = 0; // nb of ssb in the resource
int nb_meas = 0; // nb of ssb to report measurements on
@@ -2717,7 +2724,7 @@ static csi_payload_t get_ssb_sinr_payload(NR_UE_MAC_INST_t *mac,
} else
nb_meas = 2;
struct NR_CSI_SSB_ResourceSet__csi_SSB_ResourceList *SSB_resource = NULL;
const struct NR_CSI_SSB_ResourceSet__csi_SSB_ResourceList *SSB_resource = NULL;
for (int csi_ssb_idx = 0; csi_ssb_idx < csi_MeasConfig->csi_SSB_ResourceSetToAddModList->list.count; csi_ssb_idx++) {
if (csi_MeasConfig->csi_SSB_ResourceSetToAddModList->list.array[csi_ssb_idx]->csi_SSB_ResourceSetId
== *(csi_resourceconfig->csi_RS_ResourceSetList.choice.nzp_CSI_RS_SSB->csi_SSB_ResourceSetList->list.array[0])) {
@@ -2770,9 +2777,9 @@ static csi_payload_t get_ssb_sinr_payload(NR_UE_MAC_INST_t *mac,
break; // resource found
}
}
int max_bits = sizeof(((csi_payload_t *)0)->part1_payload) * 8;
int max_bits = sizeof(((nfapi_nr_ue_csi_payload_t *)0)->part1_payload) * 8;
AssertFatal(bits <= max_bits, "Not supporting CSI report with more than %d bits (payload: %d bits)\n", max_bits, bits);
csi_payload_t csi = {.part1_payload = temp_payload, .part2_payload = 0, .p1_bits = bits, csi.p2_bits = 0};
nfapi_nr_ue_csi_payload_t csi = {.part1_payload = temp_payload, .part2_payload = 0, .p1_bits = bits, csi.p2_bits = 0};
return csi;
}
@@ -2795,10 +2802,10 @@ static uint8_t get_rsrp_diff_index(int best_rsrp, int current_rsrp)
return (diff>>1);
}
static csi_payload_t get_ssb_rsrp_payload(NR_UE_MAC_INST_t *mac,
struct NR_CSI_ReportConfig *csi_reportconfig,
NR_CSI_ResourceConfigId_t csi_ResourceConfigId,
NR_CSI_MeasConfig_t *csi_MeasConfig)
static nfapi_nr_ue_csi_payload_t get_ssb_rsrp_payload(NR_UE_MAC_INST_t *mac,
const struct NR_CSI_ReportConfig *csi_reportconfig,
const NR_CSI_ResourceConfigId_t csi_ResourceConfigId,
const NR_CSI_MeasConfig_t *csi_MeasConfig)
{
int nb_ssb = 0; // nb of ssb in the resource
int nb_meas = 0; // nb of ssb to report measurements on
@@ -2817,7 +2824,7 @@ static csi_payload_t get_ssb_rsrp_payload(NR_UE_MAC_INST_t *mac,
} else
nb_meas = 2;
struct NR_CSI_SSB_ResourceSet__csi_SSB_ResourceList *SSB_resource = NULL;
const struct NR_CSI_SSB_ResourceSet__csi_SSB_ResourceList *SSB_resource = NULL;
for (int csi_ssb_idx = 0; csi_ssb_idx < csi_MeasConfig->csi_SSB_ResourceSetToAddModList->list.count; csi_ssb_idx++) {
if (csi_MeasConfig->csi_SSB_ResourceSetToAddModList->list.array[csi_ssb_idx]->csi_SSB_ResourceSetId ==
*(csi_resourceconfig->csi_RS_ResourceSetList.choice.nzp_CSI_RS_SSB->csi_SSB_ResourceSetList->list.array[0])){
@@ -2870,18 +2877,18 @@ static csi_payload_t get_ssb_rsrp_payload(NR_UE_MAC_INST_t *mac,
break; // resource found
}
}
int max_bits = sizeof(((csi_payload_t *)0)->part1_payload) * 8;
int max_bits = sizeof(((nfapi_nr_ue_csi_payload_t *)0)->part1_payload) * 8;
AssertFatal(bits <= max_bits, "Not supporting CSI report with more than %d bits (payload: %d bits)\n", max_bits, bits);
csi_payload_t csi = {.part1_payload = temp_payload, .part2_payload = 0, .p1_bits = bits, .p2_bits = 0};
nfapi_nr_ue_csi_payload_t csi = {.part1_payload = temp_payload, .part2_payload = 0, .p1_bits = bits, .p2_bits = 0};
return csi;
}
static csi_payload_t get_csirs_RI_PMI_CQI_payload(NR_UE_MAC_INST_t *mac,
struct NR_CSI_ReportConfig *csi_reportconfig,
NR_CSI_ResourceConfigId_t csi_ResourceConfigId,
NR_CSI_MeasConfig_t *csi_MeasConfig,
CSI_mapping_t mapping_type)
static nfapi_nr_ue_csi_payload_t get_csirs_RI_PMI_CQI_payload(NR_UE_MAC_INST_t *mac,
const struct NR_CSI_ReportConfig *csi_reportconfig,
const NR_CSI_ResourceConfigId_t csi_ResourceConfigId,
const NR_CSI_MeasConfig_t *csi_MeasConfig,
const CSI_mapping_t mapping_type)
{
int p1_bits = 0;
int p2_bits = 0;
@@ -2949,13 +2956,13 @@ static csi_payload_t get_csirs_RI_PMI_CQI_payload(NR_UE_MAC_INST_t *mac,
}
}
AssertFatal(p1_bits <= 32 && p2_bits <= 32, "Not supporting CSI report with more than 32 bits\n");
csi_payload_t csi = {.part1_payload = temp_payload_1, .part2_payload = temp_payload_2, .p1_bits = p1_bits, csi.p2_bits = p2_bits};
nfapi_nr_ue_csi_payload_t csi = {.part1_payload = temp_payload_1, .part2_payload = temp_payload_2, .p1_bits = p1_bits, csi.p2_bits = p2_bits};
return csi;
}
static csi_payload_t get_csirs_RSRP_payload(NR_UE_MAC_INST_t *mac,
struct NR_CSI_ReportConfig *csi_reportconfig,
NR_CSI_ResourceConfigId_t csi_ResourceConfigId,
static nfapi_nr_ue_csi_payload_t get_csirs_RSRP_payload(NR_UE_MAC_INST_t *mac,
const struct NR_CSI_ReportConfig *csi_reportconfig,
const NR_CSI_ResourceConfigId_t csi_ResourceConfigId,
const NR_CSI_MeasConfig_t *csi_MeasConfig)
{
int n_bits = 0;
@@ -3002,17 +3009,17 @@ static csi_payload_t get_csirs_RSRP_payload(NR_UE_MAC_INST_t *mac,
}
}
AssertFatal(n_bits <= 32, "Not supporting CSI report with more than 32 bits\n");
csi_payload_t csi = {.part1_payload = temp_payload, .p1_bits = n_bits, csi.p2_bits = 0};
nfapi_nr_ue_csi_payload_t csi = {.part1_payload = temp_payload, .p1_bits = n_bits, csi.p2_bits = 0};
return csi;
}
csi_payload_t nr_get_csi_payload(NR_UE_MAC_INST_t *mac,
int csi_report_id,
CSI_mapping_t mapping_type,
NR_CSI_MeasConfig_t *csi_MeasConfig)
nfapi_nr_ue_csi_payload_t nr_get_csi_payload(NR_UE_MAC_INST_t *mac,
int csi_report_id,
CSI_mapping_t mapping_type,
const NR_CSI_MeasConfig_t *csi_MeasConfig)
{
AssertFatal(csi_MeasConfig->csi_ReportConfigToAddModList->list.count > 0,"No CSI Report configuration available\n");
csi_payload_t csi = {0};
nfapi_nr_ue_csi_payload_t csi = {0};
struct NR_CSI_ReportConfig *csi_reportconfig = csi_MeasConfig->csi_ReportConfigToAddModList->list.array[csi_report_id];
NR_CSI_ResourceConfigId_t csi_ResourceConfigId = csi_reportconfig->resourcesForChannelMeasurement;
if (csi_reportconfig->ext2 && csi_reportconfig->ext2->reportQuantity_r16) {
+57 -38
View File
@@ -341,6 +341,26 @@ void ul_layers_config(NR_UE_MAC_INST_t *mac, nfapi_nr_ue_pusch_pdu_t *pusch_conf
}
}
static void fill_pusch_uci_struct(const NR_PUSCH_Config_t *pusch_Config,
const nfapi_nr_ue_csi_payload_t *csi_payload,
nfapi_nr_ue_pusch_pdu_t *pusch_config_pdu)
{
pusch_config_pdu->pusch_uci.csi_payload = *csi_payload;
AssertFatal(pusch_Config && pusch_Config->uci_OnPUSCH, "UCI on PUSCH need to be configured\n");
NR_UCI_OnPUSCH_t *onPusch = pusch_Config->uci_OnPUSCH->choice.setup;
AssertFatal(onPusch && onPusch->betaOffsets && onPusch->betaOffsets->present == NR_UCI_OnPUSCH__betaOffsets_PR_semiStatic,
"Only semistatic beta offset is supported\n");
NR_BetaOffsets_t *beta_offsets = onPusch->betaOffsets->choice.semiStatic;
pusch_config_pdu->pusch_uci.beta_offset_csi1 = pusch_config_pdu->pusch_uci.csi_payload.p1_bits < 12
? *beta_offsets->betaOffsetCSI_Part1_Index1
: *beta_offsets->betaOffsetCSI_Part1_Index2;
pusch_config_pdu->pusch_uci.beta_offset_csi2 = pusch_config_pdu->pusch_uci.csi_payload.p2_bits < 12
? *beta_offsets->betaOffsetCSI_Part2_Index1
: *beta_offsets->betaOffsetCSI_Part2_Index2;
pusch_config_pdu->pusch_uci.alpha_scaling = onPusch->scaling;
}
// Configuration of Msg3 PDU according to clauses:
// - 8.3 of 3GPP TS 38.213 version 16.3.0 Release 16
// - 6.1.2.2 of TS 38.214
@@ -353,7 +373,7 @@ int nr_config_pusch_pdu(NR_UE_MAC_INST_t *mac,
NR_tda_info_t *tda_info,
nfapi_nr_ue_pusch_pdu_t *pusch_config_pdu,
dci_pdu_rel15_t *dci,
csi_payload_t *csi_report,
nfapi_nr_ue_csi_payload_t *csi_report,
RAR_grant_t *rar_grant,
rnti_t rnti,
int ss_type,
@@ -534,29 +554,10 @@ int nr_config_pusch_pdu(NR_UE_MAC_INST_t *mac,
pusch_config_pdu->ulsch_indicator = dci->ulsch_indicator;
if (dci->csi_request.nbits > 0 && dci->csi_request.val > 0) {
AssertFatal(csi_report, "CSI report needs to be present in case of CSI request\n");
pusch_config_pdu->pusch_uci.csi_part1_bit_length = csi_report->p1_bits;
pusch_config_pdu->pusch_uci.csi_part1_payload = csi_report->part1_payload;
pusch_config_pdu->pusch_uci.csi_part2_bit_length = csi_report->p2_bits;
pusch_config_pdu->pusch_uci.csi_part2_payload = csi_report->part2_payload;
AssertFatal(pusch_Config && pusch_Config->uci_OnPUSCH, "UCI on PUSCH need to be configured\n");
NR_UCI_OnPUSCH_t *onPusch = pusch_Config->uci_OnPUSCH->choice.setup;
AssertFatal(onPusch &&
onPusch->betaOffsets &&
onPusch->betaOffsets->present == NR_UCI_OnPUSCH__betaOffsets_PR_semiStatic,
"Only semistatic beta offset is supported\n");
NR_BetaOffsets_t *beta_offsets = onPusch->betaOffsets->choice.semiStatic;
pusch_config_pdu->pusch_uci.beta_offset_csi1 = pusch_config_pdu->pusch_uci.csi_part1_bit_length < 12 ?
*beta_offsets->betaOffsetCSI_Part1_Index1 :
*beta_offsets->betaOffsetCSI_Part1_Index2;
pusch_config_pdu->pusch_uci.beta_offset_csi2 = pusch_config_pdu->pusch_uci.csi_part2_bit_length < 12 ?
*beta_offsets->betaOffsetCSI_Part2_Index1 :
*beta_offsets->betaOffsetCSI_Part2_Index2;
pusch_config_pdu->pusch_uci.alpha_scaling = onPusch->scaling;
}
else {
pusch_config_pdu->pusch_uci.csi_part1_bit_length = 0;
pusch_config_pdu->pusch_uci.csi_part2_bit_length = 0;
fill_pusch_uci_struct(pusch_Config, csi_report, pusch_config_pdu);
} else {
pusch_config_pdu->pusch_uci.csi_payload.p1_bits = 0;
pusch_config_pdu->pusch_uci.csi_payload.p2_bits = 0;
}
pusch_config_pdu->pusch_uci.harq_ack_bit_length = 0;
@@ -864,13 +865,13 @@ int nr_config_pusch_pdu(NR_UE_MAC_INST_t *mac,
return 0;
}
csi_payload_t nr_ue_aperiodic_csi_reporting(NR_UE_MAC_INST_t *mac, dci_field_t csi_request, int tda, long *k2)
nfapi_nr_ue_csi_payload_t nr_ue_aperiodic_csi_reporting(NR_UE_MAC_INST_t *mac, dci_field_t csi_request, int tda, long *k2)
{
NR_CSI_AperiodicTriggerStateList_t *aperiodicTriggerStateList = mac->sc_info.aperiodicTriggerStateList;
AssertFatal(aperiodicTriggerStateList, "Received CSI request via DCI but aperiodicTriggerStateList is not present\n");
int n_states = aperiodicTriggerStateList->list.count;
int n_ts = csi_request.nbits;
csi_payload_t csi = {0};
nfapi_nr_ue_csi_payload_t csi = {0};
AssertFatal(n_states <= ((1 << n_ts) - 1), "Case of subselection indication of trigger states not supported yet\n");
int num_trig = 0;
for (int i = 0; i < n_ts; i++) {
@@ -891,8 +892,8 @@ csi_payload_t nr_ue_aperiodic_csi_reporting(NR_UE_MAC_INST_t *mac, dci_field_t c
if (report_config->reportConfigId == id) {
struct NR_CSI_ReportConfig__reportConfigType__aperiodic__reportSlotOffsetList *offset_list = &report_config->reportConfigType.choice.aperiodic->reportSlotOffsetList;
AssertFatal(tda < offset_list->list.count, "TDA index from DCI %d exceeds slot offset list %d\n", tda, offset_list->list.count);
if (k2 == NULL || *k2 < *offset_list->list.array[tda])
k2 = offset_list->list.array[tda];
if (*k2 < *offset_list->list.array[tda])
*k2 = *offset_list->list.array[tda];
found = c;
break;
}
@@ -1791,9 +1792,17 @@ static bool schedule_uci_on_pusch(NR_UE_MAC_INST_t *mac,
LOG_E(NR_MAC, "UCI on PUSCH need to be configured to schedule UCI on PUSCH\n");
}
}
if (pusch_pdu->pusch_uci.csi_part1_bit_length == 0 && pusch_pdu->pusch_uci.csi_part2_bit_length == 0) {
// To support this we would need to shift some bits into CSI part2 -> need to change the logic
AssertFatal(pucch->n_csi == 0, "Multiplexing periodic CSI on PUSCH not supported\n");
AssertFatal(pusch_pdu->pusch_uci.csi_payload.p1_bits == 0, "PUSCH already has CSI report\n");
// Check if this PUCCH has CSI report to send. If so, multiplex it on PUSCH
if (pucch->csi_payload.p1_bits > 0) {
nfapi_nr_ue_csi_payload_t csi_payload = {0};
NR_PUSCH_Config_t *pusch_Config = mac->current_UL_BWP->pusch_Config;
NR_PUCCH_Resource_t *csi_pucch = NULL;
nr_get_csi_measurements(mac, frame_tx, slot_tx, &csi_payload, &csi_pucch, true);
fill_pusch_uci_struct(pusch_Config, &csi_payload, pusch_pdu);
mux_done = true;
}
release_ul_config(ulcfg_pdu, false);
@@ -1824,7 +1833,7 @@ static void nr_ue_pucch_scheduler(NR_UE_MAC_INST_t *mac, frame_t frame, int slot
// CSI
int csi_res = 0;
if (mac->state == UE_CONNECTED)
csi_res = nr_get_csi_measurements(mac, frame, slot, &pucch[num_res]);
csi_res = nr_get_csi_measurements(mac, frame, slot, &pucch[num_res].csi_payload, &pucch[num_res].pucch_resource, false);
if (csi_res > 0) {
num_res += csi_res;
}
@@ -1845,14 +1854,14 @@ static void nr_ue_pucch_scheduler(NR_UE_MAC_INST_t *mac, frame_t frame, int slot
}
for (int j = 0; j < num_res; j++) {
if (pucch[j].n_harq + pucch[j].n_sr + pucch[j].n_csi != 0) {
if (pucch[j].n_harq + pucch[j].n_sr + pucch[j].csi_payload.p1_bits != 0) {
LOG_D(NR_MAC,
"%d.%d configure pucch, O_ACK %d, O_SR %d, O_CSI %d\n",
frame,
slot,
pucch[j].n_harq,
pucch[j].n_sr,
pucch[j].n_csi);
pucch[j].csi_payload.p1_bits);
// checking if we need to schedule pucch[j] on PUSCH
if (schedule_uci_on_pusch(mac, frame, slot, &pucch[j], mac->current_UL_BWP))
@@ -2696,6 +2705,18 @@ void nr_ue_ul_scheduler(NR_UE_MAC_INST_t *mac, nr_uplink_indication_t *ul_info)
}
}
static void get_pusch_frame_slot(const int current_frame,
const int current_slot,
const int k2,
const int delta,
const int slots_per_frame,
frame_t *frame_tx,
int *slot_tx)
{
*slot_tx = (current_slot + k2 + delta) % slots_per_frame;
*frame_tx = (current_frame + (current_slot + k2 + delta) / slots_per_frame) % MAX_FRAME_NUMBER;
}
// PUSCH scheduler:
// - Calculate the slot in which ULSCH should be scheduled. This is current slot + K2,
// - where K2 is the offset between the slot in which UL DCI is received and the slot
@@ -2734,8 +2755,7 @@ int nr_ue_pusch_scheduler(const NR_UE_MAC_INST_t *mac,
GET_DURATION_RX_TO_TX(&mac->phy_config.config_req.ntn_config, mu));
*slot_tx = (current_slot + k2 + delta) % slots_per_frame;
*frame_tx = (current_frame + (current_slot + k2 + delta) / slots_per_frame) % MAX_FRAME_NUMBER;
get_pusch_frame_slot(current_frame, current_slot, k2, delta, slots_per_frame, frame_tx, slot_tx);
} else {
AssertFatal(k2 >= GET_DURATION_RX_TO_TX(&mac->phy_config.config_req.ntn_config, mu),
"Slot offset K2 (%ld) needs to be higher than DURATION_RX_TO_TX (%ld). Please set min_rxtxtime at least to %ld in "
@@ -2752,8 +2772,7 @@ int nr_ue_pusch_scheduler(const NR_UE_MAC_INST_t *mac,
}
// Calculate TX slot and frame
*slot_tx = (current_slot + k2) % slots_per_frame;
*frame_tx = (current_frame + (current_slot + k2) / slots_per_frame) % MAX_FRAME_NUMBER;
get_pusch_frame_slot(current_frame, current_slot, k2, 0, slots_per_frame, frame_tx, slot_tx);
}
LOG_D(NR_MAC, "[%04d.%02d] UL transmission in [%04d.%02d] (k2 %ld delta %d)\n", current_frame, current_slot, *frame_tx, *slot_tx, k2, delta);