Compare commits

...

12 Commits

Author SHA1 Message Date
Sakthivel Velumani
6177115733 phy: map CSI part 1 bits on PUSCH 2025-11-17 22:57:02 -05:00
Sakthivel Velumani
bae911936d tmp: CSI report on PUSCH for periodic CSI
if the slot is set to send CSI on PUCCH and scheduled for PUSCH, the CSI
report is multiplexed on PUSCH. Couldn't find it in the spec but COTS UE
behaves similarly.
2025-11-17 22:57:02 -05:00
Sakthivel Velumani
da69fb8a27 Revert "mac: send CSI report on PUSCH"
This reverts commit 8613d5eba6e7e782a0c6d9819133d2a1a7985ee7.
2025-11-17 22:57:02 -05:00
Sakthivel Velumani
ff8788704c mac: send CSI report on PUSCH
add periodic CSI report in PUSCH PDU if PUSCH and periodic CSI reporting
PUCCH resource overlap.
2025-11-17 22:57:02 -05:00
Sakthivel Velumani
78186f8408 mac: add function to get periodic CSI report
for sending CSI report as UCI on PUSCH
2025-11-17 22:57:02 -05:00
Sakthivel Velumani
21f0e3063d fix: return value assigned inside function 2025-11-17 22:57:02 -05:00
Sakthivel Velumani
cb05437539 clean-up: fix code repetition 2025-11-17 22:57:02 -05:00
Sakthivel Velumani
963db25e47 clean-up: Add const to input pointers 2025-11-17 22:57:02 -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
16 changed files with 520 additions and 132 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

@@ -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,8 @@ 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
uint32_t G_ulsch; // bit capacity of ULSCH
} rate_match_info_uci_t;

View File

@@ -517,6 +517,98 @@ 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_csi1(uci_on_pusch_bit_type_t *template,
const nfapi_nr_ue_pusch_pdu_t *pusch_pdu,
uint16_t G_csi1,
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[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);
}
uint32_t total_placed = 0;
for (uint8_t sym = l1_c; sym < n_symbols && total_placed < G_csi1; 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_csi1 - 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_csi1) {
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_csi1) {
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_CSI1;
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)
{
@@ -669,18 +761,26 @@ static rate_match_info_uci_t calc_rate_match_info_uci(const nfapi_nr_ue_pusch_pd
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_part1_bit_length;
rminfo.Q_dash_CSI1 = get_Qd(ocsi1, beta_csi1, alpha, sumKr, s1, s1);
rminfo.E_uci_CSI1 = rminfo.Q_dash_CSI1 * nlqm;
rminfo.G_ulsch = *G - rminfo.E_uci_CSI1;
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, G_ulsch=%u\n",
rminfo.E_uci_ACK,
rminfo.E_uci_ACK_rvd,
rminfo.E_uci_CSI1,
rminfo.G_ulsch);
return rminfo;
@@ -909,11 +1009,14 @@ 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,
uint16_t G_ack,
uint32_t G_csi1,
uint32_t G_ulsch)
{
uint32_t ulsch_idx = 0;
uint32_t ack_idx = 0;
uint32_t csi1_idx = 0;
for (uint32_t i = 0; i < codeword_len; i++) {
switch (template[i]) {
@@ -935,6 +1038,15 @@ 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_ACK_RESERVED:
case BIT_TYPE_ULSCH:
default:
@@ -957,10 +1069,12 @@ 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,
uint8_t *codeword,
uint32_t codeword_len,
const uint8_t *ulsch_bits,
const uint64_t *cack)
const uint64_t *cack,
const uint64_t *csi1)
{
if (!pusch_pdu || !codeword || codeword_len == 0 || !template)
return NULL;
@@ -1002,11 +1116,13 @@ 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);
}
map_csi1(template, pusch_pdu, G_csi1, 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, G_ack, G_csi1, G_ulsch);
return template;
}
@@ -1106,7 +1222,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_part1_bit_length != 0);
if (uci_present) {
rm_info = calc_rate_match_info_uci(pusch_pdu, harq_process_ul_ue, nl_qm, &G[pusch_id]);
}
@@ -1123,12 +1240,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 +1256,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 +1265,23 @@ 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
if (pusch_pdu->pusch_uci.csi_part1_bit_length != 0) {
nr_uci_encoding(pusch_pdu->pusch_uci.csi_part1_payload,
pusch_pdu->pusch_uci.csi_part1_bit_length,
pucch_pdu->prb_size,
true,
rm_info.E_uci_CSI1,
mod_order,
&b_csi1[0]);
uci_present |= true;
}
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 +1289,17 @@ 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,
temp_codeword,
G_initial_total_pusch_bits,
harq_process_ul_ue->f,
b);
b_ack,
b_csi1);
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 +1332,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_part1_bit_length != 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

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

@@ -115,6 +115,8 @@ 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);
csi_payload_t nr_ue_periodic_csi_reporting(NR_UE_MAC_INST_t *mac, const int frame, const int slot);
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);
void nr_ue_process_l1_measurements(NR_UE_MAC_INST_t *mac, frame_t frame, int slot, fapi_nr_l1_measurements_t *l1_measurements);
@@ -131,7 +133,7 @@ int nr_get_csi_measurements(NR_UE_MAC_INST_t *mac, frame_t frame, int slot, PUCC
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
@@ -361,4 +363,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

@@ -126,18 +126,18 @@ static void nr_ue_process_rar(NR_UE_MAC_INST_t *mac, nr_downlink_indication_t *d
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);
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);
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 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,
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);
@@ -626,12 +626,6 @@ static int nr_ue_process_dci_ul_01(NR_UE_MAC_INST_t *mac,
// - SECOND_DAI
// - SRS_RESOURCE_IND
/* CSI_REQUEST */
long csi_K2 = -1;
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);
/* SRS_REQUEST */
AssertFatal(dci->srs_request.nbits == 2, "If SUL is supported in the cell, there is an additional bit in SRS request field\n");
if (dci->srs_request.val > 0)
@@ -651,6 +645,19 @@ static int nr_ue_process_dci_ul_01(NR_UE_MAC_INST_t *mac,
if (!tda_info.valid_tda || tda_info.nrOfSymbols == 0)
return -1;
/* CSI_REQUEST */
long csi_K2 = -1;
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);
else {
frame_t frame_tx;
int slot_tx;
get_pusch_frame_slot(frame, slot, tda_info.k2, 0, mac->frame_structure.numb_slots_frame, &frame_tx, &slot_tx);
csi_report = nr_ue_periodic_csi_reporting(mac, frame_tx, slot_tx);
csi_K2 = tda_info.k2;
}
if (dci->ulsch_indicator == 0) {
// in case of CSI on PUSCH and no ULSCH we need to use reportSlotOffset in trigger state
if (csi_K2 <= 0) {
@@ -673,7 +680,7 @@ static int nr_ue_process_dci_ul_01(NR_UE_MAC_INST_t *mac,
&tda_info,
&pdu->pusch_config_pdu,
dci,
&csi_report,
(csi_report.p1_bits == 0) ? NULL : &csi_report,
NULL,
dci_ind->rnti,
dci_ind->ss_type,
@@ -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 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])) {
@@ -2857,7 +2864,7 @@ static csi_payload_t get_ssb_sinr_payload(NR_UE_MAC_INST_t *mac,
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};
@@ -2910,9 +2917,9 @@ 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)
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])){
@@ -2992,10 +2999,10 @@ static csi_payload_t get_ssb_rsrp_payload(NR_UE_MAC_INST_t *mac,
}
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)
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;
@@ -3068,8 +3075,8 @@ static csi_payload_t get_csirs_RI_PMI_CQI_payload(NR_UE_MAC_INST_t *mac,
}
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,
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;

View File

@@ -556,8 +556,8 @@ int nr_config_pusch_pdu(NR_UE_MAC_INST_t *mac,
} else if (dci) {
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");
// CSI on PUSCH
if (csi_report) {
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;
@@ -578,10 +578,6 @@ int nr_config_pusch_pdu(NR_UE_MAC_INST_t *mac,
*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;
}
pusch_config_pdu->pusch_uci.harq_ack_bit_length = 0;
@@ -916,8 +912,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 != NULL && *k2 < *offset_list->list.array[tda])
*k2 = *offset_list->list.array[tda];
found = c;
break;
}
@@ -930,6 +926,33 @@ csi_payload_t nr_ue_aperiodic_csi_reporting(NR_UE_MAC_INST_t *mac, dci_field_t c
return csi;
}
csi_payload_t nr_ue_periodic_csi_reporting(NR_UE_MAC_INST_t *mac, const int frame, const int slot)
{
csi_payload_t csi = {0};
if (!mac->sc_info.csi_MeasConfig)
return csi;
const NR_CSI_MeasConfig_t *csi_measconfig = mac->sc_info.csi_MeasConfig;
for (int csi_report_id = 0; csi_report_id < csi_measconfig->csi_ReportConfigToAddModList->list.count; csi_report_id++) {
AssertFatal(csi_report_id == 0, "Only one pediodic CSI report supported for now\n");
const NR_CSI_ReportConfig_t *csirep = csi_measconfig->csi_ReportConfigToAddModList->list.array[csi_report_id];
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;
if (((n_slots_frame * frame + slot - offset) % period)) {
continue;
}
csi = nr_get_csi_payload(mac, csi_report_id, ON_PUSCH, csi_measconfig);
}
return csi;
}
int configure_srs_pdu(NR_UE_MAC_INST_t *mac,
NR_SRS_Resource_t *srs_resource,
fapi_nr_ul_config_srs_pdu *srs_config_pdu,
@@ -1541,6 +1564,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 +1613,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 +1629,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);
@@ -1700,12 +1733,18 @@ static bool schedule_uci_on_pusch(NR_UE_MAC_INST_t *mac,
pusch_pdu->pusch_uci.alpha_scaling = onPusch->scaling;
mux_done = true;
} else {
LOG_E(NR_MAC, "UCI on PUSCH need to be configured to schedule UCI on PUSCH\n");
LOG_E(NR_MAC, "UCI on PUSCH need to be configured to schedule ACK/NACK 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");
// Check if the PUSCH PDU has CSI report filled while UL DCI was processed
if (pusch_pdu->pusch_uci.csi_part1_bit_length > 0) {
NR_PUSCH_Config_t *pusch_Config = mac->current_UL_BWP->pusch_Config;
if (pusch_Config && pusch_Config->uci_OnPUSCH) {
mux_done = true;
} else {
LOG_E(NR_MAC, "UCI on PUSCH need to be configured to schedule CSI report on PUSCH\n");
}
}
release_ul_config(ulcfg_pdu, false);