Commit 1b989c4d authored by Robert Schmidt's avatar Robert Schmidt

Merge remote-tracking branch 'origin/NR_PSBCH_MERGE3' into integration_2024_w25

parents d2f8276d 798ceeee
......@@ -1412,6 +1412,7 @@ set (MAC_NR_SRC_UE
${NR_UE_MAC_DIR}/nr_ue_procedures.c
${NR_UE_MAC_DIR}/nr_ue_procedures_sl.c
${NR_UE_MAC_DIR}/nr_ue_scheduler.c
${NR_UE_MAC_DIR}/nr_ue_scheduler_sl.c
${NR_UE_MAC_DIR}/nr_ue_dci_configuration.c
${NR_UE_MAC_DIR}/nr_ra_procedures.c
)
......
......@@ -364,14 +364,24 @@ static void UE_synch(void *arg) {
LOG_I(PHY, "[UE thread Synch] Running Initial Synch \n");
uint64_t dl_carrier, ul_carrier;
nr_get_carrier_frequencies(UE, &dl_carrier, &ul_carrier);
nr_initial_sync_t ret = nr_initial_sync(&syncD->proc, UE, 2, get_softmodem_params()->sa, syncD->gscnInfo, syncD->numGscn);
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;
dl_carrier = fp->sl_CarrierFreq;
ul_carrier = fp->sl_CarrierFreq;
ret = sl_nr_slss_search(UE, &syncD->proc, SL_NR_SSB_REPETITION_IN_FRAMES);
} else {
nr_get_carrier_frequencies(UE, &dl_carrier, &ul_carrier);
ret = nr_initial_sync(&syncD->proc, UE, 2, get_softmodem_params()->sa, syncD->gscnInfo, syncD->numGscn);
}
if (ret.cell_detected) {
syncD->rx_offset = ret.rx_offset;
const int freq_offset = UE->common_vars.freq_offset; // frequency offset computed with pss in initial sync
const int hw_slot_offset =
((ret.rx_offset << 1) / UE->frame_parms.samples_per_subframe * UE->frame_parms.slots_per_subframe)
+ round((float)((ret.rx_offset << 1) % UE->frame_parms.samples_per_subframe) / UE->frame_parms.samples_per_slot0);
((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);
// rerun with new cell parameters and frequency-offset
// todo: the freq_offset computed on DL shall be scaled before being applied to UL
......@@ -390,15 +400,19 @@ static void UE_synch(void *arg) {
}
}
static void RU_write(nr_rxtx_thread_data_t *rxtxD) {
static void RU_write(nr_rxtx_thread_data_t *rxtxD, bool sl_tx_action)
{
PHY_VARS_NR_UE *UE = rxtxD->UE;
const UE_nr_rxtx_proc_t *proc = &rxtxD->proc;
NR_DL_FRAME_PARMS *fp = &UE->frame_parms;
if (UE->sl_mode == 2)
fp = &UE->SL_UE_PHY_PARAMS.sl_frame_params;
void *txp[NB_ANTENNAS_TX];
int slot = proc->nr_slot_tx;
for (int i = 0; i < UE->frame_parms.nb_antennas_tx; i++)
txp[i] = (void *)&UE->common_vars.txData[i][UE->frame_parms.get_samples_slot_timestamp(slot, &UE->frame_parms, 0)];
for (int i = 0; i < fp->nb_antennas_tx; i++)
txp[i] = (void *)&UE->common_vars.txData[i][fp->get_samples_slot_timestamp(slot, fp, 0)];
radio_tx_burst_flag_t flags = TX_BURST_INVALID;
......@@ -406,27 +420,33 @@ static void RU_write(nr_rxtx_thread_data_t *rxtxD) {
if (mac->phy_config_request_sent &&
openair0_cfg[0].duplex_mode == duplex_mode_TDD &&
!get_softmodem_params()->continuous_tx) {
int slots_frame = UE->frame_parms.slots_per_frame;
int curr_slot = nr_ue_slot_select(&UE->nrUE_config, slot);
if (curr_slot != NR_DOWNLINK_SLOT) {
int next_slot = nr_ue_slot_select(&UE->nrUE_config, (slot + 1) % slots_frame);
int prev_slot = nr_ue_slot_select(&UE->nrUE_config, (slot + slots_frame - 1) % slots_frame);
if (prev_slot == NR_DOWNLINK_SLOT)
flags = TX_BURST_START;
else if (next_slot == NR_DOWNLINK_SLOT)
flags = TX_BURST_END;
else
flags = TX_BURST_MIDDLE;
// In case of Sidelink, USRP write needed only in case transmission
// needs to be done in this slot and not based on tdd ULDL configuration.
if (UE->sl_mode == 2) {
if (sl_tx_action)
flags = TX_BURST_START_AND_END;
} else {
int slots_frame = fp->slots_per_frame;
int curr_slot = nr_ue_slot_select(&UE->nrUE_config, slot);
if (curr_slot != NR_DOWNLINK_SLOT) {
int next_slot = nr_ue_slot_select(&UE->nrUE_config, (slot + 1) % slots_frame);
int prev_slot = nr_ue_slot_select(&UE->nrUE_config, (slot + slots_frame - 1) % slots_frame);
if (prev_slot == NR_DOWNLINK_SLOT)
flags = TX_BURST_START;
else if (next_slot == NR_DOWNLINK_SLOT)
flags = TX_BURST_END;
else
flags = TX_BURST_MIDDLE;
}
}
} else {
flags = TX_BURST_MIDDLE;
}
int tmp =
openair0_write_reorder(&UE->rfdevice, proc->timestamp_tx, txp, rxtxD->writeBlockSize, UE->frame_parms.nb_antennas_tx, flags);
int tmp = openair0_write_reorder(&UE->rfdevice, proc->timestamp_tx, txp, rxtxD->writeBlockSize, fp->nb_antennas_tx, flags);
AssertFatal(tmp == rxtxD->writeBlockSize, "");
for (int i=0; i<UE->frame_parms.nb_antennas_tx; i++)
for (int i = 0; i < fp->nb_antennas_tx; i++)
memset(txp[i], 0, rxtxD->writeBlockSize);
}
......@@ -436,6 +456,7 @@ void processSlotTX(void *arg)
const UE_nr_rxtx_proc_t *proc = &rxtxD->proc;
PHY_VARS_NR_UE *UE = rxtxD->UE;
nr_phy_data_tx_t phy_data = {0};
bool sl_tx_action = false;
// Force sequential execution, even if we launch in // for all slots
// at least ULstatus variable is a pure race condition that is quickly detected by assert() in the code because one thread sets it
......@@ -486,35 +507,72 @@ void processSlotTX(void *arg)
"Internal error: extra event on Tx waiting queue for slot %d, event comes from rx slot %d\n",
proc->nr_slot_tx,
*(int *)NotifiedFifoData(res));
// trigger L2 to run ue_scheduler thru IF module
// [TODO] mapping right after NR initial sync
if(UE->if_inst != NULL && UE->if_inst->ul_indication != NULL) {
start_meas(&UE->ue_ul_indication_stats);
nr_uplink_indication_t ul_indication = {.module_id = UE->Mod_id,
.gNB_index = proc->gNB_id,
.cc_id = UE->CC_id,
.frame = proc->frame_tx,
.slot = proc->nr_slot_tx,
.phy_data = &phy_data};
UE->if_inst->ul_indication(&ul_indication);
stop_meas(&UE->ue_ul_indication_stats);
}
phy_procedures_nrUE_TX(UE, proc, &phy_data);
if (UE->sl_mode == 2 && proc->tx_slot_type == NR_SIDELINK_SLOT) {
// trigger L2 to run ue_sidelink_scheduler thru IF module
if (UE->if_inst != NULL && UE->if_inst->sl_indication != NULL) {
start_meas(&UE->ue_ul_indication_stats);
nr_sidelink_indication_t sl_indication = {.module_id = UE->Mod_id,
.gNB_index = proc->gNB_id,
.cc_id = UE->CC_id,
.frame_tx = proc->frame_tx,
.slot_tx = proc->nr_slot_tx,
.frame_rx = proc->frame_rx,
.slot_rx = proc->nr_slot_rx,
.slot_type = SIDELINK_SLOT_TYPE_TX,
.phy_data = &phy_data};
UE->if_inst->sl_indication(&sl_indication);
stop_meas(&UE->ue_ul_indication_stats);
}
if (phy_data.sl_tx_action) {
AssertFatal((phy_data.sl_tx_action >= SL_NR_CONFIG_TYPE_TX_PSBCH &&
phy_data.sl_tx_action < SL_NR_CONFIG_TYPE_TX_MAXIMUM), "Incorrect SL TX Action Scheduled\n");
phy_procedures_nrUE_SL_TX(UE, proc, &phy_data);
sl_tx_action = true;
}
} else {
// trigger L2 to run ue_scheduler thru IF module
// [TODO] mapping right after NR initial sync
if (UE->if_inst != NULL && UE->if_inst->ul_indication != NULL) {
start_meas(&UE->ue_ul_indication_stats);
nr_uplink_indication_t ul_indication = {.module_id = UE->Mod_id,
.gNB_index = proc->gNB_id,
.cc_id = UE->CC_id,
.frame = proc->frame_tx,
.slot = proc->nr_slot_tx,
.phy_data = &phy_data};
UE->if_inst->ul_indication(&ul_indication);
stop_meas(&UE->ue_ul_indication_stats);
}
phy_procedures_nrUE_TX(UE, proc, &phy_data);
}
}
notifiedFIFO_elt_t *newElt = newNotifiedFIFO_elt(sizeof(int), 0, NULL, NULL);
int *msgData = (int *)NotifiedFifoData(newElt);
int newslot = (proc->nr_slot_tx + 1) % UE->frame_parms.slots_per_frame;
int slots_per_frame = (UE->sl_mode == 2) ? UE->SL_UE_PHY_PARAMS.sl_frame_params.slots_per_frame
: UE->frame_parms.slots_per_frame;
int newslot = (proc->nr_slot_tx + 1) % slots_per_frame;
*msgData = newslot;
pushNotifiedFIFO(UE->tx_resume_ind_fifo + newslot, newElt);
RU_write(rxtxD);
RU_write(rxtxD, sl_tx_action);
}
static int UE_dl_preprocessing(PHY_VARS_NR_UE *UE, const UE_nr_rxtx_proc_t *proc, int *tx_wait_for_dlsch, nr_phy_data_t *phy_data)
{
int sampleShift = 0;
NR_DL_FRAME_PARMS *fp = &UE->frame_parms;
if (UE->sl_mode == 2)
fp = &UE->SL_UE_PHY_PARAMS.sl_frame_params;
if (IS_SOFTMODEM_NOS1 || get_softmodem_params()->sa) {
// Start synchronization with a target gNB
......@@ -527,11 +585,11 @@ static int UE_dl_preprocessing(PHY_VARS_NR_UE *UE, const UE_nr_rxtx_proc_t *proc
}
/* send tick to RLC and PDCP every ms */
if (proc->nr_slot_rx % UE->frame_parms.slots_per_subframe == 0) {
if (proc->nr_slot_rx % fp->slots_per_subframe == 0) {
void nr_rlc_tick(int frame, int subframe);
void nr_pdcp_tick(int frame, int subframe);
nr_rlc_tick(proc->frame_rx, proc->nr_slot_rx / UE->frame_parms.slots_per_subframe);
nr_pdcp_tick(proc->frame_rx, proc->nr_slot_rx / UE->frame_parms.slots_per_subframe);
nr_rlc_tick(proc->frame_rx, proc->nr_slot_rx / fp->slots_per_subframe);
nr_pdcp_tick(proc->frame_rx, proc->nr_slot_rx / fp->slots_per_subframe);
}
}
......@@ -551,7 +609,26 @@ static int UE_dl_preprocessing(PHY_VARS_NR_UE *UE, const UE_nr_rxtx_proc_t *proc
}
}
ue_ta_procedures(UE, proc->nr_slot_tx, proc->frame_tx);
if (UE->sl_mode == 2) {
if (proc->rx_slot_type == NR_SIDELINK_SLOT) {
phy_data->sl_rx_action = 0;
if (UE->if_inst != NULL && UE->if_inst->sl_indication != NULL) {
nr_sidelink_indication_t sl_indication;
nr_fill_sl_indication(&sl_indication, NULL, NULL, proc, UE, phy_data);
UE->if_inst->sl_indication(&sl_indication);
}
if (phy_data->sl_rx_action) {
AssertFatal((phy_data->sl_rx_action >= SL_NR_CONFIG_TYPE_RX_PSBCH &&
phy_data->sl_rx_action < SL_NR_CONFIG_TYPE_RX_MAXIMUM), "Incorrect SL RX Action Scheduled\n");
sampleShift = psbch_pscch_processing(UE, proc, phy_data);
}
}
} else
ue_ta_procedures(UE, proc->nr_slot_tx, proc->frame_tx);
return sampleShift;
}
......@@ -561,80 +638,86 @@ void UE_dl_processing(void *arg) {
PHY_VARS_NR_UE *UE = rxtxD->UE;
nr_phy_data_t *phy_data = &rxtxD->phy_data;
pdsch_processing(UE, proc, phy_data);
if (!UE->sl_mode)
pdsch_processing(UE, proc, phy_data);
}
void dummyWrite(PHY_VARS_NR_UE *UE,openair0_timestamp timestamp, int writeBlockSize) {
void *dummy_tx[UE->frame_parms.nb_antennas_tx];
int16_t dummy_tx_data[UE->frame_parms.nb_antennas_tx][2*writeBlockSize]; // 2 because the function we call use pairs of int16_t implicitly as complex numbers
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[fp->nb_antennas_tx][2 * writeBlockSize];
memset(dummy_tx_data, 0, sizeof(dummy_tx_data));
for (int i=0; i<UE->frame_parms.nb_antennas_tx; i++)
for (int i = 0; i < fp->nb_antennas_tx; i++)
dummy_tx[i]=dummy_tx_data[i];
int tmp = UE->rfdevice.trx_write_func(&UE->rfdevice, timestamp, dummy_tx, writeBlockSize, UE->frame_parms.nb_antennas_tx, 4);
int tmp = UE->rfdevice.trx_write_func(&UE->rfdevice, timestamp, dummy_tx, writeBlockSize, fp->nb_antennas_tx, 4);
AssertFatal(writeBlockSize == tmp, "");
}
void readFrame(PHY_VARS_NR_UE *UE, openair0_timestamp *timestamp, bool toTrash) {
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
if (UE->sl_mode == 2) {
fp = &UE->SL_UE_PHY_PARAMS.sl_frame_params;
num_frames = SL_NR_PSBCH_REPETITION_IN_FRAMES;
}
void *rxp[NB_ANTENNAS_RX];
for(int x=0; x<20; x++) { // two frames for initial sync
for (int slot=0; slot<UE->frame_parms.slots_per_subframe; slot ++ ) {
for (int i=0; i<UE->frame_parms.nb_antennas_rx; i++) {
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 i = 0; i < fp->nb_antennas_rx; i++) {
if (toTrash)
rxp[i]=malloc16(UE->frame_parms.get_samples_per_slot(slot,&UE->frame_parms)*4);
rxp[i] = malloc16(fp->get_samples_per_slot(slot, fp) * 4);
else
rxp[i] = ((void *)&UE->common_vars.rxdata[i][0]) +
4*((x*UE->frame_parms.samples_per_subframe)+
UE->frame_parms.get_samples_slot_timestamp(slot,&UE->frame_parms,0));
rxp[i] = ((void *)&UE->common_vars.rxdata[i][0])
+ 4 * ((x * fp->samples_per_subframe) + fp->get_samples_slot_timestamp(slot, fp, 0));
}
int tmp = UE->rfdevice.trx_read_func(&UE->rfdevice,
timestamp,
rxp,
UE->frame_parms.get_samples_per_slot(slot, &UE->frame_parms),
UE->frame_parms.nb_antennas_rx);
AssertFatal(UE->frame_parms.get_samples_per_slot(slot, &UE->frame_parms) == tmp, "");
int tmp = UE->rfdevice.trx_read_func(&UE->rfdevice, timestamp, rxp, fp->get_samples_per_slot(slot, fp), fp->nb_antennas_rx);
AssertFatal(fp->get_samples_per_slot(slot, fp) == tmp, "");
if (IS_SOFTMODEM_RFSIM)
dummyWrite(UE,*timestamp, UE->frame_parms.get_samples_per_slot(slot,&UE->frame_parms));
dummyWrite(UE, *timestamp, fp->get_samples_per_slot(slot, fp));
if (toTrash)
for (int i=0; i<UE->frame_parms.nb_antennas_rx; i++)
for (int i = 0; i < fp->nb_antennas_rx; i++)
free(rxp[i]);
}
}
}
static void syncInFrame(PHY_VARS_NR_UE *UE, openair0_timestamp *timestamp, openair0_timestamp rx_offset)
{
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);
if (IS_SOFTMODEM_IQPLAYER || IS_SOFTMODEM_IQRECORDER) {
// Resynchonize by slot (will work with numerology 1 only)
for (int size = rx_offset; size > 0; size -= UE->frame_parms.samples_per_subframe / 2) {
int unitTransfer = size > UE->frame_parms.samples_per_subframe / 2 ? UE->frame_parms.samples_per_subframe / 2 : size;
int tmp = UE->rfdevice.trx_read_func(&UE->rfdevice,
timestamp,
(void **)UE->common_vars.rxdata,
unitTransfer,
UE->frame_parms.nb_antennas_rx);
for (int size = rx_offset; size > 0; size -= fp->samples_per_subframe / 2) {
int unitTransfer = size > fp->samples_per_subframe / 2 ? fp->samples_per_subframe / 2 : size;
int tmp =
UE->rfdevice.trx_read_func(&UE->rfdevice, timestamp, (void **)UE->common_vars.rxdata, unitTransfer, fp->nb_antennas_rx);
DevAssert(unitTransfer == tmp);
}
} else {
*timestamp += UE->frame_parms.get_samples_per_slot(1, &UE->frame_parms);
for (int size = rx_offset; size > 0; size -= UE->frame_parms.samples_per_subframe) {
int unitTransfer = size > UE->frame_parms.samples_per_subframe ? UE->frame_parms.samples_per_subframe : size;
*timestamp += fp->get_samples_per_slot(1, fp);
for (int size = rx_offset; size > 0; size -= fp->samples_per_subframe) {
int unitTransfer = size > fp->samples_per_subframe ? fp->samples_per_subframe : size;
// we write before read because gNB waits for UE to write and both executions halt
// this happens here as the read size is samples_per_subframe which is very much larger than samp_per_slot
if (IS_SOFTMODEM_RFSIM)
dummyWrite(UE, *timestamp, unitTransfer);
int res = UE->rfdevice.trx_read_func(&UE->rfdevice,
timestamp,
(void **)UE->common_vars.rxdata,
unitTransfer,
UE->frame_parms.nb_antennas_rx);
int res =
UE->rfdevice.trx_read_func(&UE->rfdevice, timestamp, (void **)UE->common_vars.rxdata, unitTransfer, fp->nb_antennas_rx);
DevAssert(unitTransfer == res);
*timestamp += unitTransfer; // this does not affect the read but needed for RFSIM write
}
......@@ -667,6 +750,13 @@ void *UE_thread(void *arg)
fapi_nr_config_request_t *cfg = &UE->nrUE_config;
int tmp = openair0_device_load(&(UE->rfdevice), &openair0_cfg[0]);
AssertFatal(tmp == 0, "Could not load the device\n");
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;
sl_cfg = &UE->SL_UE_PHY_PARAMS.sl_config;
}
UE->rfdevice.host_type = RAU_HOST;
UE->is_synchronized = 0;
int tmp2 = UE->rfdevice.trx_start_func(&UE->rfdevice);
......@@ -682,7 +772,7 @@ void *UE_thread(void *arg)
NR_UE_MAC_INST_t *mac = get_mac_inst(0);
bool syncRunning = false;
const int nb_slot_frame = UE->frame_parms.slots_per_frame;
const int nb_slot_frame = fp->slots_per_frame;
int absolute_slot = 0, decoded_frame_rx = INT_MAX, trashed_frames = 0;
int tx_wait_for_dlsch[NR_MAX_SLOTS_PER_FRAME];
......@@ -693,6 +783,11 @@ void *UE_thread(void *arg)
int shiftForNextFrame = 0;
int intialSyncOffset = 0;
openair0_timestamp sync_timestamp;
if (get_softmodem_params()->sync_ref && UE->sl_mode == 2) {
UE->is_synchronized = 1;
}
while (!oai_exit) {
if (syncRunning) {
notifiedFIFO_elt_t *res=tryPullTpool(&nf,&(get_nrUE_params()->Tpool));
......@@ -701,7 +796,10 @@ void *UE_thread(void *arg)
syncRunning = false;
if (UE->is_synchronized) {
UE->synch_request.received_synch_request = 0;
decoded_frame_rx = mac->mib_frame;
if (UE->sl_mode == 2)
decoded_frame_rx = UE->SL_UE_PHY_PARAMS.sync_params.DFN;
else
decoded_frame_rx = mac->mib_frame;
LOG_A(PHY,
"UE synchronized! decoded_frame_rx=%d UE->init_sync_frame=%d trashed_frames=%d\n",
decoded_frame_rx,
......@@ -723,7 +821,7 @@ void *UE_thread(void *arg)
}
} else {
readFrame(UE, &sync_timestamp, true);
trashed_frames += 2;
trashed_frames += ((UE->sl_mode == 2) ? SL_NR_PSBCH_REPETITION_IN_FRAMES : 2);
}
continue;
}
......@@ -761,18 +859,22 @@ void *UE_thread(void *arg)
openair0_write_reorder_clear_context(&UE->rfdevice);
shiftForNextFrame = 0; // will be used to track clock drift
// read in first symbol
AssertFatal(UE->frame_parms.ofdm_symbol_size + UE->frame_parms.nb_prefix_samples0
AssertFatal(fp->ofdm_symbol_size + fp->nb_prefix_samples0
== UE->rfdevice.trx_read_func(&UE->rfdevice,
&sync_timestamp,
(void **)UE->common_vars.rxdata,
UE->frame_parms.ofdm_symbol_size + UE->frame_parms.nb_prefix_samples0,
UE->frame_parms.nb_antennas_rx),
fp->ofdm_symbol_size + fp->nb_prefix_samples0,
fp->nb_antennas_rx),
"");
// we have the decoded frame index in the return of the synch process
// and we shifted above to the first slot of next frame
decoded_frame_rx++;
// we do ++ first in the regular processing, so it will be begin of frame;
absolute_slot = decoded_frame_rx * nb_slot_frame - 1;
if (UE->sl_mode == 2) {
// Set to the slot where the SL-SSB was decoded
absolute_slot += UE->SL_UE_PHY_PARAMS.sync_params.slot_offset;
}
// We have resynchronized, maybe after RF loss so we need to purge any existing context
memset(tx_wait_for_dlsch, 0, sizeof(tx_wait_for_dlsch));
for (int i = 0; i < num_ind_fifo; i++) {
......@@ -795,18 +897,22 @@ void *UE_thread(void *arg)
curMsg.proc.frame_rx = (absolute_slot / nb_slot_frame) % MAX_FRAME_NUMBER;
curMsg.proc.frame_tx = ((absolute_slot + DURATION_RX_TO_TX) / nb_slot_frame) % MAX_FRAME_NUMBER;
if (mac->phy_config_request_sent) {
curMsg.proc.rx_slot_type = nr_ue_slot_select(cfg, curMsg.proc.nr_slot_rx);
curMsg.proc.tx_slot_type = nr_ue_slot_select(cfg, curMsg.proc.nr_slot_tx);
if (UE->sl_mode) {
curMsg.proc.rx_slot_type = sl_nr_ue_slot_select(sl_cfg, curMsg.proc.nr_slot_rx, TDD);
curMsg.proc.tx_slot_type = sl_nr_ue_slot_select(sl_cfg, curMsg.proc.nr_slot_tx, TDD);
} else {
curMsg.proc.rx_slot_type = nr_ue_slot_select(cfg, curMsg.proc.nr_slot_rx);
curMsg.proc.tx_slot_type = nr_ue_slot_select(cfg, curMsg.proc.nr_slot_tx);
}
}
else {
curMsg.proc.rx_slot_type = NR_DOWNLINK_SLOT;
curMsg.proc.tx_slot_type = NR_DOWNLINK_SLOT;
}
int firstSymSamp = get_firstSymSamp(slot_nr, &UE->frame_parms);
for (int i=0; i<UE->frame_parms.nb_antennas_rx; i++)
rxp[i] = (void *)&UE->common_vars
.rxdata[i][firstSymSamp + UE->frame_parms.get_samples_slot_timestamp(slot_nr, &UE->frame_parms, 0)];
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 + fp->get_samples_slot_timestamp(slot_nr, fp, 0)];
int iq_shift_to_apply = 0;
if (slot_nr == nb_slot_frame - 1) {
......@@ -815,14 +921,14 @@ void *UE_thread(void *arg)
shiftForNextFrame = 0; // We will get a new measured offset if we decode PBCH
}
const int readBlockSize = get_readBlockSize(slot_nr, &UE->frame_parms) - iq_shift_to_apply;
const int readBlockSize = get_readBlockSize(slot_nr, fp) - iq_shift_to_apply;
openair0_timestamp rx_timestamp;
int tmp = UE->rfdevice.trx_read_func(&UE->rfdevice, &rx_timestamp, rxp, readBlockSize, UE->frame_parms.nb_antennas_rx);
int tmp = UE->rfdevice.trx_read_func(&UE->rfdevice, &rx_timestamp, rxp, readBlockSize, fp->nb_antennas_rx);
AssertFatal(readBlockSize == tmp, "");
if(slot_nr == (nb_slot_frame - 1)) {
// read in first symbol of next frame and adjust for timing drift
int first_symbols = UE->frame_parms.ofdm_symbol_size + UE->frame_parms.nb_prefix_samples0; // first symbol of every frames
int first_symbols = fp->ofdm_symbol_size + fp->nb_prefix_samples0; // first symbol of every frames
if (first_symbols > 0) {
openair0_timestamp ignore_timestamp;
......@@ -830,7 +936,7 @@ void *UE_thread(void *arg)
&ignore_timestamp,
(void **)UE->common_vars.rxdata,
first_symbols,
UE->frame_parms.nb_antennas_rx);
fp->nb_antennas_rx);
AssertFatal(first_symbols == tmp, "");
} else
......@@ -838,13 +944,11 @@ void *UE_thread(void *arg)
}
// use previous timing_advance value to compute writeTimestamp
const openair0_timestamp writeTimestamp =
rx_timestamp + UE->frame_parms.get_samples_slot_timestamp(slot_nr, &UE->frame_parms, DURATION_RX_TO_TX) - firstSymSamp
- UE->N_TA_offset - timing_advance;
const openair0_timestamp writeTimestamp = rx_timestamp + fp->get_samples_slot_timestamp(slot_nr, fp, DURATION_RX_TO_TX)
- firstSymSamp - UE->N_TA_offset - timing_advance;
// but use current UE->timing_advance value to compute writeBlockSize
int writeBlockSize =
UE->frame_parms.get_samples_per_slot((slot_nr + DURATION_RX_TO_TX) % nb_slot_frame, &UE->frame_parms) - iq_shift_to_apply;
int writeBlockSize = fp->get_samples_per_slot((slot_nr + DURATION_RX_TO_TX) % nb_slot_frame, fp) - iq_shift_to_apply;
if (UE->timing_advance != timing_advance) {
writeBlockSize -= UE->timing_advance - timing_advance;
timing_advance = UE->timing_advance;
......@@ -893,7 +997,7 @@ void init_NR_UE(int nb_inst, char *uecap_file, char *reconfig_file, char *rbconf
NR_UE_MAC_INST_t *mac = get_mac_inst(i);
mac->if_module = nr_ue_if_module_init(i);
AssertFatal(mac->if_module, "can not initialize IF module\n");
if (!get_softmodem_params()->sa) {
if (!get_softmodem_params()->sa || !get_softmodem_params()->sl_mode) {
init_nsa_message(rrc_inst, reconfig_file, rbconfig_file);
nr_rlc_activate_srb0(mac_inst->crnti, NULL, send_srb0_rrc);
}
......
......@@ -315,13 +315,17 @@ void set_options(int CC_id, PHY_VARS_NR_UE *UE){
}
void init_openair0(void) {
void init_openair0()
{
int card;
int freq_off = 0;
NR_DL_FRAME_PARMS *frame_parms = &PHY_vars_UE_g[0][0]->frame_parms;
bool is_sidelink = (get_softmodem_params()->sl_mode) ? true : false;
if (is_sidelink)
frame_parms = &PHY_vars_UE_g[0][0]->SL_UE_PHY_PARAMS.sl_frame_params;
for (card=0; card<MAX_CARDS; card++) {
uint64_t dl_carrier, ul_carrier, sl_carrier;
uint64_t dl_carrier, ul_carrier;
openair0_cfg[card].configFilename = NULL;
openair0_cfg[card].threequarter_fs = frame_parms->threequarter_fs;
openair0_cfg[card].sample_rate = frame_parms->samples_per_subframe * 1e3;
......@@ -347,15 +351,14 @@ void init_openair0(void) {
openair0_cfg[card].rx_num_channels,
duplex_mode[openair0_cfg[card].duplex_mode]);
nr_get_carrier_frequencies(PHY_vars_UE_g[0][0], &dl_carrier, &ul_carrier);
if (is_sidelink) {
dl_carrier = frame_parms->dl_CarrierFreq;
ul_carrier = frame_parms->ul_CarrierFreq;
} else
nr_get_carrier_frequencies(PHY_vars_UE_g[0][0], &dl_carrier, &ul_carrier);
nr_rf_card_config_freq(&openair0_cfg[card], ul_carrier, dl_carrier, freq_off);
if (get_softmodem_params()->sl_mode == 2) {
nr_get_carrier_frequencies_sl(PHY_vars_UE_g[0][0], &sl_carrier);
nr_rf_card_config_freq(&openair0_cfg[card], sl_carrier, sl_carrier, freq_off);
}
nr_rf_card_config_gain(&openair0_cfg[card], rx_gain_off);
openair0_cfg[card].configFilename = get_softmodem_params()->rf_config_file;
......@@ -511,7 +514,7 @@ int main(int argc, char **argv)
ue_id_g = (node_number == 0) ? 0 : node_number - 2;
AssertFatal(ue_id_g >= 0, "UE id is expected to be nonnegative.\n");
if(node_number == 0)
if (node_number == 0)
init_pdcp(0);
else
init_pdcp(mode_offset + ue_id_g);
......@@ -540,7 +543,8 @@ int main(int argc, char **argv)
set_options(CC_id, UE[CC_id]);
NR_UE_MAC_INST_t *mac = get_mac_inst(0);
if (get_softmodem_params()->sa) { // set frame config to initial values from command line and assume that the SSB is centered on the grid
if (get_softmodem_params()->sa || get_softmodem_params()->sl_mode) { // set frame config to initial values from command line
// and assume that the SSB is centered on the grid
uint16_t nr_band = get_softmodem_params()->band;
mac->nr_band = nr_band;
mac->ssb_start_subcarrier = UE[CC_id]->frame_parms.ssb_start_subcarrier;
......@@ -549,8 +553,7 @@ int main(int argc, char **argv)
uplink_frequency_offset[CC_id][0],
get_softmodem_params()->numerology,
nr_band);
}
else{
} else {
DevAssert(mac->if_module != NULL && mac->if_module->phy_config_request != NULL);
mac->if_module->phy_config_request(&mac->phy_config);
mac->phy_config_request_sent = true;
......@@ -559,7 +562,24 @@ int main(int argc, char **argv)
nr_init_frame_parms_ue(&UE[CC_id]->frame_parms, nrUE_config, mac->nr_band);
}
UE[CC_id]->sl_mode = get_softmodem_params()->sl_mode;
init_nr_ue_vars(UE[CC_id], 0, abstraction_flag);
if (UE[CC_id]->sl_mode) {
AssertFatal(UE[CC_id]->sl_mode == 2, "Only Sidelink mode 2 supported. Mode 1 not yet supported\n");
DevAssert(mac->if_module != NULL && mac->if_module->sl_phy_config_request != NULL);
nr_sl_phy_config_t *phycfg = &mac->SL_MAC_PARAMS->sl_phy_config;
phycfg->sl_config_req.sl_carrier_config.sl_num_rx_ant = get_nrUE_params()->nb_antennas_rx;
phycfg->sl_config_req.sl_carrier_config.sl_num_tx_ant = get_nrUE_params()->nb_antennas_tx;
mac->if_module->sl_phy_config_request(phycfg);
mac->phy_config_request_sent = true;
sl_nr_ue_phy_params_t *sl_phy = &UE[CC_id]->SL_UE_PHY_PARAMS;
nr_init_frame_parms_ue_sl(&sl_phy->sl_frame_params,
&sl_phy->sl_config,
get_softmodem_params()->threequarter_fs,
get_nrUE_params()->ofdm_offset_divisor);
sl_ue_phy_init(UE[CC_id]);
}
}
init_openair0();
......
......@@ -12,6 +12,7 @@
#define CONFIG_HLP_DLSCH_PARA "number of threads for dlsch processing 0 for no parallelization\n"
#define CONFIG_HLP_OFFSET_DIV "Divisor for computing OFDM symbol offset in Rx chain (num samples in CP/<the value>). Default value is 8. To set the sample offset to 0, set this value ~ 10e6\n"
#define CONFIG_HLP_MAX_LDPC_ITERATIONS "Maximum LDPC decoder iterations\n"
/***************************************************************************************************************************************/
/* command line options definitions, CMDLINE_XXXX_DESC macros are used to initialize paramdef_t arrays which are then used as argument
when calling config_get or config_getlist functions */
......
......@@ -29,6 +29,7 @@ typedef enum sl_nr_rx_config_type_enum {
SL_NR_CONFIG_TYPE_RX_PSCCH,
SL_NR_CONFIG_TYPE_RX_PSSCH_SCI,
SL_NR_CONFIG_TYPE_RX_PSSCH_SLSCH,
SL_NR_CONFIG_TYPE_RX_PSFCH,
SL_NR_CONFIG_TYPE_RX_MAXIMUM
} sl_nr_rx_config_type_enum_t;
......
......@@ -296,8 +296,12 @@ int init_nr_ue_signal(PHY_VARS_NR_UE *ue, int nb_connected_gNB)
// init RX buffers
common_vars->rxdata = malloc16(fp->nb_antennas_rx * sizeof(c16_t *));
int num_samples = 2 * fp->samples_per_frame + fp->ofdm_symbol_size;
if (ue->sl_mode == 2)
num_samples = (SL_NR_PSBCH_REPETITION_IN_FRAMES * fp->samples_per_frame) + fp->ofdm_symbol_size;
for (i=0; i<fp->nb_antennas_rx; i++) {
common_vars->rxdata[i] = malloc16_clear((2 * (fp->samples_per_frame) + fp->ofdm_symbol_size) * sizeof(c16_t));
common_vars->rxdata[i] = malloc16_clear(num_samples * sizeof(c16_t));
}
// ceil(((NB_RB<<1)*3)/32) // 3 RE *2(QPSK)
......@@ -655,7 +659,8 @@ void init_N_TA_offset(PHY_VARS_NR_UE *ue){
NR_DL_FRAME_PARMS *fp = &ue->frame_parms;
if (fp->frame_type == FDD) {
// No timing offset for Sidelink, refer to 3GPP 38.211 Section 8.5
if (fp->frame_type == FDD || ue->sl_mode == 2) {
ue->N_TA_offset = 0;
} else {
int N_TA_offset = fp->ul_CarrierFreq < 6e9 ? 400 : 431; // reference samples for 25600Tc @ 30.72 Ms/s for FR1, same @ 61.44 Ms/s for FR2
......@@ -771,6 +776,4 @@ void sl_ue_phy_init(PHY_VARS_NR_UE *UE)
// Generate PSS time domain samples used for correlation during SLSS reception.
sl_generate_pss_ifft_samples(&UE->SL_UE_PHY_PARAMS, &UE->SL_UE_PHY_PARAMS.init_params);
init_symbol_rotation(sl_fp);
init_timeshift_rotation(sl_fp);
}
......@@ -23,6 +23,7 @@
#include "common/utils/nr/nr_common.h"
#include "common/utils/LOG/log.h"
#include "executables/softmodem-common.h"
#include "PHY/MODULATION/nr_modulation.h"
/// Subcarrier spacings in Hz indexed by numerology index
static const uint32_t nr_subcarrier_spacing[MAX_NUM_SUBCARRIER_SPACING] = {15e3, 30e3, 60e3, 120e3, 240e3};
......@@ -86,18 +87,6 @@ static const int nr_ssb_table[54][3] = {
{96, 30, nr_ssb_type_C}};
void set_Lmax(NR_DL_FRAME_PARMS *fp) {
if (get_softmodem_params()->sl_mode == 2) {
int sl_NumSSB_WithinPeriod = 1; //TODO: Needs to be updated from RRC parameters
int sl_TimeOffsetSSB = 1; //TODO: Needs to be updated from RRC parameters
int sl_TimeInterval = 1; //TODO: Needs to be updated from RRC parameters
if ((sl_NumSSB_WithinPeriod == 4) && ((sl_TimeOffsetSSB % fp->slots_per_frame) + 3 * sl_TimeInterval < NR_NUMBER_OF_SUBFRAMES_PER_FRAME * 2))
fp->Lmax = 4;
else if ((sl_NumSSB_WithinPeriod == 2) && ((sl_TimeOffsetSSB % fp->slots_per_frame) + sl_TimeInterval < NR_NUMBER_OF_SUBFRAMES_PER_FRAME))
fp->Lmax = 2;
else
fp->Lmax = 1;
return;
}
// definition of Lmax according to ts 38.213 section 4.1
if (fp->dl_CarrierFreq < 6e9) {
if(fp->frame_type && (fp->ssb_type==2))
......@@ -159,19 +148,21 @@ void set_scs_parameters (NR_DL_FRAME_PARMS *fp, int mu, int N_RB_DL)
fp->subcarrier_spacing = nr_subcarrier_spacing[NR_MU_0];
fp->slots_per_subframe = nr_slots_per_subframe[NR_MU_0];
fp->ssb_type = nr_ssb_type_A;
while(nr_ssb_table[idx][0]!=fp->nr_band)
while (nr_ssb_table[idx][0] != fp->nr_band)
idx++;
AssertFatal(nr_ssb_table[idx][1]==15,"SCS %d not applicable to band %d\n",
AssertFatal(nr_ssb_table[idx][1] == 15,"SCS %d not applicable to band %d\n",
fp->subcarrier_spacing,fp->nr_band);
break;
case NR_MU_1: //30kHz scs
fp->subcarrier_spacing = nr_subcarrier_spacing[NR_MU_1];
fp->slots_per_subframe = nr_slots_per_subframe[NR_MU_1];
while(nr_ssb_table[idx][0]!=fp->nr_band ||
nr_ssb_table[idx][1]!=30) {
AssertFatal(nr_ssb_table[idx][0]<=fp->nr_band,"SCS %d not applicable to band %d\n",
fp->subcarrier_spacing,fp->nr_band);
while(nr_ssb_table[idx][0] != fp->nr_band ||
nr_ssb_table[idx][1] != 30) {
AssertFatal(nr_ssb_table[idx][0] <= fp->nr_band,
"SCS %d not applicable to band %d\n",
fp->subcarrier_spacing,
fp->nr_band);
idx++;
}
fp->ssb_type = nr_ssb_table[idx][2];
......@@ -207,9 +198,6 @@ void set_scs_parameters (NR_DL_FRAME_PARMS *fp, int mu, int N_RB_DL)
fp->ofdm_symbol_size <<= 1;
fp->first_carrier_offset = fp->ofdm_symbol_size - (N_RB_DL * 12 / 2);
// TODO: Temporarily setting fp->first_carrier_offset = 0 for SL until MAC is developed
if (get_softmodem_params()->sl_mode == 2)
fp->first_carrier_offset = 0;
fp->nb_prefix_samples = fp->ofdm_symbol_size / 128 * 9;
fp->nb_prefix_samples0 = fp->ofdm_symbol_size / 128 * (9 + (1 << mu));
LOG_I(PHY,
......@@ -221,6 +209,34 @@ void set_scs_parameters (NR_DL_FRAME_PARMS *fp, int mu, int N_RB_DL)
fp->ofdm_symbol_size);
}
void sl_set_scs_parameters (NR_DL_FRAME_PARMS *fp, int mu, int N_RB_SL)
{
AssertFatal(mu >= NR_MU_0 && mu <= NR_MU_4,"Invalid numerology index %d", mu);
fp->subcarrier_spacing = nr_subcarrier_spacing[mu];
fp->slots_per_subframe = nr_slots_per_subframe[mu];
if(fp->threequarter_fs)
fp->ofdm_symbol_size = 3 * 128;
else
fp->ofdm_symbol_size = 4 * 128;
while(fp->ofdm_symbol_size < N_RB_SL * 12)
fp->ofdm_symbol_size <<= 1;
fp->first_carrier_offset = fp->ofdm_symbol_size - (N_RB_SL * 12 / 2);
fp->nb_prefix_samples = fp->ofdm_symbol_size / 128 * 9;
fp->nb_prefix_samples0 = fp->ofdm_symbol_size / 128 * (9 + (1 << mu));
LOG_I(PHY,
"Init: N_RB_SL %d, first_carrier_offset %d, nb_prefix_samples %d,nb_prefix_samples0 %d, ofdm_symbol_size %d\n",
N_RB_SL,
fp->first_carrier_offset,
fp->nb_prefix_samples,
fp->nb_prefix_samples0,
fp->ofdm_symbol_size);
}
uint32_t get_samples_per_slot(int slot, const NR_DL_FRAME_PARMS *fp)
{
uint32_t samp_count;
......@@ -344,11 +360,6 @@ int nr_init_frame_parms_ue(NR_DL_FRAME_PARMS *fp,
LOG_D(PHY,"dl_bw_kHz %lu\n",dl_bw_khz);
LOG_D(PHY,"dl_CarrierFreq %lu\n",fp->dl_CarrierFreq);
if (get_softmodem_params()->sl_mode == 2) {
uint64_t sl_bw_khz = (12 * config->carrier_config.sl_grid_size[config->ssb_config.scs_common]) * (15 << config->ssb_config.scs_common);
fp->sl_CarrierFreq = ((sl_bw_khz >> 1) + config->carrier_config.sl_frequency) * 1000;
}
uint64_t ul_bw_khz = (12*config->carrier_config.ul_grid_size[config->ssb_config.scs_common])*(15<<config->ssb_config.scs_common);
fp->ul_CarrierFreq = ((ul_bw_khz>>1) + config->carrier_config.uplink_frequency)*1000 ;
......@@ -374,7 +385,7 @@ int nr_init_frame_parms_ue(NR_DL_FRAME_PARMS *fp,
AssertFatal(fp->numerology_index == NR_MU_2,"Invalid cyclic prefix %d for numerology index %d\n", Ncp, fp->numerology_index);
fp->Ncp = Ncp;
int N_RB = (get_softmodem_params()->sl_mode == 2) ? fp->N_RB_SL : fp->N_RB_DL;
int N_RB = fp->N_RB_DL;
set_scs_parameters(fp, fp->numerology_index, N_RB);
fp->slots_per_frame = 10* fp->slots_per_subframe;
......@@ -401,10 +412,6 @@ int nr_init_frame_parms_ue(NR_DL_FRAME_PARMS *fp,
}
fp->ssb_start_subcarrier = (12 * config->ssb_table.ssb_offset_point_a + sco);
// TODO: Temporarily setting fp->ssb_start_subcarrier = 0 for SL until MAC is developed
if (get_softmodem_params()->sl_mode == 2) {
fp->ssb_start_subcarrier = 0;
}
set_Lmax(fp);
fp->L_ssb = (((uint64_t) config->ssb_table.ssb_mask_list[0].ssb_mask)<<32) | config->ssb_table.ssb_mask_list[1].ssb_mask;
......@@ -454,12 +461,6 @@ void nr_init_frame_parms_ue_sa(NR_DL_FRAME_PARMS *frame_parms, uint64_t downlink
}
void nr_init_frame_parms_ue_sl(NR_DL_FRAME_PARMS *frame_parms, uint64_t sidelink_frequency, uint16_t nr_band) {
LOG_D(NR_PHY, "SL init parameters. SL freq %lu\n", sidelink_frequency);
frame_parms->sl_CarrierFreq = sidelink_frequency;
frame_parms->nr_band = nr_band;
}
void nr_dump_frame_parms(NR_DL_FRAME_PARMS *fp)
{
LOG_I(PHY,"fp->scs=%d\n",fp->subcarrier_spacing);
......@@ -476,4 +477,111 @@ void nr_dump_frame_parms(NR_DL_FRAME_PARMS *fp)
LOG_I(PHY, "fp->Nid_cell=%d\n", fp->Nid_cell);
LOG_I(PHY, "fp->first_carrier_offset=%d\n", fp->first_carrier_offset);
LOG_I(PHY, "fp->ssb_start_subcarrier=%d\n", fp->ssb_start_subcarrier);
LOG_I(PHY, "fp->Ncp=%d\n", fp->Ncp);
LOG_I(PHY, "fp->N_RB_DL=%d\n", fp->N_RB_DL);
LOG_I(PHY, "fp->numerology_index=%d\n", fp->numerology_index);
LOG_I(PHY, "fp->nr_band=%d\n", fp->nr_band);
LOG_I(PHY, "fp->ofdm_offset_divisor=%d\n", fp->ofdm_offset_divisor);
LOG_I(PHY, "fp->threequarter_fs=%d\n", fp->threequarter_fs);
LOG_I(PHY, "fp->sl_CarrierFreq=%lu\n", fp->sl_CarrierFreq);
LOG_I(PHY, "fp->N_RB_SL=%d\n", fp->N_RB_SL);
}
int nr_init_frame_parms_ue_sl(NR_DL_FRAME_PARMS *fp,
sl_nr_phy_config_request_t *config,
int threequarter_fs,
uint32_t ofdm_offset_divisor)
{
// Set also these parameters here instead of some where else.
fp->ofdm_offset_divisor = ofdm_offset_divisor;
fp->threequarter_fs = threequarter_fs;
fp->nr_band = get_band(config->sl_carrier_config.sl_frequency, 0);
fp->att_rx = 0;
fp->att_tx = 0;
fp->nb_antennas_rx = config->sl_carrier_config.sl_num_rx_ant;
fp->nb_antennas_tx = config->sl_carrier_config.sl_num_tx_ant;
fp->numerology_index = config->sl_bwp_config.sl_scs;
fp->N_RB_SL = config->sl_carrier_config.sl_grid_size;
fp->N_RB_DL = fp->N_RB_SL;
fp->N_RB_UL = fp->N_RB_SL;
fp->Ncp = config->sl_bwp_config.sl_cyclic_prefix;
fp->frame_type = get_frame_type(fp->nr_band, fp->numerology_index);
int32_t uplink_frequency_offset = get_delta_duplex(fp->nr_band, fp->numerology_index);
uplink_frequency_offset *= 1000;
uint64_t bw_khz = (12 * config->sl_carrier_config.sl_grid_size) * (15 << config->sl_bwp_config.sl_scs);
// REfer to section 3GPP spec 38.101 5.4E.2.1
// FrefV2x = Fref + deltashift + valueN*5Khz
uint32_t deltashift = (config->sl_carrier_config.sl_frequency_shift_7p5khz) ? 7500 : 0; // In Hz
deltashift += config->sl_carrier_config.sl_value_N * 5000; // In Hz
fp->sl_CarrierFreq = ((bw_khz >> 1) + config->sl_carrier_config.sl_frequency);
fp->sl_CarrierFreq += (deltashift >> 1);
fp->dl_CarrierFreq = fp->sl_CarrierFreq;
fp->ul_CarrierFreq = fp->sl_CarrierFreq;
LOG_D(PHY, "bw_kHz %lu, deltashift:%d Hz\n", bw_khz, deltashift);
LOG_D(PHY, "CarrierFreq %lu Hz\n", fp->sl_CarrierFreq);
LOG_I(PHY,
"Initializing frame parms: DL frequency %lu Hz, UL frequency %lu Hz SL frequency %lu Hz: band %d, uldl offset %d Hz\n",
fp->dl_CarrierFreq,
fp->ul_CarrierFreq,
fp->sl_CarrierFreq,
fp->nr_band,
uplink_frequency_offset);
AssertFatal(fp->frame_type == TDD, "Sidelink bands only support TDD");
AssertFatal(fp->ul_CarrierFreq == (fp->dl_CarrierFreq + uplink_frequency_offset),
"Disagreement in uplink frequency for band %d: ul_CarrierFreq = %lu Hz vs expected %lu Hz\n",
fp->nr_band,
fp->ul_CarrierFreq,
fp->dl_CarrierFreq + uplink_frequency_offset);
LOG_I(PHY, "Initializing frame parms for mu %d, N_RB %d, Ncp %d\n", fp->numerology_index, fp->N_RB_DL, fp->Ncp);
if (fp->Ncp == EXTENDED)
AssertFatal(fp->numerology_index == NR_MU_2,
"Invalid cyclic prefix %d for numerology index %d\n",
fp->Ncp,
fp->numerology_index);
sl_set_scs_parameters(fp, fp->numerology_index, fp->N_RB_SL);
fp->slots_per_frame = 10 * fp->slots_per_subframe;
fp->symbols_per_slot = ((fp->Ncp == NORMAL) ? 14 : 12); // to redefine for different slot formats
fp->samples_per_subframe_wCP = fp->ofdm_symbol_size * fp->symbols_per_slot * fp->slots_per_subframe;
fp->samples_per_frame_wCP = 10 * fp->samples_per_subframe_wCP;
fp->samples_per_slot_wCP = fp->symbols_per_slot * fp->ofdm_symbol_size;
fp->samples_per_slotN0 = (fp->nb_prefix_samples + fp->ofdm_symbol_size) * fp->symbols_per_slot;
fp->samples_per_slot0 =
fp->nb_prefix_samples0 + ((fp->symbols_per_slot - 1) * fp->nb_prefix_samples) + (fp->symbols_per_slot * fp->ofdm_symbol_size);
fp->samples_per_subframe = (fp->nb_prefix_samples0 + fp->ofdm_symbol_size) * 2
+ (fp->nb_prefix_samples + fp->ofdm_symbol_size) * (fp->symbols_per_slot * fp->slots_per_subframe - 2);
fp->get_samples_per_slot = &get_samples_per_slot;
fp->get_samples_slot_timestamp = &get_samples_slot_timestamp;
fp->samples_per_frame = 10 * fp->samples_per_subframe;
fp->freq_range = (fp->sl_CarrierFreq < 6e9) ? FR1 : FR2;
// ssb_offset_pointa points to the first RE where Sidelink-PSBCH starts
fp->ssb_start_subcarrier = config->sl_bwp_config.sl_ssb_offset_point_a;
perform_symbol_rotation(fp, fp->sl_CarrierFreq, fp->symbol_rotation[link_type_sl]);
init_timeshift_rotation(fp);
// Not used for Sidelink
fp->Lmax = 0;
fp->L_ssb = 0;
fp->N_ssb = 0;
fp->half_frame_bit = 0;
fp->ssb_index = 0;
fp->ssb_type = 0;
LOG_I(PHY, "Dumping Sidelink Frame Parameters\n");
nr_dump_frame_parms(fp);
return 0;
}
......@@ -29,7 +29,10 @@ int nr_get_ssb_start_symbol(const NR_DL_FRAME_PARMS *fp, uint8_t i_ssb);
void nr_init_frame_parms(nfapi_nr_config_request_scf_t *config, NR_DL_FRAME_PARMS *frame_parms);
int nr_init_frame_parms_ue(NR_DL_FRAME_PARMS *frame_parms, fapi_nr_config_request_t *config, uint16_t nr_band);
void nr_init_frame_parms_ue_sa(NR_DL_FRAME_PARMS *frame_parms, uint64_t downlink_frequency, int32_t uplink_frequency_offset, uint8_t mu, uint16_t nr_band);
void nr_init_frame_parms_ue_sl(NR_DL_FRAME_PARMS *frame_parms, uint64_t sidelink_frequency, uint16_t nr_band);
int nr_init_frame_parms_ue_sl(NR_DL_FRAME_PARMS *fp,
sl_nr_phy_config_request_t *config,
int threequarter_fs,
uint32_t ofdm_offset_divisor);
int init_nr_ue_signal(PHY_VARS_NR_UE *ue,int nb_connected_eNB);
void term_nr_ue_signal(PHY_VARS_NR_UE *ue, int nb_connected_gNB);
void init_nr_ue_transport(PHY_VARS_NR_UE *ue);
......
......@@ -578,61 +578,59 @@ void nr_dft(c16_t *z, c16_t *d, uint32_t Msc_PUSCH)
}
void init_symbol_rotation(NR_DL_FRAME_PARMS *fp) {
uint64_t dl_CarrierFreq = fp->dl_CarrierFreq;
uint64_t ul_CarrierFreq = fp->ul_CarrierFreq;
uint64_t sl_CarrierFreq = fp->sl_CarrierFreq;
double f[2] = {(double)dl_CarrierFreq, (double)ul_CarrierFreq};
void perform_symbol_rotation(NR_DL_FRAME_PARMS *fp, double f0, c16_t *symbol_rotation)
{
const int nsymb = fp->symbols_per_slot * fp->slots_per_frame/10;
const double Tc=(1/480e3/4096);
const double Nu=2048*64*(1/(float)(1<<fp->numerology_index));
const double Ncp0=16*64 + (144*64*(1/(float)(1<<fp->numerology_index)));
const double Ncp1=(144*64*(1/(float)(1<<fp->numerology_index)));
for (uint8_t ll = 0; ll < 2; ll++){
double f0 = f[ll];
LOG_D(PHY, "Doing symbol rotation calculation for gNB TX/RX, f0 %f Hz, Nsymb %d\n", f0, nsymb);
c16_t *symbol_rotation = fp->symbol_rotation[ll];
if (get_softmodem_params()->sl_mode == 2) {
f0 = (double)sl_CarrierFreq;
symbol_rotation = fp->symbol_rotation[link_type_sl];
}
double tl = 0.0;
double poff = 0.0;
double exp_re = 0.0;
double exp_im = 0.0;
LOG_I(PHY, "Doing symbol rotation calculation for TX/RX, f0 %f Hz, Nsymb %d\n", f0, nsymb);
for (int l = 0; l < nsymb; l++) {
double tl = 0.0;
double poff = 0.0;
double exp_re = 0.0;
double exp_im = 0.0;
double Ncp;
if (l == 0 || l == (7 * (1 << fp->numerology_index))) {
Ncp = Ncp0;
} else {
Ncp = Ncp1;
}
for (int l = 0; l < nsymb; l++) {
double Ncp;
if (l == 0 || l == (7 * (1 << fp->numerology_index))) {
Ncp = Ncp0;
} else {
Ncp = Ncp1;
}
poff = 2 * M_PI * (tl + (Ncp * Tc)) * f0;
exp_re = cos(poff);
exp_im = sin(-poff);
symbol_rotation[l].r = (int16_t)floor(exp_re * 32767);
symbol_rotation[l].i = (int16_t)floor(exp_im * 32767);
poff = 2 * M_PI * (tl + (Ncp * Tc)) * f0;
exp_re = cos(poff);
exp_im = sin(-poff);
symbol_rotation[l].r = (int16_t)floor(exp_re * 32767);
symbol_rotation[l].i = (int16_t)floor(exp_im * 32767);
LOG_D(PHY,
"Symbol rotation %d/%d => tl %f (%d,%d) (%f)\n",
l,
nsymb,
tl,
symbol_rotation[l].r,
symbol_rotation[l].i,
(poff / 2 / M_PI) - floor(poff / 2 / M_PI));
tl += (Nu + Ncp) * Tc;
}
}
LOG_D(PHY, "Symbol rotation %d/%d => tl %f (%d,%d) (%f)\n",
l,
nsymb,
tl,
symbol_rotation[l].r,
symbol_rotation[l].i,
(poff / 2 / M_PI) - floor(poff / 2 / M_PI));
void init_symbol_rotation(NR_DL_FRAME_PARMS *fp)
{
double f[2] = {(double)fp->dl_CarrierFreq, (double)fp->ul_CarrierFreq};
tl += (Nu + Ncp) * Tc;
for (int ll = 0; ll < 2; ll++) {
double f0 = f[ll];
if (f0 == 0)
continue;
c16_t *rot = fp->symbol_rotation[ll];
}
perform_symbol_rotation(fp, f0, rot);
}
}
......
......@@ -114,6 +114,8 @@ void apply_nr_rotation_TX(const NR_DL_FRAME_PARMS *fp,
int first_symbol,
int nsymb);
void perform_symbol_rotation(NR_DL_FRAME_PARMS *fp, double f0, c16_t *symbol_rotation);
void init_symbol_rotation(NR_DL_FRAME_PARMS *fp);
void init_timeshift_rotation(NR_DL_FRAME_PARMS *fp);
......
......@@ -94,7 +94,7 @@ int sl_nr_slot_fep(PHY_VARS_NR_UE *ue,
dft(dftsize, rxdata_ptr, (int16_t *)&rxdataF[aa][frame_params->ofdm_symbol_size * symbol], 1);
int symb_offset = (Ns % frame_params->slots_per_subframe) * frame_params->symbols_per_slot;
int32_t rot2 = ((uint32_t *)frame_params->symbol_rotation[1])[symbol + symb_offset];
int32_t rot2 = ((uint32_t *)frame_params->symbol_rotation[2])[symbol + symb_offset];
((int16_t *)&rot2)[1] = -((int16_t *)&rot2)[1];
#ifdef SL_DEBUG_SLOT_FEP
......
......@@ -351,7 +351,7 @@ void nr_sl_psbch_rsrp_measurements(sl_nr_ue_phy_params_t *sl_phy_params,
- ((int)openair0_cfg[0].rx_gain[0] - (int)openair0_cfg[0].rx_gain_offset[0])
- dB_fixed(fp->ofdm_symbol_size);
LOG_I(PHY,
LOG_D(PHY,
"PSBCH RSRP (DMRS REs): numREs:%d RSRP :%d dB/RE ,RSRP:%d dBm/RE\n",
num_re,
psbch_rx->rsrp_dB_per_RE,
......
......@@ -24,6 +24,7 @@
#include "PHY/CODING/nrPolar_tools/nr_polar_defs.h"
#include "common/utils/LOG/log.h"
#include "PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h"
#include "PHY/TOOLS/phy_scope_interface.h"
// #define DEBUG_PSBCH
......@@ -109,7 +110,7 @@ static void nr_psbch_extract(uint32_t rxdataF_sz,
}
int nr_rx_psbch(PHY_VARS_NR_UE *ue,
UE_nr_rxtx_proc_t *proc,
const UE_nr_rxtx_proc_t *proc,
int estimateSz,
struct complex16 dl_ch_estimates[][estimateSz],
NR_DL_FRAME_PARMS *frame_parms,
......@@ -122,6 +123,7 @@ int nr_rx_psbch(PHY_VARS_NR_UE *ue,
// Extra 2 bits needed as polar decoder expects a multiple of 4 as encoder length
// If these 2 bits are not added, runs compiled with --sanitize will fail.
int16_t psbch_e_rx[SL_NR_POLAR_PSBCH_E_NORMAL_CP + 2] = {0};
int16_t psbch_unClipped[SL_NR_POLAR_PSBCH_E_NORMAL_CP + 2] = {0};
#ifdef DEBUG_PSBCH
write_output("psbch_rxdataF.m",
......@@ -174,6 +176,9 @@ int nr_rx_psbch(PHY_VARS_NR_UE *ue,
nr_pbch_quantize(psbch_e_rx + psbch_e_rx_idx, (short *)rxdataF_comp[0], SL_NR_NUM_PSBCH_DATA_BITS_IN_ONE_SYMBOL);
if (ue->scopeData)
memcpy(psbch_unClipped + psbch_e_rx_idx, rxdataF_comp[0], SL_NR_NUM_PSBCH_DATA_BITS_IN_ONE_SYMBOL * sizeof(int16_t));
psbch_e_rx_idx += SL_NR_NUM_PSBCH_DATA_BITS_IN_ONE_SYMBOL;
// SKIP 2 SL-PSS AND 2 SL-SSS symbols
......@@ -181,10 +186,8 @@ int nr_rx_psbch(PHY_VARS_NR_UE *ue,
symbol = (symbol == 0) ? 5 : symbol + 1;
}
#if 0 // ENABLE SCOPE LATER
UEscopeCopy(ue, psbchRxdataF_comp, psbch_unClipped, sizeof(struct complex16), frame_parms->nb_antennas_rx, psbch_e_rx_idx/2);
UEscopeCopy(ue, psbchLlr, psbch_e_rx, sizeof(int16_t), frame_parms->nb_antennas_rx, psbch_e_rx_idx);
#endif
UEscopeCopy(ue, psbchRxdataF_comp, psbch_unClipped, sizeof(c16_t), frame_parms->nb_antennas_rx, psbch_e_rx_idx / 2, 0);
UEscopeCopy(ue, psbchLlr, psbch_e_rx, sizeof(int16_t), frame_parms->nb_antennas_rx, psbch_e_rx_idx, 0);
#ifdef DEBUG_PSBCH
write_output("psbch_rxdataFcomp.m", "psbch_rxFcomp", psbch_unClipped, SL_NR_NUM_PSBCH_DATA_RE_IN_ALL_SYMBOLS, 1, 1);
......
......@@ -257,7 +257,8 @@ uint8_t nr_ue_pusch_common_procedures(PHY_VARS_NR_UE *UE,
const uint8_t slot,
const NR_DL_FRAME_PARMS *frame_parms,
const uint8_t n_antenna_ports,
c16_t **txdataF);
c16_t **txdataF,
uint32_t linktype);
void clean_UE_harq(PHY_VARS_NR_UE *UE);
......@@ -429,7 +430,7 @@ void dump_nrdlsch(PHY_VARS_NR_UE *ue,uint8_t gNB_id,uint8_t nr_slot_rx,unsigned
void nr_a_sum_b(c16_t *input_x, c16_t *input_y, unsigned short nb_rb);
int nr_rx_psbch(PHY_VARS_NR_UE *ue,
UE_nr_rxtx_proc_t *proc,
const UE_nr_rxtx_proc_t *proc,
int estimateSz,
struct complex16 dl_ch_estimates[][estimateSz],
NR_DL_FRAME_PARMS *frame_parms,
......
......@@ -47,15 +47,7 @@ void nr_get_carrier_frequencies(PHY_VARS_NR_UE *ue, uint64_t *dl_carrier, uint64
}
void nr_get_carrier_frequencies_sl(PHY_VARS_NR_UE *ue, uint64_t *sl_carrier) {
NR_DL_FRAME_PARMS *fp = &ue->frame_parms;
if (ue->if_freq!=0) {
*sl_carrier = ue->if_freq;
} else {
*sl_carrier = fp->sl_CarrierFreq;
}
}
void nr_rf_card_config_gain(openair0_config_t *openair0_cfg,
double rx_gain_off){
......
......@@ -571,17 +571,20 @@ uint8_t nr_ue_pusch_common_procedures(PHY_VARS_NR_UE *UE,
const uint8_t slot,
const NR_DL_FRAME_PARMS *frame_parms,
const uint8_t n_antenna_ports,
c16_t **txdataF)
c16_t **txdataF,
uint32_t linktype)
{
const int tx_offset = frame_parms->get_samples_slot_timestamp(slot, frame_parms, 0);
int N_RB = (linktype == link_type_sl) ? frame_parms->N_RB_SL : frame_parms->N_RB_UL;
c16_t **txdata = UE->common_vars.txData;
for(int ap = 0; ap < n_antenna_ports; ap++) {
apply_nr_rotation_TX(frame_parms,
txdataF[ap],
frame_parms->symbol_rotation[1],
frame_parms->symbol_rotation[linktype],
slot,
frame_parms->N_RB_UL,
N_RB,
0,
NR_NUMBER_OF_SYMBOLS_PER_SLOT);
}
......
......@@ -64,10 +64,11 @@ float Limits_KPI_gNB[4][2] = {
@UE: These are the (default) lower and upper threshold values for BLER and Throughput at the UE side.
These threshold values can be further updated in run-time through the option 'Configs' in the drop-down list
*/
float Limits_KPI_ue[2][2] = {
float Limits_KPI_ue[3][2] = {
// {lower Limit, Upper Limit}
{0.0, 0.8}, // DL BLER
{0.2, 10} // Throughput in Mbs
{0.2, 10}, // Throughput in Mbs
{0, 60} // psbch RSRP db/RE
};
// Plot updater
......@@ -192,6 +193,9 @@ KPIListSelectUE::KPIListSelectUE(QWidget *parent) : QComboBox(parent)
this->addItem("Time Adv.", static_cast<int>(PlotTypeUE::timingAdvance));
this->addItem("Configs", static_cast<int>(PlotTypeUE::config));
this->addItem("LLR PSBCH", static_cast<int>(PlotTypeUE::psbchLLR));
this->addItem("I/Q PSBCH", static_cast<int>(PlotTypeUE::psbchIQ));
this->addItem("PSBCH RSRP dB/RE", static_cast<int>(PlotTypeUE::psbchRSRP));
}
WaterFall::WaterFall(complex16 *values, NR_DL_FRAME_PARMS *frame_parms, QWidget *parent)
......@@ -951,6 +955,9 @@ float PainterWidgetUE::getValue()
case PlotTypeUE::timingAdvance:
return (float)this->ue->timing_advance;
case PlotTypeUE::psbchRSRP:
return (float)this->ue->SL_UE_PHY_PARAMS.psbch.rsrp_dB_per_RE;
default:
return 0;
}
......@@ -960,15 +967,22 @@ scopeGraphData_t *PainterWidgetUE::getPlotValue()
{
scopeData_t *scope = (scopeData_t *)this->ue->scopeData;
scopeGraphData_t **data = (scopeGraphData_t **)scope->liveData;
bool is_sl = this->ue->sl_mode;
switch (this->plotType) {
case PlotTypeUE::CIR:
return data[pbchDlChEstimateTime];
return (is_sl ? data[psbchDlChEstimateTime] : data[pbchDlChEstimateTime]);
case PlotTypeUE::pbchLLR:
return data[pbchLlr];
case PlotTypeUE::pbchIQ:
return data[pbchRxdataF_comp];
case PlotTypeUE::psbchLLR:
return data[psbchLlr];
case PlotTypeUE::psbchIQ:
return data[psbchRxdataF_comp];
case PlotTypeUE::pdcchLLR:
return data[pdcchLlr];
......@@ -1039,13 +1053,14 @@ void PainterWidgetUE::makeConnections(int type)
break;
}
case PlotTypeUE::CIR: {
if (!data[pbchDlChEstimateTime]) {
enum scopeDataType typ = (this->ue->sl_mode) ? psbchDlChEstimateTime : pbchDlChEstimateTime;
if (!data[typ]) {
newChart = new QChart();
this->plotType = PlotTypeUE::empty;
this->comboBox->setCurrentIndex(static_cast<int>(PlotTypeUE::empty));
break;
}
newChart = new CIRPlot((complex16 *)(data[pbchDlChEstimateTime] + 1), data[pbchDlChEstimateTime]->lineSz);
newChart = new CIRPlot((complex16 *)(data[typ] + 1), data[typ]->lineSz);
break;
}
......@@ -1069,6 +1084,26 @@ void PainterWidgetUE::makeConnections(int type)
newChart = new IQPlotUE((complex16 *)(data[pbchRxdataF_comp] + 1), data[pbchRxdataF_comp]->lineSz, this);
break;
}
case PlotTypeUE::psbchLLR: {
if (!data[psbchLlr]) {
newChart = new QChart();
this->plotType = PlotTypeUE::empty;
this->comboBox->setCurrentIndex(static_cast<int>(PlotTypeUE::empty));
break;
}
newChart = new LLRPlotUE((int16_t *)(data[psbchLlr] + 1), data[psbchLlr]->lineSz, this);
break;
}
case PlotTypeUE::psbchIQ: {
if (!data[psbchRxdataF_comp]) {
newChart = new QChart();
this->plotType = PlotTypeUE::empty;
this->comboBox->setCurrentIndex(static_cast<int>(PlotTypeUE::empty));
break;
}
newChart = new IQPlotUE((complex16 *)(data[psbchRxdataF_comp] + 1), data[psbchRxdataF_comp]->lineSz, this);
break;
}
case PlotTypeUE::pdcchLLR: {
if (!data[pdcchLlr]) {
newChart = new QChart();
......@@ -1138,7 +1173,10 @@ void PainterWidgetUE::makeConnections(int type)
newChart = new KPIPlot(this);
break;
}
case PlotTypeUE::psbchRSRP: {
newChart = new KPIPlot(this, Limits_KPI_ue[2]);
break;
}
default:
break;
}
......@@ -1223,6 +1261,7 @@ void *nrgNBQtscopeThread(void *arg)
void *nrUEQtscopeThread(void *arg)
{
PHY_VARS_NR_UE *ue = (PHY_VARS_NR_UE *)arg;
bool is_sl = ue->sl_mode;
sleep(1);
......@@ -1256,14 +1295,20 @@ void *nrUEQtscopeThread(void *arg)
mainLayout.addWidget(&pwidgetueCombo2, 1, 1);
KPIListSelectUE combo3;
combo3.setCurrentIndex(static_cast<int>(PlotTypeUE::pbchLLR));
if (is_sl)
combo3.setCurrentIndex(static_cast<int>(PlotTypeUE::psbchLLR));
else
combo3.setCurrentIndex(static_cast<int>(PlotTypeUE::psbchLLR));
PainterWidgetUE pwidgetueCombo3(&config, &combo3, ue);
mainLayout.addWidget(&combo3, 2, 0);
mainLayout.addWidget(&pwidgetueCombo3, 3, 0);
KPIListSelectUE combo4;
combo4.setCurrentIndex(static_cast<int>(PlotTypeUE::pbchIQ));
if (is_sl)
combo4.setCurrentIndex(static_cast<int>(PlotTypeUE::psbchIQ));
else
combo4.setCurrentIndex(static_cast<int>(PlotTypeUE::psbchIQ));
PainterWidgetUE pwidgetueCombo4(&config, &combo4, ue);
mainLayout.addWidget(&combo4, 2, 1);
......
......@@ -81,7 +81,10 @@ enum class PlotTypeUE {
pdschRBs,
frequencyOffset,
timingAdvance,
config
config,
psbchLLR,
psbchIQ,
psbchRSRP,
};
/// This abstract class defines an interface how the KPIPlot class can access values for the different KPI plot types
......
......@@ -786,14 +786,14 @@ static void ueTimeResponse (OAIgraph_t *graph, PHY_VARS_NR_UE *phy_vars_ue, int
*/
static void ueChannelResponse (scopeGraphData_t **data, OAIgraph_t *graph, PHY_VARS_NR_UE *phy_vars_ue, int eNB_id, int UE_id) {
enum scopeDataType typ = (phy_vars_ue->sl_mode) ? psbchDlChEstimateTime : pbchDlChEstimateTime;
// Channel Impulse Response
if (!data[pbchDlChEstimateTime])
if (!data[typ])
return;
const scopeSample_t *tmp=(scopeSample_t *)(data[pbchDlChEstimateTime]+1);
genericPowerPerAntena(graph, data[pbchDlChEstimateTime]->colSz,
&tmp,
data[pbchDlChEstimateTime]->lineSz);
const scopeSample_t *tmp = (scopeSample_t *)(data[typ] + 1);
genericPowerPerAntena(graph, data[typ]->colSz, &tmp, data[typ]->lineSz);
}
static void ueFreqWaterFall (scopeGraphData_t **data, OAIgraph_t *graph,PHY_VARS_NR_UE *phy_vars_ue, int eNB_id, int UE_id ) {
......@@ -847,14 +847,16 @@ static void uePbchFrequencyResp (OAIgraph_t *graph, PHY_VARS_NR_UE *phy_vars_ue
}
*/
static void uePbchLLR (scopeGraphData_t **data, OAIgraph_t *graph, PHY_VARS_NR_UE *phy_vars_ue, int eNB_id, int UE_id) {
enum scopeDataType typ = (phy_vars_ue->sl_mode) ? psbchLlr : pbchLlr;
// PBCH LLRs
if ( !data[pbchLlr])
if (!data[typ])
return;
const int sz=data[pbchLlr]->lineSz;
//const int antennas=data[pbchLlr]->colSz;
const int sz = data[typ]->lineSz;
// const int antennas=data[typ]->colSz;
// We take the first antenna only for now
int16_t *llrs = (int16_t *) (data[pbchLlr]+1);
int16_t *llrs = (int16_t *)(data[typ] + 1);
float *llr_pbch=NULL, *bit_pbch=NULL;
int nx = sz;
#ifdef WEBSRVSCOPE
......@@ -870,12 +872,14 @@ static void uePbchLLR (scopeGraphData_t **data, OAIgraph_t *graph, PHY_VARS_NR_
}
static void uePbchIQ (scopeGraphData_t **data, OAIgraph_t *graph, PHY_VARS_NR_UE *phy_vars_ue, int eNB_id, int UE_id) {
enum scopeDataType typ = (phy_vars_ue->sl_mode) ? psbchRxdataF_comp : pbchRxdataF_comp;
// PBCH I/Q of MF Output
if (!data[pbchRxdataF_comp])
if (!data[typ])
return;
scopeSample_t *pbch_comp = (scopeSample_t *) (data[pbchRxdataF_comp]+1);
const int sz=data[pbchRxdataF_comp]->lineSz;
scopeSample_t *pbch_comp = (scopeSample_t *)(data[typ] + 1);
const int sz = data[typ]->lineSz;
int newsz = sz;
float *I=NULL, *Q=NULL;
#ifdef WEBSRVSCOPE
......
......@@ -67,6 +67,9 @@ enum scopeDataType {
pdschRxdataF_comp,
commonRxdataF,
gNBRxdataF,
psbchDlChEstimateTime,
psbchLlr,
psbchRxdataF_comp,
MAX_SCOPE_TYPES
};
......
......@@ -70,6 +70,7 @@
#define SL_NR_NUM_IDs_IN_PSS 2
#define SL_NR_NUM_IDs_IN_SSS 336
#define SL_NR_NUM_SLSS_IDs 672
#define SL_NR_PSBCH_REPETITION_IN_FRAMES 16
typedef enum sl_nr_sidelink_mode { SL_NOT_SUPPORTED = 0, SL_MODE1_SUPPORTED, SL_MODE2_SUPPORTED } sl_nr_sidelink_mode_t;
......
......@@ -85,6 +85,7 @@ SystemInformationBlockType1_nr_t;
#define NR_DOWNLINK_SLOT (0x01)
#define NR_UPLINK_SLOT (0x02)
#define NR_MIXED_SLOT (0x03)
#define NR_SIDELINK_SLOT NR_UPLINK_SLOT
#define FRAME_DURATION_MICRO_SEC (10000) /* frame duration in microsecond */
......
......@@ -157,21 +157,21 @@ void nr_ue_csi_rs_procedures(PHY_VARS_NR_UE *ue,
const UE_nr_rxtx_proc_t *proc,
c16_t rxdataF[][ue->frame_parms.samples_per_slot_wCP]);
int psbch_pscch_processing(PHY_VARS_NR_UE *ue, UE_nr_rxtx_proc_t *proc, nr_phy_data_t *phy_data);
int phy_procedures_nrUE_SL_TX(PHY_VARS_NR_UE *ue, UE_nr_rxtx_proc_t *proc, nr_phy_data_tx_t *phy_data);
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);
/*! \brief This function prepares the sl indication to pass to the MAC
*/
void nr_fill_sl_indication(nr_sidelink_indication_t *sl_ind,
sl_nr_rx_indication_t *rx_ind,
sl_nr_sci_indication_t *sci_ind,
UE_nr_rxtx_proc_t *proc,
const UE_nr_rxtx_proc_t *proc,
PHY_VARS_NR_UE *ue,
void *phy_data);
void nr_fill_sl_rx_indication(sl_nr_rx_indication_t *rx_ind,
uint8_t pdu_type,
PHY_VARS_NR_UE *ue,
uint16_t n_pdus,
UE_nr_rxtx_proc_t *proc,
const UE_nr_rxtx_proc_t *proc,
void *typeSpecific,
uint16_t rx_slss_id);
......
......@@ -531,7 +531,8 @@ static void nr_ue_scheduled_response_ul(PHY_VARS_NR_UE *phy, fapi_nr_ul_config_r
int8_t nr_ue_scheduled_response(nr_scheduled_response_t *scheduled_response)
{
PHY_VARS_NR_UE *phy = PHY_vars_UE_g[scheduled_response->module_id][scheduled_response->CC_id];
AssertFatal(!scheduled_response->dl_config || !scheduled_response->ul_config,
AssertFatal(!scheduled_response->dl_config || !scheduled_response->ul_config || !scheduled_response->sl_rx_config
|| !scheduled_response->sl_tx_config,
"phy_data parameter will be cast to two different types!\n");
if (scheduled_response->dl_config)
......@@ -541,6 +542,11 @@ int8_t nr_ue_scheduled_response(nr_scheduled_response_t *scheduled_response)
(nr_phy_data_t *)scheduled_response->phy_data);
if (scheduled_response->ul_config)
nr_ue_scheduled_response_ul(phy, scheduled_response->ul_config, (nr_phy_data_tx_t *)scheduled_response->phy_data);
if (scheduled_response->sl_rx_config || scheduled_response->sl_tx_config) {
sl_handle_scheduled_response(scheduled_response);
}
return 0;
}
......@@ -560,3 +566,78 @@ void nr_ue_synch_request(nr_synch_request_t *synch_request)
PHY_vars_UE_g[synch_request->Mod_id][synch_request->CC_id]->synch_request.received_synch_request = 1;
}
void nr_ue_sl_phy_config_request(nr_sl_phy_config_t *phy_config)
{
sl_nr_phy_config_request_t *sl_config = &PHY_vars_UE_g[phy_config->Mod_id][phy_config->CC_id]->SL_UE_PHY_PARAMS.sl_config;
if (phy_config != NULL) {
memcpy(sl_config, &phy_config->sl_config_req, sizeof(sl_nr_phy_config_request_t));
}
}
/*
* MAC sends the scheduled response with either TX configrequest for Sidelink Transmission requests
* or RX config request for Sidelink Reception requests.
* This procedure handles these TX/RX config requests received in this slot and configures PHY
* with a TTI action to be performed in this slot(TTI)
*/
void sl_handle_scheduled_response(nr_scheduled_response_t *scheduled_response)
{
module_id_t module_id = scheduled_response->module_id;
const char *sl_rx_action[] = {"NONE", "RX_PSBCH", "RX_PSCCH", "RX_SCI2_ON_PSSCH", "RX_SLSCH_ON_PSSCH"};
const char *sl_tx_action[] = {"TX_PSBCH", "TX_PSCCH_PSSCH", "TX_PSFCH"};
if (scheduled_response->sl_rx_config != NULL) {
sl_nr_rx_config_request_t *sl_rx_config = scheduled_response->sl_rx_config;
nr_phy_data_t *phy_data = (nr_phy_data_t *)scheduled_response->phy_data;
AssertFatal(sl_rx_config->number_pdus == SL_NR_RX_CONFIG_LIST_NUM, "sl_rx_config->number_pdus incorrect\n");
switch (sl_rx_config->sl_rx_config_list[0].pdu_type) {
case SL_NR_CONFIG_TYPE_RX_PSBCH:
phy_data->sl_rx_action = SL_NR_CONFIG_TYPE_RX_PSBCH;
LOG_D(PHY, "Recvd CONFIG_TYPE_RX_PSBCH\n");
break;
default:
AssertFatal(0, "Incorrect sl_rx config req pdutype \n");
break;
}
LOG_D(PHY,
"[UE%d] TTI %d:%d, SL-RX action:%s\n",
module_id,
sl_rx_config->sfn,
sl_rx_config->slot,
sl_rx_action[phy_data->sl_rx_action]);
} else if (scheduled_response->sl_tx_config != NULL) {
sl_nr_tx_config_request_t *sl_tx_config = scheduled_response->sl_tx_config;
nr_phy_data_tx_t *phy_data_tx = (nr_phy_data_tx_t *)scheduled_response->phy_data;
AssertFatal(sl_tx_config->number_pdus == SL_NR_TX_CONFIG_LIST_NUM, "sl_tx_config->number_pdus incorrect \n");
switch (sl_tx_config->tx_config_list[0].pdu_type) {
case SL_NR_CONFIG_TYPE_TX_PSBCH:
phy_data_tx->sl_tx_action = SL_NR_CONFIG_TYPE_TX_PSBCH;
LOG_D(PHY, "Recvd CONFIG_TYPE_TX_PSBCH\n");
*((uint32_t *)phy_data_tx->psbch_vars.psbch_payload) =
*((uint32_t *)sl_tx_config->tx_config_list[0].tx_psbch_config_pdu.psbch_payload);
phy_data_tx->psbch_vars.psbch_tx_power = sl_tx_config->tx_config_list[0].tx_psbch_config_pdu.psbch_tx_power;
phy_data_tx->psbch_vars.tx_slss_id = sl_tx_config->tx_config_list[0].tx_psbch_config_pdu.tx_slss_id;
break;
default:
AssertFatal(0, "Incorrect sl_tx config req pdutype \n");
break;
}
LOG_D(PHY,
"[UE%d] TTI %d:%d, SL-TX action:%s slss_id:%d, sl-mib:%x, psbch pwr:%d\n",
module_id,
sl_tx_config->sfn,
sl_tx_config->slot,
sl_tx_action[phy_data_tx->sl_tx_action - 6],
phy_data_tx->psbch_vars.tx_slss_id,
*((uint32_t *)phy_data_tx->psbch_vars.psbch_payload),
phy_data_tx->psbch_vars.psbch_tx_power);
}
}
......@@ -40,12 +40,14 @@
/**\brief NR UE FAPI-like P7 messages, scheduled response from L2 indicating L1
\param scheduled_response including transmission config(dl_config, ul_config) and data transmission (tx_req)*/
int8_t nr_ue_scheduled_response(nr_scheduled_response_t *scheduled_response);
void sl_handle_scheduled_response(nr_scheduled_response_t *scheduled_response);
int8_t nr_ue_scheduled_response_stub(nr_scheduled_response_t *scheduled_response);
/**\brief NR UE FAPI-like P5 message, physical configuration from L2 to configure L1
\param scheduled_response including transmission config(dl_config, ul_config) and data transmission (tx_req)*/
int8_t nr_ue_phy_config_request(nr_phy_config_t *phy_config);
void nr_ue_sl_phy_config_request(nr_sl_phy_config_t *phy_config);
/**\brief NR UE FAPI message to schedule a synchronization with target gNB
\param synch_request including target_Nid_cell*/
......
......@@ -76,3 +76,67 @@ int nr_ue_slot_select(fapi_nr_config_request_t *cfg, int nr_slot)
// if here, all the symbols where DL
return NR_DOWNLINK_SLOT;
}
/*
* This function determines if the mixed slot is a Sidelink slot
*/
uint8_t sl_determine_if_sidelink_slot(uint8_t sl_startsym, uint8_t sl_lensym, uint8_t num_ulsym)
{
uint8_t ul_startsym = NR_NUMBER_OF_SYMBOLS_PER_SLOT - num_ulsym;
if ((sl_startsym >= ul_startsym) && (sl_lensym <= NR_NUMBER_OF_SYMBOLS_PER_SLOT)) {
LOG_D(MAC,
"MIXED SLOT is a SIDELINK SLOT. Sidelink Symbols: %d-%d, Uplink Symbols: %d-%d\n",
sl_startsym,
sl_lensym - 1,
ul_startsym,
ul_startsym + num_ulsym - 1);
return NR_SIDELINK_SLOT;
} else {
LOG_D(MAC,
"MIXED SLOT is NOT SIDELINK SLOT. Sidelink Symbols: %d-%d, Uplink Symbols: %d-%d\n",
sl_startsym,
sl_lensym - 1,
ul_startsym,
ul_startsym + num_ulsym - 1);
return 0;
}
}
/*
* This function determines if the Slot is a SIDELINK SLOT
* Every Uplink Slot is a Sidelink slot
* Mixed Slot is a sidelink slot if the uplink symbols in Mixed slot
* overlaps with Sidelink start symbol and number of symbols.
*/
int sl_nr_ue_slot_select(sl_nr_phy_config_request_t *cfg, int slot, uint8_t frame_duplex_type)
{
int ul_sym = 0, slot_type = 0;
// All PC5 bands are TDD bands , hence handling only TDD in this function.
AssertFatal(frame_duplex_type == TDD, "No Sidelink operation defined for FDD in 3GPP rel16\n");
if (cfg->tdd_table.max_tdd_periodicity_list == NULL) { // this happens before receiving TDD configuration
return slot_type;
}
int period = cfg->tdd_table.tdd_period_in_slots;
int rel_slot = slot % period;
fapi_nr_tdd_table_t *tdd_table = &cfg->tdd_table;
fapi_nr_max_tdd_periodicity_t *current_slot = &tdd_table->max_tdd_periodicity_list[rel_slot];
for (int symbol_count = 0; symbol_count < NR_NUMBER_OF_SYMBOLS_PER_SLOT; symbol_count++) {
if (current_slot->max_num_of_symbol_per_slot_list[symbol_count].slot_config == 1) {
ul_sym++;
}
}
if (ul_sym == NR_NUMBER_OF_SYMBOLS_PER_SLOT) {
slot_type = NR_SIDELINK_SLOT;
} else if (ul_sym) {
slot_type = sl_determine_if_sidelink_slot(cfg->sl_bwp_config.sl_start_symbol, cfg->sl_bwp_config.sl_num_symbols, ul_sym);
}
return slot_type;
}
\ No newline at end of file
......@@ -288,7 +288,12 @@ void phy_procedures_nrUE_TX(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, n
pucch_procedures_ue_nr(ue, proc, phy_data, (c16_t **)&txdataF);
LOG_D(PHY, "Sending Uplink data \n");
nr_ue_pusch_common_procedures(ue, proc->nr_slot_tx, &ue->frame_parms, ue->frame_parms.nb_antennas_tx, (c16_t **)txdataF);
nr_ue_pusch_common_procedures(ue,
proc->nr_slot_tx,
&ue->frame_parms,
ue->frame_parms.nb_antennas_tx,
(c16_t **)txdataF,
link_type_ul);
nr_ue_prach_procedures(ue, proc);
......
......@@ -35,7 +35,7 @@
void nr_fill_sl_indication(nr_sidelink_indication_t *sl_ind,
sl_nr_rx_indication_t *rx_ind,
sl_nr_sci_indication_t *sci_ind,
UE_nr_rxtx_proc_t *proc,
const UE_nr_rxtx_proc_t *proc,
PHY_VARS_NR_UE *ue,
void *phy_data)
{
......@@ -49,6 +49,7 @@ void nr_fill_sl_indication(nr_sidelink_indication_t *sl_ind,
sl_ind->frame_tx = proc->frame_tx;
sl_ind->slot_tx = proc->nr_slot_tx;
sl_ind->phy_data = phy_data;
sl_ind->slot_type = SIDELINK_SLOT_TYPE_RX;
if (rx_ind) {
sl_ind->rx_ind = rx_ind; // hang on rx_ind instance
......@@ -64,12 +65,12 @@ void nr_fill_sl_rx_indication(sl_nr_rx_indication_t *rx_ind,
uint8_t pdu_type,
PHY_VARS_NR_UE *ue,
uint16_t n_pdus,
UE_nr_rxtx_proc_t *proc,
const UE_nr_rxtx_proc_t *proc,
void *typeSpecific,
uint16_t rx_slss_id)
{
if (n_pdus > 1) {
LOG_E(PHY, "In %s: multiple number of SL PDUs not supported yet...\n", __FUNCTION__);
LOG_E(NR_PHY, "In %s: multiple number of SL PDUs not supported yet...\n", __FUNCTION__);
}
sl_nr_ue_phy_params_t *sl_phy_params = &ue->SL_UE_PHY_PARAMS;
......@@ -85,7 +86,7 @@ void nr_fill_sl_rx_indication(sl_nr_rx_indication_t *rx_ind,
ssb_pdu->rsrp_dbm = sl_phy_params->psbch.rsrp_dBm_per_RE;
ssb_pdu->rx_slss_id = rx_slss_id;
ssb_pdu->decode_status = true;
LOG_D(PHY,
LOG_D(NR_PHY,
"SL-IND: SSB to MAC. rsrp:%d, slssid:%d, payload:%x\n",
ssb_pdu->rsrp_dbm,
ssb_pdu->rx_slss_id,
......@@ -103,7 +104,7 @@ void nr_fill_sl_rx_indication(sl_nr_rx_indication_t *rx_ind,
static int nr_ue_psbch_procedures(PHY_VARS_NR_UE *ue,
NR_DL_FRAME_PARMS *fp,
UE_nr_rxtx_proc_t *proc,
const UE_nr_rxtx_proc_t *proc,
int estimateSz,
struct complex16 dl_ch_estimates[][estimateSz],
nr_phy_data_t *phy_data,
......@@ -120,7 +121,7 @@ static int nr_ue_psbch_procedures(PHY_VARS_NR_UE *ue,
// VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_PSBCH_PROCEDURES, VCD_FUNCTION_IN);
LOG_D(PHY,
LOG_D(NR_PHY,
"[UE %d] Frame %d Slot %d, Trying PSBCH (SLSS ID %d)\n",
ue->Mod_id,
frame_rx,
......@@ -144,11 +145,11 @@ static int nr_ue_psbch_procedures(PHY_VARS_NR_UE *ue,
uint8_t *result = NULL;
if (ret) {
sl_phy_params->psbch.rx_errors++;
LOG_E(PHY, "%d:%d PSBCH RX: NOK \n", proc->frame_rx, proc->nr_slot_rx);
LOG_E(NR_PHY, "%d:%d PSBCH RX: NOK \n", proc->frame_rx, proc->nr_slot_rx);
} else {
result = decoded_pdu;
sl_phy_params->psbch.rx_ok++;
LOG_D(PHY, "%d:%d PSBCH RX: OK \n", proc->frame_rx, proc->nr_slot_rx);
LOG_I(NR_PHY, "%d:%d PSBCH RX:OK. RSRP: %d dB/RE\n", proc->frame_rx, proc->nr_slot_rx, sl_phy_params->psbch.rsrp_dB_per_RE);
}
nr_fill_sl_indication(&sl_indication, &rx_ind, NULL, proc, ue, phy_data);
......@@ -161,7 +162,7 @@ static int nr_ue_psbch_procedures(PHY_VARS_NR_UE *ue,
return ret;
}
int psbch_pscch_processing(PHY_VARS_NR_UE *ue, UE_nr_rxtx_proc_t *proc, nr_phy_data_t *phy_data)
int psbch_pscch_processing(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, nr_phy_data_t *phy_data)
{
int frame_rx = proc->frame_rx;
int nr_slot_rx = proc->nr_slot_rx;
......@@ -172,7 +173,7 @@ int psbch_pscch_processing(PHY_VARS_NR_UE *ue, UE_nr_rxtx_proc_t *proc, nr_phy_d
// VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_UE_RX_SL, VCD_FUNCTION_IN);
start_meas(&sl_phy_params->phy_proc_sl_rx);
LOG_D(PHY, " ****** Sidelink RX-Chain for Frame.Slot %d.%d ****** \n", frame_rx % 1024, nr_slot_rx);
LOG_D(NR_PHY, " ****** Sidelink RX-Chain for Frame.Slot %d.%d ****** \n", frame_rx % 1024, nr_slot_rx);
const uint32_t rxdataF_sz = fp->samples_per_slot_wCP;
__attribute__((aligned(32))) c16_t rxdataF[fp->nb_antennas_rx][rxdataF_sz];
......@@ -181,7 +182,7 @@ int psbch_pscch_processing(PHY_VARS_NR_UE *ue, UE_nr_rxtx_proc_t *proc, nr_phy_d
const int estimateSz = fp->symbols_per_slot * fp->ofdm_symbol_size;
// VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_SLOT_FEP_PSBCH, VCD_FUNCTION_IN);
LOG_D(PHY, " ----- PSBCH RX TTI: frame.slot %d.%d ------ \n", frame_rx % 1024, nr_slot_rx);
LOG_D(NR_PHY, " ----- PSBCH RX TTI: frame.slot %d.%d ------ \n", frame_rx % 1024, nr_slot_rx);
__attribute__((aligned(32))) struct complex16 dl_ch_estimates[fp->nb_antennas_rx][estimateSz];
__attribute__((aligned(32))) struct complex16 dl_ch_estimates_time[fp->nb_antennas_rx][fp->ofdm_symbol_size];
......@@ -190,7 +191,7 @@ int psbch_pscch_processing(PHY_VARS_NR_UE *ue, UE_nr_rxtx_proc_t *proc, nr_phy_d
const int numsym = (fp->Ncp) ? SL_NR_NUM_SYMBOLS_SSB_EXT_CP : SL_NR_NUM_SYMBOLS_SSB_NORMAL_CP;
for (int sym = 0; sym < numsym;) {
nr_slot_fep(ue, fp, proc, sym, rxdataF, link_type_ul);
nr_slot_fep(ue, fp, proc, sym, rxdataF, link_type_sl);
start_meas(&sl_phy_params->channel_estimation_stats);
nr_pbch_channel_estimation(fp,
......@@ -211,7 +212,7 @@ int psbch_pscch_processing(PHY_VARS_NR_UE *ue, UE_nr_rxtx_proc_t *proc, nr_phy_d
stop_meas(&sl_phy_params->channel_estimation_stats);
if (sym == 12)
UEscopeCopy(ue,
pbchDlChEstimateTime,
psbchDlChEstimateTime,
(void *)dl_ch_estimates_time,
sizeof(c16_t),
fp->nb_antennas_rx,
......@@ -224,17 +225,17 @@ int psbch_pscch_processing(PHY_VARS_NR_UE *ue, UE_nr_rxtx_proc_t *proc, nr_phy_d
nr_sl_psbch_rsrp_measurements(sl_phy_params, fp, rxdataF, false);
LOG_D(PHY, " ------ Decode SL-MIB: frame.slot %d.%d ------ \n", frame_rx % 1024, nr_slot_rx);
LOG_D(NR_PHY, " ------ Decode SL-MIB: frame.slot %d.%d ------ \n", frame_rx % 1024, nr_slot_rx);
const int psbchSuccess = nr_ue_psbch_procedures(ue, fp, proc, estimateSz, dl_ch_estimates, phy_data, rxdataF);
if (ue->no_timing_correction == 0 && psbchSuccess == 0) {
LOG_D(PHY, "start adjust sync slot = %d no timing %d\n", nr_slot_rx, ue->no_timing_correction);
LOG_D(NR_PHY, "start adjust sync slot = %d no timing %d\n", nr_slot_rx, ue->no_timing_correction);
sampleShift =
nr_adjust_synch_ue(fp, ue, proc->gNB_id, fp->ofdm_symbol_size, dl_ch_estimates_time, frame_rx, nr_slot_rx, 16384);
}
LOG_D(PHY, "Doing N0 measurements in %s\n", __FUNCTION__);
LOG_D(NR_PHY, "Doing N0 measurements in %s\n", __FUNCTION__);
// nr_ue_rrc_measurements(ue, proc, rxdataF);
// VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_SLOT_FEP_PSBCH, VCD_FUNCTION_OUT);
......@@ -254,10 +255,12 @@ int psbch_pscch_processing(PHY_VARS_NR_UE *ue, UE_nr_rxtx_proc_t *proc, nr_phy_d
}
}
UEscopeCopy(ue, commonRxdataF, rxdataF, sizeof(int32_t), fp->nb_antennas_rx, rxdataF_sz, 0);
return sampleShift;
}
int phy_procedures_nrUE_SL_TX(PHY_VARS_NR_UE *ue, UE_nr_rxtx_proc_t *proc, nr_phy_data_tx_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)
{
int slot_tx = proc->nr_slot_tx;
int frame_tx = proc->frame_tx;
......@@ -275,7 +278,7 @@ int phy_procedures_nrUE_SL_TX(PHY_VARS_NR_UE *ue, UE_nr_rxtx_proc_t *proc, nr_ph
for (int i = 0; i < fp->nb_antennas_tx; ++i)
txdataF[i] = &txdataF_buf[i * samplesF_per_slot];
LOG_D(PHY, "****** start Sidelink TX-Chain for AbsSubframe %d.%d ******\n", frame_tx, slot_tx);
LOG_D(NR_PHY, "****** start Sidelink TX-Chain for AbsSubframe %d.%d ******\n", frame_tx, slot_tx);
start_meas(&sl_phy_params->phy_proc_sl_tx);
......@@ -302,14 +305,13 @@ int phy_procedures_nrUE_SL_TX(PHY_VARS_NR_UE *ue, UE_nr_rxtx_proc_t *proc, nr_ph
}
if (tx_action) {
LOG_D(PHY, "Sending Uplink data \n");
nr_ue_pusch_common_procedures(ue, proc->nr_slot_tx, fp, fp->nb_antennas_tx, txdataF);
LOG_D(NR_PHY, "Sending Uplink data \n");
nr_ue_pusch_common_procedures(ue, proc->nr_slot_tx, fp, fp->nb_antennas_tx, txdataF, link_type_sl);
}
LOG_D(PHY, "****** end Sidelink TX-Chain for AbsSubframe %d.%d ******\n", frame_tx, slot_tx);
LOG_D(NR_PHY, "****** end Sidelink TX-Chain for AbsSubframe %d.%d ******\n", frame_tx, slot_tx);
// VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_UE_TX_SL, VCD_FUNCTION_OUT);
stop_meas(&sl_phy_params->phy_proc_sl_tx);
return tx_action;
}
......@@ -57,3 +57,15 @@ void *rrc_nrue(void *notUsed)
{
return NULL;
}
int8_t nr_mac_rrc_sl_mib_ind(const module_id_t module_id,
const int CC_id,
const uint8_t gNB_index,
const frame_t frame,
const int slot,
const int channel,
const uint8_t *pduP,
const sdu_size_t pdu_len,
const uint16_t rx_slss_id)
{
return 1;
}
......@@ -89,6 +89,12 @@ uint8_t check_if_ue_is_sl_syncsource()
{
return 0;
}
void nr_rrc_mac_config_req_sl_mib(module_id_t module_id,
NR_SL_SSB_TimeAllocation_r16_t *ssb_ta,
uint16_t rx_slss_id,
uint8_t *sl_mib)
{
}
//////////////////////////////////////////////////////////////////////////
static void prepare_mib_bits(uint8_t *buf, uint32_t frame_tx, uint32_t slot_tx)
{
......@@ -178,7 +184,8 @@ static void sl_init_frame_parameters(PHY_VARS_NR_UE *UE)
sl_fp->att_tx = 1;
sl_fp->att_rx = 1;
// band47 //UL freq will be set to Sidelink freq
sl_fp->ul_CarrierFreq = 5880000000;
sl_fp->sl_CarrierFreq = 5880000000;
sl_fp->N_RB_SL = sl_fp->N_RB_DL;
sl_fp->ssb_start_subcarrier = UE->SL_UE_PHY_PARAMS.sl_config.sl_bwp_config.sl_ssb_offset_point_a;
sl_fp->Nid_cell = UE->SL_UE_PHY_PARAMS.sl_config.sl_sync_source.rx_slss_id;
......@@ -202,7 +209,7 @@ static void configure_SL_UE(PHY_VARS_NR_UE *UE, int mu, int N_RB, int ssb_offset
sl_init_frame_parameters(UE);
sl_ue_phy_init(UE);
init_symbol_rotation(fp);
perform_symbol_rotation(fp, fp->sl_CarrierFreq, fp->symbol_rotation[link_type_sl]);
init_timeshift_rotation(fp);
LOG_I(PHY, "Dumping Sidelink Frame Parameters\n");
nr_dump_frame_parms(fp);
......
......@@ -23,11 +23,9 @@
#include "NR_SidelinkPreconfigNR-r16.h"
#include "mac_proto.h"
void sl_ue_mac_free(uint8_t module_id)
void sl_ue_mac_free(NR_UE_MAC_INST_t *mac)
{
NR_UE_MAC_INST_t *mac = get_mac_inst(module_id);
sl_nr_phy_config_request_t *sl_config =
&mac->SL_MAC_PARAMS->sl_phy_config.sl_config_req;
......@@ -372,6 +370,9 @@ int nr_rrc_mac_config_req_sl_preconfig(module_id_t module_id,
AssertFatal((tdd_uldl_config->pattern2 == NULL), "Sidelink MAC CFG: pattern2 not yet supported");
sl_mac->sl_TDD_config = sl_preconfig->sl_PreconfigGeneral_r16->sl_TDD_Configuration_r16;
// Sync source is identified, timing needs to be adjusted.
sl_mac->timing_acquired = true;
}
//Do not copy TDD config yet as SYNC source is not yet found
......@@ -474,12 +475,13 @@ void nr_rrc_mac_config_req_sl_mib(module_id_t module_id,
sl_nr_phy_config_request_t *sl_config = &sl_mac->sl_phy_config.sl_config_req;
//Update configs if Sync source is not set else nothing to be done
if ( sl_config->sl_sync_source.sync_source == SL_SYNC_SOURCE_NONE) {
if (sl_config->sl_sync_source.sync_source == SL_SYNC_SOURCE_NONE) {
//Set SYNC source as SYNC REF UE and send the remaining config to PHY
sl_config->config_mask = 0xF;//all configs done.
sl_config->sl_sync_source.sync_source = SL_SYNC_SOURCE_SYNC_REF_UE;
sl_config->sl_sync_source.rx_slss_id = rx_slss_id;
sl_mac->timing_acquired = true;
sl_mac->rx_sl_bch.status = 1;
sl_mac->rx_sl_bch.slss_id = rx_slss_id;
......@@ -524,7 +526,8 @@ void nr_rrc_mac_config_req_sl_mib(module_id_t module_id,
sl_mac->sl_TDD_config->pattern1.nrofDownlinkSlots, sl_mac->sl_TDD_config->pattern1.nrofUplinkSlots,
sl_mac->sl_TDD_config->pattern1.nrofDownlinkSymbols,sl_mac->sl_TDD_config->pattern1.nrofUplinkSymbols);
DevAssert(mac->if_module != NULL && mac->if_module->sl_phy_config_request != NULL);
mac->if_module->sl_phy_config_request(&sl_mac->sl_phy_config);
}
}
......@@ -32,6 +32,10 @@
#define SL_NR_MAC_NUM_TX_RESOURCE_POOLS 1
#define SL_NUM_BYTES_TIMERESOURCEBITMAP 20
// every 16 frames, SSB is repeated.
#define SL_NR_SSB_REPETITION_IN_FRAMES 16
#define SL_FRAME_NUMBER_CYCLE 1024
// Size of Fixed fields prio (3), sci_2ndstage(2),
// betaoffsetindicator(2), num dmrs ports (1), mcs (5bits)
#define SL_SCI_FORMAT_1A_LEN_IN_BITS_FIXED_FIELDS 13
......@@ -127,6 +131,13 @@ typedef struct sl_bch_params {
} sl_bch_params_t;
typedef struct sl_stored_tti_req {
uint32_t sl_action;
int frame;
int slot;
} sl_stored_tti_req_t;
typedef struct sl_nr_ue_mac_params {
//Holds the RX resource pool from RRC and its related parameters
......@@ -151,6 +162,27 @@ typedef struct sl_nr_ue_mac_params {
//Holds Broadcast params incase UE receives SL-SSB
sl_bch_params_t rx_sl_bch;
// SSB RSRP in dBm
int16_t ssb_rsrp_dBm;
// Bitmap indicating which slots belong to sidelink
// Right now supports 30Khz and 15Khz
uint32_t sl_slot_bitmap;
// adjust timing after new timing from sync is acquired.
bool timing_acquired;
// Sidelink slots per frame
uint16_t N_SL_SLOTS_perframe;
uint16_t decoded_DFN;
uint16_t decoded_slot;
uint32_t N_SL_SLOTS;
uint16_t N_SSB_16frames;
sl_stored_tti_req_t *future_ttis;
} sl_nr_ue_mac_params_t;
......
......@@ -391,6 +391,7 @@ void nr_rrc_mac_config_req_sl_mib(module_id_t module_id,
NR_SL_SSB_TimeAllocation_r16_t *ssb_ta,
uint16_t rx_slss_id,
uint8_t *sl_mib);
void sl_prepare_psbch_payload(NR_TDD_UL_DL_ConfigCommon_t *TDD_UL_DL_Config,
uint8_t *bits_0_to_7, uint8_t *bits_8_to_11,
uint8_t mu, uint8_t L, uint8_t Y);
......@@ -402,4 +403,24 @@ uint8_t sl_decode_sl_TDD_Config(NR_TDD_UL_DL_ConfigCommon_t *TDD_UL_DL_Config,
uint8_t sl_determine_sci_1a_len(uint16_t *num_subchannels,
NR_SL_ResourcePool_r16_t *rpool,
sidelink_sci_format_1a_fields_t *sci_1a);
/** \brief This function checks nr UE slot for Sidelink direction : Sidelink
* @param cfg : Sidelink config request
* @param nr_frame : frame number
* @param nr_slot : slot number
* @param frame duplex type : Frame type
@returns int : 0 or Sidelink slot type */
int sl_nr_ue_slot_select(sl_nr_phy_config_request_t *cfg, int nr_slot, uint8_t frame_duplex_type);
void nr_ue_sidelink_scheduler(nr_sidelink_indication_t *sl_ind, NR_UE_MAC_INST_t *mac);
void nr_mac_rrc_sl_mib_ind(const module_id_t module_id,
const int CC_id,
const uint8_t gNB_index,
const frame_t frame,
const int slot,
const channel_t channel,
uint8_t *pduP,
const sdu_size_t pdu_len,
const uint16_t rx_slss_id);
#endif
......@@ -19,7 +19,8 @@
* contact@openairinterface.org
*/
#include "mac_defs_sl.h"
#include "mac_defs.h"
#include "mac_proto.h"
#define SL_DEBUG
......@@ -348,35 +349,37 @@ uint32_t sl_prepare_MIB(NR_TDD_UL_DL_ConfigCommon_t *TDD_UL_DL_Config,
return sl_mib;
}
uint16_t sl_get_subchannel_size(NR_SL_ResourcePool_r16_t *rpool)
uint16_t sl_get_num_subch(NR_SL_ResourcePool_r16_t *rpool)
{
uint16_t subch_size = 0;
const uint8_t subchsizes[8] = {10, 12, 15, 20, 25, 50, 75, 100};
subch_size = (rpool->sl_SubchannelSize_r16)
? subchsizes[*rpool->sl_SubchannelSize_r16] : 0;
//sl-NumSubchannel - Indicates the number of subchannels in the corresponding resource pool
//which consists of contiguous PRBs only.
uint16_t num_subch = (rpool->sl_NumSubchannel_r16) ? *rpool->sl_NumSubchannel_r16 : 0;
AssertFatal(subch_size,"Subch Size cannot be 0.Resource Pool Configuration Error\n");
AssertFatal(num_subch,"NUM Subchannels cannot be 0. Resource Pool Configuration Error\n");
return subch_size;
return num_subch;
}
uint16_t sl_get_num_subch(NR_SL_ResourcePool_r16_t *rpool)
uint16_t sl_get_subchannel_size(NR_SL_ResourcePool_r16_t *rpool)
{
uint16_t num_subch = 0;
uint16_t subch_size = sl_get_subchannel_size(rpool);
uint16_t num_subch = sl_get_num_subch(rpool);
//sl-RB-Number - Indicates the number of PRBs in the corresponding resource pool.
//which consists of contiguous PRBs only.The remaining RB cannot be used
uint16_t num_rbs = (rpool->sl_RB_Number_r16) ? *rpool->sl_RB_Number_r16 : 0;
AssertFatal(num_rbs,"NumRbs in rpool cannot be 0.Resource Pool Configuration Error\n");
num_subch = num_rbs/subch_size;
uint16_t subch_size = 0;
subch_size = num_rbs/num_subch;
LOG_I(NR_MAC, "Subch_size:%d, numRBS:%d, num_subch:%d\n",
subch_size,num_rbs,num_subch);
return (num_subch);
return (subch_size);
}
//This function determines SCI 1A Len in bits based on the configuration in the resource pool.
......@@ -474,10 +477,11 @@ uint8_t sl_determine_sci_1a_len(uint16_t *num_subchannels,
AssertFatal(*rpool->sl_Additional_MCS_Table_r16<=2, "additional table value cannot be > 2. Resource Pool Configuration Error.\n");
}
LOG_D(NR_MAC,"sci 1A - additional_table:%ld, sci 1a len:%d, additional table nbits:%d\n",
*rpool->sl_Additional_MCS_Table_r16,
sci_1a_len,
sci_1a->additional_mcs_table_indicator.nbits);
LOG_D(NR_MAC,
"sci 1A - additional_table:%ld, sci 1a len:%d, additional table nbits:%d\n",
rpool->sl_Additional_MCS_Table_r16 ? *rpool->sl_Additional_MCS_Table_r16 : 0,
sci_1a_len,
sci_1a->additional_mcs_table_indicator.nbits);
uint8_t psfch_period = 0;
if (rpool->sl_PSFCH_Config_r16 &&
......
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
#include "mac_defs.h"
#include "mac_proto.h"
static uint16_t sl_adjust_ssb_indices(sl_ssb_timealloc_t *ssb_timealloc, uint32_t slot_in_16frames, uint16_t *ssb_slot_ptr)
{
uint16_t ssb_slot = ssb_timealloc->sl_TimeOffsetSSB;
uint16_t numssb = 0;
*ssb_slot_ptr = 0;
if (ssb_timealloc->sl_NumSSB_WithinPeriod == 0) {
*ssb_slot_ptr = 0;
return 0;
}
while (slot_in_16frames > ssb_slot) {
numssb = numssb + 1;
if (numssb < ssb_timealloc->sl_NumSSB_WithinPeriod)
ssb_slot = ssb_slot + ssb_timealloc->sl_TimeInterval;
else
break;
}
*ssb_slot_ptr = ssb_slot;
return numssb;
}
static uint8_t sl_get_elapsed_slots(uint32_t slot, uint32_t sl_slot_bitmap)
{
uint8_t elapsed_slots = 0;
for (int i = 0; i < slot; i++) {
if (sl_slot_bitmap & (1 << i))
elapsed_slots++;
}
return elapsed_slots;
}
static void sl_determine_slot_bitmap(sl_nr_ue_mac_params_t *sl_mac, int ue_id)
{
sl_nr_phy_config_request_t *sl_cfg = &sl_mac->sl_phy_config.sl_config_req;
uint8_t sl_scs = sl_cfg->sl_bwp_config.sl_scs;
uint8_t num_slots_per_frame = 10 * (1 << sl_scs);
uint8_t slot_type = 0;
for (int i = 0; i < num_slots_per_frame; i++) {
slot_type = sl_nr_ue_slot_select(sl_cfg, i, TDD);
if (slot_type == NR_SIDELINK_SLOT) {
sl_mac->N_SL_SLOTS_perframe += 1;
sl_mac->sl_slot_bitmap |= (1 << i);
}
}
sl_mac->future_ttis = calloc(num_slots_per_frame, sizeof(sl_stored_tti_req_t));
LOG_I(NR_MAC,
"[UE%d] SL-MAC: N_SL_SLOTS_perframe:%d, SL SLOT bitmap:%x\n",
ue_id,
sl_mac->N_SL_SLOTS_perframe,
sl_mac->sl_slot_bitmap);
}
/* This function determines the number of sidelink slots in 1024 frames - DFN cycle
* which can be used for determining reserved slots and REsource pool slots according to bitmap.
* Sidelink slots are the uplink and mixed slots with sidelink support except the SSB slots.
*/
static uint32_t sl_determine_num_sidelink_slots(sl_nr_ue_mac_params_t *sl_mac, int ue_id, uint16_t *N_SSB_16frames)
{
uint32_t N_SSB_1024frames = 0;
uint32_t N_SL_SLOTS = 0;
*N_SSB_16frames = 0;
if (sl_mac->rx_sl_bch.status) {
sl_ssb_timealloc_t *ssb_timealloc = &sl_mac->rx_sl_bch.ssb_time_alloc;
*N_SSB_16frames += ssb_timealloc->sl_NumSSB_WithinPeriod;
LOG_D(NR_MAC, "RX SSB Slots:%d\n", *N_SSB_16frames);
}
if (sl_mac->tx_sl_bch.status) {
sl_ssb_timealloc_t *ssb_timealloc = &sl_mac->tx_sl_bch.ssb_time_alloc;
*N_SSB_16frames += ssb_timealloc->sl_NumSSB_WithinPeriod;
LOG_D(NR_MAC, "TX SSB Slots:%d\n", *N_SSB_16frames);
}
// Total SSB slots in SFN cycle (1024 frames)
N_SSB_1024frames = SL_FRAME_NUMBER_CYCLE / SL_NR_SSB_REPETITION_IN_FRAMES * (*N_SSB_16frames);
// Determine total number of Valid Sidelink slots which can be used for Respool in a SFN cycle (1024 frames)
N_SL_SLOTS = (sl_mac->N_SL_SLOTS_perframe * SL_FRAME_NUMBER_CYCLE) - N_SSB_1024frames;
LOG_I(NR_MAC,
"[UE%d]SL-MAC:SSB slots in 1024 frames:%d, N_SL_SLOTS_perframe:%d, N_SL_SLOTs in 1024 frames:%d, SL SLOT bitmap:%x\n",
ue_id,
N_SSB_1024frames,
sl_mac->N_SL_SLOTS_perframe,
N_SL_SLOTS,
sl_mac->sl_slot_bitmap);
return N_SL_SLOTS;
}
/**
* DETERMINE IF SLOT IS MARKED AS SSB SLOT
* ACCORDING TO THE SSB TIME ALLOCATION PARAMETERS.
* sl_numSSB_withinPeriod - NUM SSBS in 16frames
* sl_timeoffset_SSB - time offset for first SSB at start of 16 frames cycle
* sl_timeinterval - distance in slots between 2 SSBs
*/
uint8_t sl_determine_if_SSB_slot(uint16_t frame, uint16_t slot, uint16_t slots_per_frame, sl_bch_params_t *sl_bch)
{
uint16_t frame_16 = frame % SL_NR_SSB_REPETITION_IN_FRAMES;
uint32_t slot_in_16frames = (frame_16 * slots_per_frame) + slot;
uint16_t sl_NumSSB_WithinPeriod = sl_bch->ssb_time_alloc.sl_NumSSB_WithinPeriod;
uint16_t sl_TimeOffsetSSB = sl_bch->ssb_time_alloc.sl_TimeOffsetSSB;
uint16_t sl_TimeInterval = sl_bch->ssb_time_alloc.sl_TimeInterval;
uint16_t num_ssb = sl_bch->num_ssb, ssb_slot = sl_bch->ssb_slot;
#ifdef SL_DEBUG
LOG_D(NR_MAC,
"%d:%d. num_ssb:%d,ssb_slot:%d, %d-%d-%d, status:%d\n",
frame,
slot,
sl_bch->num_ssb,
sl_bch->ssb_slot,
sl_NumSSB_WithinPeriod,
sl_TimeOffsetSSB,
sl_TimeInterval,
sl_bch->status);
#endif
if (sl_NumSSB_WithinPeriod && sl_bch->status) {
if (slot_in_16frames == sl_TimeOffsetSSB) {
num_ssb = 0;
ssb_slot = sl_TimeOffsetSSB;
}
if (num_ssb < sl_NumSSB_WithinPeriod && slot_in_16frames == ssb_slot) {
num_ssb += 1;
ssb_slot = (num_ssb < sl_NumSSB_WithinPeriod) ? (ssb_slot + sl_TimeInterval) : sl_TimeOffsetSSB;
sl_bch->ssb_slot = ssb_slot;
sl_bch->num_ssb = num_ssb;
LOG_D(NR_MAC, "%d:%d is a PSBCH SLOT. Next PSBCH Slot:%d, num_ssb:%d\n", frame, slot, sl_bch->ssb_slot, sl_bch->num_ssb);
return 1;
}
}
LOG_D(NR_MAC, "%d:%d is NOT a PSBCH SLOT. Next PSBCH Slot:%d, num_ssb:%d\n", frame, slot, sl_bch->ssb_slot, sl_bch->num_ssb);
return 0;
}
static uint8_t sl_psbch_scheduler(sl_nr_ue_mac_params_t *sl_mac_params, int ue_id, int frame, int slot)
{
uint8_t config_type = 0, is_psbch_rx_slot = 0, is_psbch_tx_slot = 0;
sl_nr_phy_config_request_t *sl_cfg = &sl_mac_params->sl_phy_config.sl_config_req;
uint16_t scs = sl_cfg->sl_bwp_config.sl_scs;
uint16_t slots_per_frame = nr_slots_per_frame[scs];
if (sl_mac_params->rx_sl_bch.status) {
is_psbch_rx_slot = sl_determine_if_SSB_slot(frame, slot, slots_per_frame, &sl_mac_params->rx_sl_bch);
if (is_psbch_rx_slot)
config_type = SL_NR_CONFIG_TYPE_RX_PSBCH;
} else if (sl_mac_params->tx_sl_bch.status) {
is_psbch_tx_slot = sl_determine_if_SSB_slot(frame, slot, slots_per_frame, &sl_mac_params->tx_sl_bch);
if (is_psbch_tx_slot)
config_type = SL_NR_CONFIG_TYPE_TX_PSBCH;
}
sl_mac_params->future_ttis[slot].frame = frame;
sl_mac_params->future_ttis[slot].slot = slot;
sl_mac_params->future_ttis[slot].sl_action = config_type;
LOG_D(NR_MAC, "[UE%d] SL-PSBCH SCHEDULER: %d:%d, config type:%d\n", ue_id, frame, slot, config_type);
return config_type;
}
/*
* This function calculates the indices based on the new timing (frame,slot)
* acquired by the UE.
* NUM SSB, SLOT_SSB needs to be calculated based on current timing
*/
static void sl_adjust_indices_based_on_timing(sl_nr_ue_mac_params_t *sl_mac,
int ue_id,
int frame, int slot,
int slots_per_frame)
{
uint8_t elapsed_slots = 0;
elapsed_slots = sl_get_elapsed_slots(slot, sl_mac->sl_slot_bitmap);
AssertFatal(elapsed_slots <= sl_mac->N_SL_SLOTS_perframe,
"Elapsed slots cannot be > N_SL_SLOTS_perframe %d,%d\n",
elapsed_slots,
sl_mac->N_SL_SLOTS_perframe);
uint16_t frame_16 = frame % SL_NR_SSB_REPETITION_IN_FRAMES;
uint32_t slot_in_16frames = (frame_16 * slots_per_frame) + slot;
LOG_I(NR_MAC,
"[UE%d]PSBCH params adjusted based on current timing %d:%d. frame_16:%d, slot_in_16frames:%d\n",
ue_id,
frame,
slot,
frame_16,
slot_in_16frames);
// Adjust PSBCH Indices based on current timing
if (sl_mac->rx_sl_bch.status) {
sl_ssb_timealloc_t *ssb_timealloc = &sl_mac->rx_sl_bch.ssb_time_alloc;
sl_mac->rx_sl_bch.num_ssb = sl_adjust_ssb_indices(ssb_timealloc, slot_in_16frames, &sl_mac->rx_sl_bch.ssb_slot);
LOG_I(NR_MAC,
"[UE%d]PSBCH RX params adjusted. NumSSB:%d, ssb_slot:%d\n",
ue_id,
sl_mac->rx_sl_bch.num_ssb,
sl_mac->rx_sl_bch.ssb_slot);
}
if (sl_mac->tx_sl_bch.status) {
sl_ssb_timealloc_t *ssb_timealloc = &sl_mac->tx_sl_bch.ssb_time_alloc;
sl_mac->tx_sl_bch.num_ssb = sl_adjust_ssb_indices(ssb_timealloc, slot_in_16frames, &sl_mac->tx_sl_bch.ssb_slot);
LOG_I(NR_MAC,
"[UE%d]PSBCH TX params adjusted. NumSSB:%d, ssb_slot:%d\n",
ue_id,
sl_mac->tx_sl_bch.num_ssb,
sl_mac->tx_sl_bch.ssb_slot);
}
}
// Adjust indices as new timing is acquired
static void sl_actions_after_new_timing(sl_nr_ue_mac_params_t *sl_mac,
int ue_id,
int frame, int slot)
{
uint8_t mu = sl_mac->sl_phy_config.sl_config_req.sl_bwp_config.sl_scs;
uint8_t slots_per_frame = nr_slots_per_frame[mu];
sl_determine_slot_bitmap(sl_mac, ue_id);
sl_mac->N_SL_SLOTS = sl_determine_num_sidelink_slots(sl_mac, ue_id, &sl_mac->N_SSB_16frames);
sl_adjust_indices_based_on_timing(sl_mac, ue_id, frame, slot, slots_per_frame);
}
static void sl_schedule_rx_actions(nr_sidelink_indication_t *sl_ind, NR_UE_MAC_INST_t *mac)
{
sl_nr_ue_mac_params_t *sl_mac = mac->SL_MAC_PARAMS;
int ue_id = mac->ue_id;
int rx_action = 0;
sl_nr_rx_config_request_t rx_config;
rx_config.number_pdus = 0;
rx_config.sfn = sl_ind->frame_rx;
rx_config.slot = sl_ind->slot_rx;
if (sl_ind->sci_ind != NULL) {
// TBD..
} else {
rx_action = sl_mac->future_ttis[sl_ind->slot_rx].sl_action;
}
if (rx_action == SL_NR_CONFIG_TYPE_RX_PSBCH) {
rx_config.number_pdus = 1;
rx_config.sl_rx_config_list[0].pdu_type = rx_action;
LOG_I(NR_MAC, "[UE%d] %d:%d CMD to PHY: RX PSBCH \n", ue_id, sl_ind->frame_rx, sl_ind->slot_rx);
} else if (rx_action >= SL_NR_CONFIG_TYPE_RX_PSCCH && rx_action <= SL_NR_CONFIG_TYPE_RX_PSSCH_SLSCH) {
// TBD..
} else if (rx_action == SL_NR_CONFIG_TYPE_RX_PSFCH) {
// TBD..
}
if (rx_config.number_pdus) {
AssertFatal(sl_ind->slot_type == SIDELINK_SLOT_TYPE_RX || sl_ind->slot_type == SIDELINK_SLOT_TYPE_BOTH,
"RX action cannot be scheduled in non Sidelink RX slot\n");
nr_scheduled_response_t scheduled_response = {.sl_rx_config = &rx_config,
.module_id = sl_ind->module_id,
.CC_id = sl_ind->cc_id,
.phy_data = sl_ind->phy_data,
.mac = mac};
sl_mac->future_ttis[sl_ind->slot_rx].sl_action = 0;
if ((mac->if_module != NULL) && (mac->if_module->scheduled_response != NULL))
mac->if_module->scheduled_response(&scheduled_response);
}
}
static void sl_schedule_tx_actions(nr_sidelink_indication_t *sl_ind, NR_UE_MAC_INST_t *mac)
{
sl_nr_ue_mac_params_t *sl_mac = mac->SL_MAC_PARAMS;
int ue_id = mac->ue_id;
int tx_action = 0;
sl_nr_tx_config_request_t tx_config;
tx_config.number_pdus = 0;
tx_config.sfn = sl_ind->frame_tx;
tx_config.slot = sl_ind->slot_tx;
tx_action = sl_mac->future_ttis[sl_ind->slot_tx].sl_action;
if (tx_action == SL_NR_CONFIG_TYPE_TX_PSBCH) {
tx_config.number_pdus = 1;
tx_config.tx_config_list[0].pdu_type = tx_action;
tx_config.tx_config_list[0].tx_psbch_config_pdu.tx_slss_id = sl_mac->tx_sl_bch.slss_id;
tx_config.tx_config_list[0].tx_psbch_config_pdu.psbch_tx_power = 0; // TBD...
memcpy(tx_config.tx_config_list[0].tx_psbch_config_pdu.psbch_payload, sl_mac->tx_sl_bch.sl_mib, 4);
LOG_I(NR_MAC, "[UE%d] %d:%d CMD to PHY: TX PSBCH \n", ue_id, sl_ind->frame_tx, sl_ind->slot_tx);
} else if (tx_action == SL_NR_CONFIG_TYPE_TX_PSCCH_PSSCH) {
// TBD....
} else if (tx_action == SL_NR_CONFIG_TYPE_TX_PSFCH) {
// TBD....
}
if (tx_config.number_pdus == 1) {
AssertFatal(sl_ind->slot_type == SIDELINK_SLOT_TYPE_TX || sl_ind->slot_type == SIDELINK_SLOT_TYPE_BOTH,
"TX action cannot be scheduled in non Sidelink TX slot\n");
nr_scheduled_response_t scheduled_response = {.sl_tx_config = &tx_config,
.module_id = sl_ind->module_id,
.CC_id = sl_ind->cc_id,
.phy_data = sl_ind->phy_data,
.mac = mac};
sl_mac->future_ttis[sl_ind->slot_tx].sl_action = 0;
if ((mac->if_module != NULL) && (mac->if_module->scheduled_response != NULL))
mac->if_module->scheduled_response(&scheduled_response);
}
}
void nr_ue_sidelink_scheduler(nr_sidelink_indication_t *sl_ind, NR_UE_MAC_INST_t *mac)
{
AssertFatal(sl_ind != NULL, "sl_indication cannot be NULL\n");
sl_nr_ue_mac_params_t *sl_mac = mac->SL_MAC_PARAMS;
int ue_id = mac->ue_id;
LOG_D(NR_MAC,
"[UE%d]SL-SCHEDULER: RX %d-%d- TX %d-%d. slot_type:%d\n",
ue_id,
sl_ind->frame_rx,
sl_ind->slot_rx,
sl_ind->frame_tx,
sl_ind->slot_tx,
sl_ind->slot_type);
// Adjust indices as new timing is acquired
if (sl_mac->timing_acquired) {
sl_actions_after_new_timing(sl_mac, ue_id, sl_ind->frame_tx, sl_ind->slot_tx);
sl_mac->timing_acquired = false;
}
if (sl_ind->slot_type == SIDELINK_SLOT_TYPE_TX || sl_ind->slot_type == SIDELINK_SLOT_TYPE_BOTH) {
int frame = sl_ind->frame_tx;
int slot = sl_ind->slot_tx;
int is_sl_slot = 0;
is_sl_slot = sl_mac->sl_slot_bitmap & (1 << slot);
if (is_sl_slot) {
uint8_t tti_action = 0;
// Check if PSBCH slot and PSBCH should be transmitted or Received
tti_action = sl_psbch_scheduler(sl_mac, ue_id, frame, slot);
#if 0 // To be expanded later
// TBD .. Check for Actions coming out of TX resource pool
if (!tti_action && sl_mac->sl_TxPool[0])
tti_action = sl_tx_scheduler(ue_id, frame, slot, sl_mac, sl_mac->sl_TxPool[0]);
//TBD .. Check for Actions coming out of RX resource pool
if (!tti_action && sl_mac->sl_RxPool[0])
tti_action = sl_rx_scheduler(ue_id, frame, slot, sl_mac, sl_mac->sl_RxPool[0]);
#endif
LOG_D(NR_MAC, "[UE%d]SL-SCHED: TTI - %d:%d scheduled action:%d\n", ue_id, frame, slot, tti_action);
} else {
AssertFatal(1 == 0, "TX SLOT not a sidelink slot. Should not occur\n");
}
// Schedule the Tx actions if any
sl_schedule_tx_actions(sl_ind, mac);
}
if (sl_ind->slot_type == SIDELINK_SLOT_TYPE_RX || sl_ind->slot_type == SIDELINK_SLOT_TYPE_BOTH)
sl_schedule_rx_actions(sl_ind, mac);
}
......@@ -1296,6 +1296,10 @@ nr_ue_if_module_t *nr_ue_if_module_init(uint32_t module_id)
nr_ue_if_module_inst[module_id]->current_slot = 0;
nr_ue_if_module_inst[module_id]->phy_config_request = nr_ue_phy_config_request;
nr_ue_if_module_inst[module_id]->synch_request = nr_ue_synch_request;
if (get_softmodem_params()->sl_mode) {
nr_ue_if_module_inst[module_id]->sl_phy_config_request = nr_ue_sl_phy_config_request;
nr_ue_if_module_inst[module_id]->sl_indication = nr_ue_sl_indication;
}
if (get_softmodem_params()->emulate_l1)
nr_ue_if_module_inst[module_id]->scheduled_response = nr_ue_scheduled_response_stub;
else
......@@ -1335,3 +1339,117 @@ void RCconfig_nr_ue_macrlc(void) {
}
}
}
static void handle_sl_bch(int ue_id,
sl_nr_ue_mac_params_t *sl_mac,
uint8_t *const sl_mib,
const uint8_t len,
uint16_t frame_rx,
uint16_t slot_rx,
uint16_t rx_slss_id)
{
LOG_D(NR_MAC, " decode SL-MIB %d\n", rx_slss_id);
uint8_t sl_tdd_config[2] = {0, 0};
sl_tdd_config[0] = sl_mib[0];
sl_tdd_config[1] = sl_mib[1] & 0xF0;
uint8_t incov = sl_mib[1] & 0x08;
uint16_t frame_0 = (sl_mib[2] & 0xFE) >> 1;
uint16_t frame_1 = sl_mib[1] & 0x07;
frame_0 |= (frame_1 & 0x01) << 7;
frame_1 = ((frame_1 & 0x06) >> 1) << 8;
uint16_t frame = frame_1 | frame_0;
uint8_t slot = ((sl_mib[2] & 0x01) << 6) | ((sl_mib[3] & 0xFC) >> 2);
LOG_D(NR_MAC,
"[UE%d]In %d:%d Received SL-MIB:%x .Contents- SL-TDD config:%x, Incov:%d, FN:%d, Slot:%d\n",
ue_id,
frame_rx,
slot_rx,
*((uint32_t *)sl_mib),
*((uint16_t *)sl_tdd_config),
incov,
frame,
slot);
sl_mac->decoded_DFN = frame;
sl_mac->decoded_slot = slot;
nr_mac_rrc_data_ind_ue(ue_id, 0, 0, frame_rx, slot_rx, 0, rx_slss_id, 0, NR_SBCCH_SL_BCH, (uint8_t *)sl_mib, len);
return;
}
/*
if PSBCH rx - handle_psbch()
- Extract FN, Slot
- Extract TDD configuration from the 12 bits
- SEND THE SL-MIB to RRC
if PSSCH DATa rx - handle slsch()
*/
void sl_nr_process_rx_ind(int ue_id,
uint32_t frame,
uint32_t slot,
sl_nr_ue_mac_params_t *sl_mac,
sl_nr_rx_indication_t *rx_ind)
{
uint8_t num_pdus = rx_ind->number_pdus;
uint8_t pdu_type = rx_ind->rx_indication_body[num_pdus - 1].pdu_type;
switch (pdu_type) {
case SL_NR_RX_PDU_TYPE_SSB:
if (rx_ind->rx_indication_body[num_pdus - 1].ssb_pdu.decode_status) {
LOG_D(NR_MAC,
"[UE%d]SL-MAC Received SL-SSB: RSRP:%d dBm/RE, rx_psbch_payload:%x, rx_slss_id:%d\n",
ue_id,
rx_ind->rx_indication_body[num_pdus - 1].ssb_pdu.rsrp_dbm,
*((uint32_t *)rx_ind->rx_indication_body[num_pdus - 1].ssb_pdu.psbch_payload),
rx_ind->rx_indication_body[num_pdus - 1].ssb_pdu.rx_slss_id);
handle_sl_bch(ue_id,
sl_mac,
rx_ind->rx_indication_body[num_pdus - 1].ssb_pdu.psbch_payload,
4,
frame,
slot,
rx_ind->rx_indication_body[num_pdus - 1].ssb_pdu.rx_slss_id);
sl_mac->ssb_rsrp_dBm = rx_ind->rx_indication_body[num_pdus - 1].ssb_pdu.rsrp_dbm;
} else {
LOG_I(NR_MAC, "[UE%d]SL-MAC - NO SL-SSB Received\n", ue_id);
}
break;
case SL_NR_RX_PDU_TYPE_SLSCH:
break;
default:
AssertFatal(1 == 0, "Incorrect type received. %s\n", __FUNCTION__);
break;
}
}
/*
* Sidelink indication is sent from PHY->MAC.
* This interface function handles these
* - rx_ind (SSB on PSBCH/SLSCH on PSSCH).
* - sci_ind (received scis during rxpool reception/txpool sensing)
*/
void nr_ue_sl_indication(nr_sidelink_indication_t *sl_indication)
{
// NR_UE_L2_STATE_t ret;
int ue_id = sl_indication->module_id;
NR_UE_MAC_INST_t *mac = get_mac_inst(ue_id);
uint16_t slot = sl_indication->slot_rx;
uint16_t frame = sl_indication->frame_rx;
sl_nr_ue_mac_params_t *sl_mac = mac->SL_MAC_PARAMS;
if (sl_indication->rx_ind) {
sl_nr_process_rx_ind(ue_id, frame, slot, sl_mac, sl_indication->rx_ind);
} else {
nr_ue_sidelink_scheduler(sl_indication, mac);
}
}
......@@ -42,6 +42,15 @@
#include "NR_Packet_Drop.h"
#include "nfapi/open-nFAPI/nfapi/public_inc/sidelink_nr_ue_interface.h"
typedef enum sl_sidelink_slot_type {
SIDELINK_SLOT_TYPE_NONE = 0,
SIDELINK_SLOT_TYPE_RX,
SIDELINK_SLOT_TYPE_TX,
SIDELINK_SLOT_TYPE_BOTH
} sl_sidelink_slot_type_t;
extern slot_rnti_mcs_s slot_rnti_mcs[NUM_NFAPI_SLOT];
typedef struct NR_UL_TIME_ALIGNMENT NR_UL_TIME_ALIGNMENT_t;
......@@ -106,6 +115,8 @@ typedef struct {
frame_t frame_tx;
/// slot tx
uint32_t slot_tx;
// slot type rx or tx
sl_sidelink_slot_type_t slot_type;
/// NR UE FAPI-like P7 message, direction: L1 to L2
/// data reception indication structure
......@@ -199,7 +210,7 @@ typedef int8_t (nr_ue_scheduled_response_f)(nr_scheduled_response_t *scheduled_r
* -1: Failed to consume bytes. Abort the mission.
* Non-negative return values indicate success, and ignored.
*/
typedef int8_t (nr_sl_ue_scheduled_response_f)(nr_scheduled_response_t *sl_scheduled_response);
typedef void (nr_sl_ue_scheduled_response_f)(nr_scheduled_response_t *sl_scheduled_response);
/*
......@@ -218,7 +229,7 @@ typedef int8_t (nr_ue_phy_config_request_f)(nr_phy_config_t *phy_config);
* -1: Failed to consume bytes. Abort the mission.
* Non-negative return values indicate success, and ignored.
*/
typedef int8_t (nr_sl_ue_phy_config_request_f)(nr_sl_phy_config_t *sl_phy_config);
typedef void(nr_ue_sl_phy_config_request_f)(nr_sl_phy_config_t *sl_phy_config);
/*
* Generic type of an application-defined callback to return various
......@@ -254,12 +265,13 @@ typedef void (nr_ue_slot_indication_f)(uint8_t mod_id);
* -1: Failed to consume bytes. Abort the mission.
* Non-negative return values indicate success, and ignored.
*/
typedef int (nr_ue_sl_indication_f)(nr_sidelink_indication_t *sl_info);
typedef void (nr_ue_sl_indication_f)(nr_sidelink_indication_t *sl_info);
// TODO check this stuff can be reuse of need modification
typedef struct nr_ue_if_module_s {
nr_ue_scheduled_response_f *scheduled_response;
nr_ue_phy_config_request_f *phy_config_request;
nr_ue_sl_phy_config_request_f *sl_phy_config_request;
nr_ue_synch_request_f *synch_request;
nr_ue_dl_indication_f *dl_indication;
nr_ue_ul_indication_f *ul_indication;
......@@ -304,5 +316,7 @@ int nr_ue_dl_indication(nr_downlink_indication_t *dl_info);
int nr_ue_ul_indication(nr_uplink_indication_t *ul_info);
void nr_ue_sl_indication(nr_sidelink_indication_t *sl_indication);
#endif
......@@ -113,8 +113,7 @@ int8_t nr_mac_rrc_data_ind_ue(const module_id_t module_id,
NR_RRC_MAC_SBCCH_DATA_IND (message_p).frame = frame; //frameP
NR_RRC_MAC_SBCCH_DATA_IND (message_p).slot = slot;
NR_RRC_MAC_SBCCH_DATA_IND (message_p).sdu_size = sdu_size;
NR_RRC_MAC_SBCCH_DATA_IND (message_p).gnb_index = gNB_index;
NR_RRC_MAC_SBCCH_DATA_IND (message_p).rx_slss_id = rnti;//rx_slss_id is rnti
NR_RRC_MAC_SBCCH_DATA_IND(message_p).rx_slss_id = cellid; // cellid is rx slss id
itti_send_msg_to_task(TASK_RRC_NRUE, GNB_MODULE_ID_TO_INSTANCE(module_id), message_p);
}
break;
......
......@@ -462,9 +462,7 @@ static int8_t nr_sl_rrc_ue_decode_SL_MIB(const uint8_t gNB_index,
uint8_t val_slot = sl_mib->slotIndex_r16.buf[0];
LOG_D(NR_RRC, "SL-RRC - Received MIB\n");
LOG_D(NR_RRC, "SL-MIB Contents - DFN:%d\n" , val_fn);
LOG_D(NR_RRC, "SL-MIB Contents - SLOT:%d\n" , val_slot >> 1);
LOG_D(NR_RRC, "%d:%d SL-RRC - Received MIB.\n", val_fn, val_slot >> 1);
LOG_D(NR_RRC, "SL-MIB Contents - Incoverage:%d\n", sl_mib->inCoverage_r16);
LOG_D(NR_RRC, "SL-MIB Contents - sl-TDD-Config:%x\n" , *((uint16_t *)(sl_mib->sl_TDD_Config_r16.buf)));
......
......@@ -4,10 +4,10 @@ SIDELINK_PRECONFIGURATION = (
{
# TDD ULDL CONFIG used for sidelink
sl_dl_UL_TransmissionPeriodicity = 6;
sl_nrofDownlinkSlots = 7;
sl_nrofDownlinkSymbols = 10;
sl_nrofUplinkSlots = 2;
sl_nrofUplinkSymbols = 4;
sl_nrofDownlinkSlots = 0;
sl_nrofDownlinkSymbols = 0;
sl_nrofUplinkSlots = 10;
sl_nrofUplinkSymbols = 0;
sl_FrequencyCommonConfig = (
{
......@@ -39,11 +39,13 @@ SIDELINK_PRECONFIGURATION = (
sl_syncCfg = (
{
#NUM SL-SSB within 16 frames
#values are [1,2,4,8,16,32,64], 0 means 1 so on
#Current value set to 4 SSBs within 16 frame period
sl_NumSSB_WithinPeriod_0 = 2;
#Slot Offset for the first txn in the 16 frame period
sl_TimeOffsetSSB_0 = 8;
#interval in slots for repetition of SL-SSB
sl_TimeInterval_0 = 120;
sl_TimeInterval_0 = 60;
}
);
......
......@@ -39,11 +39,13 @@ SIDELINK_PRECONFIGURATION = (
sl_syncCfg = (
{
#NUM SL-SSB within 16 frames
#values are [1,2,4,8,16,32,64], 0 means 1 so on
#Current value set to 4 SSBs within 16 frame period
sl_NumSSB_WithinPeriod_0 = 2;
#Slot Offset for the first txn in the 16 frame period
sl_TimeOffsetSSB_0 = 8;
#interval in slots for repetition of SL-SSB
sl_TimeInterval_0 = 120;
sl_TimeInterval_0 = 60;
}
);
......
......@@ -4,10 +4,10 @@ SIDELINK_PRECONFIGURATION = (
{
# TDD ULDL CONFIG used for sidelink
sl_dl_UL_TransmissionPeriodicity = 6;
sl_nrofDownlinkSlots = 7;
sl_nrofDownlinkSymbols = 10;
sl_nrofUplinkSlots = 2;
sl_nrofUplinkSymbols = 4;
sl_nrofDownlinkSlots = 0;
sl_nrofDownlinkSymbols = 0;
sl_nrofUplinkSlots = 10;
sl_nrofUplinkSymbols = 0;
sl_FrequencyCommonConfig = (
{
......@@ -39,11 +39,13 @@ SIDELINK_PRECONFIGURATION = (
sl_syncCfg = (
{
#NUM SL-SSB within 16 frames
#values are [1,2,4,8,16,32,64], 0 means 1 so on
#Current value set to 4 SSBs within 16 frame period
sl_NumSSB_WithinPeriod_0 = 2;
#Slot Offset for the first txn in the 16 frame period
sl_TimeOffsetSSB_0 = 8;
#interval in slots for repetition of SL-SSB
sl_TimeInterval_0 = 120;
sl_TimeInterval_0 = 60;
}
);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment