mirror of
https://gitlab.eurecom.fr/oai/openairinterface5g.git
synced 2026-07-13 20:50:28 +00:00
Compare commits
6 Commits
develop
...
NR_SL_PSBC
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4ca508228f | ||
|
|
88b6cdd209 | ||
|
|
8bb2f3991b | ||
|
|
4d369a6993 | ||
|
|
70f586cb3c | ||
|
|
745cc733ea |
@@ -689,6 +689,7 @@ target_link_libraries(SCHED_UE_LIB PRIVATE asn1_lte_rrc_hdrs asn1_nr_rrc_hdrs)
|
||||
|
||||
set(SCHED_SRC_NR_UE
|
||||
${OPENAIR1_DIR}/SCHED_NR_UE/phy_procedures_nr_ue.c
|
||||
${OPENAIR1_DIR}/SCHED_NR_UE/phy_procedures_nr_ue_sl.c
|
||||
${OPENAIR1_DIR}/SCHED_NR_UE/fapi_nr_ue_l1.c
|
||||
${OPENAIR1_DIR}/SCHED_NR_UE/phy_frame_config_nr_ue.c
|
||||
${OPENAIR1_DIR}/SCHED_NR_UE/harq_nr.c
|
||||
@@ -1060,8 +1061,11 @@ set(PHY_SRC_UE
|
||||
${OPENAIR1_DIR}/PHY/NR_UE_TRANSPORT/sss_nr.c
|
||||
${OPENAIR1_DIR}/PHY/NR_UE_TRANSPORT/cic_filter_nr.c
|
||||
${OPENAIR1_DIR}/PHY/NR_UE_TRANSPORT/nr_initial_sync.c
|
||||
${OPENAIR1_DIR}/PHY/NR_UE_TRANSPORT/nr_initial_sync_sl.c
|
||||
${OPENAIR1_DIR}/PHY/NR_UE_TRANSPORT/nr_ue_rf_helpers.c
|
||||
${OPENAIR1_DIR}/PHY/NR_UE_TRANSPORT/nr_pbch.c
|
||||
${OPENAIR1_DIR}/PHY/NR_UE_TRANSPORT/nr_psbch_rx.c
|
||||
${OPENAIR1_DIR}/PHY/NR_UE_TRANSPORT/nr_psbch_tx.c
|
||||
${OPENAIR1_DIR}/PHY/NR_UE_TRANSPORT/nr_dlsch_demodulation.c
|
||||
${OPENAIR1_DIR}/PHY/NR_UE_TRANSPORT/nr_ulsch_coding.c
|
||||
${OPENAIR1_DIR}/PHY/NR_UE_TRANSPORT/nr_dlsch_decoding.c
|
||||
@@ -1366,9 +1370,11 @@ set (MAC_NR_SRC_UE
|
||||
${NR_UE_PHY_INTERFACE_DIR}/NR_IF_Module.c
|
||||
${NR_UE_PHY_INTERFACE_DIR}/NR_Packet_Drop.c
|
||||
${NR_UE_MAC_DIR}/config_ue.c
|
||||
${NR_UE_MAC_DIR}/config_ue_sl.c
|
||||
${NR_UE_MAC_DIR}/mac_vars.c
|
||||
${NR_UE_MAC_DIR}/main_ue_nr.c
|
||||
${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_dci_configuration.c
|
||||
${NR_UE_MAC_DIR}/nr_ra_procedures.c
|
||||
@@ -2225,6 +2231,24 @@ target_link_libraries(nr_pbchsim PRIVATE
|
||||
)
|
||||
target_link_libraries(nr_pbchsim PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs)
|
||||
|
||||
add_executable(nr_psbchsim
|
||||
${OPENAIR1_DIR}/SIMULATION/NR_PHY/psbchsim.c
|
||||
${OPENAIR1_DIR}/SIMULATION/NR_PHY/nr_dummy_functions.c
|
||||
${OPENAIR_DIR}/common/utils/nr/nr_common.c
|
||||
${OPENAIR_DIR}/executables/softmodem-common.c
|
||||
${OPENAIR2_DIR}/RRC/NAS/nas_config.c
|
||||
${NR_UE_RRC_DIR}/rrc_nsa.c
|
||||
${NFAPI_USER_DIR}/nfapi.c
|
||||
${NFAPI_USER_DIR}/gnb_ind_vars.c
|
||||
${PHY_INTERFACE_DIR}/queue_t.c
|
||||
${T_SOURCE}
|
||||
${SHLIB_LOADER_SOURCES}
|
||||
)
|
||||
target_link_libraries(nr_psbchsim PRIVATE
|
||||
-Wl,--start-group UTIL SIMU SIMU_ETH PHY_COMMON PHY_NR_COMMON PHY_NR PHY_NR_UE SCHED_NR_LIB SCHED_NR_UE_LIB MAC_NR MAC_UE_NR MAC_NR_COMMON nr_rrc CONFIG_LIB L2_NR HASHTABLE x2ap SECURITY ngap -lz -Wl,--end-group
|
||||
m pthread ${ATLAS_LIBRARIES} ${T_LIB} ITTI ${OPENSSL_LIBRARIES} dl shlib_loader
|
||||
)
|
||||
target_link_libraries(nr_psbchsim PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs)
|
||||
|
||||
#PUCCH ---> Prashanth
|
||||
add_executable(nr_pucchsim
|
||||
|
||||
@@ -315,7 +315,7 @@ function main() {
|
||||
-P | --phy_simulators)
|
||||
SIMUS_PHY=1
|
||||
# TODO: fix: dlsim_tm4 pucchsim prachsim pdcchsim pbchsim mbmssim
|
||||
TARGET_LIST="$TARGET_LIST dlsim ulsim ldpctest polartest smallblocktest nr_pbchsim nr_dlschsim nr_ulschsim nr_dlsim nr_ulsim nr_pucchsim nr_prachsim"
|
||||
TARGET_LIST="$TARGET_LIST dlsim ulsim ldpctest polartest smallblocktest nr_pbchsim nr_dlschsim nr_ulschsim nr_dlsim nr_ulsim nr_pucchsim nr_prachsim nr_psbchsim"
|
||||
echo_info "Will compile dlsim, ulsim, ..."
|
||||
shift;;
|
||||
-s | --check)
|
||||
|
||||
@@ -99,7 +99,8 @@
|
||||
typedef enum {
|
||||
pss = 0,
|
||||
pbch = 1,
|
||||
si = 2
|
||||
si = 2,
|
||||
psbch = 3
|
||||
} sync_mode_t;
|
||||
|
||||
static void *NRUE_phy_stub_standalone_pnf_task(void *arg);
|
||||
@@ -376,11 +377,12 @@ static void UE_synch(void *arg) {
|
||||
int i, hw_slot_offset;
|
||||
PHY_VARS_NR_UE *UE = syncD->UE;
|
||||
sync_mode_t sync_mode = pbch;
|
||||
if (UE->sl_mode == 2 && !get_nrUE_params()->sync_ref) sync_mode = psbch;
|
||||
//int CC_id = UE->CC_id;
|
||||
static int freq_offset=0;
|
||||
UE->is_synchronized = 0;
|
||||
|
||||
if (UE->UE_scan == 0) {
|
||||
if (UE->UE_scan == 0 && !UE->sl_mode) {
|
||||
|
||||
for (i=0; i<openair0_cfg[UE->rf_map.card].rx_num_channels; i++) {
|
||||
|
||||
@@ -493,6 +495,52 @@ static void UE_synch(void *arg) {
|
||||
}
|
||||
break;
|
||||
|
||||
case psbch:
|
||||
LOG_I(PHY, "[UE thread Synch] Running Sidelink Initial Synch \n");
|
||||
NR_DL_FRAME_PARMS *fp = &UE->SL_UE_PHY_PARAMS.sl_frame_params;
|
||||
dl_carrier = fp->sl_CarrierFreq;
|
||||
ul_carrier = fp->sl_CarrierFreq;
|
||||
|
||||
if (sl_nr_slss_search(UE, &syncD->proc, 16) == 0) {
|
||||
freq_offset = UE->common_vars.freq_offset; // frequency offset computed with pss in initial sync
|
||||
hw_slot_offset = ((UE->rx_offset<<1) / fp->samples_per_subframe * fp->slots_per_subframe) +
|
||||
round((float)((UE->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
|
||||
nr_rf_card_config_freq(&openair0_cfg[UE->rf_map.card], ul_carrier, dl_carrier, freq_offset);
|
||||
|
||||
LOG_I(PHY,"Got synch: hw_slot_offset %d, carrier off %d Hz, rxgain %f (DL %f Hz, UL %f Hz)\n",
|
||||
hw_slot_offset,
|
||||
freq_offset,
|
||||
openair0_cfg[UE->rf_map.card].rx_gain[0],
|
||||
openair0_cfg[UE->rf_map.card].rx_freq[0],
|
||||
openair0_cfg[UE->rf_map.card].tx_freq[0]);
|
||||
|
||||
UE->rfdevice.trx_set_freq_func(&UE->rfdevice,&openair0_cfg[0]);
|
||||
if (UE->UE_scan_carrier == 1) {
|
||||
UE->UE_scan_carrier = 0;
|
||||
} else {
|
||||
UE->is_synchronized = 1;
|
||||
}
|
||||
} else {
|
||||
|
||||
if (UE->UE_scan_carrier == 1) {
|
||||
|
||||
if (freq_offset >= 0)
|
||||
freq_offset += 100;
|
||||
|
||||
freq_offset *= -1;
|
||||
|
||||
nr_rf_card_config_freq(&openair0_cfg[UE->rf_map.card], ul_carrier, dl_carrier, freq_offset);
|
||||
|
||||
LOG_I(PHY, "Sidelink Initial sync failed: trying carrier off %d Hz\n", freq_offset);
|
||||
|
||||
UE->rfdevice.trx_set_freq_func(&UE->rfdevice,&openair0_cfg[0]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case si:
|
||||
default:
|
||||
break;
|
||||
@@ -500,14 +548,18 @@ 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, int sl_tx_action) {
|
||||
|
||||
PHY_VARS_NR_UE *UE = rxtxD->UE;
|
||||
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];
|
||||
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(proc->nr_slot_tx, &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(proc->nr_slot_tx, fp, 0)];
|
||||
|
||||
radio_tx_burst_flag_t flags = TX_BURST_INVALID;
|
||||
|
||||
@@ -516,27 +568,34 @@ static void RU_write(nr_rxtx_thread_data_t *rxtxD) {
|
||||
openair0_cfg[0].duplex_mode == duplex_mode_TDD &&
|
||||
!get_softmodem_params()->continuous_tx) {
|
||||
|
||||
uint8_t tdd_period = mac->phy_config.config_req.tdd_table.tdd_period_in_slots;
|
||||
int nrofUplinkSlots, nrofUplinkSymbols;
|
||||
if (mac->scc) {
|
||||
nrofUplinkSlots = mac->scc->tdd_UL_DL_ConfigurationCommon->pattern1.nrofUplinkSlots;
|
||||
nrofUplinkSymbols = mac->scc->tdd_UL_DL_ConfigurationCommon->pattern1.nrofUplinkSymbols;
|
||||
}
|
||||
else {
|
||||
nrofUplinkSlots = mac->scc_SIB->tdd_UL_DL_ConfigurationCommon->pattern1.nrofUplinkSlots;
|
||||
nrofUplinkSymbols = mac->scc_SIB->tdd_UL_DL_ConfigurationCommon->pattern1.nrofUplinkSymbols;
|
||||
}
|
||||
//Perform USRP write only in case SL Txn needs to be done.
|
||||
if (UE->sl_mode == 2) {
|
||||
flags = sl_tx_action ? TX_BURST_START_AND_END
|
||||
: TX_BURST_INVALID;
|
||||
} else {
|
||||
|
||||
int slot_tx_usrp = proc->nr_slot_tx;
|
||||
uint8_t num_UL_slots = nrofUplinkSlots + (nrofUplinkSymbols != 0);
|
||||
uint8_t first_tx_slot = tdd_period - num_UL_slots;
|
||||
uint8_t tdd_period = mac->phy_config.config_req.tdd_table.tdd_period_in_slots;
|
||||
int nrofUplinkSlots, nrofUplinkSymbols;
|
||||
if (mac->scc) {
|
||||
nrofUplinkSlots = mac->scc->tdd_UL_DL_ConfigurationCommon->pattern1.nrofUplinkSlots;
|
||||
nrofUplinkSymbols = mac->scc->tdd_UL_DL_ConfigurationCommon->pattern1.nrofUplinkSymbols;
|
||||
}
|
||||
else {
|
||||
nrofUplinkSlots = mac->scc_SIB->tdd_UL_DL_ConfigurationCommon->pattern1.nrofUplinkSlots;
|
||||
nrofUplinkSymbols = mac->scc_SIB->tdd_UL_DL_ConfigurationCommon->pattern1.nrofUplinkSymbols;
|
||||
}
|
||||
|
||||
if (slot_tx_usrp % tdd_period == first_tx_slot)
|
||||
flags = TX_BURST_START;
|
||||
else if (slot_tx_usrp % tdd_period == first_tx_slot + num_UL_slots - 1)
|
||||
flags = TX_BURST_END;
|
||||
else if (slot_tx_usrp % tdd_period > first_tx_slot)
|
||||
flags = TX_BURST_MIDDLE;
|
||||
int slot_tx_usrp = proc->nr_slot_tx;
|
||||
uint8_t num_UL_slots = nrofUplinkSlots + (nrofUplinkSymbols != 0);
|
||||
uint8_t first_tx_slot = tdd_period - num_UL_slots;
|
||||
|
||||
if (slot_tx_usrp % tdd_period == first_tx_slot)
|
||||
flags = TX_BURST_START;
|
||||
else if (slot_tx_usrp % tdd_period == first_tx_slot + num_UL_slots - 1)
|
||||
flags = TX_BURST_END;
|
||||
else if (slot_tx_usrp % tdd_period > first_tx_slot)
|
||||
flags = TX_BURST_MIDDLE;
|
||||
}
|
||||
} else {
|
||||
flags = TX_BURST_MIDDLE;
|
||||
}
|
||||
@@ -547,10 +606,10 @@ static void RU_write(nr_rxtx_thread_data_t *rxtxD) {
|
||||
proc->timestamp_tx,
|
||||
txp,
|
||||
rxtxD->writeBlockSize,
|
||||
UE->frame_parms.nb_antennas_tx,
|
||||
fp->nb_antennas_tx,
|
||||
flags),"");
|
||||
|
||||
for (int i=0; i<UE->frame_parms.nb_antennas_tx; i++)
|
||||
for (int i=0; i<fp->nb_antennas_tx; i++)
|
||||
memset(txp[i], 0, rxtxD->writeBlockSize);
|
||||
|
||||
}
|
||||
@@ -561,45 +620,76 @@ void processSlotTX(void *arg) {
|
||||
UE_nr_rxtx_proc_t *proc = &rxtxD->proc;
|
||||
PHY_VARS_NR_UE *UE = rxtxD->UE;
|
||||
nr_phy_data_tx_t phy_data = {0};
|
||||
int sl_tx_action = 0;
|
||||
|
||||
LOG_D(PHY,"%d.%d => slot type %d\n", proc->frame_tx, proc->nr_slot_tx, proc->tx_slot_type);
|
||||
if (proc->tx_slot_type == NR_UPLINK_SLOT || proc->tx_slot_type == NR_MIXED_SLOT){
|
||||
|
||||
// wait for rx slots to send indication (if any) that DLSCH decoding is finished
|
||||
for(int i=0; i < rxtxD->tx_wait_for_dlsch; i++) {
|
||||
notifiedFIFO_elt_t *res = pullNotifiedFIFO(UE->tx_resume_ind_fifo[proc->nr_slot_tx]);
|
||||
delNotifiedFIFO_elt(res);
|
||||
}
|
||||
if (proc->tx_slot_type == NR_SIDELINK_SLOT && UE->sl_mode == 2) {
|
||||
|
||||
// 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) {
|
||||
// trigger L2 to run ue_scheduler thru IF module
|
||||
if(UE->if_inst != NULL && UE->if_inst->sl_indication != NULL) {
|
||||
start_meas(&UE->ue_ul_indication_stats);
|
||||
nr_uplink_indication_t ul_indication;
|
||||
memset((void*)&ul_indication, 0, sizeof(ul_indication));
|
||||
nr_sidelink_indication_t sl_indication;
|
||||
memset((void*)&sl_indication, 0, sizeof(sl_indication));
|
||||
|
||||
ul_indication.module_id = UE->Mod_id;
|
||||
ul_indication.gNB_index = proc->gNB_id;
|
||||
ul_indication.cc_id = UE->CC_id;
|
||||
ul_indication.frame_rx = proc->frame_rx;
|
||||
ul_indication.slot_rx = proc->nr_slot_rx;
|
||||
ul_indication.frame_tx = proc->frame_tx;
|
||||
ul_indication.slot_tx = proc->nr_slot_tx;
|
||||
ul_indication.phy_data = &phy_data;
|
||||
sl_indication.module_id = UE->Mod_id;
|
||||
sl_indication.gNB_index = proc->gNB_id;
|
||||
sl_indication.cc_id = UE->CC_id;
|
||||
sl_indication.frame_rx = proc->frame_rx;
|
||||
sl_indication.slot_rx = proc->nr_slot_rx;
|
||||
sl_indication.frame_tx = proc->frame_tx;
|
||||
sl_indication.slot_tx = proc->nr_slot_tx;
|
||||
sl_indication.phy_data = &phy_data;
|
||||
sl_indication.slot_type = SIDELINK_SLOT_TYPE_TX;
|
||||
|
||||
UE->if_inst->ul_indication(&ul_indication);
|
||||
UE->if_inst->sl_indication(&sl_indication);
|
||||
stop_meas(&UE->ue_ul_indication_stats);
|
||||
}
|
||||
|
||||
phy_procedures_nrUE_TX(UE, proc, &phy_data);
|
||||
sl_tx_action = phy_procedures_nrUE_SL_TX(UE, proc, &phy_data);
|
||||
|
||||
} else {
|
||||
if (proc->tx_slot_type == NR_UPLINK_SLOT || proc->tx_slot_type == NR_MIXED_SLOT){
|
||||
|
||||
// wait for rx slots to send indication (if any) that DLSCH decoding is finished
|
||||
for(int i=0; i < rxtxD->tx_wait_for_dlsch; i++) {
|
||||
notifiedFIFO_elt_t *res = pullNotifiedFIFO(UE->tx_resume_ind_fifo[proc->nr_slot_tx]);
|
||||
delNotifiedFIFO_elt(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;
|
||||
memset((void*)&ul_indication, 0, sizeof(ul_indication));
|
||||
|
||||
ul_indication.module_id = UE->Mod_id;
|
||||
ul_indication.gNB_index = proc->gNB_id;
|
||||
ul_indication.cc_id = UE->CC_id;
|
||||
ul_indication.frame_rx = proc->frame_rx;
|
||||
ul_indication.slot_rx = proc->nr_slot_rx;
|
||||
ul_indication.frame_tx = proc->frame_tx;
|
||||
ul_indication.slot_tx = proc->nr_slot_tx;
|
||||
ul_indication.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);
|
||||
}
|
||||
}
|
||||
|
||||
RU_write(rxtxD);
|
||||
RU_write(rxtxD, sl_tx_action);
|
||||
}
|
||||
|
||||
nr_phy_data_t UE_dl_preprocessing(PHY_VARS_NR_UE *UE, UE_nr_rxtx_proc_t *proc)
|
||||
{
|
||||
nr_phy_data_t phy_data = {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) {
|
||||
|
||||
@@ -614,34 +704,48 @@ nr_phy_data_t UE_dl_preprocessing(PHY_VARS_NR_UE *UE, 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);
|
||||
}
|
||||
}
|
||||
|
||||
if (proc->rx_slot_type == NR_DOWNLINK_SLOT || proc->rx_slot_type == NR_MIXED_SLOT) {
|
||||
if (UE->sl_mode == 2) {
|
||||
if (proc->rx_slot_type == NR_SIDELINK_SLOT) {
|
||||
|
||||
if(UE->if_inst != NULL && UE->if_inst->dl_indication != NULL) {
|
||||
nr_downlink_indication_t dl_indication;
|
||||
nr_fill_dl_indication(&dl_indication, NULL, NULL, proc, UE, &phy_data);
|
||||
UE->if_inst->dl_indication(&dl_indication);
|
||||
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);
|
||||
}
|
||||
uint64_t a=rdtsc_oai();
|
||||
psbch_pscch_processing(UE, proc, &phy_data);
|
||||
LOG_D(PHY, "In %s: slot %d:%d, time %llu\n", __FUNCTION__, proc->frame_rx, proc->nr_slot_rx, (rdtsc_oai()-a)/3500);
|
||||
}
|
||||
} else {
|
||||
if (proc->rx_slot_type == NR_DOWNLINK_SLOT || proc->rx_slot_type == NR_MIXED_SLOT){
|
||||
|
||||
if(UE->if_inst != NULL && UE->if_inst->dl_indication != NULL) {
|
||||
nr_downlink_indication_t dl_indication;
|
||||
nr_fill_dl_indication(&dl_indication, NULL, NULL, proc, UE, &phy_data);
|
||||
UE->if_inst->dl_indication(&dl_indication);
|
||||
}
|
||||
|
||||
uint64_t a=rdtsc_oai();
|
||||
pbch_pdcch_processing(UE, proc, &phy_data);
|
||||
if (phy_data.dlsch[0].active) {
|
||||
// indicate to tx thread to wait for DLSCH decoding
|
||||
const int ack_nack_slot = (proc->nr_slot_rx + phy_data.dlsch[0].dlsch_config.k1_feedback) % UE->frame_parms.slots_per_frame;
|
||||
UE->tx_wait_for_dlsch[ack_nack_slot]++;
|
||||
}
|
||||
|
||||
LOG_D(PHY, "In %s: slot %d, time %llu\n", __FUNCTION__, proc->nr_slot_rx, (rdtsc_oai()-a)/3500);
|
||||
}
|
||||
|
||||
uint64_t a=rdtsc_oai();
|
||||
pbch_pdcch_processing(UE, proc, &phy_data);
|
||||
if (phy_data.dlsch[0].active) {
|
||||
// indicate to tx thread to wait for DLSCH decoding
|
||||
const int ack_nack_slot = (proc->nr_slot_rx + phy_data.dlsch[0].dlsch_config.k1_feedback) % UE->frame_parms.slots_per_frame;
|
||||
UE->tx_wait_for_dlsch[ack_nack_slot]++;
|
||||
}
|
||||
|
||||
LOG_D(PHY, "In %s: slot %d, time %llu\n", __FUNCTION__, proc->nr_slot_rx, (rdtsc_oai()-a)/3500);
|
||||
ue_ta_procedures(UE, proc->nr_slot_tx, proc->frame_tx);
|
||||
}
|
||||
|
||||
ue_ta_procedures(UE, proc->nr_slot_tx, proc->frame_tx);
|
||||
return phy_data;
|
||||
}
|
||||
|
||||
@@ -651,14 +755,20 @@ 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 == 0)
|
||||
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];
|
||||
int16_t dummy_tx_data[fp->nb_antennas_tx][2*writeBlockSize]; // 2 because the function we call use pairs of int16_t implicitly as complex numbers
|
||||
memset(dummy_tx_data, 0, sizeof(dummy_tx_data));
|
||||
for (int i=0; i<UE->frame_parms.nb_antennas_tx; i++)
|
||||
for (int i=0; i<fp->nb_antennas_tx; i++)
|
||||
dummy_tx[i]=dummy_tx_data[i];
|
||||
|
||||
AssertFatal( writeBlockSize ==
|
||||
@@ -666,37 +776,45 @@ void dummyWrite(PHY_VARS_NR_UE *UE,openair0_timestamp timestamp, int writeBlockS
|
||||
timestamp,
|
||||
dummy_tx,
|
||||
writeBlockSize,
|
||||
UE->frame_parms.nb_antennas_tx,
|
||||
fp->nb_antennas_tx,
|
||||
4),"");
|
||||
|
||||
}
|
||||
|
||||
void readFrame(PHY_VARS_NR_UE *UE, openair0_timestamp *timestamp, bool toTrash) {
|
||||
|
||||
NR_DL_FRAME_PARMS *fp = &UE->frame_parms;
|
||||
int num_frames = 2;
|
||||
//In Sidelink worst case SL-SSB can be sent once in 16 frames
|
||||
if (UE->sl_mode == 2) {
|
||||
fp = &UE->SL_UE_PHY_PARAMS.sl_frame_params;
|
||||
num_frames = SL_NR_PSBCH_REPETITION_IN_FRAMES;
|
||||
}
|
||||
|
||||
void *rxp[NB_ANTENNAS_RX];
|
||||
|
||||
for(int x=0; x<20; x++) { // two frames for initial sync
|
||||
for (int slot=0; slot<UE->frame_parms.slots_per_subframe; slot ++ ) {
|
||||
for (int i=0; i<UE->frame_parms.nb_antennas_rx; i++) {
|
||||
for(int x=0; x< num_frames*NR_NUMBER_OF_SUBFRAMES_PER_FRAME; x++) { // two frames for initial sync
|
||||
for (int slot=0; slot<fp->slots_per_subframe; slot ++ ) {
|
||||
for (int i=0; i<fp->nb_antennas_rx; i++) {
|
||||
if (toTrash)
|
||||
rxp[i]=malloc16(UE->frame_parms.get_samples_per_slot(slot,&UE->frame_parms)*4);
|
||||
rxp[i]=malloc16(fp->get_samples_per_slot(slot,fp)*4);
|
||||
else
|
||||
rxp[i] = ((void *)&UE->common_vars.rxdata[i][0]) +
|
||||
4*((x*UE->frame_parms.samples_per_subframe)+
|
||||
UE->frame_parms.get_samples_slot_timestamp(slot,&UE->frame_parms,0));
|
||||
4*((x*fp->samples_per_subframe)+
|
||||
fp->get_samples_slot_timestamp(slot,fp,0));
|
||||
}
|
||||
|
||||
AssertFatal( UE->frame_parms.get_samples_per_slot(slot,&UE->frame_parms) ==
|
||||
AssertFatal( fp->get_samples_per_slot(slot,fp) ==
|
||||
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), "");
|
||||
fp->get_samples_per_slot(slot,fp),
|
||||
fp->nb_antennas_rx), "");
|
||||
|
||||
if (IS_SOFTMODEM_RFSIM)
|
||||
dummyWrite(UE,*timestamp, UE->frame_parms.get_samples_per_slot(slot,&UE->frame_parms));
|
||||
dummyWrite(UE,*timestamp, fp->get_samples_per_slot(slot,fp));
|
||||
if (toTrash)
|
||||
for (int i=0; i<UE->frame_parms.nb_antennas_rx; i++)
|
||||
for (int i=0; i<fp->nb_antennas_rx; i++)
|
||||
free(rxp[i]);
|
||||
}
|
||||
}
|
||||
@@ -707,21 +825,25 @@ void syncInFrame(PHY_VARS_NR_UE *UE, openair0_timestamp *timestamp) {
|
||||
|
||||
LOG_I(PHY,"Resynchronizing RX by %d samples\n",UE->rx_offset);
|
||||
|
||||
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_IQPLAYER || IS_SOFTMODEM_IQRECORDER) {
|
||||
// Resynchonize by slot (will work with numerology 1 only)
|
||||
for ( int size=UE->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 ;
|
||||
for ( int size=UE->rx_offset ; size > 0 ; size -= fp->samples_per_subframe/2 ) {
|
||||
int unitTransfer=size>fp->samples_per_subframe/2 ? fp->samples_per_subframe/2 : size ;
|
||||
AssertFatal(unitTransfer ==
|
||||
UE->rfdevice.trx_read_func(&UE->rfdevice,
|
||||
timestamp,
|
||||
(void **)UE->common_vars.rxdata,
|
||||
unitTransfer,
|
||||
UE->frame_parms.nb_antennas_rx),"");
|
||||
fp->nb_antennas_rx),"");
|
||||
}
|
||||
} else {
|
||||
*timestamp += UE->frame_parms.get_samples_per_slot(1,&UE->frame_parms);
|
||||
for ( int size=UE->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=UE->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);
|
||||
@@ -730,7 +852,7 @@ void syncInFrame(PHY_VARS_NR_UE *UE, openair0_timestamp *timestamp) {
|
||||
timestamp,
|
||||
(void **)UE->common_vars.rxdata,
|
||||
unitTransfer,
|
||||
UE->frame_parms.nb_antennas_rx),"");
|
||||
fp->nb_antennas_rx),"");
|
||||
*timestamp += unitTransfer; // this does not affect the read but needed for RFSIM write
|
||||
}
|
||||
}
|
||||
@@ -761,6 +883,13 @@ void *UE_thread(void *arg)
|
||||
void *rxp[NB_ANTENNAS_RX];
|
||||
int start_rx_stream = 0;
|
||||
fapi_nr_config_request_t *cfg = &UE->nrUE_config;
|
||||
NR_DL_FRAME_PARMS *fp = &UE->frame_parms;
|
||||
sl_nr_phy_config_request_t *sl_cfg = NULL;
|
||||
int is_sidelink = (UE->sl_mode == 2) ? 1 : 0;
|
||||
if (is_sidelink) {
|
||||
fp = &UE->SL_UE_PHY_PARAMS.sl_frame_params;
|
||||
sl_cfg = &UE->SL_UE_PHY_PARAMS.sl_config;
|
||||
}
|
||||
AssertFatal(0== openair0_device_load(&(UE->rfdevice), &openair0_cfg[0]), "");
|
||||
UE->rfdevice.host_type = RAU_HOST;
|
||||
UE->is_synchronized = 0;
|
||||
@@ -779,7 +908,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;
|
||||
initNotifiedFIFO(&UE->phy_config_ind);
|
||||
|
||||
@@ -790,6 +919,12 @@ void *UE_thread(void *arg)
|
||||
initNotifiedFIFO(UE->tx_resume_ind_fifo[i]);
|
||||
}
|
||||
|
||||
if (get_nrUE_params()->sync_ref &&
|
||||
UE->sl_mode == 2) {
|
||||
UE->is_synchronized = 1;
|
||||
start_rx_stream = -1;
|
||||
}
|
||||
|
||||
while (!oai_exit) {
|
||||
|
||||
if (syncRunning) {
|
||||
@@ -798,7 +933,8 @@ void *UE_thread(void *arg)
|
||||
if (res) {
|
||||
syncRunning=false;
|
||||
if (UE->is_synchronized) {
|
||||
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_I(PHY,"UE synchronized decoded_frame_rx=%d UE->init_sync_frame=%d trashed_frames=%d\n",
|
||||
decoded_frame_rx,
|
||||
UE->init_sync_frame,
|
||||
@@ -817,7 +953,7 @@ void *UE_thread(void *arg)
|
||||
}
|
||||
} else {
|
||||
readFrame(UE, ×tamp, true);
|
||||
trashed_frames+=2;
|
||||
trashed_frames+=((UE->sl_mode)?SL_NR_PSBCH_REPETITION_IN_FRAMES:2);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
@@ -843,21 +979,25 @@ void *UE_thread(void *arg)
|
||||
UE->rx_offset=0;
|
||||
UE->time_sync_cell=0;
|
||||
// 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,
|
||||
×tamp,
|
||||
(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;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
absolute_slot++;
|
||||
|
||||
int slot_nr = absolute_slot % nb_slot_frame;
|
||||
@@ -869,23 +1009,28 @@ 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.frame_rx, curMsg.proc.nr_slot_rx);
|
||||
curMsg.proc.tx_slot_type = nr_ue_slot_select(cfg, curMsg.proc.frame_tx, curMsg.proc.nr_slot_tx);
|
||||
if (is_sidelink) {
|
||||
curMsg.proc.rx_slot_type = sl_nr_ue_slot_select(sl_cfg, curMsg.proc.frame_rx, curMsg.proc.nr_slot_rx, TDD);
|
||||
curMsg.proc.tx_slot_type = sl_nr_ue_slot_select(sl_cfg, curMsg.proc.frame_tx, curMsg.proc.nr_slot_tx, TDD);
|
||||
} else {
|
||||
curMsg.proc.rx_slot_type = nr_ue_slot_select(cfg, curMsg.proc.frame_rx, curMsg.proc.nr_slot_rx);
|
||||
curMsg.proc.tx_slot_type = nr_ue_slot_select(cfg, curMsg.proc.frame_tx, curMsg.proc.nr_slot_tx);
|
||||
}
|
||||
}
|
||||
else {
|
||||
curMsg.proc.rx_slot_type = NR_DOWNLINK_SLOT;
|
||||
curMsg.proc.tx_slot_type = NR_DOWNLINK_SLOT;
|
||||
}
|
||||
|
||||
int firstSymSamp = get_firstSymSamp(slot_nr, &UE->frame_parms);
|
||||
for (int i=0; i<UE->frame_parms.nb_antennas_rx; i++)
|
||||
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+
|
||||
UE->frame_parms.get_samples_slot_timestamp(slot_nr,&UE->frame_parms,0)];
|
||||
fp->get_samples_slot_timestamp(slot_nr,fp,0)];
|
||||
|
||||
int readBlockSize, writeBlockSize;
|
||||
|
||||
readBlockSize = get_readBlockSize(slot_nr, &UE->frame_parms);
|
||||
writeBlockSize = UE->frame_parms.get_samples_per_slot((slot_nr + DURATION_RX_TO_TX) % nb_slot_frame, &UE->frame_parms);
|
||||
readBlockSize = get_readBlockSize(slot_nr, fp);
|
||||
writeBlockSize = fp->get_samples_per_slot((slot_nr + DURATION_RX_TO_TX) % nb_slot_frame, fp);
|
||||
if (UE->apply_timing_offset && (slot_nr == nb_slot_frame - 1)) {
|
||||
const int sampShift = -(UE->rx_offset>>1);
|
||||
readBlockSize -= sampShift;
|
||||
@@ -898,11 +1043,11 @@ void *UE_thread(void *arg)
|
||||
×tamp,
|
||||
rxp,
|
||||
readBlockSize,
|
||||
UE->frame_parms.nb_antennas_rx),"");
|
||||
fp->nb_antennas_rx),"");
|
||||
|
||||
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;
|
||||
@@ -911,14 +1056,14 @@ void *UE_thread(void *arg)
|
||||
&ignore_timestamp,
|
||||
(void **)UE->common_vars.rxdata,
|
||||
first_symbols,
|
||||
UE->frame_parms.nb_antennas_rx),"");
|
||||
fp->nb_antennas_rx),"");
|
||||
} else
|
||||
LOG_E(PHY,"can't compensate: diff =%d\n", first_symbols);
|
||||
}
|
||||
|
||||
// use previous timing_advance value to compute writeTimestamp
|
||||
writeTimestamp = timestamp +
|
||||
UE->frame_parms.get_samples_slot_timestamp(slot_nr,&UE->frame_parms,DURATION_RX_TO_TX)
|
||||
fp->get_samples_slot_timestamp(slot_nr,fp,DURATION_RX_TO_TX)
|
||||
- firstSymSamp - openair0_cfg[0].tx_sample_advance -
|
||||
UE->N_TA_offset - timing_advance;
|
||||
|
||||
@@ -973,6 +1118,9 @@ void init_NR_UE(int nb_inst,
|
||||
AssertFatal((mac_inst = nr_l2_init_ue(rrc_inst)) != NULL, "can not initialize L2 module\n");
|
||||
AssertFatal((mac_inst->if_module = nr_ue_if_module_init(inst)) != NULL, "can not initialize IF module\n");
|
||||
}
|
||||
if (get_softmodem_params()->sl_mode) {
|
||||
configure_NR_SL_Preconfig(0, get_nrUE_params()->sync_ref);
|
||||
}
|
||||
}
|
||||
|
||||
void init_NR_UE_threads(int nb_inst) {
|
||||
|
||||
@@ -312,13 +312,15 @@ void set_options(int CC_id, PHY_VARS_NR_UE *UE){
|
||||
|
||||
}
|
||||
|
||||
void init_openair0(void) {
|
||||
void init_openair0(bool is_sidelink) {
|
||||
int card;
|
||||
int freq_off = 0;
|
||||
NR_DL_FRAME_PARMS *frame_parms = &PHY_vars_UE_g[0][0]->frame_parms;
|
||||
if (is_sidelink)
|
||||
frame_parms = &PHY_vars_UE_g[0][0]->SL_UE_PHY_PARAMS.sl_frame_params;
|
||||
|
||||
for (card=0; card<MAX_CARDS; card++) {
|
||||
uint64_t dl_carrier, ul_carrier, sl_carrier;
|
||||
uint64_t dl_carrier, ul_carrier;
|
||||
openair0_cfg[card].configFilename = NULL;
|
||||
openair0_cfg[card].threequarter_fs = frame_parms->threequarter_fs;
|
||||
openair0_cfg[card].sample_rate = frame_parms->samples_per_subframe * 1e3;
|
||||
@@ -344,15 +346,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;
|
||||
@@ -532,10 +533,26 @@ int main( int argc, char **argv ) {
|
||||
*mac->scc->downlinkConfigCommon->frequencyInfoDL->frequencyBandList.list.array[0]);
|
||||
}
|
||||
|
||||
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");
|
||||
nr_UE_configure_Sidelink(0, get_nrUE_params()->sync_ref);
|
||||
DevAssert(mac->if_module != NULL && mac->if_module->sl_phy_config_request != NULL);
|
||||
sl_nr_ue_phy_params_t *sl_phy = &UE[CC_id]->SL_UE_PHY_PARAMS;
|
||||
mac->if_module->sl_phy_config_request(&mac->SL_MAC_PARAMS->sl_phy_config);
|
||||
nr_init_frame_parms_ue_sl(&sl_phy->sl_frame_params,&sl_phy->sl_config,
|
||||
get_nrUE_params()->threequarter_fs,
|
||||
get_nrUE_params()->ofdm_offset_divisor);
|
||||
sl_ue_phy_init(UE[CC_id]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
init_openair0();
|
||||
bool is_sl = (get_softmodem_params()->sl_mode) ? 1 : 0;
|
||||
|
||||
init_openair0(is_sl);
|
||||
// init UE_PF_PO and mutex lock
|
||||
pthread_mutex_init(&ue_pf_po_mutex, NULL);
|
||||
memset (&UE_PF_PO[0][0], 0, sizeof(UE_PF_PO_t)*NUMBER_OF_UE_MAX*MAX_NUM_CCs);
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#define CONFIG_HLP_DLSCH_PARA "number of threads for dlsch processing 0 for no parallelization\n"
|
||||
#define CONFIG_HLP_OFFSET_DIV "Divisor for computing OFDM symbol offset in Rx chain (num samples in CP/<the value>). Default value is 8. To set the sample offset to 0, set this value ~ 10e6\n"
|
||||
#define CONFIG_HLP_MAX_LDPC_ITERATIONS "Maximum LDPC decoder iterations\n"
|
||||
#define CONFIG_HLP_SL_SYNCSOURCEUE "Sidelink UE acts as SYNC REF UE"
|
||||
/***************************************************************************************************************************************/
|
||||
/* 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 */
|
||||
@@ -61,6 +62,7 @@
|
||||
{"chest-time", CONFIG_HLP_CHESTTIME, 0, .iptr=&(nrUE_params.chest_time), .defintval=0, TYPE_INT, 0}, \
|
||||
{"ue-timing-correction-disable", CONFIG_HLP_DISABLETIMECORR, PARAMFLAG_BOOL, .iptr=&(nrUE_params.no_timing_correction), .defintval=0, TYPE_INT, 0}, \
|
||||
{"SLC", CONFIG_HLP_SLF, 0, .u64ptr=&(sidelink_frequency[0][0]), .defuintval=2600000000,TYPE_UINT64,0}, \
|
||||
{"sync-ref", CONFIG_HLP_SL_SYNCSOURCEUE, PARAMFLAG_BOOL, .uptr=&(nrUE_params.sync_ref), .defuintval=0, TYPE_UINT32, 0}, \
|
||||
}
|
||||
// clang-format on
|
||||
|
||||
@@ -82,6 +84,7 @@ typedef struct {
|
||||
int threequarter_fs;
|
||||
int N_RB_DL;
|
||||
int ssb_start_subcarrier;
|
||||
uint32_t sync_ref;
|
||||
} nrUE_params_t;
|
||||
extern uint64_t get_nrUE_optmask(void);
|
||||
extern uint64_t set_nrUE_optmask(uint64_t bitmask);
|
||||
|
||||
@@ -351,7 +351,7 @@ typedef struct
|
||||
uint16_t sl_bandwidth;
|
||||
//Absolute frequency of SL point A in KHz
|
||||
//n38 (2570-2620 Mhz), n47 (5855-5925 Mhz) are defined.
|
||||
uint32_t sl_frequency;
|
||||
uint64_t sl_frequency;
|
||||
|
||||
//Only 1 SCS-SpecificCarrier allowed for NR-SL communication
|
||||
uint16_t sl_grid_size;// bandwidth for each numerology
|
||||
@@ -363,7 +363,7 @@ typedef struct
|
||||
uint8_t sl_frequency_shift_7p5khz;
|
||||
//Indicates presence of +/-5Khz shift wrt FREF for V2X reference frequencies.
|
||||
//Possible values: {-1,0,1}
|
||||
uint8_t sl_value_N;
|
||||
int8_t sl_value_N;
|
||||
|
||||
} sl_nr_carrier_config_t;
|
||||
|
||||
|
||||
@@ -304,6 +304,7 @@ void nr_polar_rm_interleaving_cb(void *in, void *out, uint16_t E)
|
||||
static inline void polar_rate_matching(const t_nrPolar_params *polarParams,void *in,void *out) __attribute__((always_inline));
|
||||
|
||||
static inline void polar_rate_matching(const t_nrPolar_params *polarParams,void *in,void *out) {
|
||||
int i = 0;
|
||||
|
||||
// handle rate matching with a single 128 bit word using bit shuffling
|
||||
// can be done with SIMD intrisics if needed
|
||||
@@ -343,15 +344,20 @@ static inline void polar_rate_matching(const t_nrPolar_params *polarParams,void
|
||||
}
|
||||
// These are based on LUTs for byte and short word groups
|
||||
else if (polarParams->groupsize == 8)
|
||||
for (int i=0; i<polarParams->encoderLength>>3; i++) ((uint8_t *)out)[i] = ((uint8_t *)in)[polarParams->rm_tab[i]];
|
||||
for (i=0; i<polarParams->encoderLength>>3; i++) ((uint8_t *)out)[i] = ((uint8_t *)in)[polarParams->rm_tab[i]];
|
||||
else // groupsize==16
|
||||
for (int i=0; i<polarParams->encoderLength>>4; i++) {
|
||||
for (i=0; i<polarParams->encoderLength>>4; i++) {
|
||||
((uint16_t *)out)[i] = ((uint16_t *)in)[polarParams->rm_tab[i]];
|
||||
}
|
||||
|
||||
if (polarParams->i_bil == 1) {
|
||||
nr_polar_rm_interleaving_cb(out, out, polarParams->encoderLength);
|
||||
}
|
||||
// handle remaining bits which do not fill a full group
|
||||
for(i=i*polarParams->groupsize; i<polarParams->encoderLength; i++) {
|
||||
uint8_t pi = polarParams->rate_matching_pattern[i];
|
||||
((uint8_t *)out)[i>>3] |= ( ((((uint8_t *)in)[pi >> 3] >> (pi & 7)) & 1) << (i&7));
|
||||
}
|
||||
}
|
||||
|
||||
void build_polar_tables(t_nrPolar_params *polarParams) {
|
||||
@@ -448,8 +454,8 @@ void build_polar_tables(t_nrPolar_params *polarParams) {
|
||||
}
|
||||
#ifdef DEBUG_POLAR_ENCODER
|
||||
groupcnt++;
|
||||
#endif
|
||||
if ((ccnt+1)<mingroupsize) mingroupsize=ccnt+1;
|
||||
#endif
|
||||
//if ((ccnt+1)<mingroupsize) mingroupsize=ccnt+1;
|
||||
#ifdef DEBUG_POLAR_ENCODER
|
||||
printf("group %d (size %d): (%d:%d) => (%d:%d)\n",groupcnt,ccnt+1,
|
||||
firstingroup_in,firstingroup_in+ccnt,
|
||||
@@ -477,8 +483,7 @@ void build_polar_tables(t_nrPolar_params *polarParams) {
|
||||
break;
|
||||
}
|
||||
|
||||
polarParams->rm_tab = (int *)malloc(sizeof(int) * (polarParams->encoderLength >> shift));
|
||||
|
||||
polarParams->rm_tab=(int *)malloc(sizeof(int)*((polarParams->encoderLength+mingroupsize-1)/mingroupsize));
|
||||
// rerun again to create groups
|
||||
int tcnt = 0;
|
||||
for (int outpos = 0; outpos < polarParams->encoderLength; outpos += mingroupsize, tcnt++)
|
||||
@@ -707,7 +712,7 @@ void polar_encoder_fast(uint64_t *A,
|
||||
printf("\n");
|
||||
#endif
|
||||
|
||||
memset((void*)out,0,polarParams->encoderLength>>3);
|
||||
memset((void*)out,0,(polarParams->encoderLength + 7)>>3);
|
||||
polar_rate_matching(polarParams,(void *)D, out);
|
||||
|
||||
#ifdef POLAR_CODING_DEBUG
|
||||
|
||||
57
openair1/PHY/CODING/nrPolar_tools/nr_polar_psbch_defs.h
Normal file
57
openair1/PHY/CODING/nrPolar_tools/nr_polar_psbch_defs.h
Normal file
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
/*! \file /PHY/CODING/nrPolar_tools/nr_polar_psbch_defs.h
|
||||
\brief Polar definitions required for Sidelink PSBCH
|
||||
\author
|
||||
\date
|
||||
\version
|
||||
\company: Fraunhofer
|
||||
\email:
|
||||
\note
|
||||
\warning
|
||||
*/
|
||||
|
||||
#ifndef __NR_POLAR_PSBCH_DEFS__H__
|
||||
#define __NR_POLAR_PSBCH_DEFS__H__
|
||||
|
||||
//PSBCH related polar parameters.
|
||||
|
||||
//PSBCH symbols sent in 11RBS, 9 symbols. 11*9*(12-3(for DMRS))*2bits = 1782 bits
|
||||
#define SL_NR_POLAR_PSBCH_E_NORMAL_CP 1782
|
||||
//PSBCH symbols sent in 11RBS, 7 symbols. 11*7*(12-3(for DMRS))*2bits = 1386 bits
|
||||
#define SL_NR_POLAR_PSBCH_E_EXT_CP 1386
|
||||
// SL_NR_POLAR_PSBCH_E_NORMAL_CP/32
|
||||
#define SL_NR_POLAR_PSBCH_E_DWORD 56
|
||||
|
||||
#define SL_NR_POLAR_PSBCH_MESSAGE_TYPE (NR_POLAR_UCI_PUCCH_MESSAGE_TYPE + 1)
|
||||
#define SL_NR_POLAR_PSBCH_PAYLOAD_BITS 32
|
||||
#define SL_NR_POLAR_PSBCH_AGGREGATION_LEVEL 0
|
||||
#define SL_NR_POLAR_PSBCH_N_MAX 9
|
||||
#define SL_NR_POLAR_PSBCH_I_IL 1
|
||||
#define SL_NR_POLAR_PSBCH_I_SEG 0
|
||||
#define SL_NR_POLAR_PSBCH_N_PC 0
|
||||
#define SL_NR_POLAR_PSBCH_N_PC_WM 0
|
||||
#define SL_NR_POLAR_PSBCH_I_BIL 0
|
||||
#define SL_NR_POLAR_PSBCH_CRC_PARITY_BITS 24
|
||||
#define SL_NR_POLAR_PSBCH_CRC_ERROR_CORRECTION_BITS 3
|
||||
|
||||
#endif
|
||||
@@ -32,6 +32,7 @@
|
||||
|
||||
#include "PHY/CODING/nrPolar_tools/nr_polar_defs.h"
|
||||
#include "PHY/NR_TRANSPORT/nr_dci.h"
|
||||
#include "nrPolar_tools/nr_polar_psbch_defs.h"
|
||||
|
||||
#define PolarKey ((messageType<<24)|(messageLength<<8)|aggregation_level)
|
||||
static t_nrPolar_params * PolarList=NULL;
|
||||
@@ -194,7 +195,19 @@ t_nrPolar_params *nr_polar_params(int8_t messageType, uint16_t messageLength, ui
|
||||
newPolarInitNode->payloadBits = messageLength;
|
||||
newPolarInitNode->crcCorrectionBits = NR_POLAR_PUCCH_CRC_ERROR_CORRECTION_BITS;
|
||||
//LOG_D(PHY,"New polar node, encoderLength %d, aggregation_level %d\n",newPolarInitNode->encoderLength,aggregation_level);
|
||||
|
||||
} else if (messageType == SL_NR_POLAR_PSBCH_MESSAGE_TYPE) { //PSBCH
|
||||
newPolarInitNode->n_max = SL_NR_POLAR_PSBCH_N_MAX;
|
||||
newPolarInitNode->i_il = SL_NR_POLAR_PSBCH_I_IL;
|
||||
newPolarInitNode->i_seg = SL_NR_POLAR_PSBCH_I_SEG;
|
||||
newPolarInitNode->n_pc = SL_NR_POLAR_PSBCH_N_PC;
|
||||
newPolarInitNode->n_pc_wm = SL_NR_POLAR_PSBCH_N_PC_WM;
|
||||
newPolarInitNode->i_bil = SL_NR_POLAR_PSBCH_I_BIL;
|
||||
newPolarInitNode->crcParityBits = SL_NR_POLAR_PSBCH_CRC_PARITY_BITS;
|
||||
newPolarInitNode->payloadBits = SL_NR_POLAR_PSBCH_PAYLOAD_BITS;
|
||||
newPolarInitNode->encoderLength = SL_NR_POLAR_PSBCH_E_NORMAL_CP;
|
||||
newPolarInitNode->crcCorrectionBits = SL_NR_POLAR_PSBCH_CRC_ERROR_CORRECTION_BITS;
|
||||
newPolarInitNode->crc_generator_matrix = crc24c_generator_matrix(newPolarInitNode->payloadBits);//G_P
|
||||
LOG_D(PHY,"SIDELINK: Initializing polar parameters for PSBCH (K %d, E %d)\n",newPolarInitNode->payloadBits,newPolarInitNode->encoderLength);
|
||||
} else {
|
||||
AssertFatal(1 == 0, "[nr_polar_init] Incorrect Message Type(%d)", messageType);
|
||||
}
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
#include "PHY/MODULATION/nr_modulation.h"
|
||||
#include "openair2/COMMON/prs_nr_paramdef.h"
|
||||
#include "SCHED_NR_UE/harq_nr.h"
|
||||
#include "PHY/NR_REFSIG/nr_mod_table.h"
|
||||
|
||||
void RCconfig_nrUE_prs(void *cfg)
|
||||
{
|
||||
@@ -296,8 +297,12 @@ int init_nr_ue_signal(PHY_VARS_NR_UE *ue, int nb_connected_gNB)
|
||||
// init RX buffers
|
||||
common_vars->rxdata = malloc16(fp->nb_antennas_rx * sizeof(c16_t *));
|
||||
|
||||
int num_samples = 2 * fp->samples_per_frame + fp->ofdm_symbol_size;
|
||||
if (ue->sl_mode == 2)
|
||||
num_samples = (SL_NR_PSBCH_REPETITION_IN_FRAMES * fp->samples_per_frame) + fp->ofdm_symbol_size;
|
||||
|
||||
for (i=0; i<fp->nb_antennas_rx; i++) {
|
||||
common_vars->rxdata[i] = malloc16_clear((2 * (fp->samples_per_frame) + fp->ofdm_symbol_size) * sizeof(c16_t));
|
||||
common_vars->rxdata[i] = malloc16_clear(num_samples * sizeof(c16_t));
|
||||
}
|
||||
|
||||
// ceil(((NB_RB<<1)*3)/32) // 3 RE *2(QPSK)
|
||||
@@ -384,6 +389,15 @@ int init_nr_ue_signal(PHY_VARS_NR_UE *ue, int nb_connected_gNB)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sl_ue_free(PHY_VARS_NR_UE *UE) {
|
||||
|
||||
if (UE->SL_UE_PHY_PARAMS.init_params.sl_pss_for_correlation) {
|
||||
free_and_zero(UE->SL_UE_PHY_PARAMS.init_params.sl_pss_for_correlation[0]);
|
||||
free_and_zero(UE->SL_UE_PHY_PARAMS.init_params.sl_pss_for_correlation[1]);
|
||||
free_and_zero(UE->SL_UE_PHY_PARAMS.init_params.sl_pss_for_correlation);
|
||||
}
|
||||
}
|
||||
|
||||
void term_nr_ue_signal(PHY_VARS_NR_UE *ue, int nb_connected_gNB)
|
||||
{
|
||||
const NR_DL_FRAME_PARMS* fp = &ue->frame_parms;
|
||||
@@ -489,6 +503,8 @@ void term_nr_ue_signal(PHY_VARS_NR_UE *ue, int nb_connected_gNB)
|
||||
|
||||
free_and_zero(ue->prs_vars[idx]);
|
||||
}
|
||||
|
||||
sl_ue_free(ue);
|
||||
}
|
||||
|
||||
void free_nr_ue_dl_harq(NR_DL_UE_HARQ_t harq_list[2][NR_MAX_DLSCH_HARQ_PROCESSES], int number_of_processes, int num_rb) {
|
||||
@@ -634,7 +650,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
|
||||
@@ -686,3 +703,246 @@ void phy_term_nr_top(void)
|
||||
free_ul_reference_signal_sequences();
|
||||
free_context_synchro_nr();
|
||||
}
|
||||
|
||||
static void sl_init_psbch_dmrs_gold_sequences(PHY_VARS_NR_UE *UE)
|
||||
{
|
||||
unsigned int x1, x2;
|
||||
uint16_t slss_id;
|
||||
uint8_t reset;
|
||||
|
||||
for (slss_id = 0; slss_id < SL_NR_NUM_SLSS_IDs; slss_id++) {
|
||||
|
||||
reset = 1;
|
||||
x2 = slss_id;
|
||||
|
||||
#ifdef SL_DEBUG_INIT
|
||||
printf("\nPSBCH DMRS GOLD SEQ for SLSSID :%d :\n", slss_id);
|
||||
#endif
|
||||
|
||||
for (uint8_t n=0; n<SL_NR_NUM_PSBCH_DMRS_RE_DWORD; n++) {
|
||||
UE->SL_UE_PHY_PARAMS.init_params.psbch_dmrs_gold_sequences[slss_id][n] = lte_gold_generic(&x1, &x2, reset);
|
||||
reset = 0;
|
||||
|
||||
#ifdef SL_DEBUG_INIT_DATA
|
||||
printf("%x\n",SL_UE_INIT_PARAMS.sl_psbch_dmrs_gold_sequences[slss_id][n]);
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void sl_generate_psbch_dmrs_qpsk_sequences(PHY_VARS_NR_UE *UE,
|
||||
struct complex16 *modulated_dmrs_sym,
|
||||
uint16_t slss_id) {
|
||||
|
||||
uint8_t idx = 0;
|
||||
uint32_t *sl_dmrs_sequence = UE->SL_UE_PHY_PARAMS.init_params.psbch_dmrs_gold_sequences[slss_id];
|
||||
|
||||
#ifdef SL_DEBUG_INIT
|
||||
printf("SIDELINK INIT: PSBCH DMRS Generation with slss_id:%d\n", slss_id);
|
||||
#endif
|
||||
|
||||
/// QPSK modulation
|
||||
for (int m=0; m<SL_NR_NUM_PSBCH_DMRS_RE; m++) {
|
||||
|
||||
idx = (((sl_dmrs_sequence[(m<<1)>>5])>>((m<<1)&0x1f))&3);
|
||||
modulated_dmrs_sym[m].r = nr_qpsk_mod_table[2*idx];
|
||||
modulated_dmrs_sym[m].i = nr_qpsk_mod_table[(2*idx) + 1];
|
||||
|
||||
#ifdef SL_DEBUG_INIT_DATA
|
||||
printf("m:%d gold seq: %d b0-b1: %d-%d DMRS Symbols: %d %d\n", m, sl_dmrs_sequence[(m<<1)>>5], (((sl_dmrs_sequence[(m<<1)>>5])>>((m<<1)&0x1f))&1),
|
||||
(((sl_dmrs_sequence[((m<<1)+1)>>5])>>(((m<<1)+1)&0x1f))&1), modulated_dmrs_sym[m].r, modulated_dmrs_sym[m].i);
|
||||
printf("idx:%d, qpsk_table.r:%d, qpsk_table.i:%d\n", idx, nr_qpsk_mod_table[2*idx], nr_qpsk_mod_table[(2*idx) + 1]);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef SL_DUMP_INIT_SAMPLES
|
||||
char filename[40], varname[25];
|
||||
sprintf(filename,"sl_psbch_dmrs_slssid_%d.m", slss_id);
|
||||
sprintf(varname,"sl_dmrs_id_%d.m", slss_id);
|
||||
LOG_M(filename, varname, (void*)modulated_dmrs_sym, SL_NR_NUM_PSBCH_DMRS_RE, 1, 1);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
||||
static void sl_generate_pss(SL_NR_UE_INIT_PARAMS_t *sl_init_params, uint8_t n_sl_id2, uint16_t scaling) {
|
||||
|
||||
int i = 0, m = 0;
|
||||
int16_t x[SL_NR_PSS_SEQUENCE_LENGTH];
|
||||
const int x_initial[7] = {0, 1, 1 , 0, 1, 1, 1};
|
||||
int16_t *sl_pss = sl_init_params->sl_pss[n_sl_id2];
|
||||
int16_t *sl_pss_for_sync = sl_init_params->sl_pss_for_sync[n_sl_id2];
|
||||
|
||||
LOG_D(PHY, "SIDELINK PSBCH INIT: PSS Generation with N_SL_id2:%d\n", n_sl_id2);
|
||||
|
||||
#ifdef SL_DEBUG_INIT
|
||||
printf("SIDELINK: PSS Generation with N_SL_id2:%d\n", n_sl_id2);
|
||||
#endif
|
||||
|
||||
/// Sequence generation
|
||||
for (i=0; i < 7; i++)
|
||||
x[i] = x_initial[i];
|
||||
|
||||
for (i=0; i < (SL_NR_PSS_SEQUENCE_LENGTH - 7); i++) {
|
||||
x[i+7] = (x[i + 4] + x[i]) %2;
|
||||
}
|
||||
|
||||
for (i=0; i < SL_NR_PSS_SEQUENCE_LENGTH; i++) {
|
||||
m = (i + 22 + 43*n_sl_id2) % SL_NR_PSS_SEQUENCE_LENGTH;
|
||||
sl_pss_for_sync[i] = (1 - 2*x[m]);
|
||||
sl_pss[i] = sl_pss_for_sync[i] * scaling;
|
||||
|
||||
#ifdef SL_DEBUG_INIT_DATA
|
||||
printf("m:%d, sl_pss[%d]:%d\n", m, i, sl_pss[i]);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#ifdef SL_DUMP_INIT_SAMPLES
|
||||
LOG_M("sl_pss_seq.m", "sl_pss", (void*)sl_pss, SL_NR_PSS_SEQUENCE_LENGTH, 1, 0);
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
static void sl_generate_sss(SL_NR_UE_INIT_PARAMS_t *sl_init_params, uint16_t slss_id, uint16_t scaling) {
|
||||
|
||||
int i = 0;
|
||||
int m0, m1;
|
||||
int n_sl_id1, n_sl_id2;
|
||||
int16_t *sl_sss = sl_init_params->sl_sss[slss_id];
|
||||
int16_t *sl_sss_for_sync = sl_init_params->sl_sss_for_sync[slss_id];
|
||||
|
||||
int16_t x0[SL_NR_SSS_SEQUENCE_LENGTH], x1[SL_NR_SSS_SEQUENCE_LENGTH];
|
||||
const int x_initial[7] = { 1, 0, 0, 0, 0, 0, 0 };
|
||||
|
||||
n_sl_id1 = slss_id % 336;
|
||||
n_sl_id2 = slss_id / 336;
|
||||
|
||||
LOG_D(PHY, "SIDELINK INIT: SSS Generation with N_SL_id1:%d N_SL_id2:%d\n", n_sl_id1, n_sl_id2);
|
||||
|
||||
#ifdef SL_DEBUG_INIT
|
||||
printf("SIDELINK: SSS Generation with slss_id:%d, N_SL_id1:%d, N_SL_id2:%d\n", slss_id, n_sl_id1, n_sl_id2);
|
||||
#endif
|
||||
|
||||
for ( i=0 ; i < 7 ; i++) {
|
||||
x0[i] = x_initial[i];
|
||||
x1[i] = x_initial[i];
|
||||
}
|
||||
|
||||
for ( i=0 ; i < SL_NR_SSS_SEQUENCE_LENGTH - 7 ; i++) {
|
||||
x0[i+7] = (x0[i + 4] + x0[i]) % 2;
|
||||
x1[i+7] = (x1[i + 1] + x1[i]) % 2;
|
||||
}
|
||||
|
||||
m0 = 15*(n_sl_id1/112) + (5*n_sl_id2);
|
||||
m1 = n_sl_id1 % 112;
|
||||
|
||||
for (i = 0; i < SL_NR_SSS_SEQUENCE_LENGTH ; i++) {
|
||||
sl_sss_for_sync[i] = (1 - 2*x0[(i + m0) % SL_NR_SSS_SEQUENCE_LENGTH] ) * (1 - 2*x1[(i + m1) % SL_NR_SSS_SEQUENCE_LENGTH] );
|
||||
sl_sss[i] = sl_sss_for_sync[i] * scaling;
|
||||
|
||||
#ifdef SL_DEBUG_INIT_DATA
|
||||
printf("m0:%d, m1:%d, sl_sss_for_sync[%d]:%d, sl_sss[%d]:%d\n", m0, m1, i, sl_sss_for_sync[i], i, sl_sss[i]);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#ifdef SL_DUMP_PSBCH_TX_SAMPLES
|
||||
LOG_M("sl_sss_seq.m", "sl_sss", (void*)sl_sss, SL_NR_SSS_SEQUENCE_LENGTH, 1, 0);
|
||||
LOG_M("sl_sss_forsync_seq.m", "sl_sss_for_sync", (void*)sl_sss_for_sync, SL_NR_SSS_SEQUENCE_LENGTH, 1, 0);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
// This cannot be done at init time as ofdm symbol size, ssb start subcarrier depends on configuration
|
||||
// done at SLSS read time.
|
||||
static void sl_generate_pss_ifft_samples(sl_nr_ue_phy_params_t *sl_ue_params, SL_NR_UE_INIT_PARAMS_t *sl_init_params) {
|
||||
|
||||
uint8_t id2 = 0;
|
||||
int16_t *sl_pss = NULL;
|
||||
NR_DL_FRAME_PARMS *sl_fp = &sl_ue_params->sl_frame_params;
|
||||
int16_t scaling_factor = AMP;
|
||||
|
||||
int16_t *pss_F = NULL; // IQ samples in freq domain
|
||||
int32_t *pss_T = NULL;
|
||||
|
||||
uint16_t k = 0;
|
||||
|
||||
pss_F = malloc16_clear(2*sizeof(int16_t) * sl_fp->ofdm_symbol_size);
|
||||
|
||||
LOG_I(PHY, "SIDELINK INIT: Generation of PSS time domain samples. scaling_factor:%d\n", scaling_factor);
|
||||
|
||||
for (id2 = 0; id2 < SL_NR_NUM_IDs_IN_PSS; id2++) {
|
||||
|
||||
k = sl_fp->first_carrier_offset + sl_fp->ssb_start_subcarrier + 2; // PSS in from REs 2-129
|
||||
if (k >= sl_fp->ofdm_symbol_size) k -= sl_fp->ofdm_symbol_size;
|
||||
|
||||
pss_T = &sl_init_params->sl_pss_for_correlation[id2][0];
|
||||
sl_pss = sl_init_params->sl_pss[id2];
|
||||
|
||||
memset(pss_T, 0, sl_fp->ofdm_symbol_size * sizeof(pss_T[0]));
|
||||
memset(pss_F, 0, sl_fp->ofdm_symbol_size * 2 * sizeof(pss_F[0]));
|
||||
|
||||
for (int i=0; i < SL_NR_PSS_SEQUENCE_LENGTH; i++) {
|
||||
|
||||
pss_F[2*k] = (sl_pss[i] * scaling_factor) >> 15;
|
||||
//pss_F[2*k] = (sl_pss[i]/23170) * 4192;
|
||||
//pss_F[2*k+1] = 0;
|
||||
|
||||
#ifdef SL_DEBUG_INIT_DATA
|
||||
printf("id:%d, k:%d, pss_F[%d]:%d, sl_pss[%d]:%d\n", id2, k, 2*k, pss_F[2*k], i, sl_pss[i]);
|
||||
#endif
|
||||
|
||||
k++;
|
||||
if (k == sl_fp->ofdm_symbol_size) k=0;
|
||||
|
||||
}
|
||||
|
||||
idft((int16_t)get_idft(sl_fp->ofdm_symbol_size),
|
||||
pss_F, /* complex input */
|
||||
(int16_t *)&pss_T[0], /* complex output */
|
||||
1); /* scaling factor */
|
||||
|
||||
}
|
||||
|
||||
#ifdef SL_DUMP_PSBCH_TX_SAMPLES
|
||||
LOG_M("sl_pss_TD_id0.m", "pss_TD_0", (void*)sl_init_params->sl_pss_for_correlation[0], sl_fp->ofdm_symbol_size, 1, 1);
|
||||
LOG_M("sl_pss_TD_id1.m", "pss_TD_1", (void*)sl_init_params->sl_pss_for_correlation[1], sl_fp->ofdm_symbol_size, 1, 1);
|
||||
#endif
|
||||
|
||||
free(pss_F);
|
||||
|
||||
}
|
||||
|
||||
void sl_ue_phy_init(PHY_VARS_NR_UE *UE) {
|
||||
|
||||
uint16_t scaling_value = ONE_OVER_SQRT2_Q15;
|
||||
|
||||
NR_DL_FRAME_PARMS *sl_fp = &UE->SL_UE_PHY_PARAMS.sl_frame_params;
|
||||
|
||||
if (!UE->SL_UE_PHY_PARAMS.init_params.sl_pss_for_correlation) {
|
||||
UE->SL_UE_PHY_PARAMS.init_params.sl_pss_for_correlation = (int32_t **)malloc16_clear(SL_NR_NUM_IDs_IN_PSS *sizeof(int32_t *) );
|
||||
UE->SL_UE_PHY_PARAMS.init_params.sl_pss_for_correlation[0] = (int32_t *)malloc16_clear( sizeof(int32_t)*sl_fp->ofdm_symbol_size);
|
||||
UE->SL_UE_PHY_PARAMS.init_params.sl_pss_for_correlation[1] = (int32_t *)malloc16_clear( sizeof(int32_t)*sl_fp->ofdm_symbol_size);
|
||||
}
|
||||
LOG_I(PHY, "SIDELINK INIT: GENERATE PSS, SSS, GOLD SEQUENCES AND PSBCH DMRS SEQUENCES FOR ALL possible SLSS IDs 0- 671\n");
|
||||
|
||||
// Generate PSS sequences for IDs 0,1 used in PSS
|
||||
sl_generate_pss(&UE->SL_UE_PHY_PARAMS.init_params,0, scaling_value);
|
||||
sl_generate_pss(&UE->SL_UE_PHY_PARAMS.init_params,1, scaling_value);
|
||||
|
||||
// Generate psbch dmrs Gold Sequences and modulated dmrs symbols
|
||||
sl_init_psbch_dmrs_gold_sequences(UE);
|
||||
for (int slss_id = 0; slss_id < SL_NR_NUM_SLSS_IDs; slss_id++) {
|
||||
sl_generate_psbch_dmrs_qpsk_sequences(UE, UE->SL_UE_PHY_PARAMS.init_params.psbch_dmrs_modsym[slss_id], slss_id);
|
||||
sl_generate_sss(&UE->SL_UE_PHY_PARAMS.init_params, slss_id, scaling_value);
|
||||
}
|
||||
|
||||
// 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);
|
||||
|
||||
}
|
||||
@@ -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};
|
||||
@@ -42,18 +43,6 @@ static const int nr_ssb_table[48][3] = {
|
||||
{93, 15, nr_ssb_type_A}, {94, 15, nr_ssb_type_A}, {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))
|
||||
@@ -115,23 +104,27 @@ void set_scs_parameters (NR_DL_FRAME_PARMS *fp, int mu, int N_RB_DL)
|
||||
case NR_MU_0: //15kHz scs
|
||||
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)
|
||||
idx++;
|
||||
AssertFatal(nr_ssb_table[idx][1]==15,"SCS %d not applicable to band %d\n",
|
||||
fp->subcarrier_spacing,fp->nr_band);
|
||||
if (fp->nr_band != 47) {
|
||||
fp->ssb_type = nr_ssb_type_A;
|
||||
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",
|
||||
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);
|
||||
idx++;
|
||||
if (fp->nr_band != 47) {
|
||||
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];
|
||||
}
|
||||
fp->ssb_type = nr_ssb_table[idx][2];
|
||||
break;
|
||||
|
||||
case NR_MU_2: //60kHz scs
|
||||
@@ -164,9 +157,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_W(PHY,"Init: N_RB_DL %d, first_carrier_offset %d, nb_prefix_samples %d,nb_prefix_samples0 %d, ofdm_symbol_size %d\n",
|
||||
@@ -299,11 +289,6 @@ int nr_init_frame_parms_ue(NR_DL_FRAME_PARMS *fp,
|
||||
LOG_D(PHY,"dl_bw_kHz %lu\n",dl_bw_khz);
|
||||
LOG_D(PHY,"dl_CarrierFreq %lu\n",fp->dl_CarrierFreq);
|
||||
|
||||
if (get_softmodem_params()->sl_mode == 2) {
|
||||
uint64_t sl_bw_khz = (12 * config->carrier_config.sl_grid_size[config->ssb_config.scs_common]) * (15 << config->ssb_config.scs_common);
|
||||
fp->sl_CarrierFreq = ((sl_bw_khz >> 1) + config->carrier_config.sl_frequency) * 1000;
|
||||
}
|
||||
|
||||
uint64_t ul_bw_khz = (12*config->carrier_config.ul_grid_size[config->ssb_config.scs_common])*(15<<config->ssb_config.scs_common);
|
||||
fp->ul_CarrierFreq = ((ul_bw_khz>>1) + config->carrier_config.uplink_frequency)*1000 ;
|
||||
|
||||
@@ -329,7 +314,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;
|
||||
@@ -354,10 +339,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;
|
||||
@@ -407,12 +388,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);
|
||||
@@ -426,7 +401,109 @@ void nr_dump_frame_parms(NR_DL_FRAME_PARMS *fp)
|
||||
LOG_I(PHY,"fp->samples_per_frame=%d\n",fp->samples_per_frame);
|
||||
LOG_I(PHY,"fp->dl_CarrierFreq=%lu\n",fp->dl_CarrierFreq);
|
||||
LOG_I(PHY,"fp->ul_CarrierFreq=%lu\n",fp->ul_CarrierFreq);
|
||||
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 = config->sl_carrier_config.sl_num_rx_ant;
|
||||
fp->att_tx = config->sl_carrier_config.sl_num_tx_ant;
|
||||
fp->nb_antennas_rx = fp->att_rx;
|
||||
fp->nb_antennas_tx = fp->att_tx;
|
||||
|
||||
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)*1000 ;
|
||||
fp->sl_CarrierFreq += (deltashift >> 1);
|
||||
fp->dl_CarrierFreq = fp->sl_CarrierFreq;
|
||||
fp->ul_CarrierFreq = fp->dl_CarrierFreq + uplink_frequency_offset;
|
||||
|
||||
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: band %d, uldl offset %d Hz\n",
|
||||
fp->dl_CarrierFreq, fp->ul_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);
|
||||
|
||||
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->dl_CarrierFreq < 6e9)? nr_FR1 : nr_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;
|
||||
|
||||
|
||||
init_symbol_rotation(fp);
|
||||
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;
|
||||
|
||||
//#ifdef SL_DEBUG
|
||||
LOG_I(PHY, "Dumping Sidelink Frame Parameters\n");
|
||||
nr_dump_frame_parms(fp);
|
||||
//#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -29,7 +29,10 @@ int nr_get_ssb_start_symbol(NR_DL_FRAME_PARMS *fp,uint8_t i_ssb);
|
||||
int 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);
|
||||
@@ -56,5 +59,6 @@ void free_nr_ue_ul_harq(NR_UL_UE_HARQ_t harq_list[NR_MAX_ULSCH_HARQ_PROCESSES],
|
||||
|
||||
void phy_init_nr_top(PHY_VARS_NR_UE *ue);
|
||||
void phy_term_nr_top(void);
|
||||
void sl_ue_phy_init(PHY_VARS_NR_UE *UE);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -49,9 +49,17 @@ int slot_fep(PHY_VARS_UE *phy_vars_ue,
|
||||
int reset_freq_est);
|
||||
|
||||
int nr_slot_fep(PHY_VARS_NR_UE *ue,
|
||||
NR_DL_FRAME_PARMS *frame_parms,
|
||||
UE_nr_rxtx_proc_t *proc,
|
||||
unsigned char symbol,
|
||||
c16_t rxdataF[][ue->frame_parms.samples_per_slot_wCP]);
|
||||
c16_t rxdataF[][frame_parms->samples_per_slot_wCP],
|
||||
uint32_t linktype);
|
||||
int sl_nr_slot_fep(PHY_VARS_NR_UE *ue,
|
||||
UE_nr_rxtx_proc_t *proc,
|
||||
unsigned char symbol,
|
||||
unsigned char Ns,
|
||||
uint32_t sample_offset,
|
||||
c16_t rxdataF[][ue->SL_UE_PHY_PARAMS.sl_frame_params.samples_per_slot_wCP]);
|
||||
|
||||
int nr_slot_fep_init_sync(PHY_VARS_NR_UE *ue,
|
||||
UE_nr_rxtx_proc_t *proc,
|
||||
|
||||
@@ -601,7 +601,7 @@ 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};
|
||||
double f[3] = {(double)dl_CarrierFreq, (double)ul_CarrierFreq, (double)sl_CarrierFreq};
|
||||
|
||||
const int nsymb = fp->symbols_per_slot * fp->slots_per_frame/10;
|
||||
const double Tc=(1/480e3/4096);
|
||||
@@ -609,15 +609,12 @@ void init_symbol_rotation(NR_DL_FRAME_PARMS *fp) {
|
||||
const double Ncp0=16*64 + (144*64*(1/(float)(1<<fp->numerology_index)));
|
||||
const double Ncp1=(144*64*(1/(float)(1<<fp->numerology_index)));
|
||||
|
||||
for (uint8_t ll = 0; ll < 2; ll++){
|
||||
for (uint8_t ll = 0; ll < 3; ll++){
|
||||
|
||||
double f0 = f[ll];
|
||||
if (f0 == 0) continue;
|
||||
LOG_D(PHY, "Doing symbol rotation calculation for gNB TX/RX, f0 %f Hz, Nsymb %d\n", f0, nsymb);
|
||||
c16_t *symbol_rotation = fp->symbol_rotation[ll];
|
||||
if (get_softmodem_params()->sl_mode == 2) {
|
||||
f0 = (double)sl_CarrierFreq;
|
||||
symbol_rotation = fp->symbol_rotation[link_type_sl];
|
||||
}
|
||||
|
||||
double tl = 0.0;
|
||||
double poff = 0.0;
|
||||
|
||||
@@ -34,12 +34,107 @@
|
||||
#define LOG_I(A,B...) printf(A)
|
||||
#endif*/
|
||||
|
||||
int nr_slot_fep(PHY_VARS_NR_UE *ue,
|
||||
int sl_nr_slot_fep(PHY_VARS_NR_UE *ue,
|
||||
UE_nr_rxtx_proc_t *proc,
|
||||
unsigned char symbol,
|
||||
c16_t rxdataF[][ue->frame_parms.samples_per_slot_wCP])
|
||||
unsigned char Ns,
|
||||
uint32_t sample_offset,
|
||||
c16_t rxdataF[][ue->SL_UE_PHY_PARAMS.sl_frame_params.samples_per_slot_wCP])
|
||||
{
|
||||
NR_DL_FRAME_PARMS *frame_parms = &ue->frame_parms;
|
||||
NR_DL_FRAME_PARMS *frame_params = &ue->SL_UE_PHY_PARAMS.sl_frame_params;
|
||||
NR_UE_COMMON *common_vars = &ue->common_vars;
|
||||
|
||||
AssertFatal(symbol < frame_params->symbols_per_slot, "slot_fep: symbol must be between 0 and %d\n", frame_params->symbols_per_slot-1);
|
||||
AssertFatal(Ns < frame_params->slots_per_frame, "slot_fep: Ns must be between 0 and %d\n", frame_params->slots_per_frame-1);
|
||||
|
||||
unsigned int nb_prefix_samples = frame_params->nb_prefix_samples;
|
||||
unsigned int nb_prefix_samples0 = frame_params->nb_prefix_samples0;
|
||||
|
||||
|
||||
dft_size_idx_t dftsize = get_dft(frame_params->ofdm_symbol_size);
|
||||
// This is for misalignment issues
|
||||
int32_t tmp_dft_in[8192] __attribute__ ((aligned (32)));
|
||||
|
||||
unsigned int rx_offset = frame_params->get_samples_slot_timestamp(Ns,frame_params,0);
|
||||
unsigned int abs_symbol = Ns * frame_params->symbols_per_slot + symbol;
|
||||
|
||||
rx_offset += sample_offset;
|
||||
rx_offset += ue->rx_offset;
|
||||
|
||||
for (int idx_symb = Ns*frame_params->symbols_per_slot; idx_symb <= abs_symbol; idx_symb++)
|
||||
rx_offset += (idx_symb%(0x7<<frame_params->numerology_index)) ? nb_prefix_samples : nb_prefix_samples0;
|
||||
rx_offset += frame_params->ofdm_symbol_size * symbol;
|
||||
|
||||
// use OFDM symbol from within 1/8th of the CP to avoid ISI
|
||||
rx_offset -= (nb_prefix_samples / frame_params->ofdm_offset_divisor);
|
||||
|
||||
#ifdef SL_DEBUG_SLOT_FEP
|
||||
// if (ue->frame <100)
|
||||
LOG_I(PHY, "slot_fep: slot %d, symbol %d, nb_prefix_samples %u, nb_prefix_samples0 %u, rx_offset %u\n",
|
||||
Ns, symbol, nb_prefix_samples, nb_prefix_samples0, rx_offset);
|
||||
#endif
|
||||
|
||||
for (unsigned char aa=0; aa<frame_params->nb_antennas_rx; aa++) {
|
||||
memset(&rxdataF[aa][frame_params->ofdm_symbol_size*symbol],0,frame_params->ofdm_symbol_size*sizeof(int32_t));
|
||||
|
||||
int16_t *rxdata_ptr = (int16_t *)&common_vars->rxdata[aa][rx_offset];
|
||||
|
||||
// if input to dft is not 256-bit aligned
|
||||
if ((rx_offset & 7) != 0) {
|
||||
memcpy((void *)&tmp_dft_in[0],
|
||||
(void *)&common_vars->rxdata[aa][rx_offset],
|
||||
frame_params->ofdm_symbol_size * sizeof(int32_t));
|
||||
|
||||
rxdata_ptr = (int16_t *)tmp_dft_in;
|
||||
}
|
||||
|
||||
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];
|
||||
((int16_t*)&rot2)[1]=-((int16_t*)&rot2)[1];
|
||||
|
||||
#ifdef SL_DEBUG_SLOT_FEP
|
||||
// if (ue->frame <100)
|
||||
LOG_I(PHY, "slot_fep: slot %d, symbol %d rx_offset %u, rotation symbol %d %d.%d\n", Ns,symbol, rx_offset,
|
||||
symbol+symb_offset,((int16_t*)&rot2)[0],((int16_t*)&rot2)[1]);
|
||||
#endif
|
||||
|
||||
rotate_cpx_vector((c16_t *)&rxdataF[aa][frame_params->ofdm_symbol_size*symbol],
|
||||
(c16_t *)&rot2,
|
||||
(c16_t *)&rxdataF[aa][frame_params->ofdm_symbol_size*symbol],
|
||||
frame_params->ofdm_symbol_size,
|
||||
15);
|
||||
|
||||
int16_t *shift_rot = (int16_t *)frame_params->timeshift_symbol_rotation;
|
||||
|
||||
multadd_cpx_vector((int16_t *)&rxdataF[aa][frame_params->ofdm_symbol_size*symbol],
|
||||
shift_rot,
|
||||
(int16_t *)&rxdataF[aa][frame_params->ofdm_symbol_size*symbol],
|
||||
1,
|
||||
frame_params->ofdm_symbol_size,
|
||||
15);
|
||||
}
|
||||
|
||||
|
||||
|
||||
LOG_D(PHY, "SIDELINK RX: Slot FEP: done for symbol:%d\n", symbol);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nr_slot_fep(PHY_VARS_NR_UE *ue,
|
||||
NR_DL_FRAME_PARMS *frame_parms,
|
||||
UE_nr_rxtx_proc_t *proc,
|
||||
unsigned char symbol,
|
||||
c16_t rxdataF[][frame_parms->samples_per_slot_wCP],
|
||||
uint32_t linktype)
|
||||
{
|
||||
|
||||
NR_UE_COMMON *common_vars = &ue->common_vars;
|
||||
int Ns = proc->nr_slot_rx;
|
||||
|
||||
@@ -98,7 +193,7 @@ int nr_slot_fep(PHY_VARS_NR_UE *ue,
|
||||
|
||||
apply_nr_rotation_RX(frame_parms,
|
||||
rxdataF[aa],
|
||||
frame_parms->symbol_rotation[0],
|
||||
frame_parms->symbol_rotation[linktype],
|
||||
Ns,
|
||||
frame_parms->N_RB_DL,
|
||||
0,
|
||||
|
||||
@@ -197,22 +197,30 @@ int nr_pdcch_dmrs_rx(PHY_VARS_NR_UE *ue,
|
||||
|
||||
int nr_pbch_dmrs_rx(int symbol,
|
||||
unsigned int *nr_gold_pbch,
|
||||
int32_t *output)
|
||||
int32_t *output,
|
||||
bool sidelink)
|
||||
{
|
||||
int m,m0,m1;
|
||||
uint8_t idx=0;
|
||||
AssertFatal(symbol>=0 && symbol <3,"illegal symbol %d\n",symbol);
|
||||
if (symbol == 0) {
|
||||
m0=0;
|
||||
m1=60;
|
||||
}
|
||||
else if (symbol == 1) {
|
||||
m0=60;
|
||||
m1=84;
|
||||
}
|
||||
else {
|
||||
m0=84;
|
||||
m1=144;
|
||||
if (sidelink) {
|
||||
AssertFatal(symbol== 0 || (symbol>=5 && symbol <=12),"illegal symbol %d\n",symbol);
|
||||
m0 = (symbol) ? (symbol - 4) * 33 : 0;
|
||||
m1 = (symbol) ? (symbol - 3) * 33 : 33;
|
||||
|
||||
} else {
|
||||
AssertFatal(symbol>=0 && symbol <3,"illegal symbol %d\n",symbol);
|
||||
if (symbol == 0) {
|
||||
m0=0;
|
||||
m1=60;
|
||||
}
|
||||
else if (symbol == 1) {
|
||||
m0=60;
|
||||
m1=84;
|
||||
}
|
||||
else {
|
||||
m0=84;
|
||||
m1=144;
|
||||
}
|
||||
}
|
||||
// printf("Generating pilots symbol %d, m0 %d, m1 %d\n",symbol,m0,m1);
|
||||
/// QPSK modulation
|
||||
|
||||
@@ -33,7 +33,8 @@
|
||||
*/
|
||||
int nr_pbch_dmrs_rx(int dmrss,
|
||||
unsigned int *nr_gold_pbch,
|
||||
int32_t *output);
|
||||
int32_t *output,
|
||||
bool sidelink);
|
||||
|
||||
/*!\brief This function generates the NR Gold sequence (38-211, Sec 5.2.1) for the PDCCH DMRS.
|
||||
@param PHY_VARS_NR_UE* ue structure provides configuration, frame parameters and the pointers to the 32 bits sequence storage tables
|
||||
|
||||
@@ -608,7 +608,7 @@ int nr_pbch_dmrs_correlation(PHY_VARS_NR_UE *ue,
|
||||
#endif
|
||||
|
||||
// generate pilot
|
||||
nr_pbch_dmrs_rx(dmrss,ue->nr_gold_pbch[n_hf][ssb_index], &pilot[0]);
|
||||
nr_pbch_dmrs_rx(dmrss,ue->nr_gold_pbch[n_hf][ssb_index], &pilot[0],0);
|
||||
|
||||
for (int aarx=0; aarx<ue->frame_parms.nb_antennas_rx; aarx++) {
|
||||
|
||||
@@ -729,15 +729,18 @@ int nr_pbch_dmrs_correlation(PHY_VARS_NR_UE *ue,
|
||||
}
|
||||
|
||||
int nr_pbch_channel_estimation(PHY_VARS_NR_UE *ue,
|
||||
NR_DL_FRAME_PARMS *fp,
|
||||
int estimateSz,
|
||||
struct complex16 dl_ch_estimates[][estimateSz],
|
||||
struct complex16 dl_ch_estimates_time[][ue->frame_parms.ofdm_symbol_size],
|
||||
struct complex16 dl_ch_estimates_time[][fp->ofdm_symbol_size],
|
||||
UE_nr_rxtx_proc_t *proc,
|
||||
unsigned char symbol,
|
||||
int dmrss,
|
||||
uint8_t ssb_index,
|
||||
uint8_t n_hf,
|
||||
c16_t rxdataF[][ue->frame_parms.samples_per_slot_wCP])
|
||||
c16_t rxdataF[][fp->samples_per_slot_wCP],
|
||||
bool sidelink,
|
||||
uint16_t Nid)
|
||||
{
|
||||
int Ns = proc->nr_slot_rx;
|
||||
int pilot[200] __attribute__((aligned(16)));
|
||||
@@ -748,25 +751,48 @@ int nr_pbch_channel_estimation(PHY_VARS_NR_UE *ue,
|
||||
int ch_offset,symbol_offset;
|
||||
//int slot_pbch;
|
||||
|
||||
uint8_t nushift;
|
||||
nushift = ue->frame_parms.Nid_cell%4;
|
||||
ue->frame_parms.nushift = nushift;
|
||||
unsigned int ssb_offset = ue->frame_parms.first_carrier_offset + ue->frame_parms.ssb_start_subcarrier;
|
||||
if (ssb_offset>= ue->frame_parms.ofdm_symbol_size) ssb_offset-=ue->frame_parms.ofdm_symbol_size;
|
||||
uint8_t nushift = 0, lastsymbol = 0;
|
||||
|
||||
ch_offset = ue->frame_parms.ofdm_symbol_size*symbol;
|
||||
uint32_t *gold_seq = NULL;
|
||||
|
||||
AssertFatal(dmrss >= 0 && dmrss < 3,
|
||||
if (sidelink) {
|
||||
|
||||
AssertFatal(dmrss == 0 || (dmrss >= 5 && dmrss <= 12),
|
||||
"symbol %d is illegal for PSBCH DM-RS \n",
|
||||
dmrss);
|
||||
|
||||
sl_nr_ue_phy_params_t *sl_phy_params = &ue->SL_UE_PHY_PARAMS;
|
||||
|
||||
LOG_D(PHY,"PSBCH Channel Estimation SLSSID:%d\n", Nid);
|
||||
|
||||
gold_seq = sl_phy_params->init_params.psbch_dmrs_gold_sequences[Nid];
|
||||
lastsymbol = 12;
|
||||
|
||||
} else {
|
||||
|
||||
nushift = fp->Nid_cell%4;
|
||||
fp->nushift = nushift;
|
||||
|
||||
AssertFatal(dmrss >= 0 && dmrss < 3,
|
||||
"symbol %d is illegal for PBCH DM-RS \n",
|
||||
dmrss);
|
||||
|
||||
symbol_offset = ue->frame_parms.ofdm_symbol_size*symbol;
|
||||
gold_seq = ue->nr_gold_pbch[n_hf][ssb_index];
|
||||
lastsymbol = 2;
|
||||
}
|
||||
|
||||
unsigned int ssb_offset = fp->first_carrier_offset + fp->ssb_start_subcarrier;
|
||||
if (ssb_offset>= fp->ofdm_symbol_size) ssb_offset-= fp->ofdm_symbol_size;
|
||||
|
||||
ch_offset = fp->ofdm_symbol_size*symbol;
|
||||
|
||||
symbol_offset = fp->ofdm_symbol_size*symbol;
|
||||
|
||||
|
||||
k = nushift;
|
||||
|
||||
#ifdef DEBUG_PBCH
|
||||
printf("PBCH Channel Estimation : gNB_id %d ch_offset %d, OFDM size %d, Ncp=%d, Ns=%d, k=%d symbol %d\n", proc->gNB_id, ch_offset, ue->frame_parms.ofdm_symbol_size, ue->frame_parms.Ncp, Ns, k, symbol);
|
||||
printf("PBCH Channel Estimation : gNB_id %d ch_offset %d, OFDM size %d, Ncp=%d, Ns=%d, k=%d symbol %d\n", proc->gNB_id, ch_offset, fp->ofdm_symbol_size, fp->Ncp, Ns, k, symbol);
|
||||
#endif
|
||||
|
||||
switch (k) {
|
||||
@@ -802,7 +828,7 @@ int nr_pbch_channel_estimation(PHY_VARS_NR_UE *ue,
|
||||
|
||||
idft_size_idx_t idftsizeidx;
|
||||
|
||||
switch (ue->frame_parms.ofdm_symbol_size) {
|
||||
switch (fp->ofdm_symbol_size) {
|
||||
case 128:
|
||||
idftsizeidx = IDFT_128;
|
||||
break;
|
||||
@@ -849,20 +875,20 @@ int nr_pbch_channel_estimation(PHY_VARS_NR_UE *ue,
|
||||
}
|
||||
|
||||
// generate pilot
|
||||
nr_pbch_dmrs_rx(dmrss,ue->nr_gold_pbch[n_hf][ssb_index], &pilot[0]);
|
||||
nr_pbch_dmrs_rx(dmrss,gold_seq, &pilot[0], sidelink);
|
||||
|
||||
for (int aarx=0; aarx<ue->frame_parms.nb_antennas_rx; aarx++) {
|
||||
for (int aarx=0; aarx<fp->nb_antennas_rx; aarx++) {
|
||||
|
||||
int re_offset = ssb_offset;
|
||||
pil = (int16_t *)&pilot[0];
|
||||
rxF = (int16_t *)&rxdataF[aarx][(symbol_offset+k+re_offset)];
|
||||
dl_ch = (int16_t *)&dl_ch_estimates[aarx][ch_offset];
|
||||
|
||||
memset(dl_ch,0,sizeof(struct complex16)*(ue->frame_parms.ofdm_symbol_size));
|
||||
memset(dl_ch,0,sizeof(struct complex16)*(fp->ofdm_symbol_size));
|
||||
|
||||
#ifdef DEBUG_PBCH
|
||||
printf("pbch ch est pilot addr %p RB_DL %d\n",&pilot[0], ue->frame_parms.N_RB_DL);
|
||||
printf("k %d, first_carrier %d\n",k,ue->frame_parms.first_carrier_offset);
|
||||
printf("pbch ch est pilot addr %p RB_DL %d\n",&pilot[0], fp->N_RB_DL);
|
||||
printf("k %d, first_carrier %d\n",k,fp->first_carrier_offset);
|
||||
printf("rxF addr %p\n", rxF);
|
||||
printf("dl_ch addr %p\n",dl_ch);
|
||||
#endif
|
||||
@@ -881,7 +907,7 @@ int nr_pbch_channel_estimation(PHY_VARS_NR_UE *ue,
|
||||
dl_ch,
|
||||
16);
|
||||
pil += 2;
|
||||
re_offset = (re_offset+4) % ue->frame_parms.ofdm_symbol_size;
|
||||
re_offset = (re_offset+4) % fp->ofdm_symbol_size;
|
||||
rxF = (int16_t *)&rxdataF[aarx][(symbol_offset+k+re_offset)];
|
||||
|
||||
//for (int i= 0; i<8; i++)
|
||||
@@ -899,7 +925,7 @@ int nr_pbch_channel_estimation(PHY_VARS_NR_UE *ue,
|
||||
dl_ch,
|
||||
16);
|
||||
pil += 2;
|
||||
re_offset = (re_offset+4) % ue->frame_parms.ofdm_symbol_size;
|
||||
re_offset = (re_offset+4) % fp->ofdm_symbol_size;
|
||||
rxF = (int16_t *)&rxdataF[aarx][(symbol_offset+k+re_offset)];
|
||||
|
||||
ch[0] = (int16_t)(((int32_t)pil[0]*rxF[0] - (int32_t)pil[1]*rxF[1])>>15);
|
||||
@@ -914,7 +940,7 @@ int nr_pbch_channel_estimation(PHY_VARS_NR_UE *ue,
|
||||
dl_ch,
|
||||
16);
|
||||
pil += 2;
|
||||
re_offset = (re_offset+4) % ue->frame_parms.ofdm_symbol_size;
|
||||
re_offset = (re_offset+4) % fp->ofdm_symbol_size;
|
||||
rxF = (int16_t *)&rxdataF[aarx][(symbol_offset+k+re_offset)];
|
||||
dl_ch += 24;
|
||||
|
||||
@@ -926,7 +952,7 @@ int nr_pbch_channel_estimation(PHY_VARS_NR_UE *ue,
|
||||
// in 2nd symbol, skip middle REs (48 with DMRS, 144 for SSS, and another 48 with DMRS)
|
||||
if (dmrss == 1 && pilot_cnt == 12) {
|
||||
pilot_cnt=48;
|
||||
re_offset = (re_offset+144) % ue->frame_parms.ofdm_symbol_size;
|
||||
re_offset = (re_offset+144) % fp->ofdm_symbol_size;
|
||||
rxF = (int16_t *)&rxdataF[aarx][(symbol_offset+k+re_offset)];
|
||||
dl_ch += 288;
|
||||
}
|
||||
@@ -945,7 +971,7 @@ int nr_pbch_channel_estimation(PHY_VARS_NR_UE *ue,
|
||||
// printf("pilot_cnt %d dl_ch %d %d\n", pilot_cnt, dl_ch+i, *(dl_ch+i));
|
||||
|
||||
pil += 2;
|
||||
re_offset = (re_offset+4) % ue->frame_parms.ofdm_symbol_size;
|
||||
re_offset = (re_offset+4) % fp->ofdm_symbol_size;
|
||||
rxF = (int16_t *)&rxdataF[aarx][(symbol_offset+k+re_offset)];
|
||||
|
||||
|
||||
@@ -960,7 +986,7 @@ int nr_pbch_channel_estimation(PHY_VARS_NR_UE *ue,
|
||||
dl_ch,
|
||||
16);
|
||||
pil += 2;
|
||||
re_offset = (re_offset+4) % ue->frame_parms.ofdm_symbol_size;
|
||||
re_offset = (re_offset+4) % fp->ofdm_symbol_size;
|
||||
rxF = (int16_t *)&rxdataF[aarx][(symbol_offset+k+re_offset)];
|
||||
|
||||
ch[0] = (int16_t)(((int32_t)pil[0]*rxF[0] - (int32_t)pil[1]*rxF[1])>>15);
|
||||
@@ -975,13 +1001,13 @@ int nr_pbch_channel_estimation(PHY_VARS_NR_UE *ue,
|
||||
dl_ch,
|
||||
16);
|
||||
pil += 2;
|
||||
re_offset = (re_offset+4) % ue->frame_parms.ofdm_symbol_size;
|
||||
re_offset = (re_offset+4) % fp->ofdm_symbol_size;
|
||||
rxF = (int16_t *)&rxdataF[aarx][(symbol_offset+k+re_offset)];
|
||||
dl_ch += 24;
|
||||
|
||||
}
|
||||
|
||||
if( dmrss == 2) // update time statistics for last PBCH symbol
|
||||
if( dmrss == lastsymbol) // update time statistics for last PBCH symbol
|
||||
{
|
||||
// do ifft of channel estimate
|
||||
LOG_D(PHY,"Channel Impulse Computation Slot %d Symbol %d ch_offset %d\n", Ns, symbol, ch_offset);
|
||||
@@ -992,14 +1018,19 @@ int nr_pbch_channel_estimation(PHY_VARS_NR_UE *ue,
|
||||
}
|
||||
}
|
||||
|
||||
if (dmrss == 2)
|
||||
if (dmrss == lastsymbol) {
|
||||
|
||||
enum scopeDataType typ = (sidelink) ? psbchDlChEstimateTime
|
||||
: pbchDlChEstimateTime;
|
||||
|
||||
UEscopeCopy(ue,
|
||||
pbchDlChEstimateTime,
|
||||
typ,
|
||||
(void *)dl_ch_estimates_time,
|
||||
sizeof(c16_t),
|
||||
ue->frame_parms.nb_antennas_rx,
|
||||
ue->frame_parms.ofdm_symbol_size,
|
||||
fp->nb_antennas_rx,
|
||||
fp->ofdm_symbol_size,
|
||||
0);
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
@@ -68,15 +68,18 @@ int nr_pbch_dmrs_correlation(PHY_VARS_NR_UE *ue,
|
||||
c16_t rxdataF[][ue->frame_parms.samples_per_slot_wCP]);
|
||||
|
||||
int nr_pbch_channel_estimation(PHY_VARS_NR_UE *ue,
|
||||
NR_DL_FRAME_PARMS *fp,
|
||||
int estimateSz,
|
||||
struct complex16 dl_ch_estimates[][estimateSz],
|
||||
struct complex16 dl_ch_estimates_time[][ue->frame_parms.ofdm_symbol_size],
|
||||
struct complex16 dl_ch_estimates_time[][fp->ofdm_symbol_size],
|
||||
UE_nr_rxtx_proc_t *proc,
|
||||
unsigned char symbol,
|
||||
int dmrss,
|
||||
uint8_t ssb_index,
|
||||
uint8_t n_hf,
|
||||
c16_t rxdataF[][ue->frame_parms.samples_per_slot_wCP]);
|
||||
c16_t rxdataF[][fp->samples_per_slot_wCP],
|
||||
bool sidelink,
|
||||
uint16_t Nid);
|
||||
|
||||
int nr_pdsch_channel_estimation(PHY_VARS_NR_UE *ue,
|
||||
UE_nr_rxtx_proc_t *proc,
|
||||
@@ -141,4 +144,9 @@ void nr_pdsch_ptrs_processing(PHY_VARS_NR_UE *ue,
|
||||
|
||||
float_t get_nr_RSRP(module_id_t Mod_id,uint8_t CC_id,uint8_t gNB_index);
|
||||
|
||||
|
||||
void nr_sl_psbch_rsrp_measurements(sl_nr_ue_phy_params_t *sl_phy_params,
|
||||
NR_DL_FRAME_PARMS *fp,
|
||||
c16_t rxdataF[][fp->samples_per_slot_wCP],
|
||||
bool use_SSS);
|
||||
#endif
|
||||
|
||||
@@ -313,3 +313,56 @@ void nr_ue_rrc_measurements(PHY_VARS_NR_UE *ue,
|
||||
ue->measurements.n0_power_tot_dB + 30 - 10*log10(pow(2, 30)) - dB_fixed(ue->frame_parms.ofdm_symbol_size) - ((int)rx_gain - (int)rx_gain_offset));
|
||||
|
||||
}
|
||||
|
||||
//PSBCH RSRP calculations according to 38.215 section 5.1.22
|
||||
void nr_sl_psbch_rsrp_measurements(sl_nr_ue_phy_params_t *sl_phy_params,
|
||||
NR_DL_FRAME_PARMS *fp,
|
||||
c16_t rxdataF[][fp->samples_per_slot_wCP],
|
||||
bool use_SSS)
|
||||
{
|
||||
|
||||
SL_NR_UE_PSBCH_t *psbch_rx = &sl_phy_params->psbch;
|
||||
uint8_t numsym = (fp->Ncp) ? SL_NR_NUM_SYMBOLS_SSB_EXT_CP
|
||||
: SL_NR_NUM_SYMBOLS_SSB_NORMAL_CP;
|
||||
uint32_t re_offset = fp->first_carrier_offset + fp->ssb_start_subcarrier;
|
||||
uint32_t rsrp = 0, num_re = 0;
|
||||
|
||||
LOG_D(PHY, "PSBCH RSRP MEAS: numsym:%d, re_offset:%d\n",numsym, re_offset);
|
||||
|
||||
for (int aarx = 0; aarx < fp->nb_antennas_rx; aarx++) {
|
||||
|
||||
//Calculate PSBCH RSRP based from DMRS REs
|
||||
for (uint8_t symbol=0; symbol<numsym;) {
|
||||
|
||||
struct complex16 *rxF = &rxdataF[aarx][symbol*fp->ofdm_symbol_size];
|
||||
|
||||
for (int re=0;re<SL_NR_NUM_PSBCH_RE_IN_ONE_SYMBOL;re++) {
|
||||
|
||||
if (re%4 == 0) { //DMRS RE
|
||||
uint16_t offset = (re_offset + re) % fp->ofdm_symbol_size;
|
||||
|
||||
rsrp += rxF[offset].r*rxF[offset].r + rxF[offset].i*rxF[offset].i;
|
||||
num_re++;
|
||||
}
|
||||
}
|
||||
symbol = (symbol == 0) ? 5 : symbol+1;
|
||||
}
|
||||
}
|
||||
|
||||
if (use_SSS) {
|
||||
//TBD...
|
||||
//UE can decide between using only PSBCH DMRS or PSBCH DMRS and SSS for PSBCH RSRP computation.
|
||||
//If needed this can be implemented. Reference Spec 38.215
|
||||
}
|
||||
|
||||
psbch_rx->rsrp_dB_per_RE = 10*log10(rsrp / num_re);
|
||||
psbch_rx->rsrp_dBm_per_RE = psbch_rx->rsrp_dB_per_RE +
|
||||
30 - 10*log10(pow(2,30)) -
|
||||
((int)openair0_cfg[0].rx_gain[0] - (int)openair0_cfg[0].rx_gain_offset[0]) -
|
||||
dB_fixed(fp->ofdm_symbol_size);
|
||||
|
||||
|
||||
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, psbch_rx->rsrp_dBm_per_RE);
|
||||
|
||||
}
|
||||
@@ -151,8 +151,8 @@ int nr_pbch_detection(UE_nr_rxtx_proc_t * proc, PHY_VARS_NR_UE *ue, int pbch_ini
|
||||
__attribute__ ((aligned(32))) struct complex16 dl_ch_estimates_time[frame_parms->nb_antennas_rx][frame_parms->ofdm_symbol_size];
|
||||
|
||||
for(int i=pbch_initial_symbol; i<pbch_initial_symbol+3;i++)
|
||||
nr_pbch_channel_estimation(ue,estimateSz, dl_ch_estimates, dl_ch_estimates_time,
|
||||
proc,i,i-pbch_initial_symbol,temp_ptr->i_ssb,temp_ptr->n_hf,rxdataF);
|
||||
nr_pbch_channel_estimation(ue,&ue->frame_parms, estimateSz, dl_ch_estimates, dl_ch_estimates_time,
|
||||
proc,i,i-pbch_initial_symbol,temp_ptr->i_ssb,temp_ptr->n_hf,rxdataF,false, frame_parms->Nid_cell);
|
||||
|
||||
stop_meas(&ue->dlsch_channel_estimation_stats);
|
||||
fapiPbch_t result = {0};
|
||||
|
||||
600
openair1/PHY/NR_UE_TRANSPORT/nr_initial_sync_sl.c
Normal file
600
openair1/PHY/NR_UE_TRANSPORT/nr_initial_sync_sl.c
Normal file
@@ -0,0 +1,600 @@
|
||||
#include "PHY/defs_nr_UE.h"
|
||||
#include "PHY/TOOLS/tools_defs.h"
|
||||
#include "PHY/NR_REFSIG/sss_nr.h"
|
||||
#include "PHY/NR_UE_ESTIMATION/nr_estimation.h"
|
||||
#include "PHY/MODULATION/modulation_UE.h"
|
||||
#include "PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h"
|
||||
#include "SCHED_NR_UE/defs.h"
|
||||
|
||||
//#define SL_DEBUG
|
||||
|
||||
static const int16_t sl_phase_re_nr[PHASE_HYPOTHESIS_NUMBER]
|
||||
// -pi/3 ---- pi/3
|
||||
= {16384, 20173, 23571, 26509, 28932, 30791, 32051, 32687, 32687, 32051, 30791, 28932, 26509, 23571, 20173, 16384};
|
||||
|
||||
static const int16_t sl_phase_im_nr[PHASE_HYPOTHESIS_NUMBER] // -pi/3 ---- pi/3
|
||||
= {-28377, -25821, -22762, -19260, -15383, -11207, -6813, -2286, 2286, 6813, 11207, 15383, 19260, 22762, 25821, 28377};
|
||||
|
||||
|
||||
static int sl_nr_pss_correlation(PHY_VARS_NR_UE *UE, int frame_index)
|
||||
{
|
||||
|
||||
sl_nr_ue_phy_params_t *sl_ue = &UE->SL_UE_PHY_PARAMS;
|
||||
SL_NR_SYNC_PARAMS_t *sync_params = &sl_ue->sync_params;
|
||||
NR_DL_FRAME_PARMS *sl_fp = &UE->SL_UE_PHY_PARAMS.sl_frame_params;
|
||||
int16_t **pss_for_correlation = (int16_t **)sl_ue->init_params.sl_pss_for_correlation;
|
||||
|
||||
int maxval=0;
|
||||
int32_t **rxdata = NULL;
|
||||
unsigned int n, ar, peak_position = 0, pss_source = 0;
|
||||
int64_t peak_value = 0;
|
||||
double ffo_est=0;
|
||||
|
||||
int64_t avg[SL_NR_NUM_IDs_IN_PSS];
|
||||
uint32_t length = (frame_index == 0) ? sl_fp->samples_per_frame + (2 * sl_fp->ofdm_symbol_size) : sl_fp->samples_per_frame;
|
||||
int64_t psss_corr_value = 0;
|
||||
|
||||
rxdata = (int32_t **)UE->common_vars.rxdata;
|
||||
|
||||
#ifdef SL_DEBUG
|
||||
char fname[50], sname[25];
|
||||
sprintf(fname,"rxdata_frame_%d.m",frame_index);
|
||||
sprintf(sname,"rxd_frame%d",frame_index);
|
||||
LOG_M(fname,sname, &rxdata[0][frame_index * sl_fp->samples_per_frame],sl_fp->samples_per_frame,1,1);
|
||||
LOG_M("pss_for_correlation0.m","pss_id0", pss_for_correlation[0],2048,1,1);
|
||||
LOG_M("pss_for_correlation1.m","pss_id1", pss_for_correlation[1],2048,1,1);
|
||||
|
||||
int64_t *pss_corr_debug_values[SL_NR_NUM_IDs_IN_PSS];
|
||||
#endif
|
||||
|
||||
for (int i=0;i<2*(sl_fp->ofdm_symbol_size);i++) {
|
||||
maxval = max(maxval,pss_for_correlation[0][i]);
|
||||
maxval = max(maxval,-pss_for_correlation[0][i]);
|
||||
maxval = max(maxval,pss_for_correlation[1][i]);
|
||||
maxval = max(maxval,-pss_for_correlation[1][i]);
|
||||
}
|
||||
|
||||
int shift = log2_approx(maxval);//*(sl_fp->ofdm_symbol_size + sl_fp->nb_prefix_samples)*2);
|
||||
|
||||
#ifdef SL_DEBUG
|
||||
LOG_I(PHY,"SIDELINK SLSS SEARCH: Function:%s\n", __func__);
|
||||
LOG_I(PHY,"maxval:%d, shift:%d\n", maxval, shift);
|
||||
#endif
|
||||
|
||||
for (int pss_index = 0; pss_index < SL_NR_NUM_IDs_IN_PSS; pss_index++) {
|
||||
avg[pss_index]=0;
|
||||
|
||||
#ifdef SL_DEBUG
|
||||
pss_corr_debug_values[pss_index] = malloc16_clear(length*sizeof(int64_t));
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
for (n=0; n < length - sl_fp->ofdm_symbol_size; n+=4) { //
|
||||
|
||||
for (int pss_index = 0; pss_index < SL_NR_NUM_IDs_IN_PSS; pss_index++) {
|
||||
psss_corr_value = 0;
|
||||
|
||||
|
||||
// calculate dot product of primary_synchro_time_nr and rxdata[ar][n] (ar=0..nb_ant_rx) and store the sum in temp[n];
|
||||
for (ar=0; ar<sl_fp->nb_antennas_rx; ar++) {
|
||||
|
||||
/* perform correlation of rx data and pss sequence ie it is a dot product */
|
||||
const c32_t result = dot_product((c16_t *)pss_for_correlation[pss_index],
|
||||
(c16_t *)&(rxdata[ar][n + frame_index * sl_fp->samples_per_frame]),
|
||||
sl_fp->ofdm_symbol_size,
|
||||
shift);
|
||||
|
||||
const c64_t r64 = {.r = result.r, .i = result.i};
|
||||
psss_corr_value += squaredMod(r64);
|
||||
|
||||
#ifdef SL_DEBUG
|
||||
pss_corr_debug_values[pss_index][n] = psss_corr_value;
|
||||
#endif
|
||||
|
||||
#ifdef SL_DEBUG
|
||||
printf("frame:%d n:%d, pss_index:%d, pss_for_correlation[pss_index][0]:%x, rxdata[n]:%x\n",
|
||||
frame_index, n, pss_index, pss_for_correlation[pss_index][0], rxdata[ar][n + frame_index * sl_fp->samples_per_frame]);
|
||||
printf("result %lld, pss_corr_values[%d][%d]:%ld\n",result, pss_index, n, pss_corr_debug_values[pss_index][n]);
|
||||
printf("pss_index %d: n %6u peak_value %15llu\n", pss_index, n, (unsigned long long)pss_corr_debug_values[pss_index][n]);
|
||||
printf("peak_value:%ld, peak_position:%d, pss_source:%d\n", peak_value, peak_position, pss_source);
|
||||
#endif
|
||||
}
|
||||
|
||||
// calculate the absolute value of sync_corr[n]
|
||||
avg[pss_index] += psss_corr_value;
|
||||
if (psss_corr_value > peak_value) {
|
||||
peak_value = psss_corr_value;
|
||||
peak_position = n;
|
||||
pss_source = pss_index;
|
||||
|
||||
#ifdef SL_DEBUG
|
||||
printf("pss_index %d: n %6u peak_value %15llu\n", pss_index, n, (unsigned long long)psss_corr_value);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef SL_DEBUG
|
||||
LOG_M("pss_corr_debug_values_0.m","pss_corr0", &pss_corr_debug_values[0][0],length,1,6);
|
||||
LOG_M("pss_corr_debug_values_1.m","pss_corr1", &pss_corr_debug_values[1][0],length,1,6);
|
||||
|
||||
for (int pss_index = 0; pss_index < SL_NR_NUM_IDs_IN_PSS; pss_index++) {
|
||||
free(pss_corr_debug_values[pss_index]);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (UE->UE_fo_compensation) { // Not tested
|
||||
|
||||
// fractional frequency offset computation according to Cross-correlation Synchronization Algorithm Using PSS
|
||||
// Shoujun Huang, Yongtao Su, Ying He and Shan Tang, "Joint time and frequency offset estimation in LTE downlink," 7th International Conference on Communications and Networking in China, 2012.
|
||||
|
||||
// Computing cross-correlation at peak on half the symbol size for first half of data
|
||||
c32_t r1 = dot_product((c16_t *)pss_for_correlation[pss_source],
|
||||
(c16_t *)&(rxdata[0][peak_position + frame_index * sl_fp->samples_per_frame]),
|
||||
sl_fp->ofdm_symbol_size>>1,
|
||||
shift);
|
||||
// Computing cross-correlation at peak on half the symbol size for data shifted by half symbol size
|
||||
// as it is real and complex it is necessary to shift by a value equal to symbol size to obtain such shift
|
||||
c32_t r2 = dot_product((c16_t *)pss_for_correlation[pss_source] + (sl_fp->ofdm_symbol_size >> 1),
|
||||
(c16_t *)&(rxdata[0][peak_position + frame_index * sl_fp->samples_per_frame]) + (sl_fp->ofdm_symbol_size >> 1),
|
||||
sl_fp->ofdm_symbol_size >> 1,
|
||||
shift);
|
||||
cd_t r1d = {r1.r, r1.i}, r2d = {r2.r, r2.i};
|
||||
// estimation of fractional frequency offset: angle[(result1)'*(result2)]/pi
|
||||
ffo_est = atan2(r1d.r * r2d.i - r2d.r * r1d.i, r1d.r * r2d.r + r1d.i * r2d.i) / M_PI;
|
||||
|
||||
#ifdef SL_DEBUG
|
||||
printf("ffo %lf\n",ffo_est);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
// computing absolute value of frequency offset
|
||||
sync_params->freq_offset = ffo_est*sl_fp->subcarrier_spacing;
|
||||
UE->common_vars.freq_offset = sync_params->freq_offset;
|
||||
for (int pss_index = 0; pss_index < SL_NR_NUM_IDs_IN_PSS; pss_index++) avg[pss_index]/=(length/4);
|
||||
|
||||
sync_params->N_sl_id2 = pss_source;
|
||||
|
||||
LOG_I(PHY,"PSS Source = %d, Peak found at pos %d, val = %llu (%d dB) avg %d dB, ffo %lf, freq offset:%d Hz\n",
|
||||
pss_source, peak_position, (unsigned long long)peak_value, dB_fixed64(peak_value),dB_fixed64(avg[pss_source]),ffo_est, sync_params->freq_offset);
|
||||
|
||||
if (peak_value < 5*avg[pss_source])
|
||||
return(-1);
|
||||
|
||||
return peak_position;
|
||||
}
|
||||
|
||||
#define SL_NR_MAX_RX_ANTENNA 1
|
||||
#define SL_NR_FIRST_PSS_SYMBOL 1
|
||||
#define SL_NR_FIRST_SSS_SYMBOL 3
|
||||
#define SL_NR_NUM_PSS_SSS_SYMBOLS 4
|
||||
|
||||
static void sl_nr_extract_sss(PHY_VARS_NR_UE *ue, UE_nr_rxtx_proc_t *proc,
|
||||
int32_t *tot_metric, uint8_t *phase_max,
|
||||
c16_t rxdataF[][ue->SL_UE_PHY_PARAMS.sl_frame_params.samples_per_slot_wCP])
|
||||
{
|
||||
|
||||
c16_t pss_ext[SL_NR_MAX_RX_ANTENNA][SL_NR_NUM_PSS_SYMBOLS][SL_NR_PSS_SEQUENCE_LENGTH];
|
||||
c16_t sss_ext[SL_NR_MAX_RX_ANTENNA][SL_NR_NUM_SSS_SYMBOLS][SL_NR_PSS_SEQUENCE_LENGTH];
|
||||
uint8_t Nid2 = ue->SL_UE_PHY_PARAMS.sync_params.N_sl_id2;
|
||||
NR_DL_FRAME_PARMS *sl_fp=&ue->SL_UE_PHY_PARAMS.sl_frame_params;
|
||||
int32_t metric, metric_re;
|
||||
int16_t *d;
|
||||
uint16_t Nid1 = 0;
|
||||
uint8_t phase;
|
||||
int16_t *sss;
|
||||
c16_t *rxF_ext;
|
||||
|
||||
for (int aarx=0; aarx < sl_fp->nb_antennas_rx; aarx++) {
|
||||
|
||||
unsigned int ofdm_symbol_size = sl_fp->ofdm_symbol_size;
|
||||
|
||||
// pss, sss extraction
|
||||
for (int sym = SL_NR_FIRST_PSS_SYMBOL; sym < SL_NR_FIRST_PSS_SYMBOL + SL_NR_NUM_PSS_SSS_SYMBOLS;sym ++) {
|
||||
|
||||
if (sym < SL_NR_FIRST_PSS_SYMBOL + SL_NR_NUM_PSS_SYMBOLS) {
|
||||
rxF_ext = &pss_ext[aarx][sym-SL_NR_FIRST_PSS_SYMBOL][0];
|
||||
} else {
|
||||
rxF_ext = &sss_ext[aarx][sym-SL_NR_FIRST_SSS_SYMBOL][0];
|
||||
}
|
||||
|
||||
unsigned int k = sl_fp->first_carrier_offset + sl_fp->ssb_start_subcarrier + 2;
|
||||
if (k >= ofdm_symbol_size) k -= ofdm_symbol_size;
|
||||
|
||||
LOG_D(PHY, "firstcarrieroffset:%d, ssb_sc:%d, k:%d, symbol:%d\n",sl_fp->first_carrier_offset, sl_fp->ssb_start_subcarrier, k, sym);
|
||||
|
||||
for (int i=0; i < SL_NR_PSS_SEQUENCE_LENGTH; i++) {
|
||||
rxF_ext[i] = rxdataF[aarx][sym*ofdm_symbol_size + k];
|
||||
k++;
|
||||
if (k == ofdm_symbol_size) k=0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
LOG_D(PHY, "SIDELINK SLSS SEARCH: EXTRACTION OF PSS, SSS done\n");
|
||||
|
||||
#ifdef SL_DEBUG
|
||||
LOG_M("pss_ext_sym1.m","pss_ext1",&pss_ext[aarx][0][0],SL_NR_PSS_SEQUENCE_LENGTH,1,1);
|
||||
LOG_M("pss_ext_sym2.m","pss_ext2",&pss_ext[aarx][1][0],SL_NR_PSS_SEQUENCE_LENGTH,1,1);
|
||||
LOG_M("sss_ext_sym3.m","sss_ext3",&sss_ext[aarx][0][0],SL_NR_PSS_SEQUENCE_LENGTH,1,1);
|
||||
LOG_M("sss_ext_sym4.m","sss_ext4",&sss_ext[aarx][1][0],SL_NR_PSS_SEQUENCE_LENGTH,1,1);
|
||||
#endif
|
||||
|
||||
|
||||
// get conjugated channel estimate from PSS, H* = R* \cdot PSS
|
||||
// and do channel estimation and compensation based on PSS
|
||||
int16_t *pss = ue->SL_UE_PHY_PARAMS.init_params.sl_pss_for_sync[Nid2];
|
||||
int16_t *pss_ext2,*sss_ext2;
|
||||
int16_t tmp_re,tmp_im,tmp_re2,tmp_im2;
|
||||
int32_t amp, shift;
|
||||
|
||||
for (int j=0; j<2;j++) {
|
||||
|
||||
int16_t *sss_ext3 = (int16_t*)&sss_ext[aarx][j][0];
|
||||
sss_ext2 = (int16_t*)&sss_ext[aarx][j][0];
|
||||
pss_ext2 = (int16_t*)&pss_ext[aarx][j][0];
|
||||
|
||||
for (int i = 0; i < SL_NR_PSS_SEQUENCE_LENGTH; i++) {
|
||||
|
||||
// This is H*(PSS) = R* \cdot PSS
|
||||
tmp_re = pss_ext2[i*2] * pss[i];
|
||||
tmp_im = -pss_ext2[i*2+1] * pss[i];
|
||||
|
||||
amp = (((int32_t)tmp_re)*tmp_re) + ((int32_t)tmp_im)*tmp_im;
|
||||
shift = log2_approx(amp)/2;
|
||||
|
||||
// This is R(SSS) \cdot H*(PSS)
|
||||
tmp_re2 = (int16_t)(((tmp_re * (int32_t)sss_ext2[i*2])>>shift) - ((tmp_im * (int32_t)sss_ext2[i*2+1]>>shift)));
|
||||
tmp_im2 = (int16_t)(((tmp_re * (int32_t)sss_ext2[i*2+1])>>shift) + ((tmp_im * (int32_t)sss_ext2[i*2]>>shift)));
|
||||
|
||||
// MRC on RX antennas
|
||||
// sss_ext now contains the compensated SSS
|
||||
if (aarx==0) {
|
||||
sss_ext3[i<<1] = tmp_re2;
|
||||
sss_ext3[1+(i<<1)] = tmp_im2;
|
||||
} else {
|
||||
AssertFatal(1==0,"SIDELINK MORE THAN 1 RX ANTENNA NOT YET SUPPORTED\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LOG_D(PHY, "SIDELINK SLSS SEARCH: Ch. estimation SSS done\n");
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
|
||||
#ifdef SL_DEBUG
|
||||
|
||||
write_output("rxsig0.m","rxs0",&ue->common_vars.rxdata[0][0],ue->frame_parms.samples_per_subframe,1,1);
|
||||
write_output("rxdataF0_pss.m","rxF0_pss",&ue->common_vars.rxdataF[0][0],frame_parms->ofdm_symbol_size,1,1);
|
||||
write_output("rxdataF0_sss.m","rxF0_sss",&ue->common_vars.rxdataF[0][(SSS_SYMBOL_NB-PSS_SYMBOL_NB)*frame_parms->ofdm_symbol_size],frame_parms->ofdm_symbol_size,1,1);
|
||||
write_output("pss_ext.m","pss_ext",pss_ext,LENGTH_PSS_NR,1,1);
|
||||
|
||||
#endif
|
||||
*/
|
||||
#if 0
|
||||
printf("H*(%d,%d) : (%d,%d)\n",aarx,i,tmp_re,tmp_im);
|
||||
printf("pss(%d,%d) : (%d,%d)\n",aarx,i,pss[2*i],pss[2*i+1]);
|
||||
printf("pss_ext(%d,%d) : (%d,%d)\n",aarx,i,pss_ext2[2*i],pss_ext2[2*i+1]);
|
||||
if (aarx==0) {
|
||||
chest[i<<1]=tmp_re;
|
||||
chest[1+(i<<1)]=tmp_im;
|
||||
}
|
||||
#endif
|
||||
// printf("SSSi(%d,%d) : (%d,%d)\n",aarx,i,sss_ext2[i<<1],sss_ext2[1+(i<<1)]);
|
||||
// printf("SSSo(%d,%d) : (%d,%d)\n",aarx,i,tmp_re2,tmp_im2);
|
||||
// MRC on RX antennas
|
||||
#if 0
|
||||
LOG_M("pssrx.m","pssrx",pss,LENGTH_PSS_NR,1,1);
|
||||
LOG_M("pss_ext.m","pssext",pss_ext2,LENGTH_PSS_NR,1,1);
|
||||
LOG_M("psschest.m","pssch",chest,LENGTH_PSS_NR,1,1);
|
||||
#endif
|
||||
#if 0
|
||||
|
||||
for (int i = 0; i < LENGTH_PSS_NR; i++) {
|
||||
printf(" sss ext 2 [%d] %d %d at address %p\n", i, sss_ext2[2*i], sss_ext2[2*i+1]);
|
||||
printf(" sss ref [%d] %d %d at address %p\n", i, d_sss[0][0][i], d_sss[0][0][i]);
|
||||
printf(" sss ext 3 [%d] %d %d at address %p\n", i, sss_ext3[2*i], sss_ext3[2*i+1]);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#if 0
|
||||
|
||||
/* simulate of a phase shift on the signal */
|
||||
|
||||
int phase_shift_index = 0;
|
||||
|
||||
phase_shift_samples(sss, LENGTH_SSS_NR, phase_re_nr[phase_shift_index], phase_im_nr[phase_shift_index]);
|
||||
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
int16_t *ps = (int16_t *)pss_ext;
|
||||
|
||||
for (int i = 0; i < LENGTH_SSS_NR; i++) {
|
||||
printf("sss ref [%i] : %d \n", i, d_sss[0][0][i]);
|
||||
printf("sss ext [%i] : %d %d \n", i, sss[2*i], sss[2*i+1]);
|
||||
|
||||
printf("pss ref [%i] : %d %d \n", i, primary_synchro_nr2[0][2*i], primary_synchro_nr2[0][2*i+1]);
|
||||
printf("pss ext [%i] : %d %d \n", i, ps[2*i], ps[2*i+1]);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* for phase evaluation, one uses an array of possible phase shifts */
|
||||
/* then a correlation is done between received signal with a shift pĥase and the reference signal */
|
||||
/* Computation of signal with shift phase is based on below formula */
|
||||
/* cosinus cos(x + y) = cos(x)cos(y) - sin(x)sin(y) */
|
||||
/* sinus sin(x + y) = sin(x)cos(y) + cos(x)sin(y) */
|
||||
|
||||
// now do the SSS detection based on the pre computed SSS sequences
|
||||
*tot_metric = INT_MIN;
|
||||
sss = (int16_t*)&sss_ext[0][0][0];
|
||||
|
||||
for (uint16_t id1 = 0 ; id1 < SL_NR_NUM_IDs_IN_SSS; id1++) { // all possible SSS Nid1 values
|
||||
for (phase=0; phase < PHASE_HYPOTHESIS_NUMBER; phase++) { // phase offset between PSS and SSS
|
||||
|
||||
metric = 0;
|
||||
metric_re = 0;
|
||||
|
||||
d = (int16_t *)&ue->SL_UE_PHY_PARAMS.init_params.sl_sss_for_sync[Nid2 * SL_NR_NUM_IDs_IN_SSS + id1];
|
||||
|
||||
// This is the inner product using one particular value of each unknown parameter
|
||||
for (int i=0; i < SL_NR_SSS_SEQUENCE_LENGTH; i++) {
|
||||
|
||||
metric_re += d[i]*(((sl_phase_re_nr[phase]*sss[2*i])>>15) - ((sl_phase_im_nr[phase]*sss[2*i+1])>>15));
|
||||
|
||||
#if 0
|
||||
printf("i %d, phase %d/%d: metric %d, phase (%d,%d) sss (%d,%d) d %d\n",i,phase,PHASE_HYPOTHESIS_NUMBER,metric_re,phase_re_nr[phase],phase_im_nr[phase],sss[2*i],sss[1+(2*i)],d[i]);
|
||||
#endif
|
||||
}
|
||||
|
||||
metric = metric_re;
|
||||
|
||||
// if the current metric is better than the last save it
|
||||
if (metric > *tot_metric) {
|
||||
*tot_metric = metric;
|
||||
Nid1 = id1;
|
||||
*phase_max = phase;
|
||||
|
||||
LOG_D(PHY, "(phase,Nid1) (%d,%d), metric_phase %d tot_metric %d, phase_max %d \n",phase, Nid1, metric, *tot_metric, *phase_max);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ue->SL_UE_PHY_PARAMS.sync_params.N_sl_id1 = Nid1;
|
||||
ue->SL_UE_PHY_PARAMS.sync_params.N_sl_id = ue->SL_UE_PHY_PARAMS.sync_params.N_sl_id1 + 336 * ue->SL_UE_PHY_PARAMS.sync_params.N_sl_id2;
|
||||
LOG_I(PHY, "UE[%d]NR-SL SLSS SEARCH: SSS Processing over. id2 from SSS:%d, id1 from PSS:%d, SLSS id:%d\n",
|
||||
ue->Mod_id, ue->SL_UE_PHY_PARAMS.sync_params.N_sl_id1, ue->SL_UE_PHY_PARAMS.sync_params.N_sl_id2,
|
||||
ue->SL_UE_PHY_PARAMS.sync_params.N_sl_id);
|
||||
|
||||
|
||||
#ifdef SL_DEBUG
|
||||
#define SSS_METRIC_FLOOR_NR (30000)
|
||||
if (*tot_metric > SSS_METRIC_FLOOR_NR) {
|
||||
Nid2 = ue->SL_UE_PHY_PARAMS.sync_params.N_sl_id2;
|
||||
Nid1 = ue->SL_UE_PHY_PARAMS.sync_params.N_sl_id1;
|
||||
printf("Nid2 %d Nid1 %d tot_metric %d, phase_max %d \n", Nid2, Nid1, *tot_metric, *phase_max);
|
||||
}
|
||||
#endif
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Right now 2 frames worth of samples get processed for PSS in OAI.
|
||||
// For PSS in Sidelink, worst case 1 SSB in 16 frames can be present
|
||||
// Hence 16 frames worth of samples needs to be correlated to find the PSS.
|
||||
int sl_nr_slss_search(PHY_VARS_NR_UE *UE, UE_nr_rxtx_proc_t *proc, int num_frames) {
|
||||
|
||||
sl_nr_ue_phy_params_t *sl_ue = &UE->SL_UE_PHY_PARAMS;
|
||||
SL_NR_SYNC_PARAMS_t *sync_params = &sl_ue->sync_params;
|
||||
NR_DL_FRAME_PARMS *sl_fp = &UE->SL_UE_PHY_PARAMS.sl_frame_params;
|
||||
|
||||
int32_t sync_pos = -1;// sync_pos_frame = -1;
|
||||
int32_t metric_tdd_ncp=0;
|
||||
uint8_t phase_tdd_ncp;
|
||||
double im, re;
|
||||
int ret=-1;
|
||||
uint16_t rx_slss_id = 65535;
|
||||
|
||||
#ifdef SL_DEBUG_SEARCH_SLSS
|
||||
LOG_D(PHY, "SIDELINK SEARCH SLSS: Function:%s\n", __func__);
|
||||
#endif
|
||||
|
||||
/* Initial synchronisation
|
||||
*
|
||||
* 1 radio frame = 10 ms
|
||||
* <--------------------------------------------------------------------------->
|
||||
* | Received UE data buffer |
|
||||
* ----------------------------------------------------------------------------
|
||||
* <-------------->|psbch|pss|pss|sss|sss|psbch sym5-sym 12|sym13 - guard|
|
||||
* sync_pos SS/PSBCH block
|
||||
*/
|
||||
|
||||
// initial sync performed on 16 successive frames. Worst case - one PSBCH can be sent in 16 frames.
|
||||
//If psbch passes on first frame, no need to process second frame
|
||||
// Problem with the frame approach is that
|
||||
// --------- SSB can be on the boundary between frames. In this case if only 1 SSB is sent we will miss it.
|
||||
// rxdata will hold 16 frames + slot worth of samples. This needs to be processed to find the best SSB
|
||||
for(int frame_index = 0; frame_index < num_frames; frame_index++) {
|
||||
|
||||
/* process pss search on received buffer */
|
||||
sync_pos = sl_nr_pss_correlation(UE, frame_index);
|
||||
|
||||
if (sync_pos == -1) {
|
||||
LOG_I(PHY,"SIDELINK SEARCH SLSS: No PSSS found in this frame\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
sync_pos += frame_index * sl_fp->samples_per_frame; // position in the num_frames frame samples
|
||||
|
||||
for (int pss_sym = 1; pss_sym < 3;pss_sym++) {
|
||||
// Now Sync pos can point to PSS 1st symbol or 2nd symbol.
|
||||
// Right now implemented the strategy to try both locations for FFT
|
||||
// Think about a better correlation strategy
|
||||
if (pss_sym == 1) { // Check if sync pos points to SYMBOL1 - first symbol of PSS location
|
||||
if (sync_pos > sl_fp->nb_prefix_samples0 + sl_fp->ofdm_symbol_size + sl_fp->nb_prefix_samples)
|
||||
sync_params->ssb_offset = sync_pos - (sl_fp->nb_prefix_samples0 + sl_fp->ofdm_symbol_size + sl_fp->nb_prefix_samples);
|
||||
else
|
||||
sync_params->ssb_offset = sync_pos + sl_fp->samples_per_frame - (sl_fp->nb_prefix_samples0 + sl_fp->ofdm_symbol_size + sl_fp->nb_prefix_samples);
|
||||
} else { // Check if sync pos points to SYMBOL2 - second symbol of PSS location
|
||||
if (sync_pos >= sl_fp->nb_prefix_samples0 + 2*(sl_fp->ofdm_symbol_size + sl_fp->nb_prefix_samples))
|
||||
sync_params->ssb_offset = sync_pos - (sl_fp->nb_prefix_samples0 + 2*(sl_fp->ofdm_symbol_size + sl_fp->nb_prefix_samples));
|
||||
else
|
||||
sync_params->ssb_offset = sync_pos + sl_fp->samples_per_frame - (sl_fp->nb_prefix_samples0 + 2*(sl_fp->ofdm_symbol_size + sl_fp->nb_prefix_samples));
|
||||
}
|
||||
|
||||
#define SL_NR_NUM_SYMBOLS_FOR_PSBCH_NORMAL_CP 14
|
||||
|
||||
LOG_I(PHY,"UE[%d]SIDELINK SEARCH SLSS: PSS Peak at %d, PSS sym:%d, Estimated PSS position %d\n",
|
||||
UE->Mod_id,sync_pos,pss_sym,sync_params->ssb_offset);
|
||||
|
||||
int slss_block_samples = (SL_NR_NUM_SYMBOLS_FOR_PSBCH_NORMAL_CP * sl_fp->ofdm_symbol_size) +
|
||||
(SL_NR_NUM_SYMBOLS_FOR_PSBCH_NORMAL_CP -1) * sl_fp->nb_prefix_samples + sl_fp->nb_prefix_samples0;
|
||||
|
||||
int ssb_end_position = sync_params->ssb_offset + slss_block_samples;
|
||||
|
||||
LOG_D(PHY, "ssb_end:%d ssb block samples:%d total samples: %d\n", ssb_end_position, slss_block_samples, num_frames * sl_fp->samples_per_frame);
|
||||
|
||||
|
||||
/* check that SSS/PBCH block is continuous inside the received buffer */
|
||||
if (ssb_end_position < num_frames * sl_fp->samples_per_frame) {
|
||||
|
||||
// digital compensation of FFO for SSB symbols
|
||||
if (UE->UE_fo_compensation){ // This code to be checked. Why do we do this before PSS detection is successful?
|
||||
double s_time = 1/(1.0e3 * sl_fp->samples_per_subframe); // sampling time
|
||||
double off_angle = -2 * M_PI * s_time * (sync_params->freq_offset); // offset rotation angle compensation per sample
|
||||
|
||||
int start = sync_params->ssb_offset; // start for offset correction is at ssb_offset (pss time position)
|
||||
// Adapt this for other numerologies number of symbols with larger cp increases TBD
|
||||
int end = ssb_end_position; // loop over samples in all symbols (ssb size), including prefix
|
||||
|
||||
|
||||
LOG_I(PHY,"SLSS SEARCH: FREQ comp of SLSS samples. Freq_OFSET:%d, startpos:%d, end_pos:%d\n",
|
||||
sync_params->freq_offset, start, end);
|
||||
for(int n=start; n<end; n++) {
|
||||
for (int ar=0; ar<sl_fp->nb_antennas_rx; ar++) {
|
||||
re = ((double)(((short *)UE->common_vars.rxdata[ar]))[2*n]);
|
||||
im = ((double)(((short *)UE->common_vars.rxdata[ar]))[2*n+1]);
|
||||
((short *)UE->common_vars.rxdata[ar])[2*n] = (short)(round(re*cos(n*off_angle) - im*sin(n*off_angle)));
|
||||
((short *)UE->common_vars.rxdata[ar])[2*n+1] = (short)(round(re*sin(n*off_angle) + im*cos(n*off_angle)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NR_DL_FRAME_PARMS *frame_parms = &UE->SL_UE_PHY_PARAMS.sl_frame_params;
|
||||
const uint32_t rxdataF_sz = frame_parms->samples_per_slot_wCP;
|
||||
__attribute__ ((aligned(32))) c16_t rxdataF[frame_parms->nb_antennas_rx][rxdataF_sz];
|
||||
|
||||
/* In order to achieve correct processing for NR prefix samples is forced to 0 and then restored after function call */
|
||||
for(int symbol=0; symbol<SL_NR_NUM_SYMBOLS_FOR_PSBCH_NORMAL_CP;symbol++) {
|
||||
sl_nr_slot_fep(UE,
|
||||
NULL,
|
||||
symbol,
|
||||
0,
|
||||
sync_params->ssb_offset,
|
||||
rxdataF);
|
||||
}
|
||||
|
||||
sl_nr_extract_sss(UE, NULL, &metric_tdd_ncp, &phase_tdd_ncp, rxdataF);
|
||||
|
||||
// save detected cell id to psbch
|
||||
rx_slss_id = UE->SL_UE_PHY_PARAMS.sync_params.N_sl_id;
|
||||
|
||||
__attribute__ ((aligned(32))) struct complex16 dl_ch_estimates[frame_parms->nb_antennas_rx][rxdataF_sz];
|
||||
__attribute__ ((aligned(32))) struct complex16 dl_ch_estimates_time[frame_parms->nb_antennas_rx][frame_parms->ofdm_symbol_size];
|
||||
|
||||
uint8_t decoded_output[4];
|
||||
|
||||
for (int symbol = 0; symbol < SL_NR_NUM_SYMBOLS_FOR_PSBCH_NORMAL_CP-1;) {
|
||||
nr_pbch_channel_estimation(UE,
|
||||
frame_parms,
|
||||
rxdataF_sz,
|
||||
dl_ch_estimates,
|
||||
dl_ch_estimates_time,
|
||||
proc,
|
||||
symbol,
|
||||
symbol,
|
||||
0,
|
||||
0,
|
||||
rxdataF,
|
||||
1,
|
||||
rx_slss_id);
|
||||
|
||||
symbol = (symbol == 0) ? 5 : symbol+1;
|
||||
}
|
||||
|
||||
ret = nr_rx_psbch(UE,proc,
|
||||
rxdataF_sz,
|
||||
dl_ch_estimates,
|
||||
frame_parms,
|
||||
decoded_output,
|
||||
rxdataF,
|
||||
rx_slss_id);
|
||||
|
||||
if (ret == 0) { // Check this later TBD
|
||||
// sync at symbol ue->symbol_offset
|
||||
// computing the offset wrt the beginning of the frame
|
||||
// SSB located at symbol 0
|
||||
sync_params->remaining_frames = (num_frames * sl_fp->samples_per_frame - sync_params->ssb_offset)/sl_fp->samples_per_frame;
|
||||
//ssb_offset points to start of sl-ssb
|
||||
//rx_offset points to remaining samples needed to fill a frame
|
||||
sync_params->rx_offset = sync_params->ssb_offset % sl_fp->samples_per_frame;
|
||||
|
||||
LOG_I(PHY,"UE[%d]SIDELINK SLSS SEARCH: PSBCH RX OK. Remainingframes:%d, rx_offset:%d\n",
|
||||
UE->Mod_id,sync_params->remaining_frames, sync_params->rx_offset);
|
||||
|
||||
uint32_t psbch_payload = (*(uint32_t *)decoded_output);
|
||||
//retrieve DFN and slot number from SL-MIB
|
||||
sync_params->DFN = (((psbch_payload & 0x0700) >> 1) | ((psbch_payload & 0xFE0000) >> 17));
|
||||
sync_params->slot_offset = (((psbch_payload & 0x010000) >> 10) | ((psbch_payload & 0xFC000000) >> 26));
|
||||
|
||||
LOG_I(PHY, "UE[%d]SIDELINK SLSS SEARCH: SL-MIB: DFN:%d, slot:%d.\n",
|
||||
UE->Mod_id, sync_params->DFN, sync_params->slot_offset);
|
||||
|
||||
nr_sl_psbch_rsrp_measurements(sl_ue,frame_parms,rxdataF, false);
|
||||
|
||||
UE->init_sync_frame = sync_params->remaining_frames;
|
||||
UE->rx_offset = sync_params->rx_offset;
|
||||
|
||||
nr_sidelink_indication_t sl_indication;
|
||||
sl_nr_rx_indication_t rx_ind = {0};
|
||||
uint16_t number_pdus = 1;
|
||||
nr_fill_sl_indication(&sl_indication, &rx_ind, NULL, proc, UE, NULL);
|
||||
nr_fill_sl_rx_indication(&rx_ind, SL_NR_RX_PDU_TYPE_SSB, UE, number_pdus, proc, (void *)decoded_output, rx_slss_id);
|
||||
|
||||
|
||||
LOG_D(PHY,"Sidelink SLSS SEARCH PSBCH RX OK. Send SL-SSB TO MAC\n");
|
||||
|
||||
if (UE->if_inst && UE->if_inst->sl_indication)
|
||||
UE->if_inst->sl_indication(&sl_indication);
|
||||
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
LOG_I(PHY,"SIDELINK SLSS SEARCH: SLSS ID: %d metric %d, phase %d, psbch CRC %s\n",
|
||||
sl_ue->sync_params.N_sl_id,metric_tdd_ncp,phase_tdd_ncp,(ret == 0) ? "OK" : "NOT OK");
|
||||
|
||||
} else {
|
||||
LOG_W(PHY,"SIDELINK SLSS SEARCH: Error: Not enough samples to process PSBCH. sync_pos %d\n", sync_pos);
|
||||
}
|
||||
}
|
||||
if (ret == 0) break;
|
||||
}
|
||||
|
||||
if (ret!=0) { // PSBCH not found so indicate sync to higher layers and configure frame parameters
|
||||
LOG_E(PHY,"SIDELINK SLSS SEARCH: PSBCH not received. Estimated PSS position:%d\n", sync_pos);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -244,7 +244,7 @@ int nr_pbch_channel_level(struct complex16 dl_ch_estimates_ext[][PBCH_MAX_RE_PER
|
||||
return(avg2);
|
||||
}
|
||||
|
||||
static void nr_pbch_channel_compensation(struct complex16 rxdataF_ext[][PBCH_MAX_RE_PER_SYMBOL],
|
||||
void nr_pbch_channel_compensation(struct complex16 rxdataF_ext[][PBCH_MAX_RE_PER_SYMBOL],
|
||||
struct complex16 dl_ch_estimates_ext[][PBCH_MAX_RE_PER_SYMBOL],
|
||||
int nb_re,
|
||||
struct complex16 rxdataF_comp[][PBCH_MAX_RE_PER_SYMBOL],
|
||||
@@ -300,7 +300,7 @@ void nr_pbch_detection_mrc(NR_DL_FRAME_PARMS *frame_parms,
|
||||
#endif
|
||||
}
|
||||
|
||||
static void nr_pbch_unscrambling(int16_t *demod_pbch_e,
|
||||
void nr_pbch_unscrambling(int16_t *demod_pbch_e,
|
||||
uint16_t Nid,
|
||||
uint8_t nushift,
|
||||
uint16_t M,
|
||||
@@ -362,7 +362,7 @@ static void nr_pbch_unscrambling(int16_t *demod_pbch_e,
|
||||
}
|
||||
}
|
||||
|
||||
static void nr_pbch_quantize(int16_t *pbch_llr8,
|
||||
void nr_pbch_quantize(int16_t *pbch_llr8,
|
||||
int16_t *pbch_llr,
|
||||
uint16_t len) {
|
||||
for (int i=0; i<len; i++) {
|
||||
|
||||
268
openair1/PHY/NR_UE_TRANSPORT/nr_psbch_rx.c
Normal file
268
openair1/PHY/NR_UE_TRANSPORT/nr_psbch_rx.c
Normal file
@@ -0,0 +1,268 @@
|
||||
/*
|
||||
* 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.0 (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 "PHY/defs_nr_UE.h"
|
||||
#include "PHY/CODING/nrPolar_tools/nr_polar_psbch_defs.h"
|
||||
#include "PHY/CODING/nrPolar_tools/nr_polar_defs.h"
|
||||
#include "common/utils/LOG/log.h"
|
||||
#include "PHY/TOOLS/phy_scope_interface.h"
|
||||
|
||||
|
||||
//#define DEBUG_PSBCH
|
||||
|
||||
//Reuse already existing PBCH functions
|
||||
extern int nr_pbch_channel_level(struct complex16 dl_ch_estimates_ext[][SL_NR_NUM_PSBCH_DATA_RE_IN_ONE_SYMBOL],
|
||||
NR_DL_FRAME_PARMS *frame_parms,
|
||||
int nb_re);
|
||||
extern void nr_pbch_channel_compensation(struct complex16 rxdataF_ext[][SL_NR_NUM_PSBCH_DATA_RE_IN_ONE_SYMBOL],
|
||||
struct complex16 dl_ch_estimates_ext[][SL_NR_NUM_PSBCH_DATA_RE_IN_ONE_SYMBOL],
|
||||
int nb_re,
|
||||
struct complex16 rxdataF_comp[][SL_NR_NUM_PSBCH_DATA_RE_IN_ONE_SYMBOL],
|
||||
NR_DL_FRAME_PARMS *frame_parms,
|
||||
uint8_t output_shift);
|
||||
extern void nr_pbch_unscrambling(int16_t *demod_pbch_e,
|
||||
uint16_t Nid,
|
||||
uint8_t nushift,
|
||||
uint16_t M,
|
||||
uint16_t length,
|
||||
uint8_t bitwise,
|
||||
uint32_t unscrambling_mask,
|
||||
uint32_t pbch_a_prime,
|
||||
uint32_t *pbch_a_interleaved);
|
||||
extern void nr_pbch_quantize(int16_t *pbch_llr8,
|
||||
int16_t *pbch_llr,
|
||||
uint16_t len);
|
||||
|
||||
|
||||
static void nr_psbch_extract(uint32_t rxdataF_sz,
|
||||
c16_t rxdataF[][rxdataF_sz],
|
||||
int estimateSz,
|
||||
struct complex16 dl_ch_estimates[][estimateSz],
|
||||
struct complex16 rxdataF_ext[][SL_NR_NUM_PSBCH_DATA_RE_IN_ONE_SYMBOL],
|
||||
struct complex16 dl_ch_estimates_ext[][SL_NR_NUM_PSBCH_DATA_RE_IN_ONE_SYMBOL],
|
||||
uint32_t symbol,
|
||||
NR_DL_FRAME_PARMS *frame_params)
|
||||
{
|
||||
uint16_t rb;
|
||||
uint8_t i,j,aarx;
|
||||
struct complex16 *dl_ch0,*dl_ch0_ext,*rxF,*rxF_ext;
|
||||
|
||||
const uint8_t nb_rb = SL_NR_NUM_PSBCH_RBS_IN_ONE_SYMBOL;
|
||||
|
||||
AssertFatal((symbol == 0 || symbol >= 5), "SIDELINK: PSBCH DMRS not contained in symbol %d \n", symbol);
|
||||
|
||||
for (aarx=0; aarx<frame_params->nb_antennas_rx; aarx++) {
|
||||
unsigned int rx_offset = frame_params->first_carrier_offset + frame_params->ssb_start_subcarrier;
|
||||
rx_offset = rx_offset % frame_params->ofdm_symbol_size;
|
||||
|
||||
rxF = &rxdataF[aarx][symbol*frame_params->ofdm_symbol_size];
|
||||
rxF_ext = &rxdataF_ext[aarx][0];
|
||||
|
||||
dl_ch0 = &dl_ch_estimates[aarx][symbol*frame_params->ofdm_symbol_size];
|
||||
dl_ch0_ext = &dl_ch_estimates_ext[aarx][0];
|
||||
|
||||
#ifdef DEBUG_PSBCH
|
||||
LOG_I(PHY, "extract_rbs: rx_offset=%d, symbol %u\n", (rx_offset + (symbol*frame_params->ofdm_symbol_size)),symbol);
|
||||
#endif
|
||||
|
||||
for (rb=0; rb<nb_rb; rb++) {
|
||||
j=0;
|
||||
|
||||
for (i=0; i<NR_NB_SC_PER_RB; i++) {
|
||||
|
||||
if (i%4 != 0) {
|
||||
|
||||
rxF_ext[j]=rxF[rx_offset];
|
||||
dl_ch0_ext[j]=dl_ch0[i];
|
||||
|
||||
#ifdef DEBUG_PSBCH
|
||||
|
||||
LOG_I(PHY,"rxF ext[%d] = (%d,%d) rxF [%u]= (%d,%d)\n",(9*rb) + j,
|
||||
((int16_t *)&rxF_ext[j])[0],
|
||||
((int16_t *)&rxF_ext[j])[1],
|
||||
rx_offset,
|
||||
((int16_t *)&rxF[rx_offset])[0],
|
||||
((int16_t *)&rxF[rx_offset])[1]);
|
||||
|
||||
LOG_I(PHY,"dl ch0 ext[%d] = (%d,%d) dl_ch0 [%d]= (%d,%d)\n", (9*rb) + j,
|
||||
((int16_t *)&dl_ch0_ext[j])[0],
|
||||
((int16_t *)&dl_ch0_ext[j])[1],
|
||||
i,
|
||||
((int16_t *)&dl_ch0[i])[0],
|
||||
((int16_t *)&dl_ch0[i])[1]);
|
||||
#endif
|
||||
j++;
|
||||
}
|
||||
rx_offset=(rx_offset+1)%(frame_params->ofdm_symbol_size);
|
||||
}
|
||||
|
||||
rxF_ext += SL_NR_NUM_PSBCH_DATA_RE_IN_ONE_RB;
|
||||
dl_ch0_ext += SL_NR_NUM_PSBCH_DATA_RE_IN_ONE_RB;
|
||||
dl_ch0 += NR_NB_SC_PER_RB;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_PSBCH
|
||||
char filename[40], varname[25];
|
||||
sprintf(filename,"psbch_dlch_sym_%d.m", symbol);
|
||||
sprintf(varname,"psbch_dlch%d.m", symbol);
|
||||
LOG_M(filename, varname, (void*)dl_ch0, frame_params->ofdm_symbol_size, 1, 1);
|
||||
sprintf(filename,"psbch_dlchext_sym_%d.m", symbol);
|
||||
sprintf(varname,"psbch_dlchext%d.m", symbol);
|
||||
LOG_M(filename, varname, (void*)&dl_ch_estimates_ext[0][0], SL_NR_NUM_PSBCH_DATA_RE_IN_ONE_SYMBOL , 1, 1);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
int nr_rx_psbch(PHY_VARS_NR_UE *ue,
|
||||
UE_nr_rxtx_proc_t *proc,
|
||||
int estimateSz,
|
||||
struct complex16 dl_ch_estimates[][estimateSz],
|
||||
NR_DL_FRAME_PARMS *frame_parms,
|
||||
uint8_t *decoded_output,
|
||||
c16_t rxdataF[][frame_parms->samples_per_slot_wCP],
|
||||
uint16_t slss_id)
|
||||
{
|
||||
|
||||
uint32_t decoderState=0;
|
||||
int psbch_e_rx_idx = 0;
|
||||
int16_t psbch_e_rx[SL_NR_POLAR_PSBCH_E_NORMAL_CP]= {0};
|
||||
int16_t psbch_unClipped[SL_NR_POLAR_PSBCH_E_NORMAL_CP]= {0};
|
||||
|
||||
#ifdef DEBUG_PSBCH
|
||||
write_output("psbch_rxdataF.m","psbchrxF",
|
||||
&rxdataF[0][0],frame_parms->ofdm_symbol_size*SL_NR_NUM_SYMBOLS_SSB_NORMAL_CP,1,1);
|
||||
#endif
|
||||
// symbol refers to symbol within SSB. symbol_offset is the offset of the SSB wrt start of slot
|
||||
double log2_maxh = 0;
|
||||
|
||||
// 0 for Normal Cyclic Prefix and 1 for EXT CyclicPrefix
|
||||
const int numsym = (frame_parms->Ncp) ? SL_NR_NUM_SYMBOLS_SSB_EXT_CP
|
||||
: SL_NR_NUM_SYMBOLS_SSB_NORMAL_CP;
|
||||
|
||||
for (int symbol=0; symbol<numsym;) {
|
||||
const uint16_t nb_re = SL_NR_NUM_PSBCH_DATA_RE_IN_ONE_SYMBOL;
|
||||
__attribute__ ((aligned(32))) struct complex16 rxdataF_ext[frame_parms->nb_antennas_rx][nb_re];
|
||||
__attribute__ ((aligned(32))) struct complex16 dl_ch_estimates_ext[frame_parms->nb_antennas_rx][nb_re];
|
||||
//memset(dl_ch_estimates_ext,0, sizeof dl_ch_estimates_ext);
|
||||
nr_psbch_extract(frame_parms->samples_per_slot_wCP,
|
||||
rxdataF,
|
||||
estimateSz,
|
||||
dl_ch_estimates,
|
||||
rxdataF_ext,
|
||||
dl_ch_estimates_ext,
|
||||
symbol,
|
||||
frame_parms);
|
||||
#ifdef DEBUG_PSBCH
|
||||
LOG_I(PHY,"PSBCH RX Symbol %d ofdm size %d\n",symbol, frame_parms->ofdm_symbol_size );
|
||||
#endif
|
||||
|
||||
int max_h=0;
|
||||
if (symbol == 0) {
|
||||
max_h = nr_pbch_channel_level(dl_ch_estimates_ext,
|
||||
frame_parms,
|
||||
nb_re);
|
||||
//log2_maxh = 3+(log2_approx(max_h)/2);
|
||||
log2_maxh = 5 +(log2_approx(max_h)/2);// LLR32 crc error. LLR 16 CRC works
|
||||
|
||||
}
|
||||
#ifdef DEBUG_PSBCH
|
||||
LOG_I(PHY,"PSBCH RX log2_maxh = %f (%d)\n", log2_maxh, max_h);
|
||||
#endif
|
||||
|
||||
__attribute__ ((aligned(32))) struct complex16 rxdataF_comp[frame_parms->nb_antennas_rx][nb_re];
|
||||
nr_pbch_channel_compensation(rxdataF_ext,
|
||||
dl_ch_estimates_ext,
|
||||
nb_re,
|
||||
rxdataF_comp,
|
||||
frame_parms,
|
||||
log2_maxh); // log2_maxh+I0_shift
|
||||
|
||||
nr_pbch_quantize(psbch_e_rx + psbch_e_rx_idx,
|
||||
(short *)rxdataF_comp[0],
|
||||
SL_NR_NUM_PSBCH_DATA_BITS_IN_ONE_SYMBOL);
|
||||
|
||||
//Unnecessary copy. Used only for SCOPE ... TBD... to remove this.
|
||||
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
|
||||
//Symbols carrying PSBCH 0, 5-12
|
||||
symbol = (symbol == 0) ? 5 : symbol + 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
UEscopeCopy(ue, psbchRxdataF_comp, psbch_unClipped, sizeof(struct complex16), 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);
|
||||
#endif
|
||||
|
||||
//un-scrambling
|
||||
LOG_D(PHY, "PSBCH RX POLAR DECODING: total PSBCH bits:%d, rx_slss_id:%d\n", psbch_e_rx_idx, slss_id);
|
||||
|
||||
nr_pbch_unscrambling(psbch_e_rx, slss_id, 0, 0, psbch_e_rx_idx,
|
||||
0, 0, 0, NULL);
|
||||
//polar decoding de-rate matching
|
||||
uint64_t tmp=0;
|
||||
decoderState = polar_decoder_int16(psbch_e_rx,(uint64_t *)&tmp,0,
|
||||
SL_NR_POLAR_PSBCH_MESSAGE_TYPE, SL_NR_POLAR_PSBCH_PAYLOAD_BITS, SL_NR_POLAR_PSBCH_AGGREGATION_LEVEL);
|
||||
|
||||
|
||||
uint32_t psbch_payload = tmp;
|
||||
|
||||
if(decoderState) {
|
||||
LOG_E(PHY,"%d:%d PSBCH RX: NOK \n",proc->frame_rx, proc->nr_slot_rx);
|
||||
return(decoderState);
|
||||
}
|
||||
|
||||
// Decoder reversal
|
||||
uint32_t a_reversed=0;
|
||||
|
||||
for (int i=0; i<SL_NR_POLAR_PSBCH_PAYLOAD_BITS; i++)
|
||||
a_reversed |= (((uint64_t)psbch_payload>>i)&1)<<(31-i);
|
||||
|
||||
psbch_payload = a_reversed;
|
||||
|
||||
*((uint32_t *)decoded_output) = psbch_payload;
|
||||
|
||||
#ifdef DEBUG_PSBCH
|
||||
for (int i=0; i<4; i++) {
|
||||
LOG_I(PHY, "decoded_output[%d]:%x\n", i, decoded_output[i]);
|
||||
}
|
||||
#endif
|
||||
|
||||
ue->symbol_offset = 0;
|
||||
|
||||
//retrieve DFN and slot number from SL-MIB
|
||||
uint32_t DFN = 0, slot_offset = 0;
|
||||
DFN = (((psbch_payload & 0x0700) >> 1) | ((psbch_payload & 0xFE0000) >> 17));
|
||||
slot_offset = (((psbch_payload & 0x010000) >> 10) | ((psbch_payload & 0xFC000000) >> 26));
|
||||
|
||||
LOG_D(PHY, "PSBCH RX SL-MIB:%x, decoded DFN:slot %d:%d, %x\n",psbch_payload, DFN, slot_offset, *(uint32_t *)decoded_output);
|
||||
|
||||
return 0;
|
||||
}
|
||||
381
openair1/PHY/NR_UE_TRANSPORT/nr_psbch_tx.c
Normal file
381
openair1/PHY/NR_UE_TRANSPORT/nr_psbch_tx.c
Normal file
@@ -0,0 +1,381 @@
|
||||
/*
|
||||
* 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 "PHY/defs_nr_UE.h"
|
||||
#include "PHY/LTE_REFSIG/lte_refsig.h"
|
||||
#include "PHY/NR_REFSIG/nr_mod_table.h"
|
||||
#include "PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h"
|
||||
#include "PHY/CODING/nrPolar_tools/nr_polar_psbch_defs.h"
|
||||
|
||||
/*
|
||||
This function performs PSBCH SCrambling as described in 38.211.
|
||||
Input parameter "output" is scrambled and the scrambled output is stored in this parameter.
|
||||
id - SLSS ID used for C_INIT
|
||||
length is the length of the buffer.
|
||||
*/
|
||||
|
||||
//#define SL_DEBUG
|
||||
|
||||
void sl_psbch_scrambling(uint32_t *output, uint32_t id, uint16_t length)
|
||||
{
|
||||
uint32_t x1, x2, s=0;
|
||||
// x1 is set in lte_gold_generic
|
||||
x2 = id; // C_INIT
|
||||
|
||||
#ifdef SL_DEBUG
|
||||
printf("SIDELINK: Function %s\n", __func__);
|
||||
printf("Scrambling params: length %d id %d \n", length, id);
|
||||
#endif
|
||||
|
||||
#ifdef SL_DEBUG
|
||||
for (int i=0; i<56;i++) {
|
||||
printf("\nBEFORE SCRAMBLING output[%d]:0x%x\n",i,output[i]);
|
||||
}
|
||||
#endif
|
||||
|
||||
// get initial 32 scrambing bits
|
||||
s = lte_gold_generic(&x1, &x2, 1);
|
||||
#ifdef SL_DEBUG
|
||||
printf("s: %04x\t", s);
|
||||
#endif
|
||||
|
||||
// scramble in 32bit chunks
|
||||
int i = 0;
|
||||
while(i+32 <= length) {
|
||||
|
||||
output[i>>5] ^= s;
|
||||
|
||||
i += 32;
|
||||
s = lte_gold_generic(&x1, &x2, 0);
|
||||
#ifdef SL_DEBUG
|
||||
printf("s: %04x\t", s);
|
||||
#endif
|
||||
}
|
||||
|
||||
// scramble remaining bits
|
||||
for (; i < length; ++i) {
|
||||
output[i>>5] ^= ((s>>(i&0x1f)&1)<<(i&0x1f));
|
||||
}
|
||||
|
||||
#ifdef SL_DEBUG
|
||||
for (int i=0; i<56;i++) {
|
||||
printf("\nAFTER SCRAMBLING output[%d]:0x%x\n",i,output[i]);
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
This function RE MAPS PSS, SSS sequences as described in 38.211.
|
||||
txF is the data in frequency domain, sync_seq = PSS or SSS seq
|
||||
startsym = 1 for PSS, 3 for SSS
|
||||
re_offset = sample which points to first RE + SSB start RE
|
||||
scaling factor = scaling factor used for PSS, SSS (determined according to PSBCH pwr)
|
||||
symbol size = OFDM symbol size used for RE Mapping
|
||||
*/
|
||||
void sl_map_pss_or_sss(struct complex16 *txF, int16_t *sync_seq, uint16_t startsym,
|
||||
uint16_t re_offset, uint16_t scaling_factor, uint16_t symbol_size)
|
||||
{
|
||||
|
||||
|
||||
#ifdef SL_DEBUG
|
||||
printf("%s. DEBUG PSBCH TX: RE MAPPING of PSS/SSS \n", __func__);
|
||||
printf("Input Params - StartSYM:%d, NUMSYM:%d, RE_OFFSET:%d, num_REs:%d, scaling_factor:%d, symbol_size:%d\n",
|
||||
startsym, SL_NR_NUM_PSS_OR_SSS_SYMBOLS,re_offset, SL_NR_NUM_PSBCH_RE_IN_ONE_SYMBOL, scaling_factor, symbol_size);
|
||||
#endif
|
||||
|
||||
// RE Mapping of SL-PSS, SL-SSS
|
||||
for (int l = startsym;l < (startsym + SL_NR_NUM_PSS_OR_SSS_SYMBOLS);l++) {
|
||||
|
||||
int k = re_offset % symbol_size;
|
||||
int index = 0, offset = 0;
|
||||
|
||||
for (int m = 0;m < SL_NR_NUM_PSBCH_RE_IN_ONE_SYMBOL;m++) {
|
||||
|
||||
offset = l*symbol_size + k;
|
||||
if ((m < 2) || (m >= (SL_NR_NUM_PSBCH_RE_IN_ONE_SYMBOL - 3))) {
|
||||
txF[offset].r = 0; //Set REs 0,1,129,130,131 = 0
|
||||
|
||||
#ifdef SL_DEBUG
|
||||
printf("sym:%d, RE:%d, txF[%d]:%d.%d \n", l, m, offset, txF[offset].r,txF[offset].i);
|
||||
#endif
|
||||
|
||||
} else {
|
||||
txF[offset].r = (sync_seq[index] * scaling_factor) >> 15;
|
||||
|
||||
#ifdef SL_DEBUG
|
||||
printf("sym:%d, RE:%d, txF[%d]:%d.%d, syncseq[%d]:%d \n", l, m, offset, txF[offset].r,txF[offset].i, index, sync_seq[index]);
|
||||
#endif
|
||||
|
||||
index++;
|
||||
}
|
||||
txF[offset].i = 0;
|
||||
k = (k + 1) % symbol_size;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
This function Generates the PSBCH DATA Modulation symbols and RE MAPS PSBCH Modulated symbols
|
||||
and PSBCH DMRS sequences as described in 38.211.
|
||||
txF is the data in frequency domain
|
||||
payload is the PSBCH payload (SL-MIB given by higher layers)
|
||||
id - SLSS ID used for knowing which DMRS sequence to be used.
|
||||
Cp - NORMAL of extended Cyclic prefix
|
||||
startsym = 0 and then PSBCH is mapped from symbols 5-13 if normal , 5-11 if extended
|
||||
re_offset = sample which points to first RE + SSB start RE
|
||||
scaling factor = scaling factor used for PSS, SSS (determined according to PSBCH pwr)
|
||||
symbol size = OFDM symbol size used for RE Mapping
|
||||
*/
|
||||
|
||||
void sl_generate_and_map_psbch(struct complex16 *txF, uint32_t *payload, uint16_t id,
|
||||
uint16_t cp, uint16_t re_offset, uint16_t scaling_factor, uint16_t symbol_size,
|
||||
struct complex16 *psbch_dmrs)
|
||||
{
|
||||
|
||||
uint64_t psbch_a_reversed = 0;
|
||||
uint16_t num_psbch_modsym = 0, numsym = 0;
|
||||
uint8_t idx = 0;
|
||||
uint32_t encoder_output[SL_NR_POLAR_PSBCH_E_DWORD];
|
||||
struct complex16 psbch_modsym[SL_NR_NUM_PSBCH_MODULATED_SYMBOLS];
|
||||
|
||||
LOG_D(PHY, "PSBCH TX: Generation accg to 38.212, 38.211. SLSS id:%d\n", id);
|
||||
|
||||
// Encoder reversal
|
||||
for (int i=0; i<SL_NR_POLAR_PSBCH_PAYLOAD_BITS; i++)
|
||||
psbch_a_reversed |= (((uint64_t)*payload>>i)&1)<<(31-i);
|
||||
|
||||
#ifdef SL_DEBUG
|
||||
printf("DEBUG PSBCH TX: 38.212 PSBCH CRC + Channel coding (POLAR) + Rate Matching:\n");
|
||||
printf("PSBCH payload:%x, Reversed Payload:%016lx\n",*payload, psbch_a_reversed);
|
||||
#endif
|
||||
|
||||
/// CRC, coding and rate matching
|
||||
polar_encoder_fast(&psbch_a_reversed, (void*)encoder_output, 0, 0,
|
||||
SL_NR_POLAR_PSBCH_MESSAGE_TYPE,
|
||||
SL_NR_POLAR_PSBCH_PAYLOAD_BITS,
|
||||
SL_NR_POLAR_PSBCH_AGGREGATION_LEVEL);
|
||||
|
||||
#ifdef SL_DEBUG
|
||||
for (int i=0; i<SL_NR_POLAR_PSBCH_E_DWORD; i++)
|
||||
printf("encoderoutput[%d]: 0x%08x\t", i, encoder_output[i]);
|
||||
printf("\n");
|
||||
#endif
|
||||
|
||||
/// 38.211 Scrambling
|
||||
if (cp) { // EXT Cyclic prefix
|
||||
sl_psbch_scrambling(encoder_output, id, SL_NR_POLAR_PSBCH_E_EXT_CP); //for Extended Cyclic prefix
|
||||
num_psbch_modsym = SL_NR_POLAR_PSBCH_E_EXT_CP/2;
|
||||
numsym = SL_NR_NUM_SYMBOLS_SSB_EXT_CP;
|
||||
AssertFatal(1==0, "EXT CP is not yet supported\n");
|
||||
}
|
||||
else { // Normal CP
|
||||
sl_psbch_scrambling(encoder_output, id, SL_NR_POLAR_PSBCH_E_NORMAL_CP); //for Cyclic prefix
|
||||
num_psbch_modsym = SL_NR_POLAR_PSBCH_E_NORMAL_CP/2;
|
||||
numsym = SL_NR_NUM_SYMBOLS_SSB_NORMAL_CP;
|
||||
}
|
||||
|
||||
LOG_D(PHY,"PSBCH TX: 38.211 Scrambling done. Number of bits:%d \n",
|
||||
SL_NR_POLAR_PSBCH_E_NORMAL_CP);
|
||||
|
||||
#ifdef SL_DEBUG
|
||||
printf("38211 STEP: PSBCH Scrambling \n");
|
||||
for (int i=0; i<SL_NR_POLAR_PSBCH_E_NORMAL_CP/32; i++)
|
||||
printf("Scrambleroutput[%d]: 0x%08x\t", i, encoder_output[i]);
|
||||
printf("\n");
|
||||
#endif
|
||||
|
||||
#ifdef SL_DEBUG
|
||||
printf("SIDELINK PSBCH TX: 38211 STEP: QPSK Modulation of PSBCH symbols:%d, symbols in PSBCH:%d\n", num_psbch_modsym, numsym);
|
||||
#endif
|
||||
|
||||
/// 38.211 QPSK modulation
|
||||
for (int j=0; j<num_psbch_modsym; j++) {
|
||||
idx = ((encoder_output[(j<<1)>>5]>>((j<<1)&0x1f))&3);
|
||||
psbch_modsym[j].r = nr_qpsk_mod_table[2*idx];
|
||||
psbch_modsym[j].i = nr_qpsk_mod_table[(2*idx)+1];
|
||||
|
||||
#ifdef SL_DEBUG
|
||||
printf("idx %d, psbch_modsym[%d]-r:%d, i:%d\n", idx, j, psbch_modsym[j].r, psbch_modsym[j].i);
|
||||
#endif
|
||||
}
|
||||
|
||||
// RE MApping of PSBCH and PSBCH DMRS
|
||||
int index = 0, dmrs_index = 0;
|
||||
const int numre=SL_NR_NUM_PSBCH_RE_IN_ONE_SYMBOL;
|
||||
|
||||
#ifdef SL_DEBUG
|
||||
LOG_M("sl_psbch_data_symbols.m", "psbch_sym", (void*)psbch_modsym, num_psbch_modsym, 1, 1);
|
||||
LOG_M("sl_psbch_dmrs_symbols.m", "psbch_dmrs", (void*)psbch_dmrs, SL_NR_NUM_PSBCH_DMRS_RE, 1, 1);
|
||||
#endif
|
||||
|
||||
#ifdef SL_DEBUG
|
||||
printf("\nMapping Sidelink PSBCH DMRS, PSBCH modulation symbols to 132 REs\n");
|
||||
#endif
|
||||
|
||||
#ifdef SL_DEBUG
|
||||
printf("%s. DEBUG PSBCH TX: RE MAPPING of PSBCH DATA AND DMRS \n", __func__);
|
||||
printf("Input Params - StartSYM:%d, NUMSYM:%d, RE_OFFSET:%d, num_REs:%d, scaling_factor:%d, symbol_size:%d\n",
|
||||
0, numsym,re_offset, numre, scaling_factor, symbol_size);
|
||||
#endif
|
||||
|
||||
for (int l=0;l < numsym;) {
|
||||
|
||||
int k = re_offset % symbol_size;
|
||||
int symbol_offset = l*symbol_size;
|
||||
int offset = 0;
|
||||
|
||||
for (int m=0; m < numre;m++) {
|
||||
|
||||
// Maps PSBCH DMRS in every 4th RE ex:0,4,....128
|
||||
// Maps PSBCH in all other REs ex: 1,2,3,5,6,...127,129,130,131
|
||||
|
||||
offset = symbol_offset + k;
|
||||
|
||||
#ifdef SL_DEBUG
|
||||
printf("symbol:%d, symbol_offset:%d, k:%d, re:%d, sampleoffset:%d ", l, symbol_offset, k, m, offset);
|
||||
#endif
|
||||
|
||||
if (m % 4 == 0) {
|
||||
txF[offset].r = (psbch_dmrs[dmrs_index].r * scaling_factor) >> 15;
|
||||
txF[offset].i = (psbch_dmrs[dmrs_index].i * scaling_factor) >> 15;
|
||||
|
||||
#ifdef SL_DEBUG
|
||||
printf("txF[%d]:%d,%d, psbch_dmrs[%d]:%d,%d ", offset, txF[offset].r,
|
||||
txF[offset].i, dmrs_index, psbch_dmrs[dmrs_index].r, psbch_dmrs[dmrs_index].i);
|
||||
#endif
|
||||
|
||||
dmrs_index++;
|
||||
|
||||
} else {
|
||||
txF[offset].r = (psbch_modsym[index].r * scaling_factor) >> 15;
|
||||
txF[offset].i = (psbch_modsym[index].i * scaling_factor) >> 15;
|
||||
|
||||
#ifdef SL_DEBUG
|
||||
printf("txF[%d]:%d,%d, psbch_modsym[%d]:%d,%d\n", offset, txF[offset].r,
|
||||
txF[offset].i, index ,psbch_modsym[index].r, psbch_modsym[index].i);
|
||||
#endif
|
||||
|
||||
index++;
|
||||
}
|
||||
|
||||
k = (k + 1) % symbol_size;
|
||||
}
|
||||
|
||||
LOG_D(PHY, "PSBCH TX: 38211 STEP: RE MAPPING OF PSBCH, PSBCH DMRS DONE. symbol:%d, first RE offset:%d, Last RE offset:%d, Num PSBCH DATA REs:%d, Num PSBCH DMRS REs:%d\n",
|
||||
l, symbol_offset+re_offset, offset, index, dmrs_index);
|
||||
|
||||
l = (l == 0) ? 5: l+1;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
This function prepares the PSBCH block and RE MAPS PSS, SSS, PSBCH DATA, PSBCH DMRS into buffer txF.
|
||||
Called by the L1 Scheduler when MAC triggers PHY to send PSBCH
|
||||
UE is the UE context.
|
||||
frame, slot points to the TTI in which PSBCH TX will be transmitted
|
||||
*/
|
||||
void nr_tx_psbch(PHY_VARS_NR_UE *UE, uint32_t frame_tx,
|
||||
uint32_t slot_tx,
|
||||
sl_nr_tx_config_psbch_pdu_t *psbch_vars,
|
||||
c16_t **txdataF)
|
||||
{
|
||||
|
||||
sl_nr_ue_phy_params_t *sl_ue_phy_params = &UE->SL_UE_PHY_PARAMS;
|
||||
uint16_t slss_id = psbch_vars->tx_slss_id;
|
||||
NR_DL_FRAME_PARMS *sl_fp = &sl_ue_phy_params->sl_frame_params;
|
||||
uint32_t psbch_payload = *((uint32_t *)psbch_vars->psbch_payload);
|
||||
|
||||
LOG_D(PHY,"PSBCH TX: slss-id %d, psbch payload %x \n", slss_id, psbch_payload);
|
||||
|
||||
// Insert FN and Slot number into SL-MIB
|
||||
uint32_t mask = ~(0x700 | 0xFE0000 | 0x10000 | 0xFC000000);
|
||||
psbch_payload &= mask;
|
||||
psbch_payload |= ((frame_tx%1024)<<1) & 0x700;
|
||||
psbch_payload |= ((frame_tx%1024)<<17) & 0xFE0000;
|
||||
psbch_payload |= (slot_tx<<10) & 0x10000;
|
||||
psbch_payload |= (slot_tx<<26) & 0xFC000000;
|
||||
|
||||
#ifdef SL_DEBUG
|
||||
printf("DEBUG PSBCH TX: DFN, SLOT included. psbch_a :0x%08x, frame:%d, slot:%d\n",
|
||||
psbch_payload, frame_tx, slot_tx);
|
||||
#endif
|
||||
|
||||
LOG_D(PHY,"PSBCH TX: Frame.Slot %d.%d. Payload::0x%08x, slssid:%d\n",
|
||||
frame_tx, slot_tx, psbch_payload, slss_id);
|
||||
|
||||
// GENERATE Sidelink PSS,SSS Sequences, PSBCH DMRS Symbols, PSBCH Symbols
|
||||
int16_t *sl_pss = &sl_ue_phy_params->init_params.sl_pss[slss_id/336][0];
|
||||
int16_t *sl_sss = &sl_ue_phy_params->init_params.sl_sss[slss_id][0];
|
||||
|
||||
uint16_t re_offset = sl_fp->first_carrier_offset + sl_fp->ssb_start_subcarrier;
|
||||
uint16_t symbol_size = sl_fp->ofdm_symbol_size;
|
||||
// TBD: Need to be replaced by function which calculates scaling factor based on psbch tx power
|
||||
uint16_t scaling_factor = AMP;
|
||||
|
||||
struct complex16 *txF = &txdataF[0][0];
|
||||
uint16_t startsym = SL_NR_PSS_START_SYMBOL;
|
||||
|
||||
|
||||
#ifdef SL_DEBUG
|
||||
printf("DEBUG PSBCH TX: MAP PSS. startsym:%d, PSS RE START:%d, scaling factor:%d\n",
|
||||
startsym, re_offset, scaling_factor);
|
||||
#endif
|
||||
sl_map_pss_or_sss(txF, sl_pss, startsym, re_offset, scaling_factor, symbol_size); // PSS
|
||||
|
||||
|
||||
startsym += SL_NR_NUM_PSS_SYMBOLS;
|
||||
#ifdef SL_DEBUG
|
||||
printf("DEBUG PSBCH TX: MAP SSS. startsym:%d, SSS RE START:%d, scaling factor:%d\n",
|
||||
startsym, re_offset, scaling_factor);
|
||||
#endif
|
||||
sl_map_pss_or_sss(txF, sl_sss, startsym, re_offset, scaling_factor, symbol_size); // SSS
|
||||
|
||||
#ifdef SL_DEBUG
|
||||
printf("DEBUG PSBCH TX: MAP PSBCH DATA AND DMRS. cyclicPrefix:%d, PSS RE START:%d, scaling factor:%d\n",
|
||||
sl_fp->Ncp, re_offset, scaling_factor);
|
||||
#endif
|
||||
|
||||
struct complex16 *psbch_dmrs = &sl_ue_phy_params->init_params.psbch_dmrs_modsym[slss_id][0];
|
||||
|
||||
sl_generate_and_map_psbch(txF, &psbch_payload, slss_id,
|
||||
sl_fp->Ncp, re_offset, scaling_factor, symbol_size,
|
||||
psbch_dmrs);
|
||||
|
||||
|
||||
#ifdef SL_DEBUG
|
||||
printf("DEBUG PSBCH TX: txdataF Prepared\n");
|
||||
#endif
|
||||
|
||||
#ifdef SL_DEBUG
|
||||
LOG_M("sl_psbch_block.m", "sl_txF", (void*)txdataF[0], symbol_size*14, 1, 1);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -410,6 +410,21 @@ int32_t generate_nr_prach(PHY_VARS_NR_UE *ue, uint8_t gNB_id, int frame, uint8_t
|
||||
|
||||
void dump_nrdlsch(PHY_VARS_NR_UE *ue,uint8_t gNB_id,uint8_t nr_slot_rx,unsigned int *coded_bits_per_codeword,int round, unsigned char harq_pid);
|
||||
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,
|
||||
int estimateSz,
|
||||
struct complex16 dl_ch_estimates[][estimateSz],
|
||||
NR_DL_FRAME_PARMS *frame_parms,
|
||||
uint8_t *decoded_output,
|
||||
c16_t rxdataF[][frame_parms->samples_per_slot_wCP],
|
||||
uint16_t slss_id);
|
||||
|
||||
void nr_tx_psbch(PHY_VARS_NR_UE *UE, uint32_t frame_tx, uint32_t slot_tx,
|
||||
sl_nr_tx_config_psbch_pdu_t *psbch_vars,
|
||||
c16_t **txdataF);
|
||||
|
||||
int sl_nr_slss_search(PHY_VARS_NR_UE *UE, UE_nr_rxtx_proc_t *proc, int num_frames);
|
||||
/**@}*/
|
||||
#endif
|
||||
|
||||
|
||||
@@ -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){
|
||||
|
||||
@@ -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
|
||||
};
|
||||
|
||||
/* This class creates the window when choosing the option 'Configs' to configure the threshold values. */
|
||||
@@ -176,6 +177,9 @@ KPIListSelectUE::KPIListSelectUE(QWidget *parent) : QComboBox(parent)
|
||||
this->addItem("Time Adv.", static_cast<int>(PlotTypeUE::timingAdvance));
|
||||
|
||||
this->addItem("Configs", static_cast<int>(PlotTypeUE::config));
|
||||
this->addItem("LLR PSBCH", static_cast<int>(PlotTypeUE::psbchLLR));
|
||||
this->addItem("I/Q PSBCH", static_cast<int>(PlotTypeUE::psbchIQ));
|
||||
this->addItem("PSBCH RSRP dB/RE", static_cast<int>(PlotTypeUE::psbchRSRP));
|
||||
}
|
||||
|
||||
WaterFall::WaterFall(complex16 *values, NR_DL_FRAME_PARMS *frame_parms, QWidget *parent) : QWidget(parent), values(values), frame_parms(frame_parms)
|
||||
@@ -891,6 +895,8 @@ 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;
|
||||
@@ -901,15 +907,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];
|
||||
|
||||
@@ -980,13 +993,14 @@ void PainterWidgetUE::makeConnections(int type)
|
||||
break;
|
||||
}
|
||||
case PlotTypeUE::CIR: {
|
||||
if (!data[pbchDlChEstimateTime]) {
|
||||
enum scopeDataType typ = (this->ue->sl_mode) ? psbchDlChEstimateTime : pbchDlChEstimateTime;
|
||||
if (!data[typ]) {
|
||||
newChart = new QChart();
|
||||
this->plotType = PlotTypeUE::empty;
|
||||
this->comboBox->setCurrentIndex(static_cast<int>(PlotTypeUE::empty));
|
||||
break;
|
||||
}
|
||||
newChart = new CIRPlot((complex16 *)(data[pbchDlChEstimateTime] + 1), data[pbchDlChEstimateTime]->lineSz);
|
||||
newChart = new CIRPlot((complex16 *)(data[typ] + 1), data[typ]->lineSz);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1010,6 +1024,26 @@ void PainterWidgetUE::makeConnections(int type)
|
||||
newChart = new IQPlotUE((complex16 *)(data[pbchRxdataF_comp] + 1), data[pbchRxdataF_comp]->lineSz, this);
|
||||
break;
|
||||
}
|
||||
case PlotTypeUE::psbchLLR: {
|
||||
if (!data[psbchLlr]) {
|
||||
newChart = new QChart();
|
||||
this->plotType = PlotTypeUE::empty;
|
||||
this->comboBox->setCurrentIndex(static_cast<int>(PlotTypeUE::empty));
|
||||
break;
|
||||
}
|
||||
newChart = new LLRPlotUE((int16_t *)(data[psbchLlr] + 1), data[psbchLlr]->lineSz, this);
|
||||
break;
|
||||
}
|
||||
case PlotTypeUE::psbchIQ: {
|
||||
if (!data[psbchRxdataF_comp]) {
|
||||
newChart = new QChart();
|
||||
this->plotType = PlotTypeUE::empty;
|
||||
this->comboBox->setCurrentIndex(static_cast<int>(PlotTypeUE::empty));
|
||||
break;
|
||||
}
|
||||
newChart = new IQPlotUE((complex16 *)(data[psbchRxdataF_comp] + 1), data[psbchRxdataF_comp]->lineSz, this);
|
||||
break;
|
||||
}
|
||||
case PlotTypeUE::pdcchLLR: {
|
||||
if (!data[pdcchLlr]) {
|
||||
newChart = new QChart();
|
||||
@@ -1079,7 +1113,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;
|
||||
}
|
||||
@@ -1164,6 +1201,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);
|
||||
|
||||
@@ -1197,14 +1235,16 @@ void *nrUEQtscopeThread(void *arg)
|
||||
mainLayout.addWidget(&pwidgetueCombo2, 1, 1);
|
||||
|
||||
KPIListSelectUE combo3;
|
||||
combo3.setCurrentIndex(static_cast<int>(PlotTypeUE::pbchLLR));
|
||||
if (is_sl) combo3.setCurrentIndex(static_cast<int>(PlotTypeUE::psbchLLR));
|
||||
else combo3.setCurrentIndex(static_cast<int>(PlotTypeUE::psbchLLR));
|
||||
PainterWidgetUE pwidgetueCombo3(&config, &combo3, ue);
|
||||
|
||||
mainLayout.addWidget(&combo3, 2, 0);
|
||||
mainLayout.addWidget(&pwidgetueCombo3, 3, 0);
|
||||
|
||||
KPIListSelectUE combo4;
|
||||
combo4.setCurrentIndex(static_cast<int>(PlotTypeUE::pbchIQ));
|
||||
if (is_sl) combo4.setCurrentIndex(static_cast<int>(PlotTypeUE::psbchIQ));
|
||||
else combo4.setCurrentIndex(static_cast<int>(PlotTypeUE::psbchIQ));
|
||||
PainterWidgetUE pwidgetueCombo4(&config, &combo4, ue);
|
||||
|
||||
mainLayout.addWidget(&combo4, 2, 1);
|
||||
|
||||
@@ -81,7 +81,10 @@ enum class PlotTypeUE {
|
||||
pdschRBs,
|
||||
frequencyOffset,
|
||||
timingAdvance,
|
||||
config
|
||||
config,
|
||||
psbchLLR,
|
||||
psbchIQ,
|
||||
psbchRSRP,
|
||||
};
|
||||
|
||||
/// This abstract class defines an interface how the KPIPlot class can access values for the different KPI plot types
|
||||
|
||||
@@ -771,14 +771,17 @@ 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,
|
||||
const scopeSample_t *tmp=(scopeSample_t *)(data[typ]+1);
|
||||
genericPowerPerAntena(graph, data[typ]->colSz,
|
||||
&tmp,
|
||||
data[pbchDlChEstimateTime]->lineSz);
|
||||
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 ) {
|
||||
@@ -832,14 +835,17 @@ 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
|
||||
@@ -855,12 +861,15 @@ static void uePbchLLR (scopeGraphData_t **data, OAIgraph_t *graph, PHY_VARS_NR_
|
||||
}
|
||||
|
||||
static void uePbchIQ (scopeGraphData_t **data, OAIgraph_t *graph, PHY_VARS_NR_UE *phy_vars_ue, int eNB_id, int UE_id) {
|
||||
|
||||
enum scopeDataType typ = (phy_vars_ue->sl_mode) ? psbchRxdataF_comp : pbchRxdataF_comp;
|
||||
|
||||
// PBCH I/Q of MF Output
|
||||
if (!data[pbchRxdataF_comp])
|
||||
if (!data[typ])
|
||||
return;
|
||||
|
||||
scopeSample_t *pbch_comp = (scopeSample_t *) (data[pbchRxdataF_comp]+1);
|
||||
const int sz=data[pbchRxdataF_comp]->lineSz;
|
||||
scopeSample_t *pbch_comp = (scopeSample_t *) (data[typ]+1);
|
||||
const int sz=data[typ]->lineSz;
|
||||
int newsz = sz;
|
||||
float *I=NULL, *Q=NULL;
|
||||
#ifdef WEBSRVSCOPE
|
||||
|
||||
@@ -67,6 +67,9 @@ enum scopeDataType {
|
||||
pdschRxdataF_comp,
|
||||
commonRxdataF,
|
||||
gNBRxdataF,
|
||||
psbchDlChEstimateTime,
|
||||
psbchLlr,
|
||||
psbchRxdataF_comp,
|
||||
MAX_SCOPE_TYPES
|
||||
};
|
||||
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
|
||||
#include "defs_nr_common.h"
|
||||
#include "CODING/nrPolar_tools/nr_polar_pbch_defs.h"
|
||||
#include "PHY/defs_nr_sl_UE.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@@ -649,6 +650,10 @@ typedef struct {
|
||||
notifiedFIFO_t phy_config_ind;
|
||||
notifiedFIFO_t *tx_resume_ind_fifo[NR_MAX_SLOTS_PER_FRAME];
|
||||
int tx_wait_for_dlsch[NR_MAX_SLOTS_PER_FRAME];
|
||||
|
||||
//Sidelink parameters
|
||||
sl_nr_sidelink_mode_t sl_mode;
|
||||
sl_nr_ue_phy_params_t SL_UE_PHY_PARAMS;
|
||||
} PHY_VARS_NR_UE;
|
||||
|
||||
typedef struct {
|
||||
@@ -670,11 +675,20 @@ typedef struct {
|
||||
typedef struct nr_phy_data_tx_s {
|
||||
NR_UE_ULSCH_t ulsch;
|
||||
NR_UE_PUCCH pucch_vars;
|
||||
|
||||
//Sidelink Rx action decided by MAC
|
||||
sl_nr_tx_config_type_enum_t sl_tx_action;
|
||||
sl_nr_tx_config_psbch_pdu_t psbch_vars;
|
||||
|
||||
} nr_phy_data_tx_t;
|
||||
|
||||
typedef struct nr_phy_data_s {
|
||||
NR_UE_PDCCH_CONFIG phy_pdcch_config;
|
||||
NR_UE_DLSCH_t dlsch[2];
|
||||
|
||||
//Sidelink Rx action decided by MAC
|
||||
sl_nr_rx_config_type_enum_t sl_rx_action;
|
||||
|
||||
} nr_phy_data_t;
|
||||
/* this structure is used to pass both UE phy vars and
|
||||
* proc to the function UE_thread_rxn_txnp4
|
||||
|
||||
@@ -169,8 +169,6 @@ struct NR_DL_FRAME_PARMS {
|
||||
/// Frame type (0 FDD, 1 TDD)
|
||||
frame_type_t frame_type;
|
||||
uint8_t tdd_config;
|
||||
/// Sidelink Cell ID
|
||||
uint16_t Nid_SL;
|
||||
/// Cell ID
|
||||
uint16_t Nid_cell;
|
||||
/// subcarrier spacing (15,30,60,120)
|
||||
|
||||
167
openair1/PHY/defs_nr_sl_UE.h
Normal file
167
openair1/PHY/defs_nr_sl_UE.h
Normal file
@@ -0,0 +1,167 @@
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
/*! \file PHY/defs_nr_sl_UE.h
|
||||
\brief Top-level defines and structure definitions
|
||||
\author
|
||||
\date
|
||||
\version
|
||||
\company Fraunhofer
|
||||
\email:
|
||||
\note
|
||||
\warning
|
||||
*/
|
||||
|
||||
#ifndef _DEFS_NR_SL_UE_H_
|
||||
#define _DEFS_NR_SL_UE_H_
|
||||
|
||||
|
||||
|
||||
#include "PHY/types.h"
|
||||
#include "PHY/defs_nr_common.h"
|
||||
#include "nfapi/open-nFAPI/nfapi/public_inc/sidelink_nr_ue_interface.h"
|
||||
#include "common/utils/time_meas.h"
|
||||
|
||||
|
||||
// (33*(13-4))
|
||||
// Normal CP - NUM_SSB_Symbols = 13. 4 symbols for PSS, SSS
|
||||
#define SL_NR_NUM_PSBCH_DMRS_RE 297
|
||||
//ceil(2(QPSK)*SL_NR_NUM_PSBCH_DMRS_RE/32)
|
||||
#define SL_NR_NUM_PSBCH_DMRS_RE_DWORD 20
|
||||
//11 RBs for PSBCH in one symbol * 12 REs
|
||||
#define SL_NR_NUM_PSBCH_RE_IN_ONE_SYMBOL 132
|
||||
//3 DMRS REs per RB * 11 RBS in one symbol
|
||||
#define SL_NR_NUM_PSBCH_DMRS_RE_IN_ONE_SYMBOL 33
|
||||
//9 PSBCH DATA REs * 11 RBS in one symbol
|
||||
#define SL_NR_NUM_PSBCH_DATA_RE_IN_ONE_SYMBOL 99
|
||||
#define SL_NR_NUM_PSBCH_RBS_IN_ONE_SYMBOL 11
|
||||
// SL_NR_POLAR_PSBCH_E_NORMAL_CP/2 bits because QPSK used for PSBCH.
|
||||
// 11 * (12-3 DMRS REs) * 9 symbols for PSBCH
|
||||
#define SL_NR_NUM_PSBCH_MODULATED_SYMBOLS 891
|
||||
#define SL_NR_NUM_PSBCH_DATA_RE_IN_ONE_RB 9
|
||||
#define SL_NR_NUM_PSBCH_DMRS_RE_IN_ONE_RB 3
|
||||
// 11 * (12-3 DMRS REs) * 9 symbols for PSBCH
|
||||
#define SL_NR_NUM_PSBCH_DATA_RE_IN_ALL_SYMBOLS 891
|
||||
|
||||
|
||||
|
||||
#define SL_NR_NUM_SYMBOLS_SSB_NORMAL_CP 13
|
||||
#define SL_NR_NUM_SYMBOLS_SSB_EXT_CP 11
|
||||
#define SL_NR_NUM_PSS_SYMBOLS 2
|
||||
#define SL_NR_NUM_SSS_SYMBOLS 2
|
||||
#define SL_NR_PSS_START_SYMBOL 1
|
||||
#define SL_NR_SSS_START_SYMBOL 3
|
||||
#define SL_NR_NUM_PSS_OR_SSS_SYMBOLS 2
|
||||
#define SL_NR_PSS_SEQUENCE_LENGTH 127
|
||||
#define SL_NR_SSS_SEQUENCE_LENGTH 127
|
||||
#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;
|
||||
|
||||
//(11*(12-3 DMRS REs) * 2 (QPSK used)
|
||||
#define SL_NR_NUM_PSBCH_DATA_BITS_IN_ONE_SYMBOL 198
|
||||
|
||||
typedef struct SL_NR_UE_INIT_PARAMS {
|
||||
|
||||
//gold sequences for PSBCH DMRS
|
||||
uint32_t psbch_dmrs_gold_sequences[SL_NR_NUM_SLSS_IDs][SL_NR_NUM_PSBCH_DMRS_RE_DWORD]; // Gold sequences for PSBCH DMRS
|
||||
|
||||
//PSBCH DMRS QPSK modulated symbols for all possible SLSS Ids
|
||||
struct complex16 psbch_dmrs_modsym[SL_NR_NUM_SLSS_IDs][SL_NR_NUM_PSBCH_DMRS_RE];
|
||||
|
||||
// Scaled values
|
||||
int16_t sl_pss[SL_NR_NUM_IDs_IN_PSS][SL_NR_PSS_SEQUENCE_LENGTH];
|
||||
int16_t sl_sss[SL_NR_NUM_SLSS_IDs][SL_NR_SSS_SEQUENCE_LENGTH];
|
||||
|
||||
// Contains Not scaled values just the simple generated sequence
|
||||
int16_t sl_pss_for_sync[SL_NR_NUM_IDs_IN_PSS][SL_NR_PSS_SEQUENCE_LENGTH];
|
||||
int16_t sl_sss_for_sync[SL_NR_NUM_SLSS_IDs][SL_NR_SSS_SEQUENCE_LENGTH];
|
||||
|
||||
int32_t **sl_pss_for_correlation; // IFFT samples for correlation
|
||||
|
||||
} SL_NR_UE_INIT_PARAMS_t;
|
||||
|
||||
typedef struct SL_NR_SYNC_PARAMS {
|
||||
|
||||
// Indicating start of SSB block in the initial set of samples
|
||||
uint32_t ssb_offset;
|
||||
// Freq Offset calculated
|
||||
int32_t freq_offset;
|
||||
|
||||
uint32_t remaining_frames;
|
||||
uint32_t rx_offset;
|
||||
uint32_t slot_offset;
|
||||
uint16_t N_sl_id2; //id2 determined from PSS during sync ref UE selection
|
||||
uint16_t N_sl_id1; //id2 determined from SSS during sync ref UE selection
|
||||
uint16_t N_sl_id; //ID calculated from ID1 and ID2
|
||||
int32_t psbch_rsrp; //rsrp of the decoded psbch during sync ref ue selection
|
||||
uint32_t DFN; // DFN calculated after sync ref UE search
|
||||
|
||||
} SL_NR_SYNC_PARAMS_t;
|
||||
|
||||
typedef struct SL_NR_UE_PSBCH {
|
||||
|
||||
// AVG POWER OF PSBCH DMRS in dB/RE
|
||||
int16_t rsrp_dB_per_RE;
|
||||
// AVG POWER OF PSBCH DMRS in dBm/RE
|
||||
int16_t rsrp_dBm_per_RE;
|
||||
|
||||
// STATS - CRC Errors observed during PSBCH reception
|
||||
uint16_t rx_errors;
|
||||
|
||||
// STATS - Receptions with CRC OK
|
||||
uint16_t rx_ok;
|
||||
|
||||
// STATS - transmissions of PSBCH by the UE
|
||||
uint16_t num_psbch_tx;
|
||||
|
||||
} SL_NR_UE_PSBCH_t;
|
||||
|
||||
typedef struct sl_nr_ue_phy_params {
|
||||
|
||||
SL_NR_UE_INIT_PARAMS_t init_params;
|
||||
|
||||
SL_NR_SYNC_PARAMS_t sync_params;
|
||||
|
||||
// Sidelink PHY PARAMETERS USED FOR PSBCH reception/Txn
|
||||
SL_NR_UE_PSBCH_t psbch;
|
||||
|
||||
//Configuration parameters from MAC
|
||||
sl_nr_phy_config_request_t sl_config;
|
||||
|
||||
NR_DL_FRAME_PARMS sl_frame_params;
|
||||
|
||||
time_stats_t phy_proc_sl_tx;
|
||||
time_stats_t phy_proc_sl_rx;
|
||||
time_stats_t channel_estimation_stats;
|
||||
time_stats_t ue_sl_indication_stats;
|
||||
|
||||
} sl_nr_ue_phy_params_t;
|
||||
|
||||
|
||||
#endif
|
||||
@@ -98,6 +98,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 */
|
||||
|
||||
|
||||
@@ -191,5 +191,28 @@ int nr_ue_csi_im_procedures(PHY_VARS_NR_UE *ue, UE_nr_rxtx_proc_t *proc, c16_t r
|
||||
|
||||
void nr_ue_csi_rs_procedures(PHY_VARS_NR_UE *ue, UE_nr_rxtx_proc_t *proc, c16_t rxdataF[][ue->frame_parms.samples_per_slot_wCP]);
|
||||
|
||||
|
||||
void 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);
|
||||
/*! \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,
|
||||
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,
|
||||
void *typeSpecific,
|
||||
uint16_t rx_slss_id);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -391,6 +391,11 @@ int8_t nr_ue_scheduled_response(nr_scheduled_response_t *scheduled_response){
|
||||
bool found = false;
|
||||
if(scheduled_response != NULL){
|
||||
|
||||
if (scheduled_response->sl_rx_config || scheduled_response->sl_tx_config) {
|
||||
sl_handle_scheduled_response(scheduled_response);
|
||||
return 0;
|
||||
}
|
||||
|
||||
module_id_t module_id = scheduled_response->module_id;
|
||||
uint8_t cc_id = scheduled_response->CC_id;
|
||||
int slot = scheduled_response->slot;
|
||||
@@ -661,3 +666,84 @@ 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;
|
||||
}
|
||||
|
||||
int8_t 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));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
* 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)
|
||||
*/
|
||||
int8_t sl_handle_scheduled_response(nr_scheduled_response_t *scheduled_response) {
|
||||
|
||||
module_id_t module_id = scheduled_response->module_id;
|
||||
uint32_t slot = scheduled_response->slot;
|
||||
uint32_t frame = scheduled_response->frame;
|
||||
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,frame,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,frame,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);
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -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);
|
||||
int8_t 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);
|
||||
int8_t 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*/
|
||||
|
||||
@@ -99,3 +99,66 @@ int nr_ue_slot_select(fapi_nr_config_request_t *cfg, int nr_frame, int nr_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 nr_frame, int nr_slot,
|
||||
uint8_t frame_duplex_type)
|
||||
{
|
||||
|
||||
int mu = cfg->sl_bwp_config.sl_scs, 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 0;
|
||||
}
|
||||
|
||||
int slot = (nr_frame%2 == 0) ? nr_slot : ((1<<mu) * NR_NUMBER_OF_SUBFRAMES_PER_FRAME) + nr_slot;
|
||||
|
||||
for(int symbol_count=0; symbol_count<NR_NUMBER_OF_SYMBOLS_PER_SLOT; symbol_count++) {
|
||||
if (cfg->tdd_table.max_tdd_periodicity_list[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;
|
||||
|
||||
}
|
||||
@@ -875,12 +875,15 @@ void pbch_pdcch_processing(PHY_VARS_NR_UE *ue,
|
||||
|
||||
for (int i=1; i<4; i++) {
|
||||
nr_slot_fep(ue,
|
||||
fp,
|
||||
proc,
|
||||
(ssb_start_symbol+i)%(fp->symbols_per_slot),
|
||||
rxdataF);
|
||||
rxdataF,
|
||||
link_type_dl);
|
||||
|
||||
start_meas(&ue->dlsch_channel_estimation_stats);
|
||||
nr_pbch_channel_estimation(ue,
|
||||
&ue->frame_parms,
|
||||
estimateSz,
|
||||
dl_ch_estimates,
|
||||
dl_ch_estimates_time,
|
||||
@@ -889,7 +892,9 @@ void pbch_pdcch_processing(PHY_VARS_NR_UE *ue,
|
||||
i-1,
|
||||
ssb_index&7,
|
||||
ssb_slot_2 == nr_slot_rx,
|
||||
rxdataF);
|
||||
rxdataF,
|
||||
false,
|
||||
fp->Nid_cell);
|
||||
stop_meas(&ue->dlsch_channel_estimation_stats);
|
||||
}
|
||||
|
||||
@@ -939,9 +944,11 @@ void pbch_pdcch_processing(PHY_VARS_NR_UE *ue,
|
||||
for(int j = prs_config->SymbolStart; j < (prs_config->SymbolStart+prs_config->NumPRSSymbols); j++)
|
||||
{
|
||||
nr_slot_fep(ue,
|
||||
fp,
|
||||
proc,
|
||||
(j%fp->symbols_per_slot),
|
||||
rxdataF);
|
||||
rxdataF,
|
||||
link_type_dl);
|
||||
}
|
||||
nr_prs_channel_estimation(rsc_id,
|
||||
i,
|
||||
@@ -978,9 +985,11 @@ void pbch_pdcch_processing(PHY_VARS_NR_UE *ue,
|
||||
|
||||
start_meas(&ue->ofdm_demod_stats);
|
||||
nr_slot_fep(ue,
|
||||
fp,
|
||||
proc,
|
||||
l,
|
||||
rxdataF);
|
||||
rxdataF,
|
||||
link_type_dl);
|
||||
}
|
||||
|
||||
// Hold the channel estimates in frequency domain.
|
||||
@@ -1039,9 +1048,11 @@ void pdsch_processing(PHY_VARS_NR_UE *ue,
|
||||
|
||||
for (uint16_t m=start_symb_sch;m<(nb_symb_sch+start_symb_sch) ; m++){
|
||||
nr_slot_fep(ue,
|
||||
&ue->frame_parms,
|
||||
proc,
|
||||
m, //to be updated from higher layer
|
||||
rxdataF);
|
||||
rxdataF,
|
||||
link_type_dl);
|
||||
}
|
||||
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_SLOT_FEP_PDSCH, VCD_FUNCTION_OUT);
|
||||
|
||||
@@ -1116,7 +1127,7 @@ void pdsch_processing(PHY_VARS_NR_UE *ue,
|
||||
}
|
||||
l_csiim[symb_idx] = ue->csiim_vars[gNB_id]->csiim_config_pdu.l_csiim[symb_idx];
|
||||
if(nr_slot_fep_done == false) {
|
||||
nr_slot_fep(ue, proc, ue->csiim_vars[gNB_id]->csiim_config_pdu.l_csiim[symb_idx], rxdataF);
|
||||
nr_slot_fep(ue, &ue->frame_parms, proc, ue->csiim_vars[gNB_id]->csiim_config_pdu.l_csiim[symb_idx], rxdataF, link_type_dl);
|
||||
}
|
||||
}
|
||||
nr_ue_csi_im_procedures(ue, proc, rxdataF);
|
||||
@@ -1127,7 +1138,7 @@ void pdsch_processing(PHY_VARS_NR_UE *ue,
|
||||
if ((ue->csirs_vars[gNB_id]) && (ue->csirs_vars[gNB_id]->active == 1)) {
|
||||
for(int symb = 0; symb < NR_SYMBOLS_PER_SLOT; symb++) {
|
||||
if(is_csi_rs_in_symbol(ue->csirs_vars[gNB_id]->csirs_config_pdu,symb)) {
|
||||
nr_slot_fep(ue, proc, symb, rxdataF);
|
||||
nr_slot_fep(ue, &ue->frame_parms, proc, symb, rxdataF, link_type_dl);
|
||||
}
|
||||
}
|
||||
nr_ue_csi_rs_procedures(ue, proc, rxdataF);
|
||||
|
||||
328
openair1/SCHED_NR_UE/phy_procedures_nr_ue_sl.c
Normal file
328
openair1/SCHED_NR_UE/phy_procedures_nr_ue_sl.c
Normal file
@@ -0,0 +1,328 @@
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include "PHY/defs_nr_UE.h"
|
||||
#include <openair1/PHY/TOOLS/phy_scope_interface.h>
|
||||
#include "common/utils/LOG/log.h"
|
||||
#include "common/utils/LOG/vcd_signal_dumper.h"
|
||||
#include "UTIL/OPT/opt.h"
|
||||
#include "intertask_interface.h"
|
||||
#include "T.h"
|
||||
#include "PHY/MODULATION/modulation_UE.h"
|
||||
#include "PHY/NR_UE_ESTIMATION/nr_estimation.h"
|
||||
#include "PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h"
|
||||
|
||||
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,
|
||||
PHY_VARS_NR_UE *ue,
|
||||
void *phy_data)
|
||||
{
|
||||
memset((void*)sl_ind, 0, sizeof(nr_sidelink_indication_t));
|
||||
|
||||
sl_ind->gNB_index = proc->gNB_id;
|
||||
sl_ind->module_id = ue->Mod_id;
|
||||
sl_ind->cc_id = ue->CC_id;
|
||||
sl_ind->frame_rx = proc->frame_rx;
|
||||
sl_ind->slot_rx = proc->nr_slot_rx;
|
||||
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
|
||||
sl_ind->sci_ind = NULL;
|
||||
}
|
||||
if (sci_ind) {
|
||||
sl_ind->rx_ind = NULL;
|
||||
sl_ind->sci_ind = sci_ind;
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
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__);
|
||||
}
|
||||
|
||||
sl_nr_ue_phy_params_t *sl_phy_params = &ue->SL_UE_PHY_PARAMS;
|
||||
|
||||
switch (pdu_type){
|
||||
case SL_NR_RX_PDU_TYPE_SLSCH:
|
||||
break;
|
||||
case FAPI_NR_RX_PDU_TYPE_SSB: {
|
||||
sl_nr_ssb_pdu_t *ssb_pdu = &rx_ind->rx_indication_body[n_pdus - 1].ssb_pdu;
|
||||
if(typeSpecific) {
|
||||
uint8_t *psbch_decoded_output = (uint8_t *)typeSpecific;
|
||||
memcpy(ssb_pdu->psbch_payload, psbch_decoded_output, sizeof(4));//4 bytes of PSBCH payload bytes
|
||||
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, "SL-IND: SSB to MAC. rsrp:%d, slssid:%d, payload:%x\n",
|
||||
ssb_pdu->rsrp_dbm,ssb_pdu->rx_slss_id,
|
||||
*((uint32_t *)(ssb_pdu->psbch_payload)) );
|
||||
}
|
||||
else
|
||||
ssb_pdu->decode_status = false;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
rx_ind->rx_indication_body[n_pdus -1].pdu_type = pdu_type;
|
||||
rx_ind->number_pdus = n_pdus;
|
||||
|
||||
}
|
||||
|
||||
static int nr_ue_psbch_procedures(PHY_VARS_NR_UE *ue,
|
||||
NR_DL_FRAME_PARMS *fp,
|
||||
UE_nr_rxtx_proc_t *proc,
|
||||
int estimateSz,
|
||||
struct complex16 dl_ch_estimates[][estimateSz],
|
||||
nr_phy_data_t *phy_data,
|
||||
c16_t rxdataF[][fp->samples_per_slot_wCP])
|
||||
{
|
||||
|
||||
int ret = 0;
|
||||
DevAssert(ue);
|
||||
|
||||
int frame_rx = proc->frame_rx;
|
||||
int nr_slot_rx = proc->nr_slot_rx;
|
||||
|
||||
sl_nr_ue_phy_params_t *sl_phy_params = &ue->SL_UE_PHY_PARAMS;
|
||||
uint16_t rx_slss_id = sl_phy_params->sl_config.sl_sync_source.rx_slss_id;
|
||||
|
||||
//VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_PSBCH_PROCEDURES, VCD_FUNCTION_IN);
|
||||
|
||||
LOG_D(PHY,"[UE %d] Frame %d Slot %d, Trying PSBCH (SLSS ID %d)\n",
|
||||
ue->Mod_id,frame_rx,nr_slot_rx,
|
||||
sl_phy_params->sl_config.sl_sync_source.rx_slss_id);
|
||||
|
||||
uint8_t decoded_pdu[4] = {0};
|
||||
ret = nr_rx_psbch(ue,
|
||||
proc,
|
||||
estimateSz,
|
||||
dl_ch_estimates,
|
||||
fp,
|
||||
decoded_pdu,
|
||||
rxdataF,
|
||||
sl_phy_params->sl_config.sl_sync_source.rx_slss_id);
|
||||
|
||||
nr_sidelink_indication_t sl_indication;
|
||||
sl_nr_rx_indication_t rx_ind = {0};
|
||||
uint16_t number_pdus = 1;
|
||||
|
||||
uint8_t *result = NULL;
|
||||
if (ret) sl_phy_params->psbch.rx_errors ++;
|
||||
else {
|
||||
result = decoded_pdu;
|
||||
sl_phy_params->psbch.rx_ok ++;
|
||||
}
|
||||
|
||||
nr_fill_sl_indication(&sl_indication, &rx_ind, NULL, proc, ue, phy_data);
|
||||
nr_fill_sl_rx_indication(&rx_ind, SL_NR_RX_PDU_TYPE_SSB, ue, number_pdus, proc, (void *)result, rx_slss_id);
|
||||
|
||||
if (ue->if_inst && ue->if_inst->sl_indication)
|
||||
ue->if_inst->sl_indication(&sl_indication);
|
||||
|
||||
//VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_PSBCH_PROCEDURES, VCD_FUNCTION_OUT);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void psbch_pscch_processing(PHY_VARS_NR_UE *ue,
|
||||
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;
|
||||
sl_nr_ue_phy_params_t *sl_phy_params = &ue->SL_UE_PHY_PARAMS;
|
||||
NR_DL_FRAME_PARMS *fp = &sl_phy_params->sl_frame_params;
|
||||
|
||||
//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);
|
||||
|
||||
const uint32_t rxdataF_sz = fp->samples_per_slot_wCP;
|
||||
__attribute__ ((aligned(32))) c16_t rxdataF[fp->nb_antennas_rx][rxdataF_sz];
|
||||
|
||||
if (phy_data->sl_rx_action == SL_NR_CONFIG_TYPE_RX_PSBCH){
|
||||
|
||||
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);
|
||||
|
||||
__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];
|
||||
|
||||
// 0 for Normal Cyclic Prefix and 1 for EXT CyclicPrefix
|
||||
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);
|
||||
|
||||
start_meas(&sl_phy_params->channel_estimation_stats);
|
||||
nr_pbch_channel_estimation(ue,
|
||||
fp,
|
||||
estimateSz,
|
||||
dl_ch_estimates,
|
||||
dl_ch_estimates_time,
|
||||
proc,
|
||||
sym,
|
||||
sym,
|
||||
0,
|
||||
0,
|
||||
rxdataF,
|
||||
true,
|
||||
sl_phy_params->sl_config.sl_sync_source.rx_slss_id);
|
||||
stop_meas(&sl_phy_params->channel_estimation_stats);
|
||||
|
||||
//PSBCH present in symbols 0, 5-12 for normal cp
|
||||
sym = (sym == 0) ? 5 : sym + 1;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
nr_adjust_synch_ue(fp,
|
||||
ue,
|
||||
proc->gNB_id,
|
||||
fp->ofdm_symbol_size,
|
||||
dl_ch_estimates_time,
|
||||
frame_rx,
|
||||
nr_slot_rx,
|
||||
0,
|
||||
16384);
|
||||
}
|
||||
ue->apply_timing_offset = true;
|
||||
|
||||
LOG_D(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);
|
||||
|
||||
if (frame_rx%64 == 0) {
|
||||
LOG_I(NR_PHY,"============================================\n");
|
||||
|
||||
LOG_I(NR_PHY,"[UE%d] %d:%d PSBCH Stats: TX %d, RX ok %d, RX not ok %d\n",
|
||||
ue->Mod_id, frame_rx, nr_slot_rx,
|
||||
sl_phy_params->psbch.num_psbch_tx,
|
||||
sl_phy_params->psbch.rx_ok,
|
||||
sl_phy_params->psbch.rx_errors);
|
||||
|
||||
LOG_I(NR_PHY,"============================================\n");
|
||||
}
|
||||
}
|
||||
|
||||
UEscopeCopy(ue, commonRxdataF, rxdataF, sizeof(int32_t), fp->nb_antennas_rx, rxdataF_sz, 0);
|
||||
}
|
||||
|
||||
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 slot_tx = proc->nr_slot_tx;
|
||||
int frame_tx = proc->frame_tx;
|
||||
int tx_action = 0;
|
||||
|
||||
sl_nr_ue_phy_params_t *sl_phy_params = &ue->SL_UE_PHY_PARAMS;
|
||||
NR_DL_FRAME_PARMS *fp = &sl_phy_params->sl_frame_params;
|
||||
|
||||
//VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_UE_TX_SL,VCD_FUNCTION_IN);
|
||||
|
||||
const int samplesF_per_slot = NR_SYMBOLS_PER_SLOT * fp->ofdm_symbol_size;
|
||||
c16_t txdataF_buf[fp->nb_antennas_tx * samplesF_per_slot] __attribute__((aligned(32)));
|
||||
memset(txdataF_buf, 0, sizeof(txdataF_buf));
|
||||
c16_t *txdataF[fp->nb_antennas_tx]; /* workaround to be compatible with current txdataF usage in all tx procedures. */
|
||||
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);
|
||||
|
||||
start_meas(&sl_phy_params->phy_proc_sl_tx);
|
||||
|
||||
if (phy_data->sl_tx_action == SL_NR_CONFIG_TYPE_TX_PSBCH) {
|
||||
sl_nr_tx_config_psbch_pdu_t *psbch_vars = &phy_data->psbch_vars;
|
||||
nr_tx_psbch(ue, frame_tx, slot_tx, psbch_vars, txdataF);
|
||||
sl_phy_params->psbch.num_psbch_tx ++;
|
||||
|
||||
if (frame_tx%64 == 0) {
|
||||
LOG_I(NR_PHY,"============================================\n");
|
||||
|
||||
LOG_I(NR_PHY,"[UE%d] %d:%d PSBCH Stats: TX %d, RX ok %d, RX not ok %d\n",
|
||||
ue->Mod_id, frame_tx, slot_tx,
|
||||
sl_phy_params->psbch.num_psbch_tx,
|
||||
sl_phy_params->psbch.rx_ok,
|
||||
sl_phy_params->psbch.rx_errors);
|
||||
|
||||
LOG_I(NR_PHY,"============================================\n");
|
||||
}
|
||||
tx_action = 1;
|
||||
}
|
||||
|
||||
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(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;
|
||||
}
|
||||
@@ -49,3 +49,12 @@ int8_t nr_mac_rrc_data_ind_ue(const module_id_t module_id,
|
||||
const channel_t channel,
|
||||
const uint8_t* pduP,
|
||||
const sdu_size_t pdu_len) { return 0; }
|
||||
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;}
|
||||
|
||||
@@ -797,12 +797,13 @@ int main(int argc, char **argv)
|
||||
proc.gNB_id = 0;
|
||||
for (int i=UE->symbol_offset+1; i<UE->symbol_offset+4; i++) {
|
||||
nr_slot_fep(UE,
|
||||
frame_parms,
|
||||
&proc,
|
||||
i%frame_parms->symbols_per_slot,
|
||||
rxdataF);
|
||||
rxdataF, link_type_dl);
|
||||
|
||||
nr_pbch_channel_estimation(UE,estimateSz, dl_ch_estimates, dl_ch_estimates_time, &proc,
|
||||
i%frame_parms->symbols_per_slot,i-(UE->symbol_offset+1),ssb_index%8,n_hf,rxdataF);
|
||||
nr_pbch_channel_estimation(UE,&UE->frame_parms, estimateSz, dl_ch_estimates, dl_ch_estimates_time, &proc,
|
||||
i%frame_parms->symbols_per_slot,i-(UE->symbol_offset+1),ssb_index%8,n_hf,rxdataF,false,frame_parms->Nid_cell);
|
||||
|
||||
}
|
||||
fapiPbch_t result;
|
||||
|
||||
657
openair1/SIMULATION/NR_PHY/psbchsim.c
Normal file
657
openair1/SIMULATION/NR_PHY/psbchsim.c
Normal file
@@ -0,0 +1,657 @@
|
||||
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/mman.h>
|
||||
#include "common/config/config_userapi.h"
|
||||
#include "common/ran_context.h"
|
||||
#include "PHY/types.h"
|
||||
#include "PHY/defs_nr_common.h"
|
||||
#include "PHY/defs_nr_UE.h"
|
||||
#include "PHY/defs_gNB.h"
|
||||
#include "PHY/phy_vars.h"
|
||||
#include "NR_MasterInformationBlockSidelink.h"
|
||||
#include "PHY/INIT/phy_init.h"
|
||||
#include "openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h"
|
||||
#include "openair1/SIMULATION/TOOLS/sim.h"
|
||||
#include "common/utils/nr/nr_common.h"
|
||||
#include "openair2/RRC/NR/nr_rrc_extern.h"
|
||||
#include "openair2/RRC/LTE/rrc_vars.h"
|
||||
#include "PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h"
|
||||
#include "PHY/INIT/nr_phy_init.h"
|
||||
#include "SIMULATION/RF/rf.h"
|
||||
#include "common/utils/load_module_shlib.h"
|
||||
#include "PHY/MODULATION/nr_modulation.h"
|
||||
#include "NR_SL-SSB-TimeAllocation-r16.h"
|
||||
void exit_function(const char* file, const char* function, const int line, const char* s, const int assert) {
|
||||
const char * msg= s==NULL ? "no comment": s;
|
||||
printf("Exiting at: %s:%d %s(), %s\n", file, line, function, msg);
|
||||
exit(-1);
|
||||
}
|
||||
int8_t nr_rrc_RA_succeeded(const module_id_t mod_id, const uint8_t gNB_index) { return 1; }
|
||||
// to solve link errors
|
||||
double cpuf;
|
||||
//void init_downlink_harq_status(NR_DL_UE_HARQ_t *dl_harq) {}
|
||||
void get_num_re_dmrs(nfapi_nr_ue_pusch_pdu_t *pusch_pdu,
|
||||
uint8_t *nb_dmrs_re_per_rb,
|
||||
uint16_t *number_dmrs_symbols){}
|
||||
uint64_t downlink_frequency[1][1];
|
||||
int32_t uplink_frequency_offset[1][1];
|
||||
THREAD_STRUCT thread_struct;
|
||||
instance_t DUuniqInstance=0;
|
||||
instance_t CUuniqInstance=0;
|
||||
openair0_config_t openair0_cfg[1];
|
||||
|
||||
RAN_CONTEXT_t RC;
|
||||
int oai_exit = 0;
|
||||
char *uecap_file;
|
||||
|
||||
void nr_rrc_ue_generate_RRCSetupRequest(module_id_t module_id, const uint8_t gNB_index)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int8_t nr_mac_rrc_data_req_ue(const module_id_t Mod_idP,
|
||||
const int CC_id,
|
||||
const uint8_t gNB_id,
|
||||
const frame_t frameP,
|
||||
const rb_id_t Srb_id,
|
||||
uint8_t *buffer_pP)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
nr_bler_struct nr_bler_data[NR_NUM_MCS];
|
||||
void get_nrUE_params(void) { return;}
|
||||
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) {
|
||||
|
||||
NR_MasterInformationBlockSidelink_t *sl_mib;
|
||||
asn_enc_rval_t enc_rval;
|
||||
|
||||
void *buffer = (void *)buf;
|
||||
|
||||
sl_mib = CALLOC(1, sizeof(NR_MasterInformationBlockSidelink_t));
|
||||
|
||||
sl_mib->inCoverage_r16 = 0;//TRUE;
|
||||
|
||||
// allocate buffer for 7 bits slotnumber
|
||||
sl_mib->slotIndex_r16.size = 1;
|
||||
sl_mib->slotIndex_r16.buf = CALLOC(1, sl_mib->slotIndex_r16.size);
|
||||
sl_mib->slotIndex_r16.bits_unused = sl_mib->slotIndex_r16.size*8 - 7;
|
||||
sl_mib->slotIndex_r16.buf[0] = slot_tx << sl_mib->slotIndex_r16.bits_unused;
|
||||
|
||||
sl_mib->directFrameNumber_r16.size = 2;
|
||||
sl_mib->directFrameNumber_r16.buf = CALLOC(1, sl_mib->directFrameNumber_r16.size);
|
||||
sl_mib->directFrameNumber_r16.bits_unused = sl_mib->directFrameNumber_r16.size*8 - 10;
|
||||
sl_mib->directFrameNumber_r16.buf[0] = frame_tx >> (8 - sl_mib->directFrameNumber_r16.bits_unused);
|
||||
sl_mib->directFrameNumber_r16.buf[1] = frame_tx << sl_mib->directFrameNumber_r16.bits_unused;
|
||||
|
||||
enc_rval = uper_encode_to_buffer(&asn_DEF_NR_MasterInformationBlockSidelink,
|
||||
NULL,
|
||||
(void *)sl_mib,
|
||||
buffer,
|
||||
100);
|
||||
|
||||
AssertFatal (enc_rval.encoded > 0, "ASN1 message encoding failed (%s, %lu)!\n",
|
||||
enc_rval.failed_type->name, enc_rval.encoded);
|
||||
|
||||
asn_DEF_NR_MasterInformationBlockSidelink.op->free_struct(&asn_DEF_NR_MasterInformationBlockSidelink, sl_mib, ASFM_FREE_EVERYTHING);
|
||||
|
||||
}
|
||||
|
||||
static int test_rx_mib(uint8_t *decoded_output, uint16_t frame, uint16_t slot) {
|
||||
|
||||
uint32_t sl_mib = *(uint32_t *)decoded_output;
|
||||
|
||||
uint32_t fn = 0, sl = 0;
|
||||
fn = (((sl_mib & 0x0700) >> 1) | ((sl_mib & 0xFE0000) >> 17));
|
||||
sl = (((sl_mib & 0x010000) >> 10) | ((sl_mib & 0xFC000000) >> 26));
|
||||
|
||||
printf("decoded output:%x, TX %d:%d, timing decoded from sl-MIB %d:%d\n",
|
||||
*(uint32_t *)decoded_output, frame, slot, fn, sl);
|
||||
|
||||
if (frame == fn && slot == sl)
|
||||
return 0;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static void configure_NR_UE(PHY_VARS_NR_UE *UE, int mu, int N_RB) {
|
||||
|
||||
fapi_nr_config_request_t config;
|
||||
NR_DL_FRAME_PARMS *fp = &UE->frame_parms;
|
||||
|
||||
config.ssb_config.scs_common = mu;
|
||||
config.cell_config.frame_duplex_type = TDD;
|
||||
config.carrier_config.dl_grid_size[mu] = N_RB;
|
||||
config.carrier_config.ul_grid_size[mu] = N_RB;
|
||||
config.carrier_config.dl_frequency = 0;
|
||||
config.carrier_config.uplink_frequency = 0;
|
||||
|
||||
int band;
|
||||
if (mu == 1) band = 78;
|
||||
if (mu == 0) band = 34;
|
||||
nr_init_frame_parms_ue(fp, &config, band);
|
||||
fp->ofdm_offset_divisor = 8;
|
||||
nr_dump_frame_parms(fp);
|
||||
|
||||
if (init_nr_ue_signal(UE, 1) != 0) {
|
||||
printf("Error at UE NR initialisation\n");
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
static void sl_init_frame_parameters(PHY_VARS_NR_UE *UE) {
|
||||
|
||||
NR_DL_FRAME_PARMS *nr_fp = &UE->frame_parms;
|
||||
NR_DL_FRAME_PARMS *sl_fp = &UE->SL_UE_PHY_PARAMS.sl_frame_params;
|
||||
|
||||
memcpy(sl_fp, nr_fp, sizeof(NR_DL_FRAME_PARMS));
|
||||
sl_fp->ofdm_offset_divisor = 8; // What is this used for?
|
||||
|
||||
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->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;
|
||||
|
||||
#ifdef DEBUG_INIT
|
||||
LOG_I(PHY, "Dumping Sidelink Frame Parameters\n");
|
||||
nr_dump_frame_parms(sl_fp);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
static void configure_SL_UE(PHY_VARS_NR_UE *UE, int mu, int N_RB, int ssb_offset, int slss_id) {
|
||||
|
||||
sl_nr_phy_config_request_t *config = &UE->SL_UE_PHY_PARAMS.sl_config;
|
||||
NR_DL_FRAME_PARMS *fp = &UE->SL_UE_PHY_PARAMS.sl_frame_params;
|
||||
|
||||
config->sl_bwp_config.sl_scs = mu;
|
||||
config->sl_bwp_config.sl_ssb_offset_point_a = ssb_offset;
|
||||
config->sl_carrier_config.sl_bandwidth = N_RB;
|
||||
config->sl_carrier_config.sl_grid_size = 106;
|
||||
config->sl_sync_source.rx_slss_id = slss_id;
|
||||
|
||||
sl_init_frame_parameters(UE);
|
||||
sl_ue_phy_init(UE);
|
||||
init_symbol_rotation(fp);
|
||||
init_timeshift_rotation(fp);
|
||||
LOG_I(PHY, "Dumping Sidelink Frame Parameters\n");
|
||||
nr_dump_frame_parms(fp);
|
||||
}
|
||||
|
||||
static int freq_domain_loopback(PHY_VARS_NR_UE *UE_tx, PHY_VARS_NR_UE *UE_rx,
|
||||
int frame, int slot,
|
||||
nr_phy_data_tx_t *phy_data) {
|
||||
|
||||
sl_nr_ue_phy_params_t *sl_ue1 = &UE_tx->SL_UE_PHY_PARAMS;
|
||||
sl_nr_ue_phy_params_t *sl_ue2 = &UE_rx->SL_UE_PHY_PARAMS;
|
||||
|
||||
printf("\nPSBCH SIM -F: %d:%d slss id TX UE:%d, RX UE:%d\n",
|
||||
frame, slot,phy_data->psbch_vars.tx_slss_id,
|
||||
sl_ue2->sl_config.sl_sync_source.rx_slss_id);
|
||||
|
||||
NR_DL_FRAME_PARMS *fp = &sl_ue1->sl_frame_params;
|
||||
const int samplesF_per_slot = NR_SYMBOLS_PER_SLOT * fp->ofdm_symbol_size;
|
||||
c16_t txdataF_buf[fp->nb_antennas_tx * samplesF_per_slot] __attribute__((aligned(32)));
|
||||
memset(txdataF_buf, 0, sizeof(txdataF_buf));
|
||||
c16_t *txdataF[fp->nb_antennas_tx]; /* workaround to be compatible with current txdataF usage in all tx procedures. */
|
||||
for(int i=0; i< fp->nb_antennas_tx; ++i)
|
||||
txdataF[i] = &txdataF_buf[i * samplesF_per_slot];
|
||||
|
||||
nr_tx_psbch(UE_tx,frame, slot, &phy_data->psbch_vars, txdataF);
|
||||
|
||||
int estimateSz = sl_ue2->sl_frame_params.samples_per_slot_wCP;
|
||||
__attribute__ ((aligned(32))) struct complex16 rxdataF[1][estimateSz];
|
||||
for (int i=0; i<sl_ue1->sl_frame_params.samples_per_slot_wCP; i++) {
|
||||
struct complex16 *txdataF_ptr = (struct complex16 *)&txdataF[0][i];
|
||||
struct complex16 *rxdataF_ptr = (struct complex16 *)&rxdataF[0][i];
|
||||
rxdataF_ptr->r = txdataF_ptr->r;
|
||||
rxdataF_ptr->i = txdataF_ptr->i;
|
||||
//printf("r,i TXDATAF[%d]- %d:%d, RXDATAF[%d]- %d:%d\n",
|
||||
// i, txdataF_ptr->r, txdataF_ptr->i, i, txdataF_ptr->r, txdataF_ptr->i);
|
||||
}
|
||||
|
||||
uint8_t err_status = 0;
|
||||
|
||||
UE_nr_rxtx_proc_t proc;
|
||||
proc.frame_rx = frame;
|
||||
proc.nr_slot_rx = slot;
|
||||
|
||||
struct complex16 dl_ch_estimates[1][estimateSz];
|
||||
uint8_t decoded_output[4] = {0};
|
||||
|
||||
LOG_I(PHY,"DEBUG: HIJACKING DL CHANNEL ESTIMATES.\n");
|
||||
for (int s=0; s<14; s++) {
|
||||
for (int j=0; j<sl_ue2->sl_frame_params.ofdm_symbol_size; j++) {
|
||||
struct complex16 *dlch = (struct complex16 *)(&dl_ch_estimates[0][s*sl_ue2->sl_frame_params.ofdm_symbol_size]);
|
||||
dlch[j].r = 128;
|
||||
dlch[j].i = 0;
|
||||
}
|
||||
}
|
||||
|
||||
err_status = nr_rx_psbch(UE_rx,
|
||||
&proc,
|
||||
estimateSz,
|
||||
dl_ch_estimates,
|
||||
&sl_ue2->sl_frame_params,
|
||||
decoded_output,
|
||||
rxdataF,
|
||||
sl_ue2->sl_config.sl_sync_source.rx_slss_id);
|
||||
|
||||
|
||||
int error_payload = 0;
|
||||
error_payload = test_rx_mib(decoded_output, frame, slot);
|
||||
|
||||
if (err_status == 0 || error_payload == 0) {
|
||||
LOG_I(PHY,"---------PSBCH -F TEST OK.\n");
|
||||
return 0;
|
||||
}
|
||||
LOG_E(PHY, "--------PSBCH -F TEST NOK. FAIL.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
PHY_VARS_NR_UE *UE_TX; // for tx
|
||||
PHY_VARS_NR_UE *UE_RX; // for rx
|
||||
double cpuf;
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
|
||||
char c;
|
||||
int test_freqdomain_loopback = 0,test_slss_search = 0;
|
||||
int frame = 5, slot = 10, frame_tx = 0, slot_tx = 0;
|
||||
int loglvl = OAILOG_INFO;
|
||||
uint16_t slss_id = 336, ssb_offset = 0;
|
||||
double snr1 = 2.0, snr0 = 2.0, SNR;
|
||||
double sigma2 = 0.0, sigma2_dB = 0.0;
|
||||
double cfo=0, ip =0.0;
|
||||
|
||||
SCM_t channel_model=AWGN;//Rayleigh1_anticorr;
|
||||
int N_RB_DL=106,mu=1;
|
||||
|
||||
uint16_t errors = 0, n_trials = 1;
|
||||
|
||||
int frame_length_complex_samples;
|
||||
//int frame_length_complex_samples_no_prefix;
|
||||
NR_DL_FRAME_PARMS *frame_parms;
|
||||
|
||||
int seed = 0;
|
||||
|
||||
cpuf = get_cpu_freq_GHz();
|
||||
|
||||
if ( load_configmodule(argc,argv,CONFIG_ENABLECMDLINEONLY) == 0 ) {
|
||||
exit_fun("SIDELINK PSBCH SIM Error, configuration module init failed\n");
|
||||
}
|
||||
|
||||
randominit(0);
|
||||
|
||||
while ((c = getopt(argc, argv, "c:hn:o:s:FIL:N:R:S:T:")) != -1) {
|
||||
|
||||
printf("SIDELINK PSBCH SIM: handling optarg %c\n",c);
|
||||
switch (c) {
|
||||
|
||||
case 'c':
|
||||
cfo = atof(optarg);
|
||||
printf("Setting CFO to %f Hz\n",cfo);
|
||||
break;
|
||||
|
||||
case 'g':
|
||||
switch((char)*optarg) {
|
||||
case 'A':
|
||||
channel_model=SCM_A;
|
||||
break;
|
||||
|
||||
case 'B':
|
||||
channel_model=SCM_B;
|
||||
break;
|
||||
|
||||
case 'C':
|
||||
channel_model=SCM_C;
|
||||
break;
|
||||
|
||||
case 'D':
|
||||
channel_model=SCM_D;
|
||||
break;
|
||||
|
||||
case 'E':
|
||||
channel_model=EPA;
|
||||
break;
|
||||
|
||||
case 'F':
|
||||
channel_model=EVA;
|
||||
break;
|
||||
|
||||
case 'G':
|
||||
channel_model=ETU;
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("Unsupported channel model! Exiting.\n");
|
||||
exit(-1);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'n':
|
||||
n_trials = atoi(optarg);
|
||||
break;
|
||||
|
||||
case 'o':
|
||||
ssb_offset = atoi(optarg);
|
||||
printf("SIDELINK PSBCH SIM: ssb offset from pointA:%d\n",ssb_offset);
|
||||
break;
|
||||
|
||||
case 's':
|
||||
slss_id = atoi(optarg);
|
||||
printf("SIDELINK PSBCH SIM: slss_id from arg:%d\n",slss_id);
|
||||
AssertFatal(slss_id >= 0 && slss_id <= 671,"SLSS ID not within Range 0-671\n");
|
||||
break;
|
||||
|
||||
case 'F':
|
||||
test_freqdomain_loopback = 1;
|
||||
break;
|
||||
|
||||
case 'I':
|
||||
test_slss_search = 1;
|
||||
printf("SIDELINK PSBCH SIM: SLSS search will be tested\n");
|
||||
break;
|
||||
|
||||
case 'L':
|
||||
loglvl = atoi(optarg);
|
||||
break;
|
||||
|
||||
case 'N':
|
||||
snr0 = atoi(optarg);
|
||||
snr1 = snr0;
|
||||
printf("Setting SNR0 to %f. Test uses this SNR as target SNR\n",snr0);
|
||||
break;
|
||||
|
||||
case 'R':
|
||||
N_RB_DL = atoi(optarg);
|
||||
printf("SIDELINK PSBCH SIM: N_RB_DL:%d\n",N_RB_DL);
|
||||
break;
|
||||
|
||||
case 'S':
|
||||
snr1 = atof(optarg);
|
||||
printf("Setting SNR1 to %f. Test will run until this SNR as target SNR\n",snr1);
|
||||
AssertFatal(snr1 <= snr0, "Test runs SNR down, set snr1 to a lower value than %f\n", snr0);
|
||||
break;
|
||||
|
||||
case 'T':
|
||||
frame = atoi(argv[2]);
|
||||
slot = atoi(argv[3]);
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
default :
|
||||
printf("\n\nSIDELINK PSBCH SIM OPTIONS LIST - hus:FL:T:\n");
|
||||
printf("-h: HELP\n");
|
||||
printf("-c Carrier frequency offset in Hz\n");
|
||||
printf("-n Number of trials\n");
|
||||
printf("-o ssb offset from PointA - indicates ssb_start subcarrier\n");
|
||||
printf("-s: set Sidelink sync id slss_id. ex -s 100\n");
|
||||
printf("-F: Run PSBCH frequency domain loopback test of the samples\n");
|
||||
printf("-I: Sidelink SLSS search will be tested.\n");
|
||||
printf("-L: Set Log Level.\n");
|
||||
printf("-N: Test with Noise. target SNR0 eg -N 10\n");
|
||||
printf("-R N_RB_DL\n");
|
||||
printf("-S Ending SNR, runs from SNR0 to SNR1\n");
|
||||
printf("-T: Frame,Slot to be sent in sl-MIB eg -T 4 2\n");
|
||||
return 1;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
randominit(seed);
|
||||
|
||||
logInit();
|
||||
set_glog(loglvl);
|
||||
T_stdout = 1;
|
||||
|
||||
double fs=0, eps;
|
||||
double scs = 30000;
|
||||
double bw = 100e6;
|
||||
|
||||
switch (mu) {
|
||||
case 1:
|
||||
scs = 30000;
|
||||
if (N_RB_DL == 217) {
|
||||
fs = 122.88e6;
|
||||
bw = 80e6;
|
||||
}
|
||||
else if (N_RB_DL == 245) {
|
||||
fs = 122.88e6;
|
||||
bw = 90e6;
|
||||
}
|
||||
else if (N_RB_DL == 273) {
|
||||
fs = 122.88e6;
|
||||
bw = 100e6;
|
||||
}
|
||||
else if (N_RB_DL == 106) {
|
||||
fs = 61.44e6;
|
||||
bw = 40e6;
|
||||
}
|
||||
else AssertFatal(1==0,"Unsupported numerology for mu %d, N_RB %d\n",mu, N_RB_DL);
|
||||
break;
|
||||
case 3:
|
||||
scs = 120000;
|
||||
if (N_RB_DL == 66) {
|
||||
fs = 122.88e6;
|
||||
bw = 100e6;
|
||||
}
|
||||
else AssertFatal(1==0,"Unsupported numerology for mu %d, N_RB %d\n",mu, N_RB_DL);
|
||||
break;
|
||||
}
|
||||
|
||||
// cfo with respect to sub-carrier spacing
|
||||
eps = cfo/scs;
|
||||
|
||||
// computation of integer and fractional FO to compare with estimation results
|
||||
int IFO;
|
||||
if(eps!=0.0){
|
||||
printf("Introducing a CFO of %lf relative to SCS of %d kHz\n",eps,(int)(scs/1000));
|
||||
if (eps>0)
|
||||
IFO=(int)(eps+0.5);
|
||||
else
|
||||
IFO=(int)(eps-0.5);
|
||||
printf("FFO = %lf; IFO = %d\n",eps-IFO,IFO);
|
||||
}
|
||||
|
||||
channel_desc_t *UE2UE;
|
||||
int n_tx = 1, n_rx = 1;
|
||||
UE2UE = new_channel_desc_scm(n_tx,
|
||||
n_rx,
|
||||
channel_model,
|
||||
fs,
|
||||
0,
|
||||
bw,
|
||||
300e-9,
|
||||
0.0,
|
||||
CORR_LEVEL_LOW,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0);
|
||||
|
||||
if (UE2UE==NULL) {
|
||||
printf("Problem generating channel model. Exiting.\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
/*****configure UE *************************/
|
||||
UE_TX = calloc(1, sizeof(PHY_VARS_NR_UE));
|
||||
UE_RX = calloc(1, sizeof(PHY_VARS_NR_UE));
|
||||
LOG_I(PHY, "Configure UE-TX and sidelink UE-TX.\n");
|
||||
configure_NR_UE(UE_TX, mu, N_RB_DL);
|
||||
configure_SL_UE(UE_TX, mu, N_RB_DL,ssb_offset, 0xFFFF);
|
||||
|
||||
LOG_I(PHY, "Configure UE-RX and sidelink UE-RX.\n");
|
||||
configure_NR_UE(UE_RX, mu, N_RB_DL);
|
||||
UE_RX->is_synchronized = (test_slss_search) ? 0 : 1;
|
||||
configure_SL_UE(UE_RX, mu, N_RB_DL,ssb_offset, slss_id);
|
||||
/*****************************************/
|
||||
sl_nr_ue_phy_params_t *sl_uetx = &UE_TX->SL_UE_PHY_PARAMS;
|
||||
sl_nr_ue_phy_params_t *sl_uerx = &UE_RX->SL_UE_PHY_PARAMS;
|
||||
frame_parms = &sl_uetx->sl_frame_params;
|
||||
frame_tx = frame % 1024;
|
||||
slot_tx = slot % frame_parms->slots_per_frame;
|
||||
|
||||
frame_length_complex_samples = frame_parms->samples_per_subframe*NR_NUMBER_OF_SUBFRAMES_PER_FRAME;
|
||||
//frame_length_complex_samples_no_prefix = frame_parms->samples_per_subframe_wCP;
|
||||
|
||||
double **s_re,**s_im,**r_re,**r_im;
|
||||
s_re = malloc(2*sizeof(double*));
|
||||
s_im = malloc(2*sizeof(double*));
|
||||
r_re = malloc(2*sizeof(double*));
|
||||
r_im = malloc(2*sizeof(double*));
|
||||
|
||||
s_re[0] = malloc16_clear(frame_length_complex_samples*sizeof(double));
|
||||
s_im[0] = malloc16_clear(frame_length_complex_samples*sizeof(double));
|
||||
r_re[0] = malloc16_clear(frame_length_complex_samples*sizeof(double));
|
||||
r_im[0] = malloc16_clear(frame_length_complex_samples*sizeof(double));
|
||||
|
||||
if(eps!=0.0)
|
||||
UE_RX->UE_fo_compensation = 1; // if a frequency offset is set then perform fo estimation and compensation
|
||||
|
||||
UE_nr_rxtx_proc_t proc;
|
||||
proc.frame_tx = frame;
|
||||
proc.nr_slot_tx = slot;
|
||||
nr_phy_data_tx_t phy_data_tx;
|
||||
phy_data_tx.psbch_vars.tx_slss_id = slss_id;
|
||||
|
||||
uint8_t sl_mib[4] = {0};
|
||||
prepare_mib_bits(sl_mib,frame, slot);
|
||||
memcpy(phy_data_tx.psbch_vars.psbch_payload,sl_mib, 4);
|
||||
|
||||
phy_data_tx.sl_tx_action = SL_NR_CONFIG_TYPE_TX_PSBCH;
|
||||
proc.frame_rx = frame;
|
||||
proc.nr_slot_rx = slot;
|
||||
nr_phy_data_t phy_data_rx;
|
||||
phy_data_rx.sl_rx_action = SL_NR_CONFIG_TYPE_RX_PSBCH;
|
||||
|
||||
if (test_freqdomain_loopback) {
|
||||
errors += freq_domain_loopback(UE_TX, UE_RX, frame_tx, slot_tx, &phy_data_tx);
|
||||
}
|
||||
|
||||
printf("\nSidelink TX UE - Frame.Slot %d.%d SLSS id:%d\n",
|
||||
frame, slot,phy_data_tx.psbch_vars.tx_slss_id);
|
||||
printf("Sidelink RX UE - Frame.Slot %d.%d SLSS id:%d\n",
|
||||
proc.frame_rx, proc.nr_slot_rx,
|
||||
sl_uerx->sl_config.sl_sync_source.rx_slss_id);
|
||||
|
||||
phy_procedures_nrUE_SL_TX(UE_TX, &proc, &phy_data_tx);
|
||||
|
||||
for (SNR=snr0; SNR>=snr1; SNR-=1) {
|
||||
|
||||
for (int trial=0; trial<n_trials; trial++) {
|
||||
|
||||
for (int i=0; i<frame_length_complex_samples; i++) {
|
||||
for (int aa=0; aa<frame_parms->nb_antennas_tx; aa++) {
|
||||
struct complex16 *txdata_ptr = (struct complex16 *)&UE_TX->common_vars.txData[aa][i];
|
||||
r_re[aa][i] = (double)txdata_ptr->r;
|
||||
r_im[aa][i] = (double)txdata_ptr->i;
|
||||
}
|
||||
}
|
||||
|
||||
LOG_M("txData0.m","txd0", UE_TX->common_vars.txData[0],frame_parms->samples_per_frame,1,1);
|
||||
|
||||
//AWGN
|
||||
sigma2_dB = 20*log10((double)AMP/4)-SNR;
|
||||
sigma2 = pow(10,sigma2_dB/10);
|
||||
//printf("sigma2 %f (%f dB), tx_lev %f (%f dB)\n",sigma2,sigma2_dB,txlev,10*log10((double)txlev));
|
||||
|
||||
if(eps!=0.0) {
|
||||
rf_rx(r_re, // real part of txdata
|
||||
r_im, // imag part of txdata
|
||||
NULL, // interference real part
|
||||
NULL, // interference imag part
|
||||
0, // interference power
|
||||
frame_parms->nb_antennas_rx, // number of rx antennas
|
||||
frame_length_complex_samples, // number of samples in frame
|
||||
1.0e9/fs, //sampling time (ns)
|
||||
cfo, // frequency offset in Hz
|
||||
0.0, // drift (not implemented)
|
||||
0.0, // noise figure (not implemented)
|
||||
0.0, // rx gain in dB ?
|
||||
200, // 3rd order non-linearity in dB ?
|
||||
&ip, // initial phase
|
||||
30.0e3, // phase noise cutoff in kHz
|
||||
-500.0, // phase noise amplitude in dBc
|
||||
0.0, // IQ imbalance (dB),
|
||||
0.0); // IQ phase imbalance (rad)
|
||||
}
|
||||
|
||||
for (int i=0; i<frame_length_complex_samples; i++) {
|
||||
for (int aa=0; aa<frame_parms->nb_antennas_rx; aa++) {
|
||||
UE_RX->common_vars.rxdata[aa][i].r = (short)(r_re[aa][i] + sqrt(sigma2 / 2) * gaussdouble(0.0, 1.0));
|
||||
UE_RX->common_vars.rxdata[aa][i].i = (short)(r_im[aa][i] + sqrt(sigma2 / 2) * gaussdouble(0.0, 1.0));
|
||||
}
|
||||
}
|
||||
|
||||
if (UE_RX->is_synchronized == 0) {
|
||||
int ret = -1;
|
||||
UE_nr_rxtx_proc_t proc={0};
|
||||
//Should not have SLSS id configured. Search should find SLSS id from TX UE
|
||||
UE_RX->SL_UE_PHY_PARAMS.sl_config.sl_sync_source.rx_slss_id = 0xFFFF;
|
||||
ret = sl_nr_slss_search(UE_RX, &proc, 1);
|
||||
printf("Sidelink SLSS search returns %d\n",ret);
|
||||
if (ret!=0) sl_uerx->psbch.rx_errors = 1;
|
||||
else {
|
||||
AssertFatal(UE_RX->SL_UE_PHY_PARAMS.sync_params.N_sl_id == slss_id,
|
||||
"DETECTED INCORRECT SLSS ID in SEARCH.CHECK id:%d\n", UE_RX->SL_UE_PHY_PARAMS.sync_params.N_sl_id);
|
||||
sl_uerx->psbch.rx_ok = 1;
|
||||
}
|
||||
} else psbch_pscch_processing(UE_RX,&proc,&phy_data_rx);
|
||||
|
||||
} //noise trials
|
||||
|
||||
printf("Runs:%d SNR %f: SLSS Search:%d crc ERRORs = %d, OK = %d\n",
|
||||
n_trials, SNR, !UE_RX->is_synchronized,
|
||||
sl_uerx->psbch.rx_errors, sl_uerx->psbch.rx_ok);
|
||||
errors += sl_uerx->psbch.rx_errors;
|
||||
sl_uerx->psbch.rx_errors = 0;
|
||||
sl_uerx->psbch.rx_ok = 0;
|
||||
|
||||
} // NSR
|
||||
|
||||
if (errors == 0)
|
||||
LOG_I(PHY,"PSBCH test OK\n");
|
||||
else
|
||||
LOG_E(PHY,"PSBCH test NOT OK\n");
|
||||
|
||||
free_channel_desc_scm(UE2UE);
|
||||
|
||||
free(s_re[0]);
|
||||
free(s_im[0]);
|
||||
free(r_re[0]);
|
||||
free(r_im[0]);
|
||||
free(s_re);
|
||||
free(s_im);
|
||||
free(r_re);
|
||||
free(r_im);
|
||||
|
||||
term_nr_ue_signal(UE_TX, 1);
|
||||
term_nr_ue_signal(UE_RX, 1);
|
||||
|
||||
free(UE_TX);
|
||||
free(UE_RX);
|
||||
logTerm();
|
||||
loader_reset();
|
||||
|
||||
return errors;
|
||||
}
|
||||
|
||||
|
||||
614
openair2/LAYER2/NR_MAC_UE/config_ue_sl.c
Normal file
614
openair2/LAYER2/NR_MAC_UE/config_ue_sl.c
Normal file
@@ -0,0 +1,614 @@
|
||||
/*
|
||||
* 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 "openair2/LAYER2/NR_MAC_UE/mac_defs.h"
|
||||
#include "NR_SidelinkPreconfigNR-r16.h"
|
||||
#include "mac_proto.h"
|
||||
|
||||
void sl_ue_mac_free(uint8_t module_id)
|
||||
{
|
||||
|
||||
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;
|
||||
|
||||
uint8_t syncsource = sl_config->sl_sync_source.sync_source;
|
||||
|
||||
//Allocated by MAC only in case of SYNC_REF_UE
|
||||
//else it is freed as part of RRC pre-config structure
|
||||
if (syncsource == SL_SYNC_SOURCE_SYNC_REF_UE &&
|
||||
mac->SL_MAC_PARAMS->sl_TDD_config) {
|
||||
ASN_STRUCT_FREE (asn_DEF_NR_TDD_UL_DL_Pattern, mac->SL_MAC_PARAMS->sl_TDD_config);
|
||||
mac->SL_MAC_PARAMS->sl_TDD_config = NULL;
|
||||
}
|
||||
|
||||
fapi_nr_max_tdd_periodicity_t *tdd_list =
|
||||
sl_config->tdd_table.max_tdd_periodicity_list;
|
||||
|
||||
// @todo: maybe this should be done by phy
|
||||
if (tdd_list) {
|
||||
int mu = sl_config->sl_bwp_config.sl_scs;
|
||||
int nb_slots_to_set = TDD_CONFIG_NB_FRAMES*(1<<mu)*NR_NUMBER_OF_SUBFRAMES_PER_FRAME;
|
||||
for (int i=0; i<nb_slots_to_set; i++) {
|
||||
free_and_zero(tdd_list[i].max_num_of_symbol_per_slot_list);
|
||||
}
|
||||
free_and_zero(sl_config->tdd_table.max_tdd_periodicity_list);
|
||||
}
|
||||
|
||||
for (int i=0;i<SL_NR_MAC_NUM_RX_RESOURCE_POOLS;i++) {
|
||||
free_and_zero(mac->SL_MAC_PARAMS->sl_RxPool[i]);
|
||||
}
|
||||
for (int i=0;i<SL_NR_MAC_NUM_TX_RESOURCE_POOLS;i++) {
|
||||
free_and_zero(mac->SL_MAC_PARAMS->sl_TxPool[i]);
|
||||
}
|
||||
|
||||
free_and_zero(mac->SL_MAC_PARAMS);
|
||||
}
|
||||
|
||||
|
||||
//Prepares the TDD config to be passed to PHY
|
||||
static int sl_set_tdd_config_nr_ue(sl_nr_phy_config_request_t *cfg,
|
||||
int mu,
|
||||
int nrofDownlinkSlots, int nrofDownlinkSymbols,
|
||||
int nrofUplinkSlots, int nrofUplinkSymbols)
|
||||
{
|
||||
|
||||
|
||||
int slot_number = 0;
|
||||
int nb_periods_per_frame = get_nb_periods_per_frame(cfg->tdd_table.tdd_period);
|
||||
int nb_slots_to_set = TDD_CONFIG_NB_FRAMES*(1<<mu)*NR_NUMBER_OF_SUBFRAMES_PER_FRAME;
|
||||
|
||||
int nb_slots_per_period = ((1<<mu) * NR_NUMBER_OF_SUBFRAMES_PER_FRAME)/nb_periods_per_frame;
|
||||
cfg->tdd_table.tdd_period_in_slots = nb_slots_per_period;
|
||||
|
||||
if ((nrofDownlinkSlots == 0) && (nrofDownlinkSymbols == 0)) {
|
||||
nrofDownlinkSymbols = (nrofUplinkSymbols) ? 14 - nrofUplinkSymbols : 0;
|
||||
nrofDownlinkSlots = nb_slots_per_period - nrofUplinkSlots;
|
||||
if (nrofDownlinkSymbols) nrofDownlinkSlots -= 1;
|
||||
}
|
||||
|
||||
LOG_I(NR_MAC,"Set Phy Sidelink TDD Config: scs:%d,dl:%d-%d, ul:%d-%d, nb_periods_per_frame:%d, nb_slots_per_period:%d\n",
|
||||
mu, nrofDownlinkSlots, nrofDownlinkSymbols, nrofUplinkSlots, nrofUplinkSymbols, nb_periods_per_frame, nb_slots_per_period);
|
||||
|
||||
if ( (nrofDownlinkSymbols + nrofUplinkSymbols) == 0 )
|
||||
AssertFatal(nb_slots_per_period == (nrofDownlinkSlots + nrofUplinkSlots),
|
||||
"set_tdd_configuration_nr: given period is inconsistent with current tdd configuration, nrofDownlinkSlots %d, nrofUplinkSlots %d, nb_slots_per_period %d \n",
|
||||
nrofDownlinkSlots,nrofUplinkSlots,nb_slots_per_period);
|
||||
else {
|
||||
AssertFatal(nrofDownlinkSymbols + nrofUplinkSymbols <= 14,"illegal symbol configuration DL %d, UL %d\n",nrofDownlinkSymbols,nrofUplinkSymbols);
|
||||
AssertFatal(nb_slots_per_period == (nrofDownlinkSlots + nrofUplinkSlots + 1),
|
||||
"set_tdd_configuration_nr: given period is inconsistent with current tdd configuration, nrofDownlinkSlots %d, nrofUplinkSlots %d, nrofMixed slots 1, nb_slots_per_period %d \n",
|
||||
nrofDownlinkSlots,nrofUplinkSlots,nb_slots_per_period);
|
||||
}
|
||||
|
||||
cfg->tdd_table.max_tdd_periodicity_list = (fapi_nr_max_tdd_periodicity_t *) malloc(nb_slots_to_set*sizeof(fapi_nr_max_tdd_periodicity_t));
|
||||
|
||||
for(int memory_alloc =0 ; memory_alloc<nb_slots_to_set; memory_alloc++)
|
||||
cfg->tdd_table.max_tdd_periodicity_list[memory_alloc].max_num_of_symbol_per_slot_list = (fapi_nr_max_num_of_symbol_per_slot_t *) malloc(NR_NUMBER_OF_SYMBOLS_PER_SLOT*sizeof(
|
||||
fapi_nr_max_num_of_symbol_per_slot_t));
|
||||
|
||||
while(slot_number != nb_slots_to_set) {
|
||||
if(nrofDownlinkSlots != 0) {
|
||||
for (int number_of_symbol = 0; number_of_symbol < nrofDownlinkSlots*NR_NUMBER_OF_SYMBOLS_PER_SLOT; number_of_symbol++) {
|
||||
cfg->tdd_table.max_tdd_periodicity_list[slot_number].max_num_of_symbol_per_slot_list[number_of_symbol%NR_NUMBER_OF_SYMBOLS_PER_SLOT].slot_config= 0;
|
||||
|
||||
if((number_of_symbol+1)%NR_NUMBER_OF_SYMBOLS_PER_SLOT == 0)
|
||||
slot_number++;
|
||||
}
|
||||
}
|
||||
|
||||
if (nrofDownlinkSymbols != 0 || nrofUplinkSymbols != 0) {
|
||||
for(int number_of_symbol =0; number_of_symbol < nrofDownlinkSymbols; number_of_symbol++) {
|
||||
cfg->tdd_table.max_tdd_periodicity_list[slot_number].max_num_of_symbol_per_slot_list[number_of_symbol].slot_config= 0;
|
||||
}
|
||||
|
||||
for(int number_of_symbol = nrofDownlinkSymbols; number_of_symbol < NR_NUMBER_OF_SYMBOLS_PER_SLOT-nrofUplinkSymbols; number_of_symbol++) {
|
||||
cfg->tdd_table.max_tdd_periodicity_list[slot_number].max_num_of_symbol_per_slot_list[number_of_symbol].slot_config= 2;
|
||||
}
|
||||
|
||||
for(int number_of_symbol = NR_NUMBER_OF_SYMBOLS_PER_SLOT-nrofUplinkSymbols; number_of_symbol < NR_NUMBER_OF_SYMBOLS_PER_SLOT; number_of_symbol++) {
|
||||
cfg->tdd_table.max_tdd_periodicity_list[slot_number].max_num_of_symbol_per_slot_list[number_of_symbol].slot_config= 1;
|
||||
}
|
||||
|
||||
slot_number++;
|
||||
}
|
||||
|
||||
if(nrofUplinkSlots != 0) {
|
||||
for (int number_of_symbol = 0; number_of_symbol < nrofUplinkSlots*NR_NUMBER_OF_SYMBOLS_PER_SLOT; number_of_symbol++) {
|
||||
cfg->tdd_table.max_tdd_periodicity_list[slot_number].max_num_of_symbol_per_slot_list[number_of_symbol%NR_NUMBER_OF_SYMBOLS_PER_SLOT].slot_config= 1;
|
||||
|
||||
if((number_of_symbol+1)%NR_NUMBER_OF_SYMBOLS_PER_SLOT == 0)
|
||||
slot_number++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
//Prepares the PHY config to be sent to PHY. Prepares from the Valus from MAC context.
|
||||
static void sl_prepare_phy_config(int module_id,
|
||||
sl_nr_phy_config_request_t *phycfg,
|
||||
NR_SL_FreqConfigCommon_r16_t *freqcfg,
|
||||
uint8_t sync_source,
|
||||
uint32_t sl_OffsetDFN,
|
||||
NR_TDD_UL_DL_ConfigCommon_t *sl_TDD_config)
|
||||
{
|
||||
|
||||
|
||||
phycfg->sl_sync_source.sync_source = sync_source;
|
||||
LOG_I(NR_MAC, "Sidelink CFG: sync source:%d\n", phycfg->sl_sync_source.sync_source);
|
||||
|
||||
uint32_t pointA_ARFCN = freqcfg->sl_AbsoluteFrequencyPointA_r16;
|
||||
AssertFatal(pointA_ARFCN, "sl_AbsoluteFrequencyPointA_r16 cannot be 0\n");
|
||||
|
||||
int sl_band = 0;
|
||||
if (pointA_ARFCN >= 790334 && pointA_ARFCN <= 795000)
|
||||
sl_band = 47;
|
||||
else if (pointA_ARFCN >= 514000 && pointA_ARFCN <= 524000)
|
||||
sl_band = 38;
|
||||
|
||||
AssertFatal(sl_band, "not valid band for Sidelink operation\n");
|
||||
|
||||
uint32_t SSB_ARFCN = (freqcfg->sl_AbsoluteFrequencySSB_r16)
|
||||
? *freqcfg->sl_AbsoluteFrequencySSB_r16 : 0;
|
||||
|
||||
AssertFatal(SSB_ARFCN, "sl_AbsoluteFrequencySSB cannot be 0\n");
|
||||
|
||||
LOG_I(NR_MAC, "SIDELINK CONFIGs: AbsFreqSSB:%d, AbsFreqPointA:%d, SL band:%d\n",
|
||||
SSB_ARFCN,pointA_ARFCN, sl_band);
|
||||
|
||||
#define SL_VALUE_FREQSHIFT_7P5KHZ_DISABLED 0
|
||||
phycfg->sl_carrier_config.sl_frequency_shift_7p5khz = SL_VALUE_FREQSHIFT_7P5KHZ_DISABLED;
|
||||
phycfg->sl_carrier_config.sl_value_N = freqcfg->valueN_r16;
|
||||
phycfg->sl_carrier_config.sl_num_tx_ant = 1;
|
||||
phycfg->sl_carrier_config.sl_num_rx_ant = 1;
|
||||
|
||||
NR_SCS_SpecificCarrier_t *carriercfg =
|
||||
freqcfg->sl_SCS_SpecificCarrierList_r16.list.array[0];
|
||||
|
||||
AssertFatal(carriercfg, "SCS_SpecificCarrier cannot be NULL");
|
||||
|
||||
int bw_index = get_supported_band_index(carriercfg->subcarrierSpacing,
|
||||
sl_band,
|
||||
carriercfg->carrierBandwidth);
|
||||
phycfg->sl_carrier_config.sl_bandwidth = get_supported_bw_mhz(FR1, bw_index);
|
||||
|
||||
phycfg->sl_carrier_config.sl_frequency =
|
||||
from_nrarfcn(sl_band,carriercfg->subcarrierSpacing,pointA_ARFCN); // freq in kHz
|
||||
|
||||
phycfg->sl_carrier_config.sl_grid_size = carriercfg->carrierBandwidth;
|
||||
//For sidelink offset to carrier is 0. hence not used
|
||||
//phycfg->sl_carrier_config.sl_k0 = carriercfg->offsetToCarrier;
|
||||
|
||||
NR_SL_BWP_Generic_r16_t *bwp_generic = NULL;
|
||||
if (freqcfg->sl_BWP_List_r16 &&
|
||||
freqcfg->sl_BWP_List_r16->list.array[0] &&
|
||||
freqcfg->sl_BWP_List_r16->list.array[0]->sl_BWP_Generic_r16)
|
||||
bwp_generic = freqcfg->sl_BWP_List_r16->list.array[0]->sl_BWP_Generic_r16;
|
||||
|
||||
AssertFatal(bwp_generic, "SL-BWP Generic cannot be NULL");
|
||||
|
||||
NR_BWP_t *sl_bwp = bwp_generic->sl_BWP_r16;
|
||||
AssertFatal(sl_bwp, "SL-BWP cannot be NULL");
|
||||
|
||||
int locbw = bwp_generic->sl_BWP_r16->locationAndBandwidth;
|
||||
phycfg->sl_bwp_config.sl_bwp_size = NRRIV2BW(locbw, MAX_BWP_SIZE);
|
||||
phycfg->sl_bwp_config.sl_bwp_start = NRRIV2PRBOFFSET(locbw, MAX_BWP_SIZE);
|
||||
phycfg->sl_bwp_config.sl_scs = sl_bwp->subcarrierSpacing;
|
||||
|
||||
|
||||
int scs_scaling = 1<<(phycfg->sl_bwp_config.sl_scs);
|
||||
|
||||
if (pointA_ARFCN < 600000)
|
||||
scs_scaling = scs_scaling*3;
|
||||
if (pointA_ARFCN > 2016666)
|
||||
scs_scaling = scs_scaling>>2;
|
||||
//SSB arfcn points to middle RE of PSBCH 11 RBs
|
||||
uint32_t diff = (SSB_ARFCN - 66*scs_scaling) - pointA_ARFCN;
|
||||
//the RE offset from pointA where SSB starts
|
||||
phycfg->sl_bwp_config.sl_ssb_offset_point_a = diff/scs_scaling;
|
||||
|
||||
#ifdef SL_DEBUG
|
||||
printf("diff:%d, scaling:%d, pointa:%d, ssb:%d\n", diff, scs_scaling, pointA_ARFCN, SSB_ARFCN);
|
||||
#endif
|
||||
|
||||
phycfg->sl_bwp_config.sl_dc_location = (bwp_generic->sl_TxDirectCurrentLocation_r16) ?
|
||||
*bwp_generic->sl_TxDirectCurrentLocation_r16 : 0;
|
||||
|
||||
const uint8_t values[] = {7,8,9,10,11,12,13,14};
|
||||
phycfg->sl_bwp_config.sl_num_symbols = (bwp_generic->sl_LengthSymbols_r16) ?
|
||||
values[*bwp_generic->sl_LengthSymbols_r16] : 0;
|
||||
|
||||
phycfg->sl_bwp_config.sl_start_symbol = (bwp_generic->sl_StartSymbol_r16) ?
|
||||
*bwp_generic->sl_StartSymbol_r16 : 0;
|
||||
|
||||
//0-EXTENDED, 1-NORMAL CP
|
||||
phycfg->sl_bwp_config.sl_cyclic_prefix = (sl_bwp->cyclicPrefix) ? EXTENDED : NORMAL;
|
||||
|
||||
AssertFatal(phycfg->sl_bwp_config.sl_cyclic_prefix == NORMAL, "Only NORMAL-CP Supported. Ext CP not yet supported\n");
|
||||
|
||||
|
||||
AssertFatal(phycfg->sl_bwp_config.sl_start_symbol >= 0 && phycfg->sl_bwp_config.sl_start_symbol <=7,
|
||||
"Sidelink Start symbol should be in range 0-7\n");
|
||||
|
||||
AssertFatal(phycfg->sl_bwp_config.sl_num_symbols >= 7 && phycfg->sl_bwp_config.sl_num_symbols <=14,
|
||||
"Num Sidelink symbols should be in range 7-14\n");
|
||||
|
||||
AssertFatal((phycfg->sl_bwp_config.sl_start_symbol + phycfg->sl_bwp_config.sl_num_symbols) <= 14,
|
||||
"Incorrect configuration of Start and num SL symbols\n");
|
||||
|
||||
//Configure PHY with TDD config only if the sync source is known.
|
||||
if (sync_source == SL_SYNC_SOURCE_LOCAL_TIMING ||
|
||||
sync_source == SL_SYNC_SOURCE_GNSS) {
|
||||
|
||||
phycfg->config_mask = 0xF;//Total config is sent
|
||||
phycfg->sl_sync_source.gnss_dfn_offset = sl_OffsetDFN;
|
||||
|
||||
// TDD Table Configuration
|
||||
if (sl_TDD_config->pattern1.ext1 == NULL)
|
||||
phycfg->tdd_table.tdd_period = sl_TDD_config->pattern1.dl_UL_TransmissionPeriodicity;
|
||||
else {
|
||||
if (sl_TDD_config->pattern1.ext1->dl_UL_TransmissionPeriodicity_v1530 != NULL)
|
||||
phycfg->tdd_table.tdd_period += (1 + *sl_TDD_config->pattern1.ext1->dl_UL_TransmissionPeriodicity_v1530);
|
||||
}
|
||||
|
||||
int return_tdd = sl_set_tdd_config_nr_ue(phycfg,
|
||||
sl_TDD_config->referenceSubcarrierSpacing,
|
||||
sl_TDD_config->pattern1.nrofDownlinkSlots,
|
||||
sl_TDD_config->pattern1.nrofDownlinkSymbols,
|
||||
sl_TDD_config->pattern1.nrofUplinkSlots,
|
||||
sl_TDD_config->pattern1.nrofUplinkSymbols);
|
||||
|
||||
if (return_tdd !=0)
|
||||
LOG_E(PHY,"TDD configuration can not be done\n");
|
||||
else {
|
||||
LOG_I(NR_MAC, "SIDELINK CONFIGs: tdd config period:%d, mu:%ld, DLslots:%ld,ULslots:%ld Mixedslotsym DL:UL %ld:%ld\n",
|
||||
phycfg->tdd_table.tdd_period, sl_TDD_config->referenceSubcarrierSpacing,
|
||||
sl_TDD_config->pattern1.nrofDownlinkSlots, sl_TDD_config->pattern1.nrofUplinkSlots,
|
||||
sl_TDD_config->pattern1.nrofDownlinkSymbols,sl_TDD_config->pattern1.nrofUplinkSymbols);
|
||||
}
|
||||
} else if (sync_source == SL_SYNC_SOURCE_NONE) {
|
||||
//Only Carrier config, BWP config sent
|
||||
phycfg->config_mask = 0x9;//partial config is sent
|
||||
}
|
||||
|
||||
//#ifdef SL_DEBUG
|
||||
char str[5][20] = {"NONE","GNBENB","GNSS","SYNC_REF_UE","LOCAL_TIMING"};
|
||||
LOG_I(NR_MAC, "UE[%d] Function %s - Phy config preparation:\n",module_id, __FUNCTION__);
|
||||
LOG_I(NR_MAC, "UE[%d] Sync source params: sync_source :%d-%s, gnss_dfn_offset:%d, rx_slss_id:%d\n",
|
||||
module_id,phycfg->sl_sync_source.sync_source,
|
||||
str[phycfg->sl_sync_source.sync_source],
|
||||
phycfg->sl_sync_source.gnss_dfn_offset,
|
||||
phycfg->sl_sync_source.rx_slss_id);
|
||||
LOG_I(NR_MAC, "UE[%d] Carrier CFG Params: freq:%ld, bw:%d, gridsize:%d, rxant:%d, txant:%d, valueN:%d\n",
|
||||
module_id,phycfg->sl_carrier_config.sl_frequency,
|
||||
phycfg->sl_carrier_config.sl_bandwidth,
|
||||
phycfg->sl_carrier_config.sl_grid_size,
|
||||
phycfg->sl_carrier_config.sl_num_rx_ant,
|
||||
phycfg->sl_carrier_config.sl_num_tx_ant,
|
||||
phycfg->sl_carrier_config.sl_value_N);
|
||||
LOG_I(NR_MAC, "UE[%d] SL-BWP Params: start:%d, size:%d, scs:%d, Ncp:%d, startsym:%d, numsym:%d,ssb_offset:%d,dcloc:%d\n",
|
||||
module_id,phycfg->sl_bwp_config.sl_bwp_start,
|
||||
phycfg->sl_bwp_config.sl_bwp_size,
|
||||
phycfg->sl_bwp_config.sl_scs,
|
||||
phycfg->sl_bwp_config.sl_cyclic_prefix,
|
||||
phycfg->sl_bwp_config.sl_start_symbol,
|
||||
phycfg->sl_bwp_config.sl_num_symbols,
|
||||
phycfg->sl_bwp_config.sl_ssb_offset_point_a,
|
||||
phycfg->sl_bwp_config.sl_dc_location);
|
||||
|
||||
//#endif
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// RRC calls this API when RRC is configured with Sidelink PRE-configuration I.E
|
||||
int nr_rrc_mac_config_req_sl_preconfig(module_id_t module_id,
|
||||
NR_SL_PreconfigurationNR_r16_t *sl_preconfiguration,
|
||||
uint8_t sync_source)
|
||||
{
|
||||
|
||||
LOG_I(NR_MAC,"[UE%d] SL RRC->MAC CONFIG RECEIVED. Syncsource:%d\n",
|
||||
module_id, sync_source);
|
||||
|
||||
NR_UE_MAC_INST_t *mac = get_mac_inst(module_id);
|
||||
AssertFatal(sl_preconfiguration !=NULL,"SL-Preconfig Cannot be NULL");
|
||||
AssertFatal(mac, "mac should have an instance");
|
||||
|
||||
mac->SL_MAC_PARAMS = CALLOC(1, sizeof(sl_nr_ue_mac_params_t));
|
||||
sl_nr_ue_mac_params_t *sl_mac = mac->SL_MAC_PARAMS;
|
||||
|
||||
NR_SidelinkPreconfigNR_r16_t *sl_preconfig = &sl_preconfiguration->sidelinkPreconfigNR_r16;
|
||||
|
||||
//Only one entry supported in rel16.
|
||||
//Carrier freq config used for Sidelink
|
||||
|
||||
NR_SL_FreqConfigCommon_r16_t *freqcfg = (sl_preconfig->sl_PreconfigFreqInfoList_r16)
|
||||
? sl_preconfig->sl_PreconfigFreqInfoList_r16->list.array[0]
|
||||
: NULL;
|
||||
|
||||
AssertFatal(freqcfg !=NULL,"SL fcfg Cannot be NULL");
|
||||
|
||||
//MAx num of consecutive HARQ DTX before triggering RLF.
|
||||
const uint8_t MaxNumConsecutiveDTX[] = {1,2,3,4,6,8,16,32};
|
||||
sl_mac->sl_MaxNumConsecutiveDTX = (sl_preconfig->sl_MaxNumConsecutiveDTX_r16)
|
||||
? MaxNumConsecutiveDTX[*sl_preconfig->sl_MaxNumConsecutiveDTX_r16]
|
||||
: 0;
|
||||
|
||||
//priority of SL-SSB tx and rx
|
||||
sl_mac->sl_SSB_PriorityNR = (sl_preconfig->sl_SSB_PriorityNR_r16)
|
||||
? *sl_preconfig->sl_SSB_PriorityNR_r16 : 0;
|
||||
|
||||
//Indicates if CSI Reporting is enabled in UNICAST. is 0-ENABLED, 1-DISABLED
|
||||
sl_mac->sl_CSI_Acquisition = (sl_preconfig->sl_CSI_Acquisition_r16) ? 0 : 1;
|
||||
|
||||
//Used for DFN calculation in case Sync source = GNSS.
|
||||
uint32_t sl_OffsetDFN = (sl_preconfig->sl_OffsetDFN_r16)
|
||||
? *sl_preconfig->sl_OffsetDFN_r16 : 0;
|
||||
|
||||
NR_SL_BWP_ConfigCommon_r16_t *bwp = NULL;
|
||||
if (freqcfg->sl_BWP_List_r16 &&
|
||||
freqcfg->sl_BWP_List_r16->list.array[0])
|
||||
bwp = freqcfg->sl_BWP_List_r16->list.array[0];
|
||||
|
||||
AssertFatal(bwp!=NULL, "BWP config common cannot be NULL\n");
|
||||
if (bwp->sl_BWP_PoolConfigCommon_r16) {
|
||||
if (bwp->sl_BWP_PoolConfigCommon_r16->sl_RxPool_r16) {
|
||||
|
||||
for (int i=0;i<bwp->sl_BWP_PoolConfigCommon_r16->sl_RxPool_r16->list.count;i++) {
|
||||
NR_SL_ResourcePool_r16_t *rxpool = bwp->sl_BWP_PoolConfigCommon_r16->sl_RxPool_r16->list.array[i];
|
||||
if (rxpool) {
|
||||
if (sl_mac->sl_RxPool[i] == NULL)
|
||||
sl_mac->sl_RxPool[i] = malloc16_clear(sizeof(SL_ResourcePool_params_t));
|
||||
sl_mac->sl_RxPool[i]->respool = rxpool;
|
||||
uint16_t sci_1a_len = 0, num_subch = 0;
|
||||
sci_1a_len = sl_determine_sci_1a_len(&num_subch,
|
||||
sl_mac->sl_RxPool[i]->respool,
|
||||
&sl_mac->sl_RxPool[i]->sci_1a);
|
||||
sl_mac->sl_RxPool[i]->num_subch = num_subch;
|
||||
sl_mac->sl_RxPool[i]->sci_1a_len = sci_1a_len;
|
||||
|
||||
LOG_I(NR_MAC,"Rxpool[%d] - num subchannels:%d, sci_1a_len:%d\n",i,
|
||||
sl_mac->sl_RxPool[i]->num_subch,
|
||||
sl_mac->sl_RxPool[i]->sci_1a_len);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (bwp->sl_BWP_PoolConfigCommon_r16->sl_TxPoolSelectedNormal_r16) {
|
||||
|
||||
for (int i=0;i<bwp->sl_BWP_PoolConfigCommon_r16->sl_TxPoolSelectedNormal_r16->list.count;i++) {
|
||||
|
||||
NR_SL_ResourcePool_r16_t *txpool =
|
||||
bwp->sl_BWP_PoolConfigCommon_r16->sl_TxPoolSelectedNormal_r16->list.array[0]->sl_ResourcePool_r16;
|
||||
|
||||
if (txpool) {
|
||||
if (sl_mac->sl_TxPool[i] == NULL)
|
||||
sl_mac->sl_TxPool[i] = malloc16_clear(sizeof(SL_ResourcePool_params_t));
|
||||
sl_mac->sl_TxPool[i]->respool = txpool;
|
||||
|
||||
uint16_t sci_1a_len = 0, num_subch = 0;
|
||||
sci_1a_len = sl_determine_sci_1a_len(&num_subch,
|
||||
sl_mac->sl_TxPool[i]->respool,
|
||||
&sl_mac->sl_TxPool[i]->sci_1a);
|
||||
|
||||
sl_mac->sl_TxPool[i]->num_subch = num_subch;
|
||||
sl_mac->sl_TxPool[i]->sci_1a_len = sci_1a_len;
|
||||
|
||||
LOG_I(NR_MAC,"Txpool[%d] - num subchannels:%d, sci_1a_len:%d\n",i,
|
||||
sl_mac->sl_TxPool[i]->num_subch,
|
||||
sl_mac->sl_TxPool[i]->sci_1a_len);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (sync_source == SL_SYNC_SOURCE_GNSS ||
|
||||
sync_source == SL_SYNC_SOURCE_LOCAL_TIMING) {
|
||||
|
||||
NR_TDD_UL_DL_ConfigCommon_t *tdd_uldl_config = NULL;
|
||||
if (sl_preconfig->sl_PreconfigGeneral_r16 &&
|
||||
sl_preconfig->sl_PreconfigGeneral_r16->sl_TDD_Configuration_r16)
|
||||
tdd_uldl_config = sl_preconfig->sl_PreconfigGeneral_r16->sl_TDD_Configuration_r16;
|
||||
|
||||
AssertFatal((tdd_uldl_config!=NULL), "Sidelink MAC CFG: TDD Config cannot be NULL");
|
||||
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->adjust_timing = 1;
|
||||
}
|
||||
|
||||
//Do not copy TDD config yet as SYNC source is not yet found
|
||||
if (sync_source == SL_SYNC_SOURCE_NONE) {
|
||||
if (sl_mac->sl_TDD_config)
|
||||
ASN_STRUCT_FREE(asn_DEF_NR_TDD_UL_DL_ConfigCommon, sl_mac->sl_TDD_config);
|
||||
sl_mac->sl_TDD_config = NULL;
|
||||
}
|
||||
|
||||
nr_sl_phy_config_t *sl_phy_cfg = &sl_mac->sl_phy_config;
|
||||
sl_phy_cfg->Mod_id = module_id;
|
||||
sl_phy_cfg->CC_id = 0;
|
||||
|
||||
sl_prepare_phy_config(module_id, &sl_phy_cfg->sl_config_req,
|
||||
freqcfg, sync_source, sl_OffsetDFN, sl_mac->sl_TDD_config);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
//Copies the values of SSB time allocation from ASN format to MAC context
|
||||
static void sl_mac_config_ssb_time_alloc(uint8_t module_id,
|
||||
NR_SL_SSB_TimeAllocation_r16_t *sl_SSB_TimeAllocation_r16,
|
||||
sl_ssb_timealloc_t *ssb_time_alloc)
|
||||
{
|
||||
|
||||
const uint8_t values[] = {1,2,4,8,16,32,64};
|
||||
ssb_time_alloc->sl_NumSSB_WithinPeriod =
|
||||
(sl_SSB_TimeAllocation_r16->sl_NumSSB_WithinPeriod_r16 != NULL)
|
||||
? values[*sl_SSB_TimeAllocation_r16->sl_NumSSB_WithinPeriod_r16] : 0;
|
||||
ssb_time_alloc->sl_TimeOffsetSSB = (sl_SSB_TimeAllocation_r16->sl_TimeOffsetSSB_r16 != NULL)
|
||||
? *sl_SSB_TimeAllocation_r16->sl_TimeOffsetSSB_r16 : 0;
|
||||
ssb_time_alloc->sl_TimeInterval = (sl_SSB_TimeAllocation_r16->sl_TimeInterval_r16 != NULL)
|
||||
? *sl_SSB_TimeAllocation_r16->sl_TimeInterval_r16 : 0;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
//This API is called by RRC after it determines that UE needs to transmit SL-SSB
|
||||
// SLSS id and SL-MIB is given to MAC by RRC
|
||||
void nr_rrc_mac_transmit_slss_req(module_id_t module_id,
|
||||
uint8_t *sl_mib_payload,
|
||||
uint16_t tx_slss_id,
|
||||
NR_SL_SSB_TimeAllocation_r16_t *ssb_ta)
|
||||
{
|
||||
|
||||
sl_nr_ue_mac_params_t *sl_mac = get_mac_inst(module_id)->SL_MAC_PARAMS;
|
||||
AssertFatal(sl_mac,"sidelink MAC cannot be NULL");
|
||||
AssertFatal(tx_slss_id < 672,"SLSS id cannot be >= 672. id:%d", tx_slss_id);
|
||||
AssertFatal(ssb_ta,"ssb_ta cannot be NULL");
|
||||
|
||||
sl_mac->tx_sl_bch.slss_id = tx_slss_id;
|
||||
sl_mac->tx_sl_bch.status = 1;
|
||||
memcpy(sl_mac->tx_sl_bch.sl_mib,sl_mib_payload, 4);
|
||||
|
||||
sl_mac->tx_sl_bch.num_ssb = 0;
|
||||
sl_mac->tx_sl_bch.ssb_slot = 0;
|
||||
|
||||
sl_mac_config_ssb_time_alloc(module_id,
|
||||
ssb_ta,
|
||||
&sl_mac->tx_sl_bch.ssb_time_alloc);
|
||||
|
||||
LOG_I(NR_MAC,"[UE%d]SL RRC->MAC: TX SLSS REQ SLSS-id:%d, SL-MIB:%x, numssb:%d, offset:%d, interval:%d\n",
|
||||
module_id, sl_mac->tx_sl_bch.slss_id,
|
||||
*((uint32_t *)sl_mib_payload),
|
||||
sl_mac->tx_sl_bch.ssb_time_alloc.sl_NumSSB_WithinPeriod,
|
||||
sl_mac->tx_sl_bch.ssb_time_alloc.sl_TimeOffsetSSB,
|
||||
sl_mac->tx_sl_bch.ssb_time_alloc.sl_TimeInterval);
|
||||
|
||||
uint8_t byte0 = 0;
|
||||
uint8_t byte1 = 0;
|
||||
sl_nr_bwp_config_t *cfg = &sl_mac->sl_phy_config.sl_config_req.sl_bwp_config;
|
||||
sl_prepare_psbch_payload(sl_mac->sl_TDD_config, &byte0, &byte1,
|
||||
cfg->sl_scs,cfg->sl_num_symbols,cfg->sl_start_symbol);
|
||||
|
||||
sl_mac->tx_sl_bch.sl_mib[0] = byte0;
|
||||
sl_mac->tx_sl_bch.sl_mib[1] = byte1 | sl_mac->tx_sl_bch.sl_mib[1];
|
||||
|
||||
LOG_I(NR_MAC, "[UE%d]SL RRC->MAC: TX SLSS REQ - TDD CONFIG STUFFED INSIDE - SL-MIB :%x\n",
|
||||
module_id, *((uint32_t *)sl_mac->tx_sl_bch.sl_mib));
|
||||
}
|
||||
|
||||
//This API is called by RRC after it determines that UE needs to keep
|
||||
// receiving SL-SSB from the sync ref UE
|
||||
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)
|
||||
{
|
||||
|
||||
NR_UE_MAC_INST_t *mac = get_mac_inst(module_id);
|
||||
sl_nr_ue_mac_params_t *sl_mac = mac->SL_MAC_PARAMS;
|
||||
AssertFatal(sl_mac,"Sidelink MAC instance cannot be NULL");
|
||||
|
||||
AssertFatal(ssb_ta,"ssb_ta cannot be NULL");
|
||||
AssertFatal(rx_slss_id < 672,"SLSS id cannot be >= 672. id:%d", rx_slss_id);
|
||||
AssertFatal(sl_mib,"sl_mib cannot be NULL");
|
||||
|
||||
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) {
|
||||
//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->adjust_timing = 1;
|
||||
|
||||
sl_mac->rx_sl_bch.status = 1;
|
||||
sl_mac->rx_sl_bch.slss_id = rx_slss_id;
|
||||
|
||||
sl_mac->rx_sl_bch.num_ssb = 0;
|
||||
sl_mac->rx_sl_bch.ssb_slot = 0;
|
||||
|
||||
sl_mac_config_ssb_time_alloc(module_id,
|
||||
ssb_ta,
|
||||
&sl_mac->rx_sl_bch.ssb_time_alloc);
|
||||
|
||||
LOG_I(NR_MAC,"[UE%d]SL RRC->MAC: RX SLSS REQ SLSS-id:%d, SL-MIB:%x, numssb:%d, offset:%d, interval:%d\n",
|
||||
module_id, sl_mac->rx_sl_bch.slss_id,
|
||||
*((uint32_t *)sl_mib),
|
||||
sl_mac->rx_sl_bch.ssb_time_alloc.sl_NumSSB_WithinPeriod,
|
||||
sl_mac->rx_sl_bch.ssb_time_alloc.sl_TimeOffsetSSB,
|
||||
sl_mac->rx_sl_bch.ssb_time_alloc.sl_TimeInterval);
|
||||
|
||||
if (sl_mac->sl_TDD_config == NULL)
|
||||
sl_mac->sl_TDD_config = CALLOC(sizeof(NR_TDD_UL_DL_ConfigCommon_t), 1);
|
||||
|
||||
sl_nr_phy_config_request_t *cfg = &sl_mac->sl_phy_config.sl_config_req;
|
||||
int ret = 1;
|
||||
ret = sl_decode_sl_TDD_Config(sl_mac->sl_TDD_config,
|
||||
sl_mib[0], sl_mib[1]&0xF0,
|
||||
cfg->sl_bwp_config.sl_scs,
|
||||
cfg->sl_bwp_config.sl_num_symbols,
|
||||
cfg->sl_bwp_config.sl_start_symbol);
|
||||
|
||||
if (ret == 0) {
|
||||
//sl_tdd_config bytes are all 1's - no TDD config present use all slots for sidelink.
|
||||
//Spec not clear -- TBD...
|
||||
sl_config->tdd_table.tdd_period = 7;// set it to frame period
|
||||
sl_mac->sl_TDD_config->pattern1.nrofUplinkSlots =
|
||||
NR_NUMBER_OF_SUBFRAMES_PER_FRAME*(1<<cfg->sl_bwp_config.sl_scs);
|
||||
} else {
|
||||
if (sl_mac->sl_TDD_config->pattern1.ext1 == NULL)
|
||||
sl_config->tdd_table.tdd_period = sl_mac->sl_TDD_config->pattern1.dl_UL_TransmissionPeriodicity;
|
||||
else {
|
||||
if (sl_mac->sl_TDD_config->pattern1.ext1->dl_UL_TransmissionPeriodicity_v1530 != NULL)
|
||||
sl_config->tdd_table.tdd_period += (1 + *sl_mac->sl_TDD_config->pattern1.ext1->dl_UL_TransmissionPeriodicity_v1530);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t return_tdd = 0;
|
||||
return_tdd = sl_set_tdd_config_nr_ue(cfg,
|
||||
cfg->sl_bwp_config.sl_scs,
|
||||
sl_mac->sl_TDD_config->pattern1.nrofDownlinkSlots,
|
||||
sl_mac->sl_TDD_config->pattern1.nrofDownlinkSymbols,
|
||||
sl_mac->sl_TDD_config->pattern1.nrofUplinkSlots,
|
||||
sl_mac->sl_TDD_config->pattern1.nrofUplinkSymbols);
|
||||
if (return_tdd !=0)
|
||||
LOG_E(PHY,"TDD configuration can not be done\n");
|
||||
|
||||
LOG_I(MAC, "SIDELINK CONFIGs: tdd config period:%d, mu:%ld, DLslots:%ld,ULslots:%ld Mixedslotsym DL:UL %ld:%ld\n",
|
||||
sl_config->tdd_table.tdd_period, sl_mac->sl_TDD_config->referenceSubcarrierSpacing,
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -47,6 +47,7 @@
|
||||
#include "LAYER2/NR_MAC_COMMON/nr_mac_common.h"
|
||||
#include "LAYER2/MAC/mac.h"
|
||||
#include "NR_MAC_COMMON/nr_mac_extern.h"
|
||||
#include "mac_defs_sl.h"
|
||||
|
||||
/* RRC */
|
||||
#include "NR_DRX-Config.h"
|
||||
@@ -526,6 +527,9 @@ typedef struct {
|
||||
|
||||
pthread_mutex_t mutex_dl_info;
|
||||
|
||||
//SIDELINK MAC PARAMETERS
|
||||
sl_nr_ue_mac_params_t *SL_MAC_PARAMS;
|
||||
|
||||
} NR_UE_MAC_INST_t;
|
||||
|
||||
/*@}*/
|
||||
|
||||
177
openair2/LAYER2/NR_MAC_UE/mac_defs_sl.h
Normal file
177
openair2/LAYER2/NR_MAC_UE/mac_defs_sl.h
Normal file
@@ -0,0 +1,177 @@
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#ifndef __MAC_DEFS_SL_H__
|
||||
#define __MAC_DEFS_SL_H__
|
||||
|
||||
#include "sidelink_nr_ue_interface.h"
|
||||
#include "NR_SL-ResourcePool-r16.h"
|
||||
#include "NR_TDD-UL-DL-ConfigCommon.h"
|
||||
#include "NR_MAC_COMMON/nr_mac.h"
|
||||
#include "NR_UE_PHY_INTERFACE/NR_IF_Module.h"
|
||||
|
||||
|
||||
#define SL_NR_MAC_NUM_RX_RESOURCE_POOLS 1
|
||||
#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
|
||||
|
||||
|
||||
#define sci_field_t dci_field_t
|
||||
|
||||
typedef struct sidelink_sci_format_1a_fields {
|
||||
|
||||
// Priority of this transmission
|
||||
uint8_t priority; //3 bits
|
||||
//Indicates the format to be used in 2nd stage i.e SCI format 2 sent on PSSCH
|
||||
//00 - SCI FORMAT 2A, 01 - SCI FORMAT 2B, 10, 11 - Reserved
|
||||
//Spec 38.212 Table 8.3.1.1-1
|
||||
uint8_t sci_format_2nd_stage; //2 bits
|
||||
//Num modulated symbols for stage 2 SCI - TBD:
|
||||
// Spec 38.212 Table 8.3.1.1-2
|
||||
uint8_t beta_offset_indicator; //2 bits
|
||||
//determine the number of layers for data on PSSCH
|
||||
// Spec 38.212 Table 8.3.1.1-3
|
||||
uint8_t num_dmrs_ports; //1 bit
|
||||
//Modulation and coding scheme to be used for data on PSSCH
|
||||
uint8_t mcs; //5 bits
|
||||
|
||||
//Identifies the frequence resource (subchannels) to be used for PSSCH/PSCCH
|
||||
//sl-MaxNumPerReserve is 2 - ceil(log2(N_subch*(N_subch+1)/2)) bits
|
||||
//sl-MaxNumPerReserve is 3 - ceil(log2(N_subch*(N_subch+1)(2*N_subch+1)/6)) bits
|
||||
sci_field_t frequency_resource_assignment; //variable
|
||||
//Identifies the Time resource (slots) to be used for PSSCH/PSCCH
|
||||
//sl-MaxNumPerReserve is 2 - 5 bits
|
||||
//sl-MaxNumPerReserve is 3 - 9 bits
|
||||
sci_field_t time_resource_assignment; //variable
|
||||
//TBD:
|
||||
//sl-MultiReserveResource is not configured - 0 bits
|
||||
//sl-MultiReserveResource is configured - ceil(log2(number of entries in sl-ResourceReservePeriodList)) bits
|
||||
sci_field_t resource_reservation_period; //variable
|
||||
//Identifies the DMRS Pattern to be used on PSSCH
|
||||
//ceil(log2(number of dmrs patterns in sl-PSSCH-DMRS-TimePatternList)) bits
|
||||
sci_field_t dmrs_pattern; //variable
|
||||
//Identifies the TABLE to be used to determine MCS on PSSCH
|
||||
//1 table configured in sl-Additional-MCS-Table - 1 bit
|
||||
//2 tables configured in sl-Additional-MCS-Table - 2 bits
|
||||
//Not configured- 0 bits
|
||||
sci_field_t additional_mcs_table_indicator; //variable
|
||||
//Identifies the number of symbols for PSFCH
|
||||
//sl-PSFCH-Period Not configured- 0 bits
|
||||
//if sl-PSFCH-Period configured and value 2 or 4 - 1 bit
|
||||
sci_field_t psfch_overhead_indication; //variable
|
||||
//number of bits determined by sl-NumReservedbits
|
||||
//Value encoded is 0
|
||||
sci_field_t reserved_bits;
|
||||
|
||||
} sidelink_sci_format_1a_fields_t;
|
||||
|
||||
typedef struct SL_ResourcePool_params {
|
||||
|
||||
//This holds the structure from RRC
|
||||
NR_SL_ResourcePool_r16_t *respool;
|
||||
|
||||
//NUM Subchannels in this resource pool
|
||||
uint16_t num_subch;
|
||||
|
||||
//SCI-1A length is the same for this resource pool.
|
||||
uint16_t sci_1a_len;
|
||||
|
||||
//SCI-1A configuration according to RESPOOL configured.
|
||||
sidelink_sci_format_1a_fields_t sci_1a;
|
||||
|
||||
} SL_ResourcePool_params_t;
|
||||
|
||||
typedef struct sl_ssb_timealloc {
|
||||
|
||||
uint32_t sl_NumSSB_WithinPeriod;
|
||||
uint32_t sl_TimeOffsetSSB;
|
||||
uint32_t sl_TimeInterval;
|
||||
|
||||
} sl_ssb_timealloc_t;
|
||||
|
||||
typedef struct sl_bch_params {
|
||||
|
||||
//configured from RRC
|
||||
//Parameters used to determine PSBCH slot
|
||||
sl_ssb_timealloc_t ssb_time_alloc;
|
||||
uint16_t slss_id;
|
||||
bool status;
|
||||
uint8_t sl_mib[4];
|
||||
|
||||
//Parameters incremented by MAC PSBCH scheduler
|
||||
//after every SSB txn/reception
|
||||
uint16_t num_ssb;
|
||||
uint16_t ssb_slot;
|
||||
|
||||
} sl_bch_params_t;
|
||||
|
||||
typedef struct sl_nr_ue_mac_params {
|
||||
|
||||
//Holds the RX resource pool from RRC and its related parameters
|
||||
SL_ResourcePool_params_t *sl_RxPool[SL_NR_MAC_NUM_RX_RESOURCE_POOLS];
|
||||
//Holds the TX resource pool from RRC and its related parameters
|
||||
SL_ResourcePool_params_t *sl_TxPool[SL_NR_MAC_NUM_TX_RESOURCE_POOLS];
|
||||
|
||||
//Holds either the TDD config from RRC
|
||||
//or TDD config decoded from SL-MIB
|
||||
NR_TDD_UL_DL_ConfigCommon_t *sl_TDD_config;
|
||||
|
||||
//Configured from RRC
|
||||
uint32_t sl_MaxNumConsecutiveDTX;
|
||||
uint32_t sl_SSB_PriorityNR;
|
||||
uint8_t sl_CSI_Acquisition;
|
||||
|
||||
//MAC prepares this and sends it to PHY
|
||||
nr_sl_phy_config_t sl_phy_config;
|
||||
|
||||
//Holds Broadcast params incase UE sends Sidelink SSB
|
||||
sl_bch_params_t tx_sl_bch;
|
||||
//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.
|
||||
uint8_t adjust_timing;
|
||||
|
||||
//Sidelink slots per frame
|
||||
uint16_t N_SL_SLOTS_perframe;
|
||||
|
||||
uint16_t decoded_DFN;
|
||||
uint16_t decoded_slot;
|
||||
|
||||
} sl_nr_ue_mac_params_t;
|
||||
|
||||
|
||||
#endif
|
||||
@@ -113,6 +113,8 @@ void nr_ue_dl_scheduler(nr_downlink_indication_t *dl_info);
|
||||
@param fapi_nr_dl_config_request_t* pointer to dl_config,
|
||||
@param fapi_nr_ul_config_request_t* pointer to ul_config,
|
||||
@param fapi_nr_tx_request_t* pointer to tx_request;
|
||||
@param sl_nr_rx_config_request_t* pointer to sl_rx_config,
|
||||
@param sl_nr_tx_config_request_t* pointer to sl_tx_config,
|
||||
@param module_id_t mod_id module ID
|
||||
@param int cc_id CC ID
|
||||
@param frame_t frame frame number
|
||||
@@ -122,6 +124,8 @@ void fill_scheduled_response(nr_scheduled_response_t *scheduled_response,
|
||||
fapi_nr_dl_config_request_t *dl_config,
|
||||
fapi_nr_ul_config_request_t *ul_config,
|
||||
fapi_nr_tx_request_t *tx_request,
|
||||
sl_nr_rx_config_request_t *sl_rx_config,
|
||||
sl_nr_tx_config_request_t *sl_tx_config,
|
||||
module_id_t mod_id,
|
||||
int cc_id,
|
||||
frame_t frame,
|
||||
@@ -430,5 +434,51 @@ int nr_config_pusch_pdu(NR_UE_MAC_INST_t *mac,
|
||||
RAR_grant_t *rar_grant,
|
||||
uint16_t rnti,
|
||||
const nr_dci_format_t *dci_format);
|
||||
|
||||
int nr_rrc_mac_config_req_sl_preconfig(module_id_t module_id,
|
||||
NR_SL_PreconfigurationNR_r16_t *sl_preconfiguration,
|
||||
uint8_t sync_source);
|
||||
|
||||
void nr_rrc_mac_transmit_slss_req(module_id_t module_id,
|
||||
uint8_t *sl_mib_payload,
|
||||
uint16_t tx_slss_id,
|
||||
NR_SL_SSB_TimeAllocation_r16_t *ssb_ta);
|
||||
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);
|
||||
|
||||
uint8_t sl_decode_sl_TDD_Config(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);
|
||||
|
||||
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_frame, int nr_slot,
|
||||
uint8_t frame_duplex_type);
|
||||
|
||||
void nr_ue_sidelink_scheduler(nr_sidelink_indication_t *sl_ind);
|
||||
|
||||
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
|
||||
/** @}*/
|
||||
|
||||
577
openair2/LAYER2/NR_MAC_UE/nr_ue_procedures_sl.c
Normal file
577
openair2/LAYER2/NR_MAC_UE/nr_ue_procedures_sl.c
Normal file
@@ -0,0 +1,577 @@
|
||||
/*
|
||||
* 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"
|
||||
|
||||
#define SL_DEBUG
|
||||
|
||||
uint8_t sl_process_TDD_UL_DL_config_patterns(NR_TDD_UL_DL_ConfigCommon_t *TDD_UL_DL_Config,
|
||||
uint8_t mu,
|
||||
double *slot_period_P,
|
||||
uint8_t *w)
|
||||
{
|
||||
|
||||
uint8_t return_value = 255;
|
||||
*w = 0;
|
||||
int pattern1_dlul_period = TDD_UL_DL_Config->pattern1.dl_UL_TransmissionPeriodicity;
|
||||
|
||||
#ifdef SL_DEBUG
|
||||
|
||||
printf("INPUT VALUES: function: %s\n", __func__);
|
||||
printf("pattern1 periodicity:%d\n", pattern1_dlul_period);
|
||||
if (TDD_UL_DL_Config->pattern1.ext1 != NULL && TDD_UL_DL_Config->pattern1.ext1->dl_UL_TransmissionPeriodicity_v1530 != NULL )
|
||||
printf("pattern1 periodicity_v1530:%ld\n", *TDD_UL_DL_Config->pattern1.ext1->dl_UL_TransmissionPeriodicity_v1530);
|
||||
if (TDD_UL_DL_Config->pattern2 != NULL) {
|
||||
printf("mu:%d, pattern2 periodicity:%d\n", mu, pattern1_dlul_period);
|
||||
if (TDD_UL_DL_Config->pattern2->ext1 != NULL && TDD_UL_DL_Config->pattern2->ext1->dl_UL_TransmissionPeriodicity_v1530 != NULL )
|
||||
printf("pattern2 periodicity_v1530:%ld\n", *TDD_UL_DL_Config->pattern2->ext1->dl_UL_TransmissionPeriodicity_v1530);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
return_value = pattern1_dlul_period;
|
||||
switch (pattern1_dlul_period) {
|
||||
case 0:
|
||||
*slot_period_P = 0.5;
|
||||
break;
|
||||
case 1:
|
||||
*slot_period_P = 0.625;
|
||||
break;
|
||||
case 2:
|
||||
*slot_period_P = 1.0;
|
||||
break;
|
||||
case 3:
|
||||
*slot_period_P = 1.25;
|
||||
break;
|
||||
case 4:
|
||||
*slot_period_P = 2.0;
|
||||
break;
|
||||
case 5:
|
||||
*slot_period_P = 2.5;
|
||||
break;
|
||||
case 6:
|
||||
*slot_period_P = 5.0;
|
||||
return_value = 7;
|
||||
break;
|
||||
case 7:
|
||||
*slot_period_P = 10.0;
|
||||
return_value = 8;
|
||||
break;
|
||||
default:
|
||||
AssertFatal(1==0,"Incorrect value of dl_UL_TransmissionPeriodicity\n");
|
||||
break;
|
||||
}
|
||||
|
||||
if (TDD_UL_DL_Config->pattern1.ext1 != NULL &&
|
||||
TDD_UL_DL_Config->pattern1.ext1->dl_UL_TransmissionPeriodicity_v1530 != NULL ) {
|
||||
if (*TDD_UL_DL_Config->pattern1.ext1->dl_UL_TransmissionPeriodicity_v1530 == 1) {
|
||||
*slot_period_P = 4.0;
|
||||
return_value = 6;
|
||||
} else {
|
||||
*slot_period_P = 3.0;
|
||||
return_value = 255;
|
||||
}
|
||||
}
|
||||
|
||||
if (TDD_UL_DL_Config->pattern2 != NULL) {
|
||||
|
||||
return_value = 255;
|
||||
*w = 1;
|
||||
|
||||
if ((*slot_period_P == 4.0 ) && (TDD_UL_DL_Config->pattern2->dl_UL_TransmissionPeriodicity == 1)) {
|
||||
return_value = 13;
|
||||
*w = (mu == 3)? 2: 1;
|
||||
} else if ((*slot_period_P == 3.0 ) && (TDD_UL_DL_Config->pattern2->dl_UL_TransmissionPeriodicity == 4)) {
|
||||
return_value = 12;
|
||||
*w = (mu == 3)? 2: 1;
|
||||
} else if ((*slot_period_P == 3.0 ) && (TDD_UL_DL_Config->pattern2->dl_UL_TransmissionPeriodicity == 2)) {
|
||||
return_value = 8;
|
||||
*w = (mu == 3)? 2: 1;
|
||||
} else {
|
||||
|
||||
switch (pattern1_dlul_period) {
|
||||
case 7:
|
||||
if (TDD_UL_DL_Config->pattern2->dl_UL_TransmissionPeriodicity == 7) {
|
||||
return_value = 15;
|
||||
*w = 1<<mu;
|
||||
}
|
||||
break;
|
||||
case 6:
|
||||
if (TDD_UL_DL_Config->pattern2->dl_UL_TransmissionPeriodicity == 6) {
|
||||
return_value = 14;
|
||||
*w = (mu==0)?1:1<<(mu-1);
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
if (TDD_UL_DL_Config->pattern2->dl_UL_TransmissionPeriodicity == 5) {
|
||||
return_value = 11;
|
||||
*w = (mu == 3)? 2: 1;
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
if (TDD_UL_DL_Config->pattern2->dl_UL_TransmissionPeriodicity == 0) {
|
||||
return_value = 5;
|
||||
}
|
||||
else if (TDD_UL_DL_Config->pattern2->dl_UL_TransmissionPeriodicity == 4) {
|
||||
return_value = 7;
|
||||
}
|
||||
else if (TDD_UL_DL_Config->pattern2->ext1 != NULL && *TDD_UL_DL_Config->pattern2->ext1->dl_UL_TransmissionPeriodicity_v1530 == 0) {
|
||||
return_value = 10;
|
||||
*w = (mu == 3)? 2: 1;
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
if (TDD_UL_DL_Config->pattern2->dl_UL_TransmissionPeriodicity == 3) {
|
||||
return_value = 4;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
if (TDD_UL_DL_Config->pattern2->dl_UL_TransmissionPeriodicity == 2) {
|
||||
return_value = 2;
|
||||
}
|
||||
else if (TDD_UL_DL_Config->pattern2->ext1 != NULL && *TDD_UL_DL_Config->pattern2->ext1->dl_UL_TransmissionPeriodicity_v1530 == 0) {
|
||||
return_value = 6;
|
||||
*w = (mu == 3)? 2: 1;
|
||||
}
|
||||
else if (TDD_UL_DL_Config->pattern2->ext1 != NULL && *TDD_UL_DL_Config->pattern2->ext1->dl_UL_TransmissionPeriodicity_v1530 == 1) {
|
||||
return_value = 9;
|
||||
*w = (mu == 3)? 2: 1;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
if (TDD_UL_DL_Config->pattern2->dl_UL_TransmissionPeriodicity == 1) {
|
||||
return_value = 1;
|
||||
}
|
||||
break;
|
||||
case 0:
|
||||
if (TDD_UL_DL_Config->pattern2->dl_UL_TransmissionPeriodicity == 0) {
|
||||
return_value = 0;
|
||||
}
|
||||
else if (TDD_UL_DL_Config->pattern2->dl_UL_TransmissionPeriodicity == 4) {
|
||||
return_value = 3;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
AssertFatal(1==0,"Incorrect value of dl_UL_TransmissionPeriodicity");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef SL_DEBUG
|
||||
printf("OUTPUT VALUES: function %s\n",__func__);
|
||||
printf("return_value:%d, *w:%d, slot_period_P:%f\n", return_value, *w, *slot_period_P);
|
||||
#endif
|
||||
|
||||
return return_value;
|
||||
}
|
||||
|
||||
/*
|
||||
This procedures prepares the psbch payload of tdd configuration according
|
||||
to section 16.1 in 38.213
|
||||
*/
|
||||
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)
|
||||
{
|
||||
|
||||
uint8_t w = 0, a1_to_a4 = 0;
|
||||
uint8_t mu_ref = 0, diff = 0;
|
||||
uint8_t u_slots = 0, u_sym = 0, I1 = 0;
|
||||
uint8_t u_sl_slots = 0, u_sl_slots_2 = 0;
|
||||
double slot_period_P = 0.0;
|
||||
|
||||
*bits_0_to_7 = 0xFF; // If TDD_UL_DL_Config = NULL all 12 bits are set to 1
|
||||
*bits_8_to_11 = 0xF0;
|
||||
|
||||
if (TDD_UL_DL_Config != NULL) {
|
||||
|
||||
mu_ref = TDD_UL_DL_Config->referenceSubcarrierSpacing;
|
||||
diff = 1 << (mu-mu_ref);
|
||||
u_slots = TDD_UL_DL_Config->pattern1.nrofUplinkSlots;
|
||||
u_sym = TDD_UL_DL_Config->pattern1.nrofUplinkSymbols;
|
||||
I1 = ((u_sym * diff) % L >= (L-Y)) ? 1 : 0;
|
||||
|
||||
#ifdef SL_DEBUG
|
||||
printf("INPUT VALUES: function %s\n", __func__);
|
||||
printf("numerology:%d, number of symbols:%d, sl-startSymbol:%d\n", mu, L, Y);
|
||||
printf("mu_ref:%d, u_slots:%d, u_sym:%d\n", mu_ref, u_slots, u_sym);
|
||||
if (TDD_UL_DL_Config->pattern2 != NULL)
|
||||
printf("u_slots_2:%ld, u_sym_2:%ld\n", TDD_UL_DL_Config->pattern2->nrofUplinkSlots,
|
||||
TDD_UL_DL_Config->pattern2->nrofUplinkSymbols);
|
||||
#endif
|
||||
|
||||
u_sl_slots = (u_slots * diff) + floor((u_sym*diff)/L) + I1;
|
||||
a1_to_a4 = sl_process_TDD_UL_DL_config_patterns(TDD_UL_DL_Config, mu, &slot_period_P, &w);
|
||||
AssertFatal(a1_to_a4 != 255,"Incorrect return value, wrong configuration.\n");
|
||||
|
||||
#ifdef SL_DEBUG
|
||||
printf("I1:%d, a1_to_a2:%d, u_sl_slots:%d\n", I1, a1_to_a4, u_sl_slots);
|
||||
#endif
|
||||
|
||||
if (TDD_UL_DL_Config->pattern2 != NULL) {
|
||||
|
||||
uint8_t u_slots_2 = TDD_UL_DL_Config->pattern2->nrofUplinkSlots;
|
||||
uint8_t u_sym_2 = TDD_UL_DL_Config->pattern2->nrofUplinkSymbols;
|
||||
uint8_t I2 = ((u_sym_2 * diff) % L >= (L-Y)) ? 1 : 0;
|
||||
uint16_t val = floor(((u_slots_2 * diff) + floor((u_sym_2*diff)/L) + I2)/w);
|
||||
|
||||
u_sl_slots_2 = val * ceil((slot_period_P*(1<<mu)+1)/w) + floor(u_sl_slots/w);
|
||||
|
||||
*bits_0_to_7 = 0x80 | (a1_to_a4 << 3) | ((u_sl_slots_2 & 0x70) >> 4);
|
||||
*bits_8_to_11 = (u_sl_slots_2 & 0x0F) << 4;
|
||||
|
||||
#ifdef SL_DEBUG
|
||||
printf("I2:%d, val:%d, u_sl_slots_2:%d\n", I2, val, u_sl_slots_2);
|
||||
#endif
|
||||
|
||||
} else {
|
||||
*bits_0_to_7 = 0x00 | (a1_to_a4 << 3) | ((u_sl_slots & 0x70) >> 4);
|
||||
*bits_8_to_11 = (u_sl_slots & 0x0F) << 4;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef SL_DEBUG
|
||||
printf("OUTPUT VALUES: function %s\n", __func__);
|
||||
printf("12 bits payload buf[0]:%x, buf[1]:%x\n", *bits_0_to_7, *bits_8_to_11);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
This procedures prepares the psbch payload of tdd configuration according
|
||||
to section 16.1 in 38.213
|
||||
*/
|
||||
uint8_t sl_decode_sl_TDD_Config(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)
|
||||
{
|
||||
|
||||
AssertFatal(TDD_UL_DL_Config, "TDD_UL_DL_Config cannot be null");
|
||||
uint16_t num_SL_slots = 0, mixed_slot_numsym = 0;
|
||||
|
||||
TDD_UL_DL_Config->pattern1.nrofDownlinkSlots = 0;
|
||||
TDD_UL_DL_Config->pattern1.nrofDownlinkSymbols = 0;
|
||||
TDD_UL_DL_Config->pattern1.nrofUplinkSlots = 0;
|
||||
TDD_UL_DL_Config->pattern1.nrofUplinkSymbols = 0;
|
||||
TDD_UL_DL_Config->referenceSubcarrierSpacing = mu;
|
||||
TDD_UL_DL_Config->pattern1.ext1 = NULL;
|
||||
|
||||
LOG_D(MAC, "bits_0_to_7:%x, bits_8_to_11:%x, mu:%d, L:%d, Y:%d\n",
|
||||
bits_0_to_7, bits_8_to_11,mu, L, Y);
|
||||
|
||||
//If all bits are 1 - indicates that no TDD config was present.
|
||||
if ((bits_0_to_7 == 0xFF) && ((bits_8_to_11 & 0xF0) == 0xF0)) {
|
||||
//If no TDD config present - use all slots for Sidelink.
|
||||
//Spec not clear -- TBD....
|
||||
return 0;
|
||||
}
|
||||
|
||||
//Bit A0 if 1 indicates pattern2 as present.
|
||||
if (bits_0_to_7 & 0x80) {
|
||||
//Pattern1 and Pattern2 Present.
|
||||
TDD_UL_DL_Config->pattern2 = malloc16_clear(sizeof(*TDD_UL_DL_Config->pattern2));
|
||||
AssertFatal(1==0,"Decoding Pattern2 - NOT YET IMPLEMENTED\n");
|
||||
} else {
|
||||
|
||||
//Only Pattern1 Present. bits a1..a4 identify the periodicity.
|
||||
uint8_t val = (bits_0_to_7 & 0x78) >> 3;
|
||||
if (val >= 7)
|
||||
TDD_UL_DL_Config->pattern1.dl_UL_TransmissionPeriodicity = val-1;
|
||||
|
||||
if (val == 6) {
|
||||
if (TDD_UL_DL_Config->pattern1.ext1 == NULL)
|
||||
TDD_UL_DL_Config->pattern1.ext1 = calloc(1, sizeof(*TDD_UL_DL_Config->pattern1.ext1));
|
||||
if (TDD_UL_DL_Config->pattern1.ext1->dl_UL_TransmissionPeriodicity_v1530 == NULL)
|
||||
TDD_UL_DL_Config->pattern1.ext1->dl_UL_TransmissionPeriodicity_v1530 = calloc(1, sizeof(long));
|
||||
*TDD_UL_DL_Config->pattern1.ext1->dl_UL_TransmissionPeriodicity_v1530 = 1;
|
||||
}
|
||||
|
||||
//a5,a6..a11 bits from the 7th to 1st LSB of num SL slots
|
||||
num_SL_slots = ((bits_0_to_7 & 0x07) << 4 ) | ((bits_8_to_11 & 0xF0) >> 4);
|
||||
|
||||
TDD_UL_DL_Config->pattern1.nrofUplinkSlots = num_SL_slots;
|
||||
TDD_UL_DL_Config->pattern1.nrofUplinkSymbols = mixed_slot_numsym;
|
||||
|
||||
LOG_D(MAC, "SIDELINK: EXtracted TDD config from 12 bits - Sidelink Slots:%ld, Mixed_slot_symbols:%ld,dl_UL_TransmissionPeriodicity:%ld\n",
|
||||
TDD_UL_DL_Config->pattern1.nrofUplinkSlots, TDD_UL_DL_Config->pattern1.nrofUplinkSymbols,
|
||||
TDD_UL_DL_Config->pattern1.dl_UL_TransmissionPeriodicity);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*Function used to prepare Sidelink MIB*/
|
||||
uint32_t sl_prepare_MIB(NR_TDD_UL_DL_ConfigCommon_t *TDD_UL_DL_Config,
|
||||
uint8_t incoverage, uint8_t mu,
|
||||
uint8_t start_symbol, uint8_t L) {
|
||||
|
||||
uint8_t sl_mib_payload[4] = {0,0,0,0};
|
||||
//int mu = UE->sl_frame_params.numerology_index, start_symbol = UE->start_symbol;
|
||||
uint8_t byte0, byte1;
|
||||
//int L = (UE->sl_frame_params.Ncp == 0) ? 14 : 12;
|
||||
uint32_t sl_mib=0;
|
||||
|
||||
sl_prepare_psbch_payload(TDD_UL_DL_Config, &byte0, &byte1, mu, L, start_symbol);
|
||||
sl_mib_payload[0] = byte0;
|
||||
sl_mib_payload[1] = byte1;
|
||||
|
||||
AssertFatal(incoverage <= 1, "Invalid value for incoverage paramter for SL-MIB. Accepted values 0 or 1\n");
|
||||
sl_mib_payload[1] |= (incoverage << 3);
|
||||
|
||||
sl_mib = sl_mib_payload[1]<<8 | sl_mib_payload[0];
|
||||
|
||||
#ifdef SL_DEBUG
|
||||
printf("SIDELINK PSBCH SIM: NUM SYMBOLS:%d, mu:%d, start_symbol:%d incoverage:%d \n",
|
||||
L, mu, start_symbol, incoverage);
|
||||
printf("SIDELINK PSBCH PAYLOAD: psbch_a:%x, sl_mib_payload:%x %x %x %x\n",
|
||||
sl_mib, sl_mib_payload[0],sl_mib_payload[1], sl_mib_payload[2], sl_mib_payload[3]);
|
||||
#endif
|
||||
|
||||
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);
|
||||
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;
|
||||
|
||||
LOG_I(NR_MAC, "Subch_size:%d, numRBS:%d, num_subch:%d\n",
|
||||
subch_size,num_rbs,num_subch);
|
||||
|
||||
return (num_subch);
|
||||
}
|
||||
|
||||
//This function determines SCI 1A Len in bits based on the configuration in the resource pool.
|
||||
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)
|
||||
{
|
||||
|
||||
uint8_t num_bits = 0;
|
||||
|
||||
//Size of Fixed fields prio (3), sci_2ndstage(2),
|
||||
//betaoffsetindicator(2), num dmrs ports (1), mcs (5bits)
|
||||
uint8_t sci_1a_len = SL_SCI_FORMAT_1A_LEN_IN_BITS_FIXED_FIELDS;
|
||||
|
||||
*num_subchannels = sl_get_num_subch(rpool);
|
||||
|
||||
uint16_t n_subch = *num_subchannels;
|
||||
|
||||
LOG_D(NR_MAC,"Determine SCI-1A len - Num Subch:%d, sci 1A len fixed fields:%d\n",
|
||||
*num_subchannels, sci_1a_len);
|
||||
|
||||
NR_SL_UE_SelectedConfigRP_r16_t *selectedconfigRP = rpool->sl_UE_SelectedConfigRP_r16;
|
||||
const uint8_t maxnum_values[] = {2,3};
|
||||
uint8_t sl_MaxNumPerReserve = (selectedconfigRP &&
|
||||
selectedconfigRP->sl_MaxNumPerReserve_r16)
|
||||
? maxnum_values[*selectedconfigRP->sl_MaxNumPerReserve_r16]
|
||||
: 0;
|
||||
|
||||
//Determine bits for Freq and Time Resource assignment
|
||||
if (sl_MaxNumPerReserve == 3) {
|
||||
num_bits = ceil(log2(n_subch * (n_subch + 1) * (2*n_subch + 1)/6));
|
||||
sci_1a_len += num_bits;
|
||||
sci_1a->frequency_resource_assignment.nbits = num_bits;
|
||||
sci_1a_len += 9;
|
||||
sci_1a->time_resource_assignment.nbits = 9;
|
||||
} else {
|
||||
num_bits = ceil(log2((n_subch * (n_subch + 1)) >> 1));
|
||||
sci_1a_len += num_bits;
|
||||
sci_1a->frequency_resource_assignment.nbits = num_bits;
|
||||
sci_1a_len += 5;
|
||||
sci_1a->time_resource_assignment.nbits = 5;
|
||||
}
|
||||
|
||||
LOG_D(NR_MAC,"sci 1A - sl_MaxNumPerReserve:%d, sci 1a len:%d, FRA nbits:%d, TRA nbits:%d\n",
|
||||
sl_MaxNumPerReserve,sci_1a_len,
|
||||
sci_1a->frequency_resource_assignment.nbits,
|
||||
sci_1a->time_resource_assignment.nbits);
|
||||
|
||||
//Determine bits for res reservation period
|
||||
uint8_t n_rsvperiod = (selectedconfigRP &&
|
||||
selectedconfigRP->sl_ResourceReservePeriodList_r16)
|
||||
? selectedconfigRP->sl_ResourceReservePeriodList_r16->list.count : 0;
|
||||
|
||||
#define SL_IE_ENABLED 0
|
||||
if (selectedconfigRP &&
|
||||
selectedconfigRP->sl_MultiReserveResource_r16 == SL_IE_ENABLED) {
|
||||
num_bits = ceil(log2(n_rsvperiod));
|
||||
sci_1a_len += num_bits;
|
||||
sci_1a->resource_reservation_period.nbits = num_bits;
|
||||
} else
|
||||
sci_1a->resource_reservation_period.nbits = 0;
|
||||
|
||||
LOG_D(NR_MAC,"sci 1A - n_rsvperiod:%d, sci 1a len:%d, res reserve period.nbits:%d\n",
|
||||
n_rsvperiod, sci_1a_len,
|
||||
sci_1a->resource_reservation_period.nbits);
|
||||
|
||||
|
||||
uint8_t n_dmrspatterns = 0;
|
||||
if (rpool->sl_PSSCH_Config_r16 &&
|
||||
rpool->sl_PSSCH_Config_r16->present == NR_SetupRelease_SL_PSSCH_Config_r16_PR_setup) {
|
||||
NR_SL_PSSCH_Config_r16_t *pssch_cfg = rpool->sl_PSSCH_Config_r16->choice.setup;
|
||||
|
||||
//Determine bits for DMRS PATTERNS
|
||||
n_dmrspatterns = (pssch_cfg && pssch_cfg->sl_PSSCH_DMRS_TimePatternList_r16)
|
||||
? pssch_cfg->sl_PSSCH_DMRS_TimePatternList_r16->list.count : 0;
|
||||
}
|
||||
|
||||
AssertFatal((n_dmrspatterns>=1) && (n_dmrspatterns <=3),
|
||||
"Number of DMRS Patterns should be 1or2or3. Resource Pool Configuration Error.\n");
|
||||
|
||||
if (n_dmrspatterns) {
|
||||
num_bits = ceil(log2(n_dmrspatterns));
|
||||
sci_1a_len += num_bits;
|
||||
sci_1a->dmrs_pattern.nbits = num_bits;
|
||||
}
|
||||
|
||||
LOG_D(NR_MAC,"sci 1A - n_dmrspatterns:%d, sci 1a len:%d, dmrs_pattern.nbits:%d\n",
|
||||
n_dmrspatterns, sci_1a_len, sci_1a->dmrs_pattern.nbits);
|
||||
|
||||
//Determine bits for Additional MCS table
|
||||
if (rpool->sl_Additional_MCS_Table_r16) {
|
||||
int numbits = (*rpool->sl_Additional_MCS_Table_r16 > 1) ? 2 : 1;
|
||||
sci_1a_len += numbits;
|
||||
sci_1a->additional_mcs_table_indicator.nbits = numbits;
|
||||
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 ? *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 &&
|
||||
rpool->sl_PSFCH_Config_r16->present == NR_SetupRelease_SL_PSFCH_Config_r16_PR_setup) {
|
||||
NR_SL_PSFCH_Config_r16_t *psfch_config = rpool->sl_PSFCH_Config_r16->choice.setup;
|
||||
|
||||
//Determine bits for PSFCH overhead indication
|
||||
const uint8_t psfch_periods[] = {0,1,2,4};
|
||||
psfch_period = (psfch_config->sl_PSFCH_Period_r16)
|
||||
? psfch_periods[*psfch_config->sl_PSFCH_Period_r16] : 0;
|
||||
}
|
||||
|
||||
if ((psfch_period == 2) || (psfch_period == 4)) {
|
||||
sci_1a_len += 1;
|
||||
sci_1a->psfch_overhead_indication.nbits = 1;
|
||||
} else
|
||||
sci_1a->psfch_overhead_indication.nbits = 0;
|
||||
|
||||
LOG_D(NR_MAC,"sci 1A - psfch_period:%d, sci 1a len:%d, psfch overhead nbits:%d\n",
|
||||
psfch_period, sci_1a_len,
|
||||
sci_1a->psfch_overhead_indication.nbits);
|
||||
|
||||
//Determine number of reserved bits
|
||||
uint8_t num_reservedbits = 0;
|
||||
if (rpool->sl_PSCCH_Config_r16 &&
|
||||
rpool->sl_PSCCH_Config_r16->present == NR_SetupRelease_SL_PSCCH_Config_r16_PR_setup) {
|
||||
NR_SL_PSCCH_Config_r16_t *pscch_config = rpool->sl_PSCCH_Config_r16->choice.setup;
|
||||
|
||||
num_reservedbits = (pscch_config->sl_NumReservedBits_r16)
|
||||
? *pscch_config->sl_NumReservedBits_r16 : 0;
|
||||
}
|
||||
|
||||
AssertFatal((num_reservedbits>=2) || (num_reservedbits<=4) ,
|
||||
"Num Reserved bits can only be 2or3or4. Resource Pool Configuration Error.\n");
|
||||
sci_1a_len += num_reservedbits;
|
||||
sci_1a->reserved_bits.nbits = num_reservedbits;
|
||||
LOG_D(NR_MAC,"sci 1A - reserved_bits:%d, sci 1a len:%d, sci_1a->reserved_bits.nbits:%d\n",
|
||||
num_reservedbits, sci_1a_len, sci_1a->reserved_bits.nbits);
|
||||
|
||||
|
||||
LOG_D(NR_MAC,"sci 1A Length in bits: %d \n",sci_1a_len);
|
||||
|
||||
return sci_1a_len;
|
||||
}
|
||||
|
||||
/* 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.
|
||||
*/
|
||||
uint32_t sl_determine_num_sidelink_slots(uint8_t mod_id, uint16_t *N_SSB_16frames, uint16_t *N_SL_SLOTS_perframe)
|
||||
{
|
||||
|
||||
NR_UE_MAC_INST_t *mac = get_mac_inst(mod_id);
|
||||
sl_nr_ue_mac_params_t *sl_mac = mac->SL_MAC_PARAMS;
|
||||
uint32_t N_SSB_1024frames = 0;
|
||||
uint32_t N_SL_SLOTS = 0;
|
||||
*N_SL_SLOTS_perframe = 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(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(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);
|
||||
|
||||
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, 0, i, TDD);
|
||||
if (slot_type == NR_SIDELINK_SLOT) {
|
||||
*N_SL_SLOTS_perframe = *N_SL_SLOTS_perframe + 1;
|
||||
sl_mac->sl_slot_bitmap |= (1<<i);
|
||||
}
|
||||
}
|
||||
|
||||
//Determine total number of Valid Sidelink slots which can be used for Respool in a SFN cycle (1024 frames)
|
||||
N_SL_SLOTS = (*N_SL_SLOTS_perframe * SL_FRAME_NUMBER_CYCLE) - N_SSB_1024frames;
|
||||
|
||||
LOG_I(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",
|
||||
mod_id,N_SSB_1024frames, *N_SL_SLOTS_perframe,
|
||||
N_SL_SLOTS, sl_mac->sl_slot_bitmap);
|
||||
|
||||
|
||||
return N_SL_SLOTS;
|
||||
}
|
||||
|
||||
@@ -87,6 +87,8 @@ void fill_scheduled_response(nr_scheduled_response_t *scheduled_response,
|
||||
fapi_nr_dl_config_request_t *dl_config,
|
||||
fapi_nr_ul_config_request_t *ul_config,
|
||||
fapi_nr_tx_request_t *tx_request,
|
||||
sl_nr_rx_config_request_t *sl_rx_config,
|
||||
sl_nr_tx_config_request_t *sl_tx_config,
|
||||
module_id_t mod_id,
|
||||
int cc_id,
|
||||
frame_t frame,
|
||||
@@ -101,6 +103,8 @@ void fill_scheduled_response(nr_scheduled_response_t *scheduled_response,
|
||||
scheduled_response->frame = frame;
|
||||
scheduled_response->slot = slot;
|
||||
scheduled_response->phy_data = phy_data;
|
||||
scheduled_response->sl_rx_config = sl_rx_config;
|
||||
scheduled_response->sl_tx_config = sl_tx_config;
|
||||
|
||||
}
|
||||
|
||||
@@ -970,7 +974,7 @@ void nr_ue_dl_scheduler(nr_downlink_indication_t *dl_info)
|
||||
}
|
||||
dcireq.dl_config_req = *dl_config;
|
||||
|
||||
fill_scheduled_response(&scheduled_response, &dcireq.dl_config_req, NULL, NULL, mod_id, cc_id, rx_frame, rx_slot, dl_info->phy_data);
|
||||
fill_scheduled_response(&scheduled_response, &dcireq.dl_config_req, NULL, NULL, NULL, NULL,mod_id, cc_id, rx_frame, rx_slot, dl_info->phy_data);
|
||||
if(mac->if_module != NULL && mac->if_module->scheduled_response != NULL) {
|
||||
LOG_D(NR_MAC,"1# scheduled_response transmitted, %d, %d\n", rx_frame, rx_slot);
|
||||
mac->if_module->scheduled_response(&scheduled_response);
|
||||
@@ -1079,7 +1083,7 @@ void nr_ue_ul_scheduler(nr_uplink_indication_t *ul_info)
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&ul_config->mutex_ul_config); // avoid double lock
|
||||
fill_scheduled_response(&scheduled_response, NULL, ul_config, &tx_req, mod_id, cc_id, frame_tx, slot_tx, ul_info->phy_data);
|
||||
fill_scheduled_response(&scheduled_response, NULL, ul_config, &tx_req, NULL, NULL,mod_id, cc_id, frame_tx, slot_tx, ul_info->phy_data);
|
||||
if(mac->if_module != NULL && mac->if_module->scheduled_response != NULL){
|
||||
LOG_D(NR_MAC,"3# scheduled_response transmitted,%d, %d\n", frame_tx, slot_tx);
|
||||
mac->if_module->scheduled_response(&scheduled_response);
|
||||
@@ -2190,7 +2194,7 @@ void nr_ue_pucch_scheduler(module_id_t module_idP, frame_t frameP, int slotP, vo
|
||||
&pucch[j],
|
||||
pucch_pdu);
|
||||
nr_scheduled_response_t scheduled_response;
|
||||
fill_scheduled_response(&scheduled_response, NULL, ul_config, NULL, module_idP, 0 /*TBR fix*/, frameP, slotP, phy_data);
|
||||
fill_scheduled_response(&scheduled_response, NULL, ul_config, NULL, NULL, NULL,module_idP, 0 /*TBR fix*/, frameP, slotP, phy_data);
|
||||
if (mac->if_module != NULL && mac->if_module->scheduled_response != NULL)
|
||||
mac->if_module->scheduled_response(&scheduled_response);
|
||||
if (mac->state == UE_WAIT_TX_ACK_MSG4)
|
||||
@@ -2639,7 +2643,7 @@ static void nr_ue_prach_scheduler(module_id_t module_idP, frame_t frameP, sub_fr
|
||||
prach_config_pdu->prach_tx_power = get_prach_tx_power(module_idP);
|
||||
set_ra_rnti(mac, prach_config_pdu);
|
||||
|
||||
fill_scheduled_response(&scheduled_response, NULL, ul_config, NULL, module_idP, 0 /*TBR fix*/, frameP, slotP, NULL);
|
||||
fill_scheduled_response(&scheduled_response, NULL, ul_config, NULL, NULL, NULL,module_idP, 0 /*TBR fix*/, frameP, slotP, NULL);
|
||||
if(mac->if_module != NULL && mac->if_module->scheduled_response != NULL)
|
||||
mac->if_module->scheduled_response(&scheduled_response);
|
||||
|
||||
@@ -3116,3 +3120,298 @@ void schedule_ta_command(fapi_nr_dl_config_request_t *dl_config, NR_UL_TIME_ALIG
|
||||
dl_config->number_pdus += 1;
|
||||
ul_time_alignment->ta_apply = false;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
void sl_adjust_indices_based_on_timing(uint32_t frame, uint32_t slot,
|
||||
uint32_t frame_tx, uint32_t slot_tx,
|
||||
uint16_t mod_id, uint16_t slots_per_frame)
|
||||
{
|
||||
|
||||
NR_UE_MAC_INST_t *mac = get_mac_inst(mod_id);
|
||||
sl_nr_ue_mac_params_t *sl_mac = mac->SL_MAC_PARAMS;
|
||||
|
||||
uint16_t frame_16 = frame % SL_NR_SSB_REPETITION_IN_FRAMES;
|
||||
uint32_t slot_in_16frames = (frame_16 * slots_per_frame) + slot;
|
||||
uint16_t frame_tx_16 = frame_tx % SL_NR_SSB_REPETITION_IN_FRAMES;
|
||||
uint32_t slot_tx_in_16frames = (frame_tx_16 * slots_per_frame) + slot_tx;
|
||||
LOG_I(NR_MAC,"[UE%d]PSBCH params adjusted based on RX current timing %d:%d. frame_16:%d, slot_in_16frames:%d\n",
|
||||
mod_id, frame, slot, frame_16, slot_in_16frames);
|
||||
LOG_I(NR_MAC,"[UE%d]PSBCH params adjusted based on TX current timing %d:%d. frame_16:%d, slot_in_16frames:%d\n",
|
||||
mod_id, frame_tx, slot_tx, frame_tx_16, slot_tx_in_16frames);
|
||||
|
||||
//Adjust PSBCH Indices based on current RX timing
|
||||
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);
|
||||
|
||||
//Adjust PSBCH Indices based on current TX timing
|
||||
ssb_timealloc = &sl_mac->tx_sl_bch.ssb_time_alloc;
|
||||
sl_mac->tx_sl_bch.num_ssb = sl_adjust_ssb_indices(ssb_timealloc, slot_tx_in_16frames, &sl_mac->tx_sl_bch.ssb_slot);
|
||||
|
||||
LOG_I(NR_MAC,"[UE%d]PSBCH params adjusted based on RX current timing %d:%d. NumSSB:%d, ssb_slot:%d\n",
|
||||
mod_id, frame, slot, sl_mac->rx_sl_bch.num_ssb,
|
||||
sl_mac->rx_sl_bch.ssb_slot);
|
||||
LOG_I(NR_MAC,"[UE%d]PSBCH params adjusted based on TX current timing %d:%d. NumSSB:%d, ssb_slot:%d\n",
|
||||
mod_id, frame_tx, slot_tx, sl_mac->tx_sl_bch.num_ssb,
|
||||
sl_mac->tx_sl_bch.ssb_slot);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
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,
|
||||
sl_sidelink_slot_type_t slot_type) {
|
||||
|
||||
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;
|
||||
|
||||
LOG_D(NR_MAC, "%d:%d. slot_type:%d, num_ssb:%d,ssb_slot:%d, %d-%d-%d, status:%d\n",
|
||||
frame, slot, slot_type,
|
||||
sl_bch->num_ssb,sl_bch->ssb_slot,
|
||||
sl_NumSSB_WithinPeriod, sl_TimeOffsetSSB, sl_TimeInterval, sl_bch->status);
|
||||
|
||||
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;
|
||||
|
||||
//Update the time when the same slot with RX SLOT type is called
|
||||
if (slot_type == SIDELINK_SLOT_TYPE_RX) {
|
||||
sl_bch->ssb_slot = ssb_slot;
|
||||
sl_bch->num_ssb = num_ssb;
|
||||
}
|
||||
|
||||
LOG_D(NR_MAC, "%d:%d is a PSBCH SLOT. Slot type:%d Next PSBCH Slot:%d, num_ssb:%d\n",
|
||||
frame, slot, slot_type,
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
* determine if sidelink slot is a PSBCH slot
|
||||
* If PSBCH rx slot and sync_source == SYNC_REF_UE
|
||||
* TTI COMMAND = PSBCH RX
|
||||
* if PSBCH tx slot and transmit SLSS == true
|
||||
* TTI_COMMAND = PSBCH TX
|
||||
* Sidelink UE can rx and tx a SSB however the SSB time
|
||||
* allocation will be different
|
||||
*/
|
||||
uint8_t nr_ue_sl_psbch_scheduler(nr_sidelink_indication_t *sl_ind,
|
||||
sl_nr_ue_mac_params_t *sl_mac_params,
|
||||
sl_nr_rx_config_request_t *rx_config,
|
||||
sl_nr_tx_config_request_t *tx_config,
|
||||
uint8_t *config_type) {
|
||||
|
||||
uint8_t ret_status = 0, is_psbch_rx_slot = 0, is_psbch_tx_slot = 0;
|
||||
uint16_t slot = sl_ind->slot_rx;
|
||||
uint16_t frame = sl_ind->frame_rx;
|
||||
|
||||
// Schedule TX only if slot type is TX.
|
||||
if (sl_ind->slot_type == SIDELINK_SLOT_TYPE_TX) {
|
||||
slot = sl_ind->slot_tx;
|
||||
frame = sl_ind->frame_tx;
|
||||
}
|
||||
|
||||
|
||||
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];
|
||||
|
||||
LOG_D(NR_MAC,"[UE%d] SL-PSBCH SCHEDULER: Frame:SLOT %d:%d, slot_type:%d\n",
|
||||
sl_ind->module_id, frame, slot,sl_ind->slot_type);
|
||||
|
||||
is_psbch_rx_slot = sl_determine_if_SSB_slot(frame, slot, slots_per_frame,
|
||||
&sl_mac_params->rx_sl_bch,
|
||||
sl_ind->slot_type);
|
||||
|
||||
if (is_psbch_rx_slot &&
|
||||
sl_ind->slot_type == SIDELINK_SLOT_TYPE_RX) {
|
||||
|
||||
*config_type = SL_NR_CONFIG_TYPE_RX_PSBCH;
|
||||
rx_config->number_pdus = 1;
|
||||
rx_config->sfn = frame;
|
||||
rx_config->slot = slot;
|
||||
rx_config->sl_rx_config_list[0].pdu_type = *config_type;
|
||||
|
||||
LOG_I(NR_MAC, "[UE%d] TTI-%d:%d RX PSBCH REQ- rx_slss_id:%d, numSSB:%d, next slot_SSB:%d\n",
|
||||
sl_ind->module_id,frame, slot,
|
||||
sl_cfg->sl_sync_source.rx_slss_id,
|
||||
sl_mac_params->rx_sl_bch.num_ssb,
|
||||
sl_mac_params->rx_sl_bch.ssb_slot);
|
||||
|
||||
}
|
||||
if (!is_psbch_rx_slot) {
|
||||
|
||||
is_psbch_tx_slot = sl_determine_if_SSB_slot(frame, slot, slots_per_frame,
|
||||
&sl_mac_params->tx_sl_bch,
|
||||
sl_ind->slot_type);
|
||||
|
||||
if (is_psbch_tx_slot &&
|
||||
sl_ind->slot_type == SIDELINK_SLOT_TYPE_TX) {
|
||||
|
||||
*config_type = SL_NR_CONFIG_TYPE_TX_PSBCH;
|
||||
tx_config->number_pdus = 1;
|
||||
tx_config->sfn = frame;
|
||||
tx_config->slot = slot;
|
||||
tx_config->tx_config_list[0].pdu_type = *config_type;
|
||||
tx_config->tx_config_list[0].tx_psbch_config_pdu.tx_slss_id = sl_mac_params->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_params->tx_sl_bch.sl_mib, 4);
|
||||
|
||||
LOG_I(NR_MAC, "[UE%d] TTI-%d:%d TX PSBCH REQ- tx_slss_id:%d, sl-mib:%x, numSSB:%d, next SSB slot:%d\n",
|
||||
sl_ind->module_id,frame, slot,
|
||||
sl_mac_params->tx_sl_bch.slss_id,
|
||||
(*(uint32_t *)tx_config->tx_config_list[0].tx_psbch_config_pdu.psbch_payload),
|
||||
sl_mac_params->tx_sl_bch.num_ssb,
|
||||
sl_mac_params->tx_sl_bch.ssb_slot);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ret_status = is_psbch_rx_slot | is_psbch_tx_slot;
|
||||
|
||||
LOG_D(NR_MAC,"[UE%d] SL-PSBCH SCHEDULER: %d:%d,is psbch slot:%d, config type:%d\n",
|
||||
sl_ind->module_id,frame, slot, ret_status, *config_type);
|
||||
return ret_status;
|
||||
}
|
||||
|
||||
/*
|
||||
// This function will be called only for SIDELINK CAPABLE SLOTS.
|
||||
// UPLINK SLOT OR MIXED SLOT which is SIDELINK SLOT
|
||||
|
||||
//Determine if PSBCH SLOT and if PSBCH RX/TX should be done
|
||||
// IF NOT PSBCH SLOT continue ahead
|
||||
|
||||
// IF RX RES POOL CONFIGURED
|
||||
// Determine if SLOT is a RX RES POOL RESERVED
|
||||
// OR RX RES POOL RESOURCE SLOT according to time resource bitmap
|
||||
// IF resource slot PSCCH RX action should be done
|
||||
|
||||
// IF TX RES POOL CONFIGURED
|
||||
// Determine if SLOT is a TX RES POOL RESERVED
|
||||
// OR RX RES POOL RESOURCE SLOT according to time resource bitmap
|
||||
// IF resource slot PSCCH TX action should be done in case TX is scheduled
|
||||
// ELSE SENSING SHOULD BE DONE
|
||||
|
||||
// IF TX/RX ACTION SHOULD BE DONE in this slot
|
||||
// SEND SIDELINK TX/RX CONFIG REQUEST TO PHY
|
||||
*/
|
||||
void nr_ue_sidelink_scheduler(nr_sidelink_indication_t *sl_ind) {
|
||||
|
||||
AssertFatal(sl_ind != NULL, "sl_indication cannot be NULL\n");
|
||||
|
||||
module_id_t mod_id = sl_ind->module_id;
|
||||
frame_t frame = sl_ind->frame_rx;
|
||||
slot_t slot = sl_ind->slot_rx;
|
||||
|
||||
if (sl_ind->slot_type == SIDELINK_SLOT_TYPE_TX) {
|
||||
frame = sl_ind->frame_tx;
|
||||
slot = sl_ind->slot_tx;
|
||||
}
|
||||
|
||||
NR_UE_MAC_INST_t *mac = get_mac_inst(mod_id);
|
||||
sl_nr_ue_mac_params_t *sl_mac = mac->SL_MAC_PARAMS;
|
||||
sl_nr_phy_config_request_t *sl_cfg = &sl_mac->sl_phy_config.sl_config_req;
|
||||
|
||||
uint8_t mu = sl_cfg->sl_bwp_config.sl_scs;
|
||||
uint8_t slots_per_frame = nr_slots_per_frame[mu];
|
||||
|
||||
//Adjust indices as new timing is acquired
|
||||
if (sl_mac->adjust_timing) {
|
||||
sl_adjust_indices_based_on_timing(sl_ind->frame_rx, sl_ind->slot_rx,
|
||||
sl_ind->frame_tx, sl_ind->slot_tx,
|
||||
mod_id, slots_per_frame);
|
||||
sl_mac->adjust_timing = 0;
|
||||
}
|
||||
|
||||
sl_nr_rx_config_request_t rx_config;
|
||||
sl_nr_tx_config_request_t tx_config;
|
||||
|
||||
rx_config.number_pdus = 0;
|
||||
tx_config.number_pdus = 0;
|
||||
|
||||
nr_scheduled_response_t scheduled_response;
|
||||
memset(&scheduled_response,0, sizeof(nr_scheduled_response_t));
|
||||
|
||||
uint8_t tti_action = 0, is_psbch_slot = 0;
|
||||
|
||||
// Check if PSBCH slot and PSBCH should be transmitted or Received
|
||||
is_psbch_slot = nr_ue_sl_psbch_scheduler(sl_ind, sl_mac, &rx_config, &tx_config, &tti_action);
|
||||
|
||||
if (!is_psbch_slot) {
|
||||
//Check if reserved slot or a sidelink resource configured in Rx/Tx resource pool timeresource bitmap
|
||||
}
|
||||
|
||||
if (tti_action == SL_NR_CONFIG_TYPE_RX_PSBCH) {
|
||||
fill_scheduled_response(&scheduled_response, NULL, NULL, NULL, &rx_config, NULL, mod_id, 0,frame, slot, sl_ind->phy_data);
|
||||
}
|
||||
if (tti_action == SL_NR_CONFIG_TYPE_TX_PSBCH) {
|
||||
fill_scheduled_response(&scheduled_response, NULL, NULL, NULL, NULL, &tx_config, mod_id, 0,frame, slot, sl_ind->phy_data);
|
||||
}
|
||||
|
||||
|
||||
LOG_D(NR_MAC,"[UE%d]SL-SCHEDULER: TTI-RX-%d:%d, TX-%d:%d is_psbch_slot:%d TTIaction:%d\n",
|
||||
mod_id,sl_ind->frame_rx, sl_ind->slot_rx,
|
||||
sl_ind->frame_tx, sl_ind->slot_tx,
|
||||
is_psbch_slot, tti_action);
|
||||
|
||||
if (tti_action) {
|
||||
if ((mac->if_module != NULL) && (mac->if_module->scheduled_response != NULL))
|
||||
mac->if_module->scheduled_response(&scheduled_response);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1183,7 +1183,7 @@ int nr_ue_dl_indication(nr_downlink_indication_t *dl_info)
|
||||
AssertFatal( nr_ue_if_module_inst[module_id] != NULL, "IF module is NULL!\n" );
|
||||
AssertFatal( nr_ue_if_module_inst[module_id]->scheduled_response != NULL, "scheduled_response is NULL!\n" );
|
||||
fapi_nr_dl_config_request_t *dl_config = get_dl_config_request(mac, dl_info->slot);
|
||||
fill_scheduled_response(&scheduled_response, dl_config, NULL, NULL, dl_info->module_id, dl_info->cc_id, dl_info->frame, dl_info->slot, dl_info->phy_data);
|
||||
fill_scheduled_response(&scheduled_response, dl_config, NULL, NULL, NULL, NULL,dl_info->module_id, dl_info->cc_id, dl_info->frame, dl_info->slot, dl_info->phy_data);
|
||||
nr_ue_if_module_inst[module_id]->scheduled_response(&scheduled_response);
|
||||
memset(def_dci_pdu_rel15, 0, sizeof(*def_dci_pdu_rel15));
|
||||
}
|
||||
@@ -1262,6 +1262,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
|
||||
@@ -1324,3 +1328,109 @@ void RCconfig_nr_ue_macrlc(void) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void handle_sl_bch(module_id_t module_id,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);
|
||||
|
||||
NR_UE_MAC_INST_t *mac = get_mac_inst(module_id);
|
||||
sl_nr_ue_mac_params_t *sl_mac = mac->SL_MAC_PARAMS;
|
||||
|
||||
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_I(NR_MAC, "[UE%d]In %d:%d Received SL-MIB:%x .Contents- SL-TDD config:%x, Incov:%d, FN:%d, Slot:%d\n",
|
||||
module_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;
|
||||
|
||||
#define NR_SBCCH_SL_BCH 5
|
||||
nr_mac_rrc_sl_mib_ind(module_id,0,0,frame_rx, slot_rx, NR_SBCCH_SL_BCH, sl_mib, len, rx_slss_id);
|
||||
|
||||
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(uint16_t mod_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_I(NR_MAC, "[UE%d]SL-MAC Received SL-SSB: RSRP:%d dBm/RE, rx_psbch_payload:%x, rx_slss_id:%d\n",
|
||||
mod_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(mod_id, 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",mod_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)
|
||||
*/
|
||||
int nr_ue_sl_indication(nr_sidelink_indication_t *sl_indication)
|
||||
{
|
||||
|
||||
//NR_UE_L2_STATE_t ret;
|
||||
module_id_t module_id = sl_indication->module_id;
|
||||
NR_UE_MAC_INST_t *mac = get_mac_inst(module_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(module_id, frame, slot, sl_mac, sl_indication->rx_ind);
|
||||
} else {
|
||||
nr_ue_sidelink_scheduler(sl_indication);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -42,6 +42,16 @@
|
||||
#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;
|
||||
@@ -118,7 +128,7 @@ typedef struct {
|
||||
uint32_t gNB_index;
|
||||
/// component carrier id
|
||||
int cc_id;
|
||||
/// frame
|
||||
/// frame rx
|
||||
frame_t frame_rx;
|
||||
/// slot rx
|
||||
uint32_t slot_rx;
|
||||
@@ -126,6 +136,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
|
||||
@@ -244,7 +256,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 int8_t (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
|
||||
@@ -285,6 +297,7 @@ typedef int (nr_ue_sl_indication_f)(nr_sidelink_indication_t *sl_info);
|
||||
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;
|
||||
@@ -333,6 +346,8 @@ int nr_ue_dl_indication(nr_downlink_indication_t *dl_info);
|
||||
|
||||
int nr_ue_ul_indication(nr_uplink_indication_t *ul_info);
|
||||
|
||||
int nr_ue_sl_indication(nr_sidelink_indication_t *sl_indication);
|
||||
|
||||
int nr_ue_dcireq(nr_dcireq_t *dcireq);
|
||||
|
||||
// TODO check
|
||||
|
||||
@@ -453,7 +453,7 @@ NR_UE_RRC_INST_t* openair_rrc_top_init_ue_nr(char* uecap_file, char* rrc_config_
|
||||
}
|
||||
|
||||
if (get_softmodem_params()->sl_mode) {
|
||||
configure_NR_SL_Preconfig(get_softmodem_params()->sync_ref);
|
||||
configure_NR_SL_Preconfig(0,get_nrUE_params()->sync_ref);
|
||||
}
|
||||
}
|
||||
else{
|
||||
|
||||
@@ -53,6 +53,8 @@
|
||||
#include "NR_DL-DCCH-Message.h"
|
||||
#include "NR_SystemInformation.h"
|
||||
#include "NR_UE-NR-Capability.h"
|
||||
#include "NR_SL-PreconfigurationNR-r16.h"
|
||||
#include "NR_MasterInformationBlockSidelink.h"
|
||||
|
||||
#include "RRC/NR/nr_rrc_common.h"
|
||||
#include "as_message.h"
|
||||
@@ -254,6 +256,11 @@ typedef struct NR_UE_RRC_INST_s {
|
||||
Rrc_State_NR_t nrRrcState;
|
||||
Rrc_Sub_State_NR_t nrRrcSubState;
|
||||
as_nas_info_t initialNasMsg;
|
||||
|
||||
//Sidelink params
|
||||
NR_SL_PreconfigurationNR_r16_t *sl_preconfig;
|
||||
NR_MasterInformationBlockSidelink_t *sl_mib;
|
||||
|
||||
} NR_UE_RRC_INST_t;
|
||||
|
||||
#endif
|
||||
|
||||
@@ -173,7 +173,9 @@ void handle_rlf_sync(NR_UE_Timers_Constants_t *tac,
|
||||
void nr_rrc_handle_SetupRelease_RLF_TimersAndConstants(NR_UE_RRC_INST_t *rrc,
|
||||
struct NR_SetupRelease_RLF_TimersAndConstants *rlf_TimersAndConstants);
|
||||
|
||||
int configure_NR_SL_Preconfig(int sync_source);
|
||||
int configure_NR_SL_Preconfig(uint8_t id,int sync_source);
|
||||
void nr_UE_configure_Sidelink(uint8_t id, uint8_t is_sync_source);
|
||||
|
||||
/** @}*/
|
||||
#endif
|
||||
|
||||
|
||||
@@ -27,6 +27,19 @@
|
||||
#include "common/utils/LOG/log.h"
|
||||
#include "sl_preconfig_paramvalues.h"
|
||||
#include "common/config/config_userapi.h"
|
||||
#include "rrc_defs.h"
|
||||
#include "rrc_vars.h"
|
||||
#include "LAYER2/NR_MAC_UE/mac_proto.h"
|
||||
|
||||
#define GNSS_SUPPORT 0
|
||||
|
||||
#define SL_SYNC_SOURCE_NONE 0 //No sync source selected
|
||||
#define SL_SYNC_SOURCE_GNBENB 1 // GNB/ENB as sync source
|
||||
#define SL_SYNC_SOURCE_GNSS 2 // GPS as sync source
|
||||
#define SL_SYNC_SOURCE_SYNC_REF_UE 3 // another SYNC REF UE as sync source
|
||||
#define SL_SYNC_SOURCE_LOCAL_TIMING 4 //UE acts as sync source
|
||||
|
||||
|
||||
|
||||
static void prepare_NR_SL_SyncConfig(NR_SL_SyncConfig_r16_t *sl_syncconfig)
|
||||
{
|
||||
@@ -399,8 +412,7 @@ NR_SL_PreconfigurationNR_r16_t *prepare_NR_SL_PRECONFIGURATION(uint16_t num_tx_p
|
||||
return sl_preconfiguration;
|
||||
}
|
||||
|
||||
|
||||
int configure_NR_SL_Preconfig(int sync_source)
|
||||
int configure_NR_SL_Preconfig(uint8_t id,int sync_source)
|
||||
{
|
||||
|
||||
NR_SL_PreconfigurationNR_r16_t *sl_preconfig = NULL;
|
||||
@@ -424,9 +436,155 @@ int configure_NR_SL_Preconfig(int sync_source)
|
||||
}
|
||||
}
|
||||
|
||||
ASN_STRUCT_FREE(asn_DEF_NR_SL_PreconfigurationNR_r16, sl_preconfig);
|
||||
sl_preconfig = NULL;
|
||||
//END.......
|
||||
NR_UE_RRC_INST_t *rrc = &NR_UE_rrc_inst[id];
|
||||
rrc->sl_preconfig = sl_preconfig;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This functions configures SIdelink operation in the UE.
|
||||
* RRC configures MAC with sidelink parameters
|
||||
* In case UE is a sync source/Master UE - then sends transmit SLSS REQ
|
||||
*/
|
||||
void nr_UE_configure_Sidelink(uint8_t id, uint8_t is_sync_source) {
|
||||
|
||||
NR_UE_RRC_INST_t *rrc = &NR_UE_rrc_inst[id];
|
||||
|
||||
AssertFatal(rrc, "Check if rrc instance was created.");
|
||||
|
||||
NR_SL_PreconfigurationNR_r16_t *sl_preconfig = rrc->sl_preconfig;
|
||||
AssertFatal(sl_preconfig, "Check if SL-preconfig was created.");
|
||||
|
||||
uint8_t sync_source = SL_SYNC_SOURCE_NONE;
|
||||
|
||||
if (is_sync_source) {
|
||||
sync_source = (GNSS_SUPPORT) ? SL_SYNC_SOURCE_GNSS
|
||||
: SL_SYNC_SOURCE_LOCAL_TIMING;
|
||||
}
|
||||
|
||||
nr_rrc_mac_config_req_sl_preconfig(id, sl_preconfig, sync_source);
|
||||
|
||||
//TBD.. These should be chosen by RRC according to 3GPP 38.331 RRC specification.
|
||||
//Currently hardcoding the values to these
|
||||
uint16_t slss_id = 671, ssb_ta_index = 1;
|
||||
//12 bits -sl-TDD-config will be filled by MAC
|
||||
//Incoverage 1bit is FALSE
|
||||
//DFN, sfn will be filled by PHY
|
||||
uint8_t sl_mib_payload[4] = {0,0,0,0};
|
||||
|
||||
NR_SL_SSB_TimeAllocation_r16_t *ssb_ta = NULL;
|
||||
NR_SL_FreqConfigCommon_r16_t *fcfg = NULL;
|
||||
NR_SL_SyncConfig_r16_t *synccfg = NULL;
|
||||
if (rrc->sl_preconfig->sidelinkPreconfigNR_r16.sl_PreconfigFreqInfoList_r16)
|
||||
fcfg = rrc->sl_preconfig->sidelinkPreconfigNR_r16.sl_PreconfigFreqInfoList_r16->list.array[0];
|
||||
AssertFatal(fcfg, "Fcfg cannot be NULL\n");
|
||||
if (fcfg->sl_SyncConfigList_r16)
|
||||
synccfg = fcfg->sl_SyncConfigList_r16->list.array[0];
|
||||
AssertFatal(synccfg, "Synccfg cannot be NULL\n");
|
||||
|
||||
if (ssb_ta_index == 1)
|
||||
ssb_ta = synccfg->sl_SSB_TimeAllocation1_r16;
|
||||
else if (ssb_ta_index == 2)
|
||||
ssb_ta = synccfg->sl_SSB_TimeAllocation2_r16;
|
||||
else if (ssb_ta_index == 3)
|
||||
ssb_ta = synccfg->sl_SSB_TimeAllocation3_r16;
|
||||
else DevAssert(0);
|
||||
|
||||
AssertFatal(ssb_ta, "SSB_timeallocation cannot be NULL\n");
|
||||
|
||||
if (sync_source == SL_SYNC_SOURCE_LOCAL_TIMING || sync_source == SL_SYNC_SOURCE_GNSS)
|
||||
nr_rrc_mac_transmit_slss_req(id,sl_mib_payload, slss_id, ssb_ta);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*decode SL-BCH (SL-MIB) message*/
|
||||
static int8_t nr_sl_rrc_ue_decode_SL_MIB(const module_id_t module_id,
|
||||
const uint8_t gNB_index,
|
||||
uint8_t *const bufferP,
|
||||
const uint8_t buffer_len)
|
||||
{
|
||||
NR_MasterInformationBlockSidelink_t *sl_mib = NULL;
|
||||
|
||||
asn_dec_rval_t dec_rval = uper_decode_complete(NULL, &asn_DEF_NR_MasterInformationBlockSidelink,
|
||||
(void **)&sl_mib,
|
||||
(const void *)bufferP, buffer_len);
|
||||
|
||||
uint16_t val_fn = sl_mib->directFrameNumber_r16.buf[0];
|
||||
val_fn = (val_fn << 2) + (sl_mib->directFrameNumber_r16.buf[1] >> sl_mib->directFrameNumber_r16.bits_unused);
|
||||
|
||||
uint8_t val_slot = sl_mib->slotIndex_r16.buf[0];
|
||||
|
||||
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, "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)));
|
||||
|
||||
int ret = 1;
|
||||
if ((dec_rval.code != RC_OK) || (dec_rval.consumed == 0)) {
|
||||
LOG_E(NR_RRC, "SL-MIB decode error\n");
|
||||
ret = -1;
|
||||
} else {
|
||||
ret = 0;
|
||||
if (NR_UE_rrc_inst[module_id].sl_mib == NULL) {
|
||||
LOG_I(NR_RRC, "Sidelink RRC first MIB reception\n");
|
||||
} else {
|
||||
ASN_STRUCT_FREE(asn_DEF_NR_MasterInformationBlockSidelink, NR_UE_rrc_inst[module_id].sl_mib);
|
||||
}
|
||||
NR_UE_rrc_inst[module_id].sl_mib = sl_mib;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
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)
|
||||
{
|
||||
|
||||
nr_sl_rrc_ue_decode_SL_MIB(module_id, gNB_index, (uint8_t*)pduP, pdu_len);
|
||||
|
||||
DevAssert(NR_UE_rrc_inst[module_id].sl_preconfig);
|
||||
|
||||
NR_SL_FreqConfigCommon_r16_t *fcfg = NULL;
|
||||
if (NR_UE_rrc_inst[module_id].sl_preconfig->sidelinkPreconfigNR_r16.sl_PreconfigFreqInfoList_r16)
|
||||
fcfg = NR_UE_rrc_inst[module_id].sl_preconfig->sidelinkPreconfigNR_r16.sl_PreconfigFreqInfoList_r16->list.array[0];
|
||||
DevAssert(fcfg);
|
||||
|
||||
NR_SL_SSB_TimeAllocation_r16_t *sl_SSB_TimeAllocation = NULL;
|
||||
|
||||
//Current implementation only supports one SSB Timeallocation
|
||||
//Extend RRC to use multiple SSB Time allocations TBD....
|
||||
if (fcfg->sl_SyncConfigList_r16)
|
||||
sl_SSB_TimeAllocation = fcfg->sl_SyncConfigList_r16->list.array[0]->sl_SSB_TimeAllocation1_r16;
|
||||
DevAssert(sl_SSB_TimeAllocation);
|
||||
|
||||
nr_rrc_mac_config_req_sl_mib(module_id,
|
||||
sl_SSB_TimeAllocation,
|
||||
rx_slss_id,
|
||||
pduP);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
void free_sl_rrc(uint8_t id) {
|
||||
|
||||
NR_UE_RRC_INST_t *rrc = &NR_UE_rrc_inst[id];
|
||||
|
||||
if (rrc->sl_preconfig) {
|
||||
ASN_STRUCT_FREE(asn_DEF_NR_SL_PreconfigurationNR_r16, rrc->sl_preconfig);
|
||||
}
|
||||
if (rrc->sl_mib) {
|
||||
ASN_STRUCT_FREE(asn_DEF_NR_MasterInformationBlockSidelink, rrc->sl_mib);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user