Compare commits

...

15 Commits

Author SHA1 Message Date
Sakthivel Velumani
14e47ed9f4 tbs: harmonize filling csi report pdu for pusch and pucch 2025-11-21 17:35:01 -05:00
Sakthivel Velumani
b3581ecfa4 mac: harmonize function to get csi reports
Use nr_get_csi_measurements() function to get CSI report for PUCCH and
UCI on PUSCH.
2025-11-21 15:48:51 -05:00
Sakthivel Velumani
33ebe98a34 mac: harmonize csi_payload_t struct
1. Reuse csi_payload_t struct to hold CSI report payload on PUSCH and
PUCCH PDU.
2. Move the struct to fapi header file
2025-11-21 15:48:51 -05:00
Sakthivel Velumani
9da5dd472c clean-up: reduce nested if in CSI meas function 2025-11-21 15:48:51 -05:00
Sakthivel Velumani
eebe5f0373 ulsim: enable CSI part 2 in unit test 2025-11-21 15:48:51 -05:00
Sakthivel Velumani
ae4c690c7e phy: map CSI part 2 bits on PUSCH 2025-11-21 15:48:51 -05:00
Sakthivel Velumani
444587bf53 ulsim: enable CSI part 1 in unit test
Update matlab script too.
2025-11-21 15:48:51 -05:00
Sakthivel Velumani
80cbb0348d phy: map CSI part 1 bits on PUSCH 2025-11-21 15:48:51 -05:00
Sakthivel Velumani
0a7dbe6aa7 fix: return value assigned inside function 2025-11-21 15:48:51 -05:00
Sakthivel Velumani
f624629a78 clean-up: fix code repetition 2025-11-21 15:48:51 -05:00
Sakthivel Velumani
ec2f9f489d clean-up: Add const to input pointers 2025-11-21 15:48:51 -05:00
Sakthivel Velumani
1a29bd120d Add timing stats for TRS processing 2025-11-10 22:55:40 -05:00
Sakthivel Velumani
57ca0458fc fix: tracking CSI-RS measurement bitmap
measurement bitmap for CSI-RS is 0 means CSI-RS for tracking. So don't
return and proceed with processing the CSI-RS.
2025-11-10 22:55:40 -05:00
Sakthivel Velumani
59054cb34e feature: Estimate CFO from CSI-RS tracking signal
TRS resources if configured by gnb, is present in two consequtive slots
and two symbols per slot. LS estimates from the first symbol is saved
and in second symbol frequency offset and time offset is estimated. The
estimated FO is saved in UE global structure which is used in the last
TRS slot. If the FO is above a threshold, the radio's center frequency
is adjusted.

Time offset is estimated but not used because time is already tracked
using PBCH DMRS.
2025-11-10 22:55:16 -05:00
Sakthivel Velumani
882b34c10d Remove unnecessary FO compensation
After detecting PSS, SSS and PBCH there is no need to compensate for FO
in rxbuffer. SIB1 is detected from freshly received samples that are FO
compensated at the radio.
2025-11-09 15:36:06 -05:00
20 changed files with 682 additions and 271 deletions

View File

@@ -256,9 +256,8 @@ static void UE_synch(void *arg) {
((ret.rx_offset << 1) / fp->samples_per_subframe * fp->slots_per_subframe)
+ round((float)((ret.rx_offset << 1) % fp->samples_per_subframe) / fp->samples_per_slot0);
if (get_nrUE_params()->cont_fo_comp) {
UE->freq_offset = freq_offset;
} else {
UE->freq_offset = freq_offset;
if (!get_nrUE_params()->cont_fo_comp) {
// rerun with new cell parameters and frequency-offset
nr_rf_card_config_freq(cfg0, ul_carrier, dl_carrier, freq_offset);
UE->rfdevice.trx_set_freq_func(&UE->rfdevice, cfg0);
@@ -773,6 +772,38 @@ static inline void apply_ntn_config(PHY_VARS_NR_UE *UE,
}
}
void trs_freq_correction(PHY_VARS_NR_UE *ue)
{
if (ue->trs_cfo[NUM_TRS_SLOT - 1].valid) { // last slot in a TRS burst
const int avg_trs_cfo = (ue->trs_cfo[0].cfo + ue->trs_cfo[1].cfo) / 2;
if (abs(avg_trs_cfo) > TRS_CFO_THRESH) {
LOG_A(PHY, "CFO estimated (%d) from TRS exceeded threshold (%d). Adjusting radio CF\n", avg_trs_cfo, TRS_CFO_THRESH);
ue->freq_offset += avg_trs_cfo;
uint64_t dl_carrier;
uint64_t ul_carrier;
nr_get_carrier_frequencies(ue, &dl_carrier, &ul_carrier);
openair0_config_t *cfg0 = &ue->openair0_cfg[ue->rf_map.card];
nr_rf_card_config_freq(cfg0, ul_carrier, dl_carrier, ue->freq_offset);
ue->rfdevice.trx_set_freq_func(&ue->rfdevice, cfg0);
}
ue->trs_cfo[0].valid = ue->trs_cfo[1].valid = false;
}
}
static bool get_is_last_trs_slot(const int current_slot, const int last_slot)
{
// TRS can be 2 consequtive slots or 1 slot in a frame
return (current_slot == (last_slot + 1) || current_slot == last_slot);
}
static void update_trs_info(nr_phy_data_t *d, int *last_slot, const int current_slot)
{
if (d->csirs_vars[0].active && d->csirs_vars[0].csirs_config_pdu.csi_type == 0) {
d->is_last_trs_slot = get_is_last_trs_slot(current_slot, *last_slot);
*last_slot = current_slot;
}
}
void *UE_thread(void *arg)
{
//this thread should be over the processing thread to keep in real time
@@ -825,6 +856,7 @@ void *UE_thread(void *arg)
int intialSyncOffset = 0;
openair0_timestamp sync_timestamp;
bool stats_printed = false;
int last_trs_slot = 0;
if (get_softmodem_params()->sync_ref && UE->sl_mode == 2) {
UE->is_synchronized = 1;
@@ -1055,6 +1087,7 @@ void *UE_thread(void *arg)
nr_rxtx_thread_data_t *curMsgRx = (nr_rxtx_thread_data_t *)NotifiedFifoData(newRx);
*curMsgRx = (nr_rxtx_thread_data_t){.proc = curMsg.proc, .UE = UE};
int ret = UE_dl_preprocessing(UE, &curMsgRx->proc, tx_wait_for_dlsch, &curMsgRx->phy_data, &stats_printed);
update_trs_info(&curMsgRx->phy_data, &last_trs_slot, curMsgRx->proc.nr_slot_rx);
if (ret != INT_MAX)
shiftForNextFrame = ret;
if (get_nrUE_params()->num_dl_actors > 0) {

View File

@@ -253,6 +253,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
@@ -260,10 +267,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;

View File

@@ -265,6 +265,7 @@ uint32_t calc_power_csirs(const uint16_t *x, const fapi_nr_dl_config_csirs_pdu_r
static int nr_csi_rs_channel_estimation(
const NR_DL_FRAME_PARMS *fp,
const int meas_bitmap,
const UE_nr_rxtx_proc_t *proc,
const fapi_nr_dl_config_csirs_pdu_rel15_t *csirs_config_pdu,
const nr_csi_info_t *nr_csi_info,
@@ -317,10 +318,16 @@ static int nr_csi_rs_channel_estimation(
const c16_t *tx_csi_rs_signal = &csi_rs_generated_signal[port_tx][symbol_offset+dataF_offset];
const c16_t *rx_csi_rs_signal = &csi_rs_received_signal[ant_rx][symbol_offset];
c16_t tmp = c16MulConjShift(tx_csi_rs_signal[k], rx_csi_rs_signal[k], nr_csi_info->csi_rs_generated_signal_bits);
// This is not just the LS estimation for each (k,l), but also the sum of the different contributions
// for the sake of optimizing the memory used.
csi_rs_ls_estimated_channel[ant_rx][port_tx][kinit].r += tmp.r;
csi_rs_ls_estimated_channel[ant_rx][port_tx][kinit].i += tmp.i;
if (csirs_config_pdu->csi_type != 0) {
// This is not just the LS estimation for each (k,l), but also the sum of the different contributions
// for the sake of optimizing the memory used.
csi_rs_ls_estimated_channel[ant_rx][port_tx][kinit].r += tmp.r;
csi_rs_ls_estimated_channel[ant_rx][port_tx][kinit].i += tmp.i;
} else {
// for tracking we want estimates of all sub carriers having CSI-RS
csi_rs_ls_estimated_channel[ant_rx][port_tx][k].r = tmp.r;
csi_rs_ls_estimated_channel[ant_rx][port_tx][k].i = tmp.i;
}
}
}
}
@@ -381,6 +388,10 @@ static int nr_csi_rs_channel_estimation(
}
}
// we need only ls estimates for tracing CSI
if (meas_bitmap < 2)
continue;
/// Power noise estimation
AssertFatal(csirs_config_pdu->nr_of_rbs > 0, " nr_of_rbs needs to be greater than 0\n");
uint16_t noise_real[fp->nb_antennas_rx][csi_mapping->ports][csirs_config_pdu->nr_of_rbs];
@@ -425,9 +436,11 @@ static int nr_csi_rs_channel_estimation(
}
*noise_power /= (fp->nb_antennas_rx * csi_mapping->ports);
*log2_maxh = log2_approx(maxh - 1);
*log2_re = log2_approx(count - 1);
if (meas_bitmap > 1) {
*noise_power /= (fp->nb_antennas_rx * csi_mapping->ports);
*log2_maxh = log2_approx(maxh - 1);
*log2_re = log2_approx(count - 1);
}
#ifdef NR_CSIRS_DEBUG
LOG_I(NR_PHY, "Noise power estimation based on CSI-RS: %i\n", *noise_power);
@@ -804,6 +817,75 @@ static void nr_csi_im_power_estimation(const PHY_VARS_NR_UE *ue,
#endif
}
static double get_cfo(const double phase_diff, const int sym0, const int sym1, const NR_DL_FRAME_PARMS *fp)
{
const double one_fs = 1.0 / (fp->samples_per_frame * 100);
int sample_count = 0;
for (int s = sym0 + 1; s <= sym1; s++) {
const int prefix = (s % (7 * (1 << fp->numerology_index))) ? fp->nb_prefix_samples : fp->nb_prefix_samples0;
sample_count += (fp->ofdm_symbol_size + prefix);
}
const double delta_time = sample_count * one_fs;
const double cfo = phase_diff / (2 * M_PI * delta_time);
return cfo;
}
static void nr_ue_trs_processing(PHY_VARS_NR_UE *ue,
const c16_t res0_est[][1][ue->frame_parms.ofdm_symbol_size],
const c16_t res1_est[][1][ue->frame_parms.ofdm_symbol_size],
const c16_t freq_interp_est[][1][ue->frame_parms.ofdm_symbol_size + FILTER_MARGIN],
const fapi_nr_dl_config_csirs_pdu_rel15_t *csirs_config_pdu,
const csi_mapping_parms_t *csi_mapping,
const int sym0,
const int sym1,
int *cfo,
int *time_offset)
{
AssertFatal((sym0 > -1) && (sym1 > -1), "Invalid symbol index for TRS estimation\n");
const NR_DL_FRAME_PARMS *fp = &ue->frame_parms;
for (int ant_rx = 0; ant_rx < fp->nb_antennas_rx; ant_rx++) {
// CFO estimation
double phase_diff = 0.0;
int count = 0;
for (int rb = csirs_config_pdu->start_rb; rb < (csirs_config_pdu->start_rb + csirs_config_pdu->nr_of_rbs); rb++) {
// for freq density 0.5 checks if even or odd RB
if (csirs_config_pdu->freq_density <= 1 && csirs_config_pdu->freq_density != (rb % 2)) {
continue;
}
for (int cdm_id = 0; cdm_id < csi_mapping->size; cdm_id++) {
// loop over frequency resource elements within a group
for (int kp = 0; kp <= csi_mapping->kprime; kp++) {
uint16_t kinit = (fp->first_carrier_offset + rb * NR_NB_SC_PER_RB) % fp->ofdm_symbol_size;
uint16_t k = kinit + csi_mapping->koverline[cdm_id] + kp;
// loop over time resource elements within a group
for (int lp = 0; lp <= csi_mapping->lprime; lp++) {
const c16_t *res0 = res0_est[ant_rx][0];
const c16_t *res1 = res1_est[ant_rx][0];
double tmp_phase = atan2((double)res1[k].i, (double)res1[k].r) - atan2((double)res0[k].i, (double)res0[k].r);
// wrap around phase
tmp_phase = (tmp_phase > M_PI) ? tmp_phase - 2 * M_PI : tmp_phase;
tmp_phase = (tmp_phase < -M_PI) ? tmp_phase + 2 * M_PI : tmp_phase;
phase_diff += tmp_phase;
count++;
}
}
}
}
phase_diff /= count;
*cfo = (int)get_cfo(phase_diff, sym0, sym1, fp);
// Time offset estimation
__attribute__((aligned(32))) c16_t time_est[fp->ofdm_symbol_size];
delay_t delay = {0};
nr_est_delay(fp->ofdm_symbol_size, freq_interp_est[ant_rx][0], time_est, &delay);
*time_offset = delay.delay_max_pos;
// estimate only for first antenna port
break;
}
}
void nr_ue_csi_im_procedures(PHY_VARS_NR_UE *ue,
const UE_nr_rxtx_proc_t *proc,
const c16_t rxdataF[][ue->frame_parms.samples_per_slot_wCP],
@@ -827,7 +909,10 @@ void nr_ue_csi_im_procedures(PHY_VARS_NR_UE *ue,
void nr_ue_csi_rs_procedures(PHY_VARS_NR_UE *ue,
const UE_nr_rxtx_proc_t *proc,
const c16_t rxdataF[][ue->frame_parms.samples_per_slot_wCP],
fapi_nr_dl_config_csirs_pdu_rel15_t *csirs_config_pdu)
fapi_nr_dl_config_csirs_pdu_rel15_t *csirs_config_pdu,
c16_t trs_estimates[][1][ue->frame_parms.ofdm_symbol_size],
const int res_idx,
const int trs_sym0)
{
#ifdef NR_CSIRS_DEBUG
@@ -847,11 +932,6 @@ void nr_ue_csi_rs_procedures(PHY_VARS_NR_UE *ue,
LOG_I(NR_PHY, "csirs_config_pdu->power_control_offset_ss = %i\n", csirs_config_pdu->power_control_offset_ss);
#endif
if(csirs_config_pdu->csi_type == 0) {
LOG_E(NR_PHY, "Handling of CSI-RS for tracking not handled yet at PHY\n");
return;
}
if(csirs_config_pdu->csi_type == 2) {
LOG_E(NR_PHY, "Handling of ZP CSI-RS not handled yet at PHY\n");
return;
@@ -904,31 +984,26 @@ void nr_ue_csi_rs_procedures(PHY_VARS_NR_UE *ue,
&rsrp_dBm,
rxdataF);
if (csirs_config_pdu->measurement_bitmap == 0) {
LOG_D(NR_PHY, "No CSI-RS measurements configured\n");
return;
}
uint32_t noise_power = 0;
int16_t log2_re = 0;
int16_t log2_maxh = 0;
// if we need to measure only RSRP no need to do channel estimation
if (csirs_config_pdu->measurement_bitmap > 1)
nr_csi_rs_channel_estimation(frame_parms,
proc,
csirs_config_pdu,
csi_info,
(const c16_t **)csi_info->csi_rs_generated_signal,
csi_rs_received_signal,
&mapping_parms,
CDM_group_size,
mem_offset,
csi_rs_ls_estimated_channel,
csi_rs_estimated_channel_freq,
&log2_re,
&log2_maxh,
&noise_power);
const bool use_trs_buff = (csirs_config_pdu->csi_type == 0 && res_idx == 0);
nr_csi_rs_channel_estimation(frame_parms,
csirs_config_pdu->measurement_bitmap,
proc,
csirs_config_pdu,
csi_info,
(const c16_t **)csi_info->csi_rs_generated_signal,
csi_rs_received_signal,
&mapping_parms,
CDM_group_size,
mem_offset,
(use_trs_buff) ? trs_estimates : csi_rs_ls_estimated_channel,
csi_rs_estimated_channel_freq,
&log2_re,
&log2_maxh,
&noise_power);
uint8_t rank_indicator = 0;
// bit 1 in bitmap to indicate RI measurment
@@ -967,9 +1042,54 @@ void nr_ue_csi_rs_procedures(PHY_VARS_NR_UE *ue,
nr_csi_rs_cqi_estimation(precoded_sinr_dB, &cqi);
}
int trs_cfo = 0;
int trs_time = 0;
const bool do_trs_est = (csirs_config_pdu->csi_type == 0) && (res_idx == 1);
if (do_trs_est) {
start_meas_nr_ue_phy(ue, TRS_PROCESSING);
nr_ue_trs_processing(ue,
trs_estimates,
csi_rs_ls_estimated_channel,
csi_rs_estimated_channel_freq,
csirs_config_pdu,
&mapping_parms,
trs_sym0,
csirs_config_pdu->symb_l0,
&trs_cfo,
&trs_time);
stop_meas_nr_ue_phy(ue, TRS_PROCESSING);
for (int i = 0; i < NUM_TRS_SLOT; i++) {
if (ue->trs_cfo[i].valid)
continue;
ue->trs_cfo[i].cfo = trs_cfo;
ue->trs_cfo[i].valid = true;
}
}
#if 0
// dump csi estimates for csi tracking resource in slot
if (csirs_config_pdu->csi_type == 0 && proc->frame_rx == 344) {
char fname[40];
snprintf(fname, sizeof(fname), "trs_slot%d_sym%d", proc->nr_slot_rx, csirs_config_pdu->symb_l0);
if (do_trs_est)
LOG_M(fname, "trs", csi_rs_ls_estimated_channel[0][0], frame_parms->ofdm_symbol_size, 1, 1 | MATLAB_RAW);
else
LOG_M(fname, "trs", trs_estimates[0][0], frame_parms->ofdm_symbol_size, 1, 1 | MATLAB_RAW);
}
#endif
switch (csirs_config_pdu->measurement_bitmap) {
case 1 :
LOG_I(NR_PHY, "[UE %d] RSRP = %i dBm\n", ue->Mod_id, rsrp_dBm);
case 0:
if (do_trs_est)
LOG_I(NR_PHY,
"%d.%d TRS estimated CFO: %d Hz, estimated time offset: %d samples\n",
proc->frame_rx,
proc->nr_slot_rx,
trs_cfo,
trs_time);
break;
case 1:
LOG_I(NR_PHY, "%d.%d [UE %d] RSRP = %i dBm\n", proc->frame_rx, proc->nr_slot_rx, ue->Mod_id, rsrp_dBm);
break;
case 26 :
LOG_I(NR_PHY, "RI = %i i1 = %i.%i.%i, i2 = %i, SINR = %i dB, CQI = %i\n",

View File

@@ -398,12 +398,6 @@ nr_initial_sync_t nr_initial_sync(UE_nr_rxtx_proc_t *proc,
LOG_D(PHY, "nr_initial sync ue RB_DL %d\n", fp->N_RB_DL);
if (res) {
// digital compensation of FFO for SSB symbols
if (res->freqOffset && ue->UE_fo_compensation) {
// In SA we need to perform frequency offset correction until the end of buffer because we need to decode SIB1
// and we do not know yet in which slot it goes.
compensate_freq_offset(ue->common_vars.rxdata, fp, res->freqOffset, res->syncRes.frame_id);
}
// sync at symbol ue->symbol_offset
// computing the offset wrt the beginning of the frame
int mu = fp->numerology_index;

View File

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

View File

@@ -517,6 +517,99 @@ 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];
}
/*
* This function maps the CSI part 1 bits
*/
static void map_csi(uci_on_pusch_bit_type_t *template,
const nfapi_nr_ue_pusch_pdu_t *pusch_pdu,
const bool is_csi1,
uint16_t G_csi,
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;
uint32_t symbol_start_bit_idx[NR_SYMBOLS_PER_SLOT] = {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);
}
uint32_t total_placed = 0;
for (uint8_t sym = l1_c; sym < n_symbols && total_placed < G_csi; sym++) {
const uint32_t uci_re_on_sym = m_uci_current[sym];
if (uci_re_on_sym <= 0) {
continue;
}
const uint32_t remaining_to_place = G_csi - total_placed;
uint32_t d_factor_re;
const uint32_t num_re_to_select = ceil((double)remaining_to_place / 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;
}
}
uint32_t re_offset = 0;
while (re_offset < uci_re_on_sym && total_placed < G_csi) {
if (template[symbol_start_bit_idx[sym] + (re_offset * nlqm)] != BIT_TYPE_ULSCH) {
re_offset++;
continue; // if RE already allocated to UCI or reserved for ACK
}
for (uint32_t bit_in_re = 0; bit_in_re < nlqm; bit_in_re++) {
if (total_placed >= G_csi) {
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] = is_csi1 ? BIT_TYPE_CSI1 : BIT_TYPE_CSI2;
total_placed++;
}
re_offset += 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 +679,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 +760,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 1 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",
LOG_I(PHY,
"[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;
@@ -909,11 +1023,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 +1055,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 +1095,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;
@@ -1002,11 +1144,16 @@ static uci_on_pusch_bit_type_t *nr_data_control_mapping(const nfapi_nr_ue_pusch_
map_non_overlapped_ack(template, pusch_pdu, G_ack, l1_c, m_uci_current, m_ulsch_initial);
}
// CSI part 1
map_csi(template, pusch_pdu, true, G_csi1, first_non_dmrs_sym, m_uci_current, m_ulsch_initial);
// CSI part 2
map_csi(template, pusch_pdu, false, G_csi2, first_non_dmrs_sym, m_uci_current, m_ulsch_initial);
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 +1253,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 +1271,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 +1287,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 +1296,34 @@ 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);
uci_present |= true;
}
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]);
uci_present |= true;
// 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 +1331,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,7 +1376,7 @@ 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);
bool is_uci_on_pusch = (pusch_pdu->pusch_uci.harq_ack_bit_length != 0 || pusch_pdu->pusch_uci.csi_payload.p1_bits != 0);
if (is_uci_on_pusch) {
// UCI on PUSCH is present, so available bits are the total codeword length

View File

@@ -91,6 +91,13 @@
// (0 + 0 * 20) % 512 = 0
#define NUM_PROCESS_SLOT_TX_BARRIERS 512
// CSI for tracking can have up to 2 resources per slot
#define MAX_CSI_RES_SLOT 2
// Number of consequtive slots carrying TRS
#define NUM_TRS_SLOT 2
// Threshold to change radio frequency
#define TRS_CFO_THRESH 500
#include "impl_defs_top.h"
#include "impl_defs_nr.h"
#include "time_meas.h"
@@ -334,6 +341,11 @@ typedef struct {
fapi_nr_dl_ntn_config_command_pdu ntn_config_params;
} ntn_config_message_t;
typedef struct {
_Atomic bool valid;
int cfo;
} trs_cfo_t;
/// Top-level PHY Data Structure for UE
typedef struct PHY_VARS_NR_UE_s {
openair0_config_t openair0_cfg[MAX_CARDS];
@@ -465,6 +477,9 @@ typedef struct PHY_VARS_NR_UE_s {
double freq_offset; /// currently compensated frequency offset
double freq_off_acc; /// accumulated frequency error (for PI controller)
/// Frequency offset estimated from TRS
trs_cfo_t trs_cfo[NUM_TRS_SLOT];
/// Timing Advance updates variables
/// Timing advance update computed from the TA command signalled from gNB
int timing_advance;
@@ -589,7 +604,9 @@ typedef struct nr_phy_data_s {
// Sidelink Rx action decided by MAC
sl_nr_rx_config_type_enum_t sl_rx_action;
NR_UE_CSI_RS csirs_vars;
int num_csirs;
NR_UE_CSI_RS csirs_vars[MAX_CSI_RES_SLOT];
bool is_last_trs_slot;
NR_UE_CSI_IM csiim_vars;
} nr_phy_data_t;

View File

@@ -54,7 +54,8 @@
FN(ULSCH_INTERLEAVING_STATS),\
FN(ULSCH_ENCODING_STATS),\
FN(OFDM_MOD_STATS),\
FN(PRACH_GEN_STATS)
FN(PRACH_GEN_STATS),\
FN(TRS_PROCESSING)
typedef enum {
FOREACH_NR_PHY_CPU_MEAS(NOOP),

View File

@@ -163,7 +163,12 @@ void nr_ue_csi_im_procedures(PHY_VARS_NR_UE *ue,
void nr_ue_csi_rs_procedures(PHY_VARS_NR_UE *ue,
const UE_nr_rxtx_proc_t *proc,
const c16_t rxdataF[][ue->frame_parms.samples_per_slot_wCP],
fapi_nr_dl_config_csirs_pdu_rel15_t *csirs_config_pdu);
fapi_nr_dl_config_csirs_pdu_rel15_t *csirs_config_pdu,
c16_t trs_estimates[][1][ue->frame_parms.ofdm_symbol_size],
const int res_idx,
const int trs_sym0);
void trs_freq_correction(PHY_VARS_NR_UE *ue);
int psbch_pscch_processing(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, nr_phy_data_t *phy_data);
void phy_procedures_nrUE_SL_TX(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, nr_phy_data_tx_t *phy_data, c16_t **txp);

View File

@@ -193,8 +193,15 @@ static void nr_ue_scheduled_response_dl(NR_UE_MAC_INST_t *mac,
phy_data->csiim_vars.active = true;
break;
case FAPI_NR_DL_CONFIG_TYPE_CSI_RS:
phy_data->csirs_vars.csirs_config_pdu = pdu->csirs_config_pdu.csirs_config_rel15;
phy_data->csirs_vars.active = true;
AssertFatal(phy_data->num_csirs < MAX_CSI_RES_SLOT, "CSI resources per slot exceeded limit\n");
const int c = phy_data->num_csirs;
if (phy_data->csirs_vars[c].active) {
AssertFatal(false, "Resource should not be active before its configured\n");
continue;
}
phy_data->csirs_vars[c].csirs_config_pdu = pdu->csirs_config_pdu.csirs_config_rel15;
phy_data->csirs_vars[c].active = true;
phy_data->num_csirs++;
break;
case FAPI_NR_DL_CONFIG_TYPE_RA_DLSCH: {
fapi_nr_dl_config_dlsch_pdu_rel15_t *dlsch_config_pdu = &pdu->dlsch_config_pdu.dlsch_config_rel15;

View File

@@ -1218,16 +1218,35 @@ void pdsch_processing(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, nr_phy_
}
// do procedures for CSI-RS
if (phy_data->csirs_vars.active == 1) {
for(int symb = 0; symb < NR_SYMBOLS_PER_SLOT; symb++) {
if(is_csi_rs_in_symbol(phy_data->csirs_vars.csirs_config_pdu, symb)) {
if (!slot_fep_map[symb]) {
nr_slot_fep(ue, &ue->frame_parms, proc->nr_slot_rx, symb, rxdataF, link_type_dl, 0, ue->common_vars.rxdata);
slot_fep_map[symb] = true;
{
/*
CSI-RS for tracking use only one port.
Number of CSI-RS resources for tracking is always 2 per slot.
Computed estimates from first resource is saved and used while estimating second resource.
*/
c16_t trs_estimates[ue->frame_parms.nb_antennas_rx][1][ue->frame_parms.ofdm_symbol_size];
for (int res = 0; res < MAX_CSI_RES_SLOT; res++) {
if (phy_data->csirs_vars[res].active == 1) {
for (int symb = 0; symb < NR_SYMBOLS_PER_SLOT; symb++) {
if (is_csi_rs_in_symbol(phy_data->csirs_vars[res].csirs_config_pdu, symb)) {
if (!slot_fep_map[symb]) {
nr_slot_fep(ue, &ue->frame_parms, proc->nr_slot_rx, symb, rxdataF, link_type_dl, 0, ue->common_vars.rxdata);
slot_fep_map[symb] = true;
}
}
}
nr_ue_csi_rs_procedures(ue,
proc,
rxdataF,
&phy_data->csirs_vars[res].csirs_config_pdu,
trs_estimates,
res,
(res == 1) ? phy_data->csirs_vars[0].csirs_config_pdu.symb_l0 : -1);
}
}
nr_ue_csi_rs_procedures(ue, proc, rxdataF, &phy_data->csirs_vars.csirs_config_pdu);
if (!get_nrUE_params()->cont_fo_comp && phy_data->is_last_trs_slot) {
trs_freq_correction(ue);
}
}
if (dlsch[0].active) {

View File

@@ -187,3 +187,7 @@ void nr_mac_rrc_meas_ind_ue(module_id_t module_id,
int rsrp_dBm)
{
}
void trs_freq_correction(PHY_VARS_NR_UE *ue)
{
}

View File

@@ -249,15 +249,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);
}
@@ -1347,9 +1347,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);
}
@@ -1620,7 +1618,6 @@ int main(int argc, char *argv[])
}
}
}
round++;
if (uci_on_pusch && uci_ulsch_matlab_vec && (errors_scrambling[round] == 0)) {
ret = 0;
printf("*************\n");
@@ -1628,6 +1625,7 @@ int main(int argc, char *argv[])
printf("*************\n");
break;
}
round++;
} // round
if (n_trials == 1 && errors_scrambling[0] > 0) {

View File

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

View File

@@ -3401,11 +3401,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;

View File

@@ -287,9 +287,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,

View File

@@ -307,10 +307,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;
@@ -487,13 +485,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,

View File

@@ -113,7 +113,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);
@@ -126,12 +126,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
@@ -319,7 +324,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,
@@ -361,4 +366,11 @@ void nr_ue_sidelink_scheduler(nr_sidelink_indication_t *sl_ind, NR_UE_MAC_INST_t
NR_SearchSpace_t *get_common_search_space(const NR_UE_MAC_INST_t *mac, const NR_SearchSpaceId_t ss_id);
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);
#endif

View File

@@ -125,19 +125,19 @@ static void nr_ue_process_rar(NR_UE_MAC_INST_t *mac, nr_downlink_indication_t *d
If the max number of retransmissions is reached, it triggers a new RA */
static int8_t nr_ue_get_SR(NR_UE_MAC_INST_t *mac, frame_t frame, slot_t slot, NR_SchedulingRequestId_t sr_id);
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);
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 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_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);
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);
static uint8_t get_rsrp_diff_index(int best_rsrp, int current_rsrp);
@@ -628,7 +628,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);
@@ -1691,7 +1691,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;
@@ -1733,14 +1733,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;
@@ -1768,14 +1769,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;
@@ -1793,7 +1795,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");
@@ -2234,8 +2237,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");
@@ -2248,8 +2251,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 {
@@ -2270,8 +2273,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");
@@ -2284,8 +2287,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) {
@@ -2675,68 +2678,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;
int num_csi = 0;
if (mac->sc_info.csi_MeasConfig) {
NR_CSI_MeasConfig_t *csi_measconfig = mac->sc_info.csi_MeasConfig;
if (!mac->sc_info.csi_MeasConfig || !pucch_Config)
return num_csi;
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];
NR_CSI_MeasConfig_t *csi_measconfig = mac->sc_info.csi_MeasConfig;
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;
}
}
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");
// Only periodic CSI measurements is handled for now
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;
@@ -2774,10 +2781,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(const 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
@@ -2795,7 +2802,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])) {
@@ -2848,19 +2855,19 @@ 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;
}
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)
{
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) {
@@ -2909,10 +2916,10 @@ static int compare_ssb_rsrp(const void *a, const void *b)
}
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
@@ -2931,7 +2938,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])){
@@ -2984,18 +2991,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;
@@ -3063,13 +3070,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;
@@ -3116,7 +3123,7 @@ 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;
}

View File

@@ -366,6 +366,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
@@ -378,7 +398,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,
@@ -558,29 +578,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;
@@ -889,13 +890,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++) {
@@ -916,8 +917,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;
}
@@ -1541,6 +1542,18 @@ static uint8_t nr_locate_BsrIndexByBufferSize(int size, int value)
}
}
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
@@ -1578,8 +1591,7 @@ int nr_ue_pusch_scheduler(const NR_UE_MAC_INST_t *mac,
GET_DURATION_RX_TO_TX(&mac->ntn_ta, mu),
GET_DURATION_RX_TO_TX(&mac->ntn_ta, 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->ntn_ta, mu),
"Slot offset K2 (%ld) needs to be higher than DURATION_RX_TO_TX (%ld). Please set min_rxtxtime at least to %ld in "
@@ -1595,8 +1607,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);
@@ -1703,9 +1714,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);
@@ -1736,7 +1755,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;
}
@@ -1757,14 +1776,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))