From 798ceeeef2793f9595e8dc500c8196e87a7372ef Mon Sep 17 00:00:00 2001 From: Raghavendra Dinavahi Date: Mon, 24 Jul 2023 23:12:50 +0200 Subject: [PATCH] SL PSBCH: MAC->PHY cfg, PSBCH scheduler + supporting functions + enable system testing & scope - Phy config update and Sidelink frame parameters initialisation - PSBCH scheduler to trigger TX PSBCH/RX PSBCH actions - Sidelink indication with rx ind to trigger send SL-MIB to MAC - Enable Scope for PSBCH use -d or --dqt - Enable system testing of PSBCH for example using RFSIMULATOR: - UE1 is a SYNCRONISATION SOURCE UE which transmits PSBCH started using command - sudo ./nr-uesoftmodem --sl-mode 2 --sync-ref 4 --rfsim --rfsimulator.serveraddr server - UE2 syncs onto UE1 during sidelink search, gets the timing and continues to receive PSBCH started using command - sudo ./nr-uesoftmodem --sl-mode 2 --rfsim --rfsimulator.serveraddr 127.0.0.1 - In the default use case 2 Sidelink SSBs sent over 16 frames. - In case SL-SSB configuration needs to be changed use -O option in the above command like -O ../../../targets/PROJECTS/NR-SIDELINK/CONF/sidelink_preconfig_1txpool.conf --- CMakeLists.txt | 1 + executables/nr-ue.c | 304 +++++++++---- executables/nr-uesoftmodem.c | 44 +- executables/nr-uesoftmodem.h | 1 + .../public_inc/sidelink_nr_ue_interface.h | 1 + openair1/PHY/INIT/nr_init_ue.c | 11 +- openair1/PHY/INIT/nr_parms.c | 182 ++++++-- openair1/PHY/INIT/nr_phy_init.h | 5 +- openair1/PHY/MODULATION/nr_modulation.c | 90 ++-- openair1/PHY/MODULATION/nr_modulation.h | 2 + openair1/PHY/MODULATION/slot_fep_nr.c | 2 +- .../PHY/NR_UE_ESTIMATION/nr_ue_measurements.c | 2 +- openair1/PHY/NR_UE_TRANSPORT/nr_psbch_rx.c | 13 +- .../NR_UE_TRANSPORT/nr_transport_proto_ue.h | 5 +- .../PHY/NR_UE_TRANSPORT/nr_ue_rf_helpers.c | 8 - openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c | 9 +- openair1/PHY/TOOLS/nr_phy_qt_scope.cpp | 61 ++- openair1/PHY/TOOLS/nr_phy_qt_scope.h | 5 +- openair1/PHY/TOOLS/nr_phy_scope.c | 28 +- openair1/PHY/TOOLS/phy_scope_interface.h | 3 + openair1/PHY/defs_nr_sl_UE.h | 1 + openair1/PHY/impl_defs_nr.h | 1 + openair1/SCHED_NR_UE/defs.h | 8 +- openair1/SCHED_NR_UE/fapi_nr_ue_l1.c | 83 +++- openair1/SCHED_NR_UE/fapi_nr_ue_l1.h | 2 + openair1/SCHED_NR_UE/phy_frame_config_nr_ue.c | 64 +++ openair1/SCHED_NR_UE/phy_procedures_nr_ue.c | 7 +- .../SCHED_NR_UE/phy_procedures_nr_ue_sl.c | 46 +- .../SIMULATION/NR_PHY/nr_dummy_functions.c | 12 + openair1/SIMULATION/NR_PHY/psbchsim.c | 11 +- openair2/LAYER2/NR_MAC_UE/config_ue_sl.c | 13 +- openair2/LAYER2/NR_MAC_UE/mac_defs_sl.h | 32 ++ openair2/LAYER2/NR_MAC_UE/mac_proto.h | 21 + .../LAYER2/NR_MAC_UE/nr_ue_procedures_sl.c | 50 +- .../LAYER2/NR_MAC_UE/nr_ue_scheduler_sl.c | 426 ++++++++++++++++++ openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.c | 118 +++++ openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.h | 20 +- openair2/RRC/NR_UE/L2_interface_ue.c | 3 +- openair2/RRC/NR_UE/rrc_sl_preconfig.c | 4 +- .../CONF/sidelink_preconfig_1rxpool.conf | 12 +- .../sidelink_preconfig_1rxpool_1txpool.conf | 4 +- .../CONF/sidelink_preconfig_1txpool.conf | 12 +- 42 files changed, 1409 insertions(+), 318 deletions(-) create mode 100644 openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler_sl.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 03cbc144c7..329c7ffadf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1411,6 +1411,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 ${NR_UE_MAC_DIR}/nr_ue_power_procedures.c diff --git a/executables/nr-ue.c b/executables/nr-ue.c index 0a47de2a59..b4a1a1fd21 100644 --- a/executables/nr-ue.c +++ b/executables/nr-ue.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; iframe_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); + 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); } - - 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; iframe_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; slotframe_parms.slots_per_subframe; slot ++ ) { - for (int i=0; iframe_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; iframe_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; } @@ -763,18 +861,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++) { @@ -797,18 +899,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; iframe_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) { @@ -817,14 +923,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; @@ -832,7 +938,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 @@ -840,13 +946,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; @@ -895,7 +999,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); } diff --git a/executables/nr-uesoftmodem.c b/executables/nr-uesoftmodem.c index e588e2f75b..befc03a2da 100644 --- a/executables/nr-uesoftmodem.c +++ b/executables/nr-uesoftmodem.c @@ -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; cardthreequarter_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(); diff --git a/executables/nr-uesoftmodem.h b/executables/nr-uesoftmodem.h index bdd739a823..4c3a35b048 100644 --- a/executables/nr-uesoftmodem.h +++ b/executables/nr-uesoftmodem.h @@ -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/). 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 */ diff --git a/nfapi/open-nFAPI/nfapi/public_inc/sidelink_nr_ue_interface.h b/nfapi/open-nFAPI/nfapi/public_inc/sidelink_nr_ue_interface.h index 7ff96637b0..4110d88ed0 100644 --- a/nfapi/open-nFAPI/nfapi/public_inc/sidelink_nr_ue_interface.h +++ b/nfapi/open-nFAPI/nfapi/public_inc/sidelink_nr_ue_interface.h @@ -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; diff --git a/openair1/PHY/INIT/nr_init_ue.c b/openair1/PHY/INIT/nr_init_ue.c index 0552ddb68b..3967090aeb 100644 --- a/openair1/PHY/INIT/nr_init_ue.c +++ b/openair1/PHY/INIT/nr_init_ue.c @@ -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; inb_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); } diff --git a/openair1/PHY/INIT/nr_parms.c b/openair1/PHY/INIT/nr_parms.c index 4f0a84cffe..4fc91037b8 100644 --- a/openair1/PHY/INIT/nr_parms.c +++ b/openair1/PHY/INIT/nr_parms.c @@ -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<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; } diff --git a/openair1/PHY/INIT/nr_phy_init.h b/openair1/PHY/INIT/nr_phy_init.h index bfbe21ce04..a6a7852d2c 100644 --- a/openair1/PHY/INIT/nr_phy_init.h +++ b/openair1/PHY/INIT/nr_phy_init.h @@ -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); diff --git a/openair1/PHY/MODULATION/nr_modulation.c b/openair1/PHY/MODULATION/nr_modulation.c index c01514e990..85490be63b 100644 --- a/openair1/PHY/MODULATION/nr_modulation.c +++ b/openair1/PHY/MODULATION/nr_modulation.c @@ -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<numerology_index)); const double Ncp0=16*64 + (144*64*(1/(float)(1<numerology_index))); const double Ncp1=(144*64*(1/(float)(1<numerology_index))); - for (uint8_t ll = 0; ll < 2; ll++){ + LOG_I(PHY, "Doing symbol rotation calculation for TX/RX, f0 %f Hz, Nsymb %d\n", f0, nsymb); + double tl = 0.0; + double poff = 0.0; + double exp_re = 0.0; + double exp_im = 0.0; + + 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); + + 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; + } +} + +void init_symbol_rotation(NR_DL_FRAME_PARMS *fp) +{ + double f[2] = {(double)fp->dl_CarrierFreq, (double)fp->ul_CarrierFreq}; + + for (int 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]; - } + if (f0 == 0) + continue; + c16_t *rot = fp->symbol_rotation[ll]; - double tl = 0.0; - double poff = 0.0; - double exp_re = 0.0; - double exp_im = 0.0; - - 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); - - 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; - - } + perform_symbol_rotation(fp, f0, rot); } } diff --git a/openair1/PHY/MODULATION/nr_modulation.h b/openair1/PHY/MODULATION/nr_modulation.h index 2bec9c2aa1..dfb9340459 100644 --- a/openair1/PHY/MODULATION/nr_modulation.h +++ b/openair1/PHY/MODULATION/nr_modulation.h @@ -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); diff --git a/openair1/PHY/MODULATION/slot_fep_nr.c b/openair1/PHY/MODULATION/slot_fep_nr.c index 57d37a2fe6..ffcd0b13ad 100644 --- a/openair1/PHY/MODULATION/slot_fep_nr.c +++ b/openair1/PHY/MODULATION/slot_fep_nr.c @@ -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 diff --git a/openair1/PHY/NR_UE_ESTIMATION/nr_ue_measurements.c b/openair1/PHY/NR_UE_ESTIMATION/nr_ue_measurements.c index 8aa00b4683..30ff7a2f9b 100644 --- a/openair1/PHY/NR_UE_ESTIMATION/nr_ue_measurements.c +++ b/openair1/PHY/NR_UE_ESTIMATION/nr_ue_measurements.c @@ -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, diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_psbch_rx.c b/openair1/PHY/NR_UE_TRANSPORT/nr_psbch_rx.c index cf8ea994f1..7406855cc4 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_psbch_rx.c +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_psbch_rx.c @@ -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); diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h b/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h index 9f46ae38ce..9b7fbb1023 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h @@ -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, diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_ue_rf_helpers.c b/openair1/PHY/NR_UE_TRANSPORT/nr_ue_rf_helpers.c index d07ad7fa88..8199b45fc6 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_ue_rf_helpers.c +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_ue_rf_helpers.c @@ -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){ diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c b/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c index 482c49be25..3dec9e2c45 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c @@ -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); } diff --git a/openair1/PHY/TOOLS/nr_phy_qt_scope.cpp b/openair1/PHY/TOOLS/nr_phy_qt_scope.cpp index 4151a7e4cd..7ea53b4a52 100644 --- a/openair1/PHY/TOOLS/nr_phy_qt_scope.cpp +++ b/openair1/PHY/TOOLS/nr_phy_qt_scope.cpp @@ -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(PlotTypeUE::timingAdvance)); this->addItem("Configs", static_cast(PlotTypeUE::config)); + this->addItem("LLR PSBCH", static_cast(PlotTypeUE::psbchLLR)); + this->addItem("I/Q PSBCH", static_cast(PlotTypeUE::psbchIQ)); + this->addItem("PSBCH RSRP dB/RE", static_cast(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(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(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(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(PlotTypeUE::pbchLLR)); + if (is_sl) + combo3.setCurrentIndex(static_cast(PlotTypeUE::psbchLLR)); + else + combo3.setCurrentIndex(static_cast(PlotTypeUE::psbchLLR)); PainterWidgetUE pwidgetueCombo3(&config, &combo3, ue); mainLayout.addWidget(&combo3, 2, 0); mainLayout.addWidget(&pwidgetueCombo3, 3, 0); KPIListSelectUE combo4; - combo4.setCurrentIndex(static_cast(PlotTypeUE::pbchIQ)); + if (is_sl) + combo4.setCurrentIndex(static_cast(PlotTypeUE::psbchIQ)); + else + combo4.setCurrentIndex(static_cast(PlotTypeUE::psbchIQ)); PainterWidgetUE pwidgetueCombo4(&config, &combo4, ue); mainLayout.addWidget(&combo4, 2, 1); diff --git a/openair1/PHY/TOOLS/nr_phy_qt_scope.h b/openair1/PHY/TOOLS/nr_phy_qt_scope.h index 08296e03d7..f00103aad7 100644 --- a/openair1/PHY/TOOLS/nr_phy_qt_scope.h +++ b/openair1/PHY/TOOLS/nr_phy_qt_scope.h @@ -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 diff --git a/openair1/PHY/TOOLS/nr_phy_scope.c b/openair1/PHY/TOOLS/nr_phy_scope.c index f9abcf211b..c6a9b796c0 100644 --- a/openair1/PHY/TOOLS/nr_phy_scope.c +++ b/openair1/PHY/TOOLS/nr_phy_scope.c @@ -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 diff --git a/openair1/PHY/TOOLS/phy_scope_interface.h b/openair1/PHY/TOOLS/phy_scope_interface.h index ca0f14e019..7c5e33b379 100644 --- a/openair1/PHY/TOOLS/phy_scope_interface.h +++ b/openair1/PHY/TOOLS/phy_scope_interface.h @@ -67,6 +67,9 @@ enum scopeDataType { pdschRxdataF_comp, commonRxdataF, gNBRxdataF, + psbchDlChEstimateTime, + psbchLlr, + psbchRxdataF_comp, MAX_SCOPE_TYPES }; diff --git a/openair1/PHY/defs_nr_sl_UE.h b/openair1/PHY/defs_nr_sl_UE.h index 29958ac75a..4fec84f550 100644 --- a/openair1/PHY/defs_nr_sl_UE.h +++ b/openair1/PHY/defs_nr_sl_UE.h @@ -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; diff --git a/openair1/PHY/impl_defs_nr.h b/openair1/PHY/impl_defs_nr.h index 9c6376a06f..7f9dfad719 100644 --- a/openair1/PHY/impl_defs_nr.h +++ b/openair1/PHY/impl_defs_nr.h @@ -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 */ diff --git a/openair1/SCHED_NR_UE/defs.h b/openair1/SCHED_NR_UE/defs.h index bdb3341387..f0273e1102 100644 --- a/openair1/SCHED_NR_UE/defs.h +++ b/openair1/SCHED_NR_UE/defs.h @@ -159,21 +159,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); diff --git a/openair1/SCHED_NR_UE/fapi_nr_ue_l1.c b/openair1/SCHED_NR_UE/fapi_nr_ue_l1.c index e47a3f6b7b..a1c09c022f 100644 --- a/openair1/SCHED_NR_UE/fapi_nr_ue_l1.c +++ b/openair1/SCHED_NR_UE/fapi_nr_ue_l1.c @@ -523,7 +523,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) @@ -533,6 +534,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; } @@ -552,3 +558,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); + } + +} diff --git a/openair1/SCHED_NR_UE/fapi_nr_ue_l1.h b/openair1/SCHED_NR_UE/fapi_nr_ue_l1.h index 65ca845526..c574b5b3e2 100644 --- a/openair1/SCHED_NR_UE/fapi_nr_ue_l1.h +++ b/openair1/SCHED_NR_UE/fapi_nr_ue_l1.h @@ -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*/ diff --git a/openair1/SCHED_NR_UE/phy_frame_config_nr_ue.c b/openair1/SCHED_NR_UE/phy_frame_config_nr_ue.c index be1f39ab67..f2541d21b3 100644 --- a/openair1/SCHED_NR_UE/phy_frame_config_nr_ue.c +++ b/openair1/SCHED_NR_UE/phy_frame_config_nr_ue.c @@ -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 diff --git a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c index cbeda2e106..b12363968c 100644 --- a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c +++ b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c @@ -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); diff --git a/openair1/SCHED_NR_UE/phy_procedures_nr_ue_sl.c b/openair1/SCHED_NR_UE/phy_procedures_nr_ue_sl.c index d9a3d51267..b4335c7480 100644 --- a/openair1/SCHED_NR_UE/phy_procedures_nr_ue_sl.c +++ b/openair1/SCHED_NR_UE/phy_procedures_nr_ue_sl.c @@ -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; } diff --git a/openair1/SIMULATION/NR_PHY/nr_dummy_functions.c b/openair1/SIMULATION/NR_PHY/nr_dummy_functions.c index 78906f5489..8d02ee9927 100644 --- a/openair1/SIMULATION/NR_PHY/nr_dummy_functions.c +++ b/openair1/SIMULATION/NR_PHY/nr_dummy_functions.c @@ -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; +} diff --git a/openair1/SIMULATION/NR_PHY/psbchsim.c b/openair1/SIMULATION/NR_PHY/psbchsim.c index fd96f233ca..0d29615f66 100644 --- a/openair1/SIMULATION/NR_PHY/psbchsim.c +++ b/openair1/SIMULATION/NR_PHY/psbchsim.c @@ -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); diff --git a/openair2/LAYER2/NR_MAC_UE/config_ue_sl.c b/openair2/LAYER2/NR_MAC_UE/config_ue_sl.c index 044ad3b255..04cf626a54 100644 --- a/openair2/LAYER2/NR_MAC_UE/config_ue_sl.c +++ b/openair2/LAYER2/NR_MAC_UE/config_ue_sl.c @@ -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); } - } diff --git a/openair2/LAYER2/NR_MAC_UE/mac_defs_sl.h b/openair2/LAYER2/NR_MAC_UE/mac_defs_sl.h index 5e3dc39e38..5960a30a46 100644 --- a/openair2/LAYER2/NR_MAC_UE/mac_defs_sl.h +++ b/openair2/LAYER2/NR_MAC_UE/mac_defs_sl.h @@ -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; diff --git a/openair2/LAYER2/NR_MAC_UE/mac_proto.h b/openair2/LAYER2/NR_MAC_UE/mac_proto.h index a6a60fbd7f..c2a4147c20 100644 --- a/openair2/LAYER2/NR_MAC_UE/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_UE/mac_proto.h @@ -382,6 +382,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); @@ -393,4 +394,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 diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures_sl.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures_sl.c index c485461e56..7214912ea5 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures_sl.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures_sl.c @@ -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 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; - - AssertFatal(subch_size,"Subch Size cannot be 0.Resource Pool Configuration Error\n"); - - return subch_size; -} - uint16_t sl_get_num_subch(NR_SL_ResourcePool_r16_t *rpool) { - uint16_t num_subch = 0; - uint16_t subch_size = sl_get_subchannel_size(rpool); + //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(num_subch,"NUM Subchannels cannot be 0. Resource Pool Configuration Error\n"); + + return num_subch; +} + +uint16_t sl_get_subchannel_size(NR_SL_ResourcePool_r16_t *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 && diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler_sl.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler_sl.c new file mode 100644 index 0000000000..483241b17b --- /dev/null +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler_sl.c @@ -0,0 +1,426 @@ +/* + * 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); +} diff --git a/openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.c b/openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.c index e599ec5608..4044cfd9dc 100644 --- a/openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.c +++ b/openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.c @@ -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); + } + +} diff --git a/openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.h b/openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.h index 5cca5b0f80..26502cacf1 100644 --- a/openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.h +++ b/openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.h @@ -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 diff --git a/openair2/RRC/NR_UE/L2_interface_ue.c b/openair2/RRC/NR_UE/L2_interface_ue.c index 2958609fda..feda34be67 100644 --- a/openair2/RRC/NR_UE/L2_interface_ue.c +++ b/openair2/RRC/NR_UE/L2_interface_ue.c @@ -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; diff --git a/openair2/RRC/NR_UE/rrc_sl_preconfig.c b/openair2/RRC/NR_UE/rrc_sl_preconfig.c index 7fe57ad1fb..b5ae64b96e 100644 --- a/openair2/RRC/NR_UE/rrc_sl_preconfig.c +++ b/openair2/RRC/NR_UE/rrc_sl_preconfig.c @@ -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))); diff --git a/targets/PROJECTS/NR-SIDELINK/CONF/sidelink_preconfig_1rxpool.conf b/targets/PROJECTS/NR-SIDELINK/CONF/sidelink_preconfig_1rxpool.conf index f6a934e0a3..5210a914e3 100644 --- a/targets/PROJECTS/NR-SIDELINK/CONF/sidelink_preconfig_1rxpool.conf +++ b/targets/PROJECTS/NR-SIDELINK/CONF/sidelink_preconfig_1rxpool.conf @@ -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; } ); diff --git a/targets/PROJECTS/NR-SIDELINK/CONF/sidelink_preconfig_1rxpool_1txpool.conf b/targets/PROJECTS/NR-SIDELINK/CONF/sidelink_preconfig_1rxpool_1txpool.conf index b65b785393..5a60658cfa 100644 --- a/targets/PROJECTS/NR-SIDELINK/CONF/sidelink_preconfig_1rxpool_1txpool.conf +++ b/targets/PROJECTS/NR-SIDELINK/CONF/sidelink_preconfig_1rxpool_1txpool.conf @@ -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; } ); diff --git a/targets/PROJECTS/NR-SIDELINK/CONF/sidelink_preconfig_1txpool.conf b/targets/PROJECTS/NR-SIDELINK/CONF/sidelink_preconfig_1txpool.conf index 46a2773f5a..e81a54e0aa 100644 --- a/targets/PROJECTS/NR-SIDELINK/CONF/sidelink_preconfig_1txpool.conf +++ b/targets/PROJECTS/NR-SIDELINK/CONF/sidelink_preconfig_1txpool.conf @@ -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; } );