Merge remote-tracking branch 'origin/nrue_write_timestamp_fix' into integration_2026_w09 (!3928)
NR UE: correctly compute writeTimestamp for SCS > 30 kHz with rf-simulator Contains also two minor cleanups for nr-ue.c: - make fp point to constant NR_DL_FRAME_PARMS where possible - use c16_t type for I/Q sample arrays
This commit is contained in:
+41
-37
@@ -216,7 +216,7 @@ static void UE_synch(void *arg) {
|
||||
LOG_I(PHY, "[UE thread Synch] Running Initial Synch \n");
|
||||
|
||||
uint64_t dl_carrier, ul_carrier;
|
||||
NR_DL_FRAME_PARMS *fp = &UE->frame_parms;
|
||||
const NR_DL_FRAME_PARMS *fp = &UE->frame_parms;
|
||||
nr_initial_sync_t ret = {false, 0, 0};
|
||||
if (UE->sl_mode == 2) {
|
||||
fp = &UE->SL_UE_PHY_PARAMS.sl_frame_params;
|
||||
@@ -294,11 +294,15 @@ static int nr_ue_slot_select(const fapi_nr_config_request_t *cfg, int nr_slot)
|
||||
|
||||
static void RU_write(nr_rxtx_thread_data_t *rxtxD, bool sl_tx_action, c16_t **txp)
|
||||
{
|
||||
int writeBlockSize = rxtxD->writeBlockSize;
|
||||
if (writeBlockSize == 0)
|
||||
return;
|
||||
|
||||
PHY_VARS_NR_UE *UE = rxtxD->UE;
|
||||
const fapi_nr_config_request_t *cfg = &UE->nrUE_config;
|
||||
const UE_nr_rxtx_proc_t *proc = &rxtxD->proc;
|
||||
|
||||
NR_DL_FRAME_PARMS *fp = &UE->frame_parms;
|
||||
const NR_DL_FRAME_PARMS *fp = &UE->frame_parms;
|
||||
if (UE->sl_mode == 2)
|
||||
fp = &UE->SL_UE_PHY_PARAMS.sl_frame_params;
|
||||
|
||||
@@ -353,7 +357,6 @@ static void RU_write(nr_rxtx_thread_data_t *rxtxD, bool sl_tx_action, c16_t **tx
|
||||
}
|
||||
|
||||
openair0_timestamp_t writeTimestamp = proc->timestamp_tx;
|
||||
int writeBlockSize = rxtxD->writeBlockSize;
|
||||
// if writeBlockSize gets longer that slot size, fill with dummy
|
||||
const int maxWriteBlockSize = get_samples_per_slot(proc->nr_slot_tx, fp);
|
||||
while (writeBlockSize > maxWriteBlockSize) {
|
||||
@@ -399,7 +402,7 @@ void processSlotTX(void *arg)
|
||||
|
||||
LOG_D(PHY, "SlotTx %d.%d => slot type %d\n", proc->frame_tx, proc->nr_slot_tx, proc->tx_slot_type);
|
||||
|
||||
NR_DL_FRAME_PARMS *fp = &UE->frame_parms;
|
||||
const NR_DL_FRAME_PARMS *fp = &UE->frame_parms;
|
||||
c16_t *txp[fp->nb_antennas_tx];
|
||||
for (int i = 0; i < fp->nb_antennas_tx; i++) {
|
||||
txp[i] = UE->common_vars.txData[i] + get_samples_slot_timestamp(fp, proc->nr_slot_tx);
|
||||
@@ -533,7 +536,7 @@ static int UE_dl_preprocessing(PHY_VARS_NR_UE *UE,
|
||||
{
|
||||
TracyCZone(ctx, true);
|
||||
int sampleShift = INT_MAX;
|
||||
NR_DL_FRAME_PARMS *fp = &UE->frame_parms;
|
||||
const NR_DL_FRAME_PARMS *fp = &UE->frame_parms;
|
||||
if (UE->sl_mode == 2)
|
||||
fp = &UE->SL_UE_PHY_PARAMS.sl_frame_params;
|
||||
|
||||
@@ -621,24 +624,23 @@ void UE_dl_processing(void *arg) {
|
||||
|
||||
void dummyWrite(PHY_VARS_NR_UE *UE, openair0_timestamp_t timestamp, int writeBlockSize)
|
||||
{
|
||||
NR_DL_FRAME_PARMS *fp = &UE->frame_parms;
|
||||
const NR_DL_FRAME_PARMS *fp = &UE->frame_parms;
|
||||
if (UE->sl_mode == 2)
|
||||
fp = &UE->SL_UE_PHY_PARAMS.sl_frame_params;
|
||||
|
||||
void *dummy_tx[fp->nb_antennas_tx];
|
||||
// 2 because the function we call use pairs of int16_t implicitly as complex numbers
|
||||
int16_t dummy_tx_data[2 * writeBlockSize];
|
||||
c16_t *dummy_tx[fp->nb_antennas_tx];
|
||||
c16_t dummy_tx_data[writeBlockSize];
|
||||
memset(dummy_tx_data, 0, sizeof(dummy_tx_data));
|
||||
for (int i = 0; i < fp->nb_antennas_tx; i++)
|
||||
dummy_tx[i] = dummy_tx_data;
|
||||
|
||||
int tmp = nrue_ru_write(UE, timestamp, dummy_tx, writeBlockSize, fp->nb_antennas_tx, 4);
|
||||
int tmp = nrue_ru_write(UE, timestamp, (void **)dummy_tx, writeBlockSize, fp->nb_antennas_tx, 4);
|
||||
AssertFatal(writeBlockSize == tmp, "");
|
||||
}
|
||||
|
||||
void readFrame(PHY_VARS_NR_UE *UE, openair0_timestamp_t *timestamp, int duration_rx_to_tx, bool toTrash)
|
||||
{
|
||||
NR_DL_FRAME_PARMS *fp = &UE->frame_parms;
|
||||
const NR_DL_FRAME_PARMS *fp = &UE->frame_parms;
|
||||
// two frames for initial sync
|
||||
int num_frames = 2;
|
||||
// In Sidelink worst case SL-SSB can be sent once in 16 frames
|
||||
@@ -647,30 +649,31 @@ void readFrame(PHY_VARS_NR_UE *UE, openair0_timestamp_t *timestamp, int duration
|
||||
num_frames = SL_NR_PSBCH_REPETITION_IN_FRAMES;
|
||||
}
|
||||
|
||||
void *rxp[NB_ANTENNAS_RX];
|
||||
c16_t *rxp[fp->nb_antennas_rx];
|
||||
if (toTrash) {
|
||||
rxp[0] = malloc16(get_samples_per_slot(0, fp) * 4);
|
||||
rxp[0] = malloc16(get_samples_per_slot(0, fp) * sizeof(c16_t));
|
||||
for (int i = 1; i < fp->nb_antennas_rx; i++)
|
||||
rxp[i] = rxp[0];
|
||||
}
|
||||
|
||||
for (int x = 0; x < num_frames * NR_NUMBER_OF_SUBFRAMES_PER_FRAME; x++) { // two frames for initial sync
|
||||
for (int slot = 0; slot < fp->slots_per_subframe; slot++) {
|
||||
for (int slot_rx = 0; slot_rx < fp->slots_per_subframe; slot_rx++) {
|
||||
if (!toTrash)
|
||||
for (int i = 0; i < fp->nb_antennas_rx; i++)
|
||||
rxp[i] =
|
||||
((void *)&UE->common_vars.rxdata[i][0]) + 4 * ((x * fp->samples_per_subframe) + get_samples_slot_timestamp(fp, slot));
|
||||
rxp[i] = &UE->common_vars.rxdata[i][x * fp->samples_per_subframe + get_samples_slot_timestamp(fp, slot_rx)];
|
||||
|
||||
int read_block_size = get_samples_per_slot(slot, fp);
|
||||
int tmp = nrue_ru_read(UE, timestamp, rxp, read_block_size, fp->nb_antennas_rx);
|
||||
UEscopeCopy(UE, ueTimeDomainSamplesBeforeSync, rxp[0], sizeof(c16_t), 1, read_block_size, 0);
|
||||
AssertFatal(read_block_size == tmp, "");
|
||||
int readBlockSize = get_samples_per_slot(slot_rx, fp);
|
||||
int tmp = nrue_ru_read(UE, timestamp, (void **)rxp, readBlockSize, fp->nb_antennas_rx);
|
||||
UEscopeCopy(UE, ueTimeDomainSamplesBeforeSync, rxp[0], sizeof(c16_t), 1, readBlockSize, 0);
|
||||
AssertFatal(readBlockSize == tmp, "");
|
||||
|
||||
if (IS_SOFTMODEM_RFSIM) {
|
||||
int slot_tx = (slot_rx + duration_rx_to_tx) % fp->slots_per_frame;
|
||||
int writeBlockSize = get_samples_per_slot(slot_tx, fp);
|
||||
int ta = UE->timing_advance + UE->timing_advance_ntn;
|
||||
const openair0_timestamp_t writeTimestamp =
|
||||
*timestamp + get_samples_slot_duration(fp, slot, duration_rx_to_tx) - UE->N_TA_offset - ta;
|
||||
dummyWrite(UE, writeTimestamp, get_samples_per_slot(slot, fp));
|
||||
*timestamp + get_samples_slot_duration(fp, slot_rx, duration_rx_to_tx) - UE->N_TA_offset - ta;
|
||||
dummyWrite(UE, writeTimestamp, writeBlockSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -681,34 +684,35 @@ void readFrame(PHY_VARS_NR_UE *UE, openair0_timestamp_t *timestamp, int duration
|
||||
|
||||
static void syncInFrame(PHY_VARS_NR_UE *UE, openair0_timestamp_t *timestamp, int duration_rx_to_tx, openair0_timestamp_t rx_offset)
|
||||
{
|
||||
NR_DL_FRAME_PARMS *fp = &UE->frame_parms;
|
||||
const NR_DL_FRAME_PARMS *fp = &UE->frame_parms;
|
||||
if (UE->sl_mode == 2)
|
||||
fp = &UE->SL_UE_PHY_PARAMS.sl_frame_params;
|
||||
|
||||
LOG_I(PHY, "Resynchronizing RX by %ld samples\n", rx_offset);
|
||||
|
||||
int slot = 0;
|
||||
int size = rx_offset;
|
||||
while (size > 0) {
|
||||
const int unitTransfer = min(get_samples_per_slot(slot, fp), size);
|
||||
// Set a maximum transfer size. As we usually read/write single slots, we use the size of slot 0 as maximum here.
|
||||
const int unitTransfer = min(get_samples_per_slot(0, fp), size);
|
||||
const int res = nrue_ru_read(UE, timestamp, (void **)UE->common_vars.rxdata, unitTransfer, fp->nb_antennas_rx);
|
||||
DevAssert(unitTransfer == res);
|
||||
if (IS_SOFTMODEM_RFSIM) {
|
||||
int ta = UE->timing_advance + UE->timing_advance_ntn;
|
||||
const openair0_timestamp_t writeTimestamp =
|
||||
*timestamp + get_samples_slot_duration(fp, slot, duration_rx_to_tx) - UE->N_TA_offset - ta;
|
||||
*timestamp + get_samples_slot_duration(fp, 0, duration_rx_to_tx) - UE->N_TA_offset - ta;
|
||||
dummyWrite(UE, writeTimestamp, unitTransfer);
|
||||
}
|
||||
slot = (slot + 1) % fp->slots_per_subframe;
|
||||
size -= unitTransfer;
|
||||
}
|
||||
}
|
||||
|
||||
static inline int get_firstSymSamp(uint16_t slot, NR_DL_FRAME_PARMS *fp) {
|
||||
static inline int get_firstSymSamp(uint16_t slot, const NR_DL_FRAME_PARMS *fp)
|
||||
{
|
||||
return get_samples_symbol_duration(fp, slot, 0, 1);
|
||||
}
|
||||
|
||||
static inline int get_readBlockSize(uint16_t slot, NR_DL_FRAME_PARMS *fp) {
|
||||
static inline int get_readBlockSize(uint16_t slot, const NR_DL_FRAME_PARMS *fp)
|
||||
{
|
||||
int rem_samples = get_samples_per_slot(slot, fp) - get_firstSymSamp(slot, fp);
|
||||
int next_slot_first_symbol = 0;
|
||||
if (slot < (fp->slots_per_frame-1))
|
||||
@@ -720,11 +724,11 @@ void *UE_thread(void *arg)
|
||||
{
|
||||
//this thread should be over the processing thread to keep in real time
|
||||
PHY_VARS_NR_UE *UE = (PHY_VARS_NR_UE *)arg;
|
||||
const NR_DL_FRAME_PARMS *fp = &UE->frame_parms;
|
||||
// int tx_enabled = 0;
|
||||
void *rxp[NB_ANTENNAS_RX];
|
||||
c16_t *rxp[fp->nb_antennas_rx];
|
||||
enum stream_status_e stream_status = STREAM_STATUS_UNSYNC;
|
||||
fapi_nr_config_request_t *cfg = &UE->nrUE_config;
|
||||
NR_DL_FRAME_PARMS *fp = &UE->frame_parms;
|
||||
sl_nr_phy_config_request_t *sl_cfg = NULL;
|
||||
if (UE->sl_mode == 2) {
|
||||
fp = &UE->SL_UE_PHY_PARAMS.sl_frame_params;
|
||||
@@ -943,7 +947,7 @@ void *UE_thread(void *arg)
|
||||
|
||||
int firstSymSamp = get_firstSymSamp(slot_nr, fp);
|
||||
for (int i = 0; i < fp->nb_antennas_rx; i++)
|
||||
rxp[i] = (void *)&UE->common_vars.rxdata[i][firstSymSamp + get_samples_slot_timestamp(fp, slot_nr)];
|
||||
rxp[i] = &UE->common_vars.rxdata[i][firstSymSamp + get_samples_slot_timestamp(fp, slot_nr)];
|
||||
|
||||
int iq_shift_to_apply = 0;
|
||||
if (slot_nr == nb_slot_frame - 1) {
|
||||
@@ -964,9 +968,9 @@ void *UE_thread(void *arg)
|
||||
|
||||
const int readBlockSize = get_readBlockSize(slot_nr, fp) - iq_shift_to_apply;
|
||||
openair0_timestamp_t rx_timestamp;
|
||||
int tmp = nrue_ru_read(UE, &rx_timestamp, rxp, readBlockSize, fp->nb_antennas_rx);
|
||||
int tmp = nrue_ru_read(UE, &rx_timestamp, (void **)rxp, readBlockSize, fp->nb_antennas_rx);
|
||||
metadata meta = {.slot = curMsg.proc.nr_slot_rx, .frame = curMsg.proc.frame_rx};
|
||||
UEscopeCopyWithMetadata(UE, ueTimeDomainSamples, rxp[0] - firstSymSamp * sizeof(c16_t), sizeof(c16_t), 1, readBlockSize, 0, &meta);
|
||||
UEscopeCopyWithMetadata(UE, ueTimeDomainSamples, rxp[0] - firstSymSamp, sizeof(c16_t), 1, readBlockSize, 0, &meta);
|
||||
AssertFatal(readBlockSize == tmp, "");
|
||||
struct timespec current_time;
|
||||
if (clock_gettime(CLOCK_REALTIME, ¤t_time)) {
|
||||
@@ -1009,9 +1013,9 @@ void *UE_thread(void *arg)
|
||||
UE->N_TA_offset = new_N_TA_offset;
|
||||
}
|
||||
if (writeBlockSize < 0) {
|
||||
timing_advance += writeBlockSize - 1;
|
||||
LOG_I(PHY, "writeBlockSize is %d, setting it to 1 and changing timing_advance to %d\n", writeBlockSize, timing_advance);
|
||||
writeBlockSize = 1;
|
||||
timing_advance += writeBlockSize;
|
||||
LOG_I(PHY, "writeBlockSize is %d, setting it to 0 and changing timing_advance to %d\n", writeBlockSize, timing_advance);
|
||||
writeBlockSize = 0;
|
||||
}
|
||||
|
||||
if (curMsg.proc.nr_slot_rx == 0)
|
||||
|
||||
@@ -140,7 +140,7 @@ void apply_ntn_timing_advance_and_doppler(PHY_VARS_NR_UE *UE, const NR_DL_FRAME_
|
||||
|
||||
// apply values based on the NTN-Config
|
||||
void apply_ntn_config(PHY_VARS_NR_UE *UE,
|
||||
NR_DL_FRAME_PARMS *fp,
|
||||
const NR_DL_FRAME_PARMS *fp,
|
||||
int hfn_rx,
|
||||
int frame_rx,
|
||||
int slot_rx,
|
||||
|
||||
@@ -331,7 +331,7 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue,
|
||||
|
||||
int32_t generate_nr_prach(PHY_VARS_NR_UE *ue, uint8_t gNB_id, int frame, uint8_t slot, c16_t **txData);
|
||||
void apply_ntn_config(PHY_VARS_NR_UE *UE,
|
||||
NR_DL_FRAME_PARMS *fp,
|
||||
const NR_DL_FRAME_PARMS *fp,
|
||||
int hfn_rx,
|
||||
int frame_rx,
|
||||
int slot_rx,
|
||||
|
||||
Reference in New Issue
Block a user