From 26175c5413219f26d299d242ebdbd29796b23e4a Mon Sep 17 00:00:00 2001 From: Thomas Schlichter Date: Tue, 7 May 2024 19:49:35 +0200 Subject: [PATCH 1/7] NR UE: add NTN specific parameter cellSpecificKoffset_r17 and use it for UL scheduling According to the RRC specification, cellSpecificKoffset is: Scheduling offset used for the timing relationships that are modified for NTN (see TS 38.213 [13]). The unit of the field K_offset is number of slots for a given subcarrier spacing of 15 kHz. If the field is absent UE assumes value 0 This parameter `cellSpecificKoffset_r17` can be set via UE command line parameter `--ntn-koffset`. --- executables/nr-uesoftmodem.h | 5 +- openair2/LAYER2/NR_MAC_COMMON/nr_mac.h | 1 + openair2/LAYER2/NR_MAC_UE/config_ue.c | 18 +++++++ openair2/LAYER2/NR_MAC_UE/mac_proto.h | 5 +- openair2/LAYER2/NR_MAC_UE/main_ue_nr.c | 18 ++++++- openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c | 52 ++++++++++++++------ openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c | 10 ++-- 7 files changed, 84 insertions(+), 25 deletions(-) diff --git a/executables/nr-uesoftmodem.h b/executables/nr-uesoftmodem.h index 28de10154d..c95a6dc98c 100644 --- a/executables/nr-uesoftmodem.h +++ b/executables/nr-uesoftmodem.h @@ -12,6 +12,7 @@ #define CONFIG_HLP_DLSCH_PARA "number of threads for dlsch processing 0 for no parallelization\n" #define CONFIG_HLP_OFFSET_DIV "Divisor for computing OFDM symbol offset in Rx chain (num samples in CP/). Default value is 8. To set the sample offset to 0, set this value ~ 10e6\n" #define CONFIG_HLP_MAX_LDPC_ITERATIONS "Maximum LDPC decoder iterations\n" +#define CONFIG_HLP_NTN_KOFFSET "NTN cellSpecificKoffset-r17 (number of slots for a given subcarrier spacing of 15 kHz)\n" /***************************************************************************************************************************************/ /* command line options definitions, CMDLINE_XXXX_DESC macros are used to initialize paramdef_t arrays which are then used as argument @@ -63,7 +64,8 @@ {"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}, \ - {"num-ues", NULL, 0, .iptr=&(NB_UE_INST), .defuintval=1, TYPE_INT,0}, \ + {"num-ues", NULL, 0, .iptr=&(NB_UE_INST), .defuintval=1, TYPE_INT, 0}, \ + {"ntn-koffset", CONFIG_HLP_NTN_KOFFSET, 0, .uptr=&(nrUE_params.ntn_koffset), .defuintval=0, TYPE_UINT, 0}, \ } // clang-format on @@ -84,6 +86,7 @@ typedef struct { int N_RB_DL; int ssb_start_subcarrier; int ldpc_offload_flag; + unsigned int ntn_koffset; } nrUE_params_t; extern uint64_t get_nrUE_optmask(void); extern uint64_t set_nrUE_optmask(uint64_t bitmask); diff --git a/openair2/LAYER2/NR_MAC_COMMON/nr_mac.h b/openair2/LAYER2/NR_MAC_COMMON/nr_mac.h index 6973f06103..46ef4050e9 100644 --- a/openair2/LAYER2/NR_MAC_COMMON/nr_mac.h +++ b/openair2/LAYER2/NR_MAC_COMMON/nr_mac.h @@ -597,6 +597,7 @@ typedef struct { int n_ul_bwp; int dl_bw_tbslbrm; int ul_bw_tbslbrm; + NR_NTN_Config_r17_t *ntn_Config_r17; } NR_UE_ServingCell_Info_t; typedef enum { diff --git a/openair2/LAYER2/NR_MAC_UE/config_ue.c b/openair2/LAYER2/NR_MAC_UE/config_ue.c index d8b1ac158d..ccff0020c3 100644 --- a/openair2/LAYER2/NR_MAC_UE/config_ue.c +++ b/openair2/LAYER2/NR_MAC_UE/config_ue.c @@ -409,6 +409,13 @@ static void config_common_ue(NR_UE_MAC_INST_t *mac, // prach_fd_occasion->num_unused_root_sequences = ??? } } + + // NTN Config + if (scc->ext2) { + UPDATE_IE(mac->sc_info.ntn_Config_r17, scc->ext2->ntn_Config_r17, NR_NTN_Config_r17_t); + } else { + asn1cFreeStruc(asn_DEF_NR_NTN_Config_r17, mac->sc_info.ntn_Config_r17); + } } void release_common_ss_cset(NR_BWP_PDCCH_t *pdcch) @@ -1585,6 +1592,17 @@ void nr_rrc_mac_config_req_sib1(module_id_t module_id, mac->phy_config_request_sent = true; } +void nr_rrc_mac_config_req_sib19_r17(module_id_t module_id, + NR_SIB19_r17_t *sib19_r17) +{ + NR_UE_MAC_INST_t *mac = get_mac_inst(module_id); + + // ntn-Config-r17 + UPDATE_IE(mac->sc_info.ntn_Config_r17, sib19_r17->ntn_Config_r17, NR_NTN_Config_r17_t); + + // TODO handle other SIB19 elements +} + static void handle_reconfiguration_with_sync(NR_UE_MAC_INST_t *mac, int cc_idP, const NR_ReconfigurationWithSync_t *reconfigurationWithSync) diff --git a/openair2/LAYER2/NR_MAC_UE/mac_proto.h b/openair2/LAYER2/NR_MAC_UE/mac_proto.h index 6b849415f8..79a367de4c 100644 --- a/openair2/LAYER2/NR_MAC_UE/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_UE/mac_proto.h @@ -90,6 +90,9 @@ void nr_rrc_mac_config_req_sib1(module_id_t module_id, NR_SI_SchedulingInfo_t *si_SchedulingInfo, NR_ServingCellConfigCommonSIB_t *scc); +void nr_rrc_mac_config_req_sib19_r17(module_id_t module_id, + NR_SIB19_r17_t *sib19_r17); + void nr_rrc_mac_config_req_reset(module_id_t module_id, NR_UE_MAC_reset_cause_t cause); /**\brief initialization NR UE MAC instance(s)*/ @@ -196,7 +199,7 @@ void set_harq_status(NR_UE_MAC_INST_t *mac, uint8_t pucch_id, uint8_t harq_id, int8_t delta_pucch, - uint8_t data_toul_fb, + uint16_t data_toul_fb, uint8_t dai, int n_CCE, int N_CCE, diff --git a/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c b/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c index 4d8b79a2ab..2230d92729 100644 --- a/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c +++ b/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c @@ -35,7 +35,7 @@ #include "radio/COMMON/common_lib.h" //#undef MALLOC #include "assertions.h" -#include "executables/softmodem-common.h" +#include "executables/nr-uesoftmodem.h" #include "nr_rlc/nr_rlc_oai_api.h" #include "RRC/NR_UE/rrc_proto.h" #include @@ -84,6 +84,21 @@ void nr_ue_init_mac(NR_UE_MAC_INST_t *mac) memset(&mac->scheduling_info.sr_info[i], 0, sizeof(mac->scheduling_info.sr_info[i])); mac->pucch_power_control_initialized = false; + + // Fake SIB19 reception for NTN + // TODO: remove this and implement the actual SIB19 reception instead! + if (get_nrUE_params()->ntn_koffset) { + NR_SIB19_r17_t *sib19_r17 = calloc(1, sizeof(*sib19_r17)); + sib19_r17->ntn_Config_r17 = calloc(1, sizeof(*sib19_r17->ntn_Config_r17)); + + // NTN cellSpecificKoffset-r17 + if (get_nrUE_params()->ntn_koffset) { + asn1cCallocOne(sib19_r17->ntn_Config_r17->cellSpecificKoffset_r17, get_nrUE_params()->ntn_koffset); + } + + nr_rrc_mac_config_req_sib19_r17(mac->ue_id, sib19_r17); + asn1cFreeStruc(asn_DEF_NR_SIB19_r17, sib19_r17); + } } void nr_ue_mac_default_configs(NR_UE_MAC_INST_t *mac) @@ -246,6 +261,7 @@ void release_mac_configuration(NR_UE_MAC_INST_t *mac, asn1cFreeStruc(asn_DEF_NR_PUSCH_CodeBlockGroupTransmission, sc->pusch_CGB_Transmission); asn1cFreeStruc(asn_DEF_NR_CSI_MeasConfig, sc->csi_MeasConfig); asn1cFreeStruc(asn_DEF_NR_CSI_AperiodicTriggerStateList, sc->aperiodicTriggerStateList); + asn1cFreeStruc(asn_DEF_NR_NTN_Config_r17, sc->ntn_Config_r17); free(sc->xOverhead_PDSCH); free(sc->nrofHARQ_ProcessesForPDSCH); free(sc->rateMatching_PUSCH); diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c index 2954cf246b..af148e6bd5 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c @@ -148,6 +148,13 @@ static nr_dci_format_t nr_extract_dci_info(NR_UE_MAC_INST_t *mac, const uint8_t *dci_pdu, const int slot); +static int get_NTN_UE_Koffset(NR_NTN_Config_r17_t *ntn_Config_r17, int scs) +{ + if (ntn_Config_r17 && ntn_Config_r17->cellSpecificKoffset_r17) + return *ntn_Config_r17->cellSpecificKoffset_r17 << scs; + return 0; +} + int get_rnti_type(const NR_UE_MAC_INST_t *mac, const uint16_t rnti) { const RA_config_t *ra = &mac->ra; @@ -492,7 +499,8 @@ static int nr_ue_process_dci_ul_00(NR_UE_MAC_INST_t *mac, frame_t frame_tx; int slot_tx; - if (-1 == nr_ue_pusch_scheduler(mac, 0, frame, slot, &frame_tx, &slot_tx, tda_info.k2)) { + const int ntn_ue_koffset = get_NTN_UE_Koffset(mac->sc_info.ntn_Config_r17, mac->current_UL_BWP->scs); + if (-1 == nr_ue_pusch_scheduler(mac, 0, frame, slot, &frame_tx, &slot_tx, tda_info.k2 + ntn_ue_koffset)) { LOG_E(MAC, "Cannot schedule PUSCH\n"); return -1; } @@ -589,7 +597,8 @@ static int nr_ue_process_dci_ul_01(NR_UE_MAC_INST_t *mac, tda_info.k2 = csi_K2; } - if (-1 == nr_ue_pusch_scheduler(mac, 0, frame, slot, &frame_tx, &slot_tx, tda_info.k2)) { + const int ntn_ue_koffset = get_NTN_UE_Koffset(mac->sc_info.ntn_Config_r17, mac->current_UL_BWP->scs); + if (-1 == nr_ue_pusch_scheduler(mac, 0, frame, slot, &frame_tx, &slot_tx, tda_info.k2 + ntn_ue_koffset)) { LOG_E(MAC, "Cannot schedule PUSCH\n"); return -1; } @@ -903,10 +912,15 @@ static int nr_ue_process_dci_dl_10(NR_UE_MAC_INST_t *mac, return -1; } + /* PDSCH_TO_HARQ_FEEDBACK_TIME_IND */ + // according to TS 38.213 9.2.3 + const int ntn_ue_koffset = get_NTN_UE_Koffset(mac->sc_info.ntn_Config_r17, dlsch_pdu->SubcarrierSpacing); + const uint16_t feedback_ti = 1 + dci->pdsch_to_harq_feedback_timing_indicator.val + ntn_ue_koffset; + if (rnti_type != TYPE_RA_RNTI_ && rnti_type != TYPE_SI_RNTI_) { - AssertFatal(1 + dci->pdsch_to_harq_feedback_timing_indicator.val > DURATION_RX_TO_TX, + AssertFatal(feedback_ti > DURATION_RX_TO_TX, "PDSCH to HARQ feedback time (%d) needs to be higher than DURATION_RX_TO_TX (%d).\n", - 1 + dci->pdsch_to_harq_feedback_timing_indicator.val, + feedback_ti, DURATION_RX_TO_TX); // set the harq status at MAC for feedback const int tpc[] = {-1, 0, 1, 3}; @@ -914,7 +928,7 @@ static int nr_ue_process_dci_dl_10(NR_UE_MAC_INST_t *mac, dci->pucch_resource_indicator, dci->harq_pid, tpc[dci->tpc], - 1 + dci->pdsch_to_harq_feedback_timing_indicator.val, + feedback_ti, dci->dai[0].val, dci_ind->n_CCE, dci_ind->N_CCE, @@ -948,9 +962,9 @@ static int nr_ue_process_dci_dl_10(NR_UE_MAC_INST_t *mac, dlsch_pdu->scaling_factor_S, dci->tpc, dci->pucch_resource_indicator, - 1 + dci->pdsch_to_harq_feedback_timing_indicator.val); + feedback_ti); - dlsch_pdu->k1_feedback = 1 + dci->pdsch_to_harq_feedback_timing_indicator.val; + dlsch_pdu->k1_feedback = feedback_ti; LOG_D(MAC, "(nr_ue_procedures.c) pdu_type=%d\n\n", dl_conf_req->pdu_type); @@ -1239,7 +1253,8 @@ static int nr_ue_process_dci_dl_11(NR_UE_MAC_INST_t *mac, /* PDSCH_TO_HARQ_FEEDBACK_TIME_IND */ // according to TS 38.213 Table 9.2.3-1 - uint8_t feedback_ti = pucch_Config->dl_DataToUL_ACK->list.array[dci->pdsch_to_harq_feedback_timing_indicator.val][0]; + const int ntn_ue_koffset = get_NTN_UE_Koffset(mac->sc_info.ntn_Config_r17, dlsch_pdu->SubcarrierSpacing); + const uint16_t feedback_ti = pucch_Config->dl_DataToUL_ACK->list.array[dci->pdsch_to_harq_feedback_timing_indicator.val][0] + ntn_ue_koffset; AssertFatal(feedback_ti > DURATION_RX_TO_TX, "PDSCH to HARQ feedback time (%d) needs to be higher than DURATION_RX_TO_TX (%d). Min feedback time set in config " @@ -1436,7 +1451,7 @@ void set_harq_status(NR_UE_MAC_INST_t *mac, uint8_t pucch_id, uint8_t harq_id, int8_t delta_pucch, - uint8_t data_toul_fb, + uint16_t data_toul_fb, uint8_t dai, int n_CCE, int N_CCE, @@ -1457,7 +1472,7 @@ void set_harq_status(NR_UE_MAC_INST_t *mac, current_harq->ul_frame = frame; current_harq->ul_slot = slot + data_toul_fb; if (current_harq->ul_slot >= slots_per_frame) { - current_harq->ul_frame = (frame + 1) % 1024; + current_harq->ul_frame = (frame + current_harq->ul_slot / slots_per_frame) % MAX_FRAME_NUMBER; current_harq->ul_slot %= slots_per_frame; } // counter DAI in DCI ranges from 0 to 3 @@ -3544,9 +3559,13 @@ void nr_ue_process_mac_pdu(NR_UE_MAC_INST_t *mac, nr_downlink_indication_t *dl_i NR_UL_TIME_ALIGNMENT_t *ul_time_alignment = &mac->ul_time_alignment; ul_time_alignment->tag_id = tag; ul_time_alignment->ta_command = ta; - ul_time_alignment->frame = frameP; - ul_time_alignment->slot = slot; ul_time_alignment->ta_apply = adjustment_ta; + + const int ntn_ue_koffset = get_NTN_UE_Koffset(mac->sc_info.ntn_Config_r17, mac->current_UL_BWP->scs); + const int n_slots_frame = nr_slots_per_frame[mac->current_UL_BWP->scs]; + ul_time_alignment->frame = (frameP + (slot + ntn_ue_koffset) / n_slots_frame) % MAX_FRAME_NUMBER; + ul_time_alignment->slot = (slot + ntn_ue_koffset) % n_slots_frame; + /* #ifdef DEBUG_HEADER_PARSING LOG_D(MAC, "[UE] CE %d : UE Timing Advance : %d\n", i, pduP[1]); @@ -4023,9 +4042,12 @@ static void nr_ue_process_rar(NR_UE_MAC_INST_t *mac, nr_downlink_indication_t *d LOG_E(MAC, "Cannot schedule Msg3. Something wrong in TDA information\n"); return; } - ret = nr_ue_pusch_scheduler(mac, is_Msg3, frame, slot, &frame_tx, &slot_tx, tda_info.k2); - ul_time_alignment->frame = frame_tx; - ul_time_alignment->slot = slot_tx; + const int ntn_ue_koffset = get_NTN_UE_Koffset(mac->sc_info.ntn_Config_r17, mac->current_UL_BWP->scs); + ret = nr_ue_pusch_scheduler(mac, is_Msg3, frame, slot, &frame_tx, &slot_tx, tda_info.k2 + ntn_ue_koffset); + + const int n_slots_frame = nr_slots_per_frame[current_UL_BWP->scs]; + ul_time_alignment->frame = (frame_tx + (slot_tx + ntn_ue_koffset) / n_slots_frame) % MAX_FRAME_NUMBER; + ul_time_alignment->slot = (slot_tx + ntn_ue_koffset) % n_slots_frame; if (ret != -1) { uint16_t rnti = mac->crnti; diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c index b88ca7e5f3..a5c7982ddf 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c @@ -1112,7 +1112,7 @@ void nr_ue_aperiodic_srs_scheduling(NR_UE_MAC_INST_t *mac, long resource_trigger LOG_E(NR_MAC, "Slot for scheduling aperiodic SRS %d is not an UL slot\n", sched_slot); return; } - int sched_frame = frame + (slot + slot_offset >= n_slots_frame) % 1024; + int sched_frame = frame + (slot + slot_offset / n_slots_frame) % MAX_FRAME_NUMBER; fapi_nr_ul_config_request_pdu_t *pdu = lockGet_ul_config(mac, sched_frame, sched_slot, FAPI_NR_UL_CONFIG_TYPE_SRS); if (!pdu) return; @@ -1571,11 +1571,7 @@ int nr_ue_pusch_scheduler(const NR_UE_MAC_INST_t *mac, DURATION_RX_TO_TX); *slot_tx = (current_slot + k2 + delta) % nr_slots_per_frame[mu]; - if (current_slot + k2 + delta >= nr_slots_per_frame[mu]){ - *frame_tx = (current_frame + 1) % 1024; - } else { - *frame_tx = current_frame; - } + *frame_tx = (current_frame + (current_slot + k2 + delta) / nr_slots_per_frame[mu]) % MAX_FRAME_NUMBER; } else { @@ -1593,7 +1589,7 @@ int nr_ue_pusch_scheduler(const NR_UE_MAC_INST_t *mac, // Calculate TX slot and frame *slot_tx = (current_slot + k2) % nr_slots_per_frame[mu]; - *frame_tx = ((current_slot + k2) > (nr_slots_per_frame[mu]-1)) ? (current_frame + 1) % 1024 : current_frame; + *frame_tx = (current_frame + (current_slot + k2) / nr_slots_per_frame[mu]) % MAX_FRAME_NUMBER; } From 021f97cf10adffb15397b1d9ae05321d78ede337 Mon Sep 17 00:00:00 2001 From: Thomas Schlichter Date: Tue, 7 May 2024 19:53:54 +0200 Subject: [PATCH 2/7] NR UE: increase DURATION_RX_TO_TX by cellSpecificKoffset_r17 --- executables/nr-uesoftmodem.c | 6 ++++++ openair1/PHY/INIT/nr_parms.c | 6 +++--- openair1/PHY/defs_nr_common.h | 2 +- openair1/PHY/impl_defs_top.h | 21 ++++++++++++++++----- openair1/SIMULATION/NR_PHY/dlsim.c | 3 +++ openair1/SIMULATION/NR_PHY/ulsim.c | 3 +++ 6 files changed, 32 insertions(+), 9 deletions(-) diff --git a/executables/nr-uesoftmodem.c b/executables/nr-uesoftmodem.c index 262f0b1631..047ef6c557 100644 --- a/executables/nr-uesoftmodem.c +++ b/executables/nr-uesoftmodem.c @@ -159,6 +159,9 @@ int oaisim_flag = 0; int emulate_rf = 0; uint32_t N_RB_DL = 106; +// NTN cellSpecificKoffset-r17, but in slots for DL SCS +unsigned int NTN_UE_Koffset = 0; + /* see file openair2/LAYER2/MAC/main.c for why abstraction_flag is needed * this is very hackish - find a proper solution */ @@ -591,6 +594,9 @@ int main(int argc, char **argv) } } + // NTN cellSpecificKoffset-r17, but in slots for DL SCS + NTN_UE_Koffset = nrUE_params.ntn_koffset << PHY_vars_UE_g[0][0]->frame_parms.numerology_index; + init_openair0(); lock_memory_to_ram(); diff --git a/openair1/PHY/INIT/nr_parms.c b/openair1/PHY/INIT/nr_parms.c index 4fc91037b8..6a2c300b72 100644 --- a/openair1/PHY/INIT/nr_parms.c +++ b/openair1/PHY/INIT/nr_parms.c @@ -262,15 +262,15 @@ uint32_t get_slot_from_timestamp(openair0_timestamp timestamp_rx, const NR_DL_FR return slot_idx; } -uint32_t get_samples_slot_timestamp(int slot, const NR_DL_FRAME_PARMS *fp, uint8_t sl_ahead) +uint32_t get_samples_slot_timestamp(int slot, const NR_DL_FRAME_PARMS *fp, unsigned int sl_ahead) { uint32_t samp_count = 0; if(!sl_ahead) { - for(uint8_t idx_slot = 0; idx_slot < slot; idx_slot++) + for(unsigned int idx_slot = 0; idx_slot < slot; idx_slot++) samp_count += fp->get_samples_per_slot(idx_slot, fp); } else { - for(uint8_t idx_slot = slot; idx_slot < slot+sl_ahead; idx_slot++) + for(unsigned int idx_slot = slot; idx_slot < slot+sl_ahead; idx_slot++) samp_count += fp->get_samples_per_slot(idx_slot, fp); } return samp_count; diff --git a/openair1/PHY/defs_nr_common.h b/openair1/PHY/defs_nr_common.h index 3d0f2efa88..9c2dff22b8 100644 --- a/openair1/PHY/defs_nr_common.h +++ b/openair1/PHY/defs_nr_common.h @@ -135,7 +135,7 @@ typedef struct NR_DL_FRAME_PARMS NR_DL_FRAME_PARMS; typedef uint32_t (*get_samples_per_slot_t)(int slot, const NR_DL_FRAME_PARMS *fp); typedef uint32_t (*get_slot_from_timestamp_t)(openair0_timestamp timestamp_rx, const NR_DL_FRAME_PARMS *fp); -typedef uint32_t (*get_samples_slot_timestamp_t)(int slot, const NR_DL_FRAME_PARMS *fp, uint8_t sl_ahead); +typedef uint32_t (*get_samples_slot_timestamp_t)(int slot, const NR_DL_FRAME_PARMS *fp, unsigned int sl_ahead); struct NR_DL_FRAME_PARMS { /// frequency range diff --git a/openair1/PHY/impl_defs_top.h b/openair1/PHY/impl_defs_top.h index c06cd13ff7..618a7e6c58 100644 --- a/openair1/PHY/impl_defs_top.h +++ b/openair1/PHY/impl_defs_top.h @@ -268,13 +268,24 @@ #define TDD_CONFIG_NB_FRAMES (2) #define NR_MAX_SLOTS_PER_FRAME (160) /* number of slots per frame */ -/* FFS_NR_TODO it defines ue capability which is the number of slots */ -/* - between reception of pdsch and tarnsmission of its acknowlegment */ -/* - between reception of un uplink grant and its related transmission */ -// should be 2 as per NR standard, but current UE is not able to perform this value +/* FFS_NR_TODO it defines ue capability which is the number of slots */ +/* - between reception of pdsch and transmission of its acknowlegment (k1) */ +/* - between reception of un uplink grant and its related transmission (k2) */ #define NR_UE_CAPABILITY_SLOT_RX_TO_TX (3) -#define DURATION_RX_TO_TX (NR_UE_CAPABILITY_SLOT_RX_TO_TX) +/* When the OAI UE receives RX slot N, it starts sending TX slot N+DURATION_RX_TO_TX. + * Therefore DURATION_RX_TO_TX must not be larger than the minimum k1 and k2 values (NR_UE_CAPABILITY_SLOT_RX_TO_TX). + * In case of NTN, the propagation delay is so large, that the TX slot needs to be transmitted far in advance. + * Therefore, the NTN_UE_Koffset is added to DURATION_RX_TO_TX. + * + * Note: currently, the UE requires this to be a constant. + * But in case of NTN, Koffset is only known after receiving SIB19. + * Therefore, support should be added to allow changing DURATION_RX_TO_TX on reception of SIB19 (via FAPI-like interface). + * E.g. no transmission before successful reception of SIB19, and re-sync with disabled transmission if Koffset changes. + * When this has been implemented, the global variable NTN_UE_Koffset should be removed, too. + */ +extern unsigned int NTN_UE_Koffset; +#define DURATION_RX_TO_TX (NR_UE_CAPABILITY_SLOT_RX_TO_TX + NTN_UE_Koffset) #define NR_MAX_ULSCH_HARQ_PROCESSES (NR_MAX_HARQ_PROCESSES) /* cf 38.214 6.1 UE procedure for receiving the physical uplink shared channel */ #define NR_MAX_DLSCH_HARQ_PROCESSES (NR_MAX_HARQ_PROCESSES) /* cf 38.214 5.1 UE procedure for receiving the physical downlink shared channel */ diff --git a/openair1/SIMULATION/NR_PHY/dlsim.c b/openair1/SIMULATION/NR_PHY/dlsim.c index 728163e049..d6be222a9b 100644 --- a/openair1/SIMULATION/NR_PHY/dlsim.c +++ b/openair1/SIMULATION/NR_PHY/dlsim.c @@ -95,6 +95,9 @@ nfapi_ue_release_request_body_t release_rntis; instance_t DUuniqInstance=0; instance_t CUuniqInstance=0; +// NTN cellSpecificKoffset-r17, but in slots for DL SCS +unsigned int NTN_UE_Koffset = 0; + void nr_derive_key_ng_ran_star(uint16_t pci, uint64_t nr_arfcn_dl, const uint8_t key[32], uint8_t *key_ng_ran_star) { } diff --git a/openair1/SIMULATION/NR_PHY/ulsim.c b/openair1/SIMULATION/NR_PHY/ulsim.c index 822153fd14..e0cf501e96 100644 --- a/openair1/SIMULATION/NR_PHY/ulsim.c +++ b/openair1/SIMULATION/NR_PHY/ulsim.c @@ -93,6 +93,9 @@ nfapi_ue_release_request_body_t release_rntis; instance_t DUuniqInstance=0; instance_t CUuniqInstance=0; +// NTN cellSpecificKoffset-r17, but in slots for DL SCS +unsigned int NTN_UE_Koffset = 0; + void nr_derive_key_ng_ran_star(uint16_t pci, uint64_t nr_arfcn_dl, const uint8_t key[32], uint8_t *key_ng_ran_star) { } From 75efcf49b9d660b8146a4936ef69821a5665de66 Mon Sep 17 00:00:00 2001 From: Thomas Schlichter Date: Tue, 7 May 2024 19:59:03 +0200 Subject: [PATCH 3/7] NR UE: add NTN specific parameter ta-Common and use it for initial timing advance, RA_contention_resolution_timer and RA_window_cnt The value for this parameter can be set via UE command line parameter `--ntn-ta-common` in milliseconds. --- executables/nr-ue.c | 1 + executables/nr-uesoftmodem.h | 3 ++ openair1/SCHED_NR_UE/fapi_nr_ue_l1.c | 1 - openair2/LAYER2/NR_MAC_UE/main_ue_nr.c | 8 ++++- openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c | 32 +++++++++++++++----- 5 files changed, 35 insertions(+), 10 deletions(-) diff --git a/executables/nr-ue.c b/executables/nr-ue.c index 8a73bdd311..447c99182b 100644 --- a/executables/nr-ue.c +++ b/executables/nr-ue.c @@ -149,6 +149,7 @@ void init_nr_ue_vars(PHY_VARS_NR_UE *ue, ue->if_inst = nr_ue_if_module_init(UE_id); ue->dci_thres = 0; ue->target_Nid_cell = -1; + ue->timing_advance = ue->frame_parms.samples_per_subframe * get_nrUE_params()->ntn_ta_common; // initialize all signal buffers init_nr_ue_signal(ue, nb_connected_gNB); diff --git a/executables/nr-uesoftmodem.h b/executables/nr-uesoftmodem.h index c95a6dc98c..8e0650b4e4 100644 --- a/executables/nr-uesoftmodem.h +++ b/executables/nr-uesoftmodem.h @@ -13,6 +13,7 @@ #define CONFIG_HLP_OFFSET_DIV "Divisor for computing OFDM symbol offset in Rx chain (num samples in CP/). Default value is 8. To set the sample offset to 0, set this value ~ 10e6\n" #define CONFIG_HLP_MAX_LDPC_ITERATIONS "Maximum LDPC decoder iterations\n" #define CONFIG_HLP_NTN_KOFFSET "NTN cellSpecificKoffset-r17 (number of slots for a given subcarrier spacing of 15 kHz)\n" +#define CONFIG_HLP_NTN_TA_COMMON "NTN ta-Common, but given in ms\n" /***************************************************************************************************************************************/ /* command line options definitions, CMDLINE_XXXX_DESC macros are used to initialize paramdef_t arrays which are then used as argument @@ -66,6 +67,7 @@ {"SLC", CONFIG_HLP_SLF, 0, .u64ptr=&(sidelink_frequency[0][0]), .defuintval=2600000000,TYPE_UINT64,0}, \ {"num-ues", NULL, 0, .iptr=&(NB_UE_INST), .defuintval=1, TYPE_INT, 0}, \ {"ntn-koffset", CONFIG_HLP_NTN_KOFFSET, 0, .uptr=&(nrUE_params.ntn_koffset), .defuintval=0, TYPE_UINT, 0}, \ + {"ntn-ta-common", CONFIG_HLP_NTN_TA_COMMON, 0, .dblptr=&(nrUE_params.ntn_ta_common), .defdblval=0.0, TYPE_DOUBLE, 0}, \ } // clang-format on @@ -87,6 +89,7 @@ typedef struct { int ssb_start_subcarrier; int ldpc_offload_flag; unsigned int ntn_koffset; + double ntn_ta_common; } nrUE_params_t; extern uint64_t get_nrUE_optmask(void); extern uint64_t set_nrUE_optmask(uint64_t bitmask); diff --git a/openair1/SCHED_NR_UE/fapi_nr_ue_l1.c b/openair1/SCHED_NR_UE/fapi_nr_ue_l1.c index d01f1e3e94..b408b9fed3 100644 --- a/openair1/SCHED_NR_UE/fapi_nr_ue_l1.c +++ b/openair1/SCHED_NR_UE/fapi_nr_ue_l1.c @@ -373,7 +373,6 @@ static void configure_ta_command(PHY_VARS_NR_UE *ue, fapi_nr_ta_command_pdu *ta_ if (ta_command_pdu->is_rar) { ue->ta_slot = ta_command_pdu->ta_slot; ue->ta_frame = ta_command_pdu->ta_frame; - ue->timing_advance = 0; ue->ta_command = ta_command_pdu->ta_command + 31; // To use TA adjustment algo in ue_ta_procedures() } else { ue->ta_slot = (ta_command_pdu->ta_slot + ul_tx_timing_adjustment) % slots_per_frame; diff --git a/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c b/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c index 2230d92729..501c1022f1 100644 --- a/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c +++ b/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c @@ -87,7 +87,7 @@ void nr_ue_init_mac(NR_UE_MAC_INST_t *mac) // Fake SIB19 reception for NTN // TODO: remove this and implement the actual SIB19 reception instead! - if (get_nrUE_params()->ntn_koffset) { + if (get_nrUE_params()->ntn_koffset || get_nrUE_params()->ntn_ta_common) { NR_SIB19_r17_t *sib19_r17 = calloc(1, sizeof(*sib19_r17)); sib19_r17->ntn_Config_r17 = calloc(1, sizeof(*sib19_r17->ntn_Config_r17)); @@ -96,6 +96,12 @@ void nr_ue_init_mac(NR_UE_MAC_INST_t *mac) asn1cCallocOne(sib19_r17->ntn_Config_r17->cellSpecificKoffset_r17, get_nrUE_params()->ntn_koffset); } + // NTN ta-Common-r17 + if (get_nrUE_params()->ntn_ta_common) { + sib19_r17->ntn_Config_r17->ta_Info_r17 = calloc(1, sizeof(*sib19_r17->ntn_Config_r17->ta_Info_r17)); + sib19_r17->ntn_Config_r17->ta_Info_r17->ta_Common_r17 = get_nrUE_params()->ntn_ta_common / 4.072e-6; // ta-Common-r17 is in units of 4.072e-3 µs, ntn_ta_common is in ms + } + nr_rrc_mac_config_req_sib19_r17(mac->ue_id, sib19_r17); asn1cFreeStruc(asn_DEF_NR_SIB19_r17, sib19_r17); } diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c index ebf3ee2703..11ce2c5c30 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c @@ -41,6 +41,13 @@ #include #include "openair2/LAYER2/RLC/rlc.h" +static double get_ta_Common_ms(NR_NTN_Config_r17_t *ntn_Config_r17) +{ + if (ntn_Config_r17 && ntn_Config_r17->ta_Info_r17) + return ntn_Config_r17->ta_Info_r17->ta_Common_r17 * 4.072e-6; // ta_Common_r17 is in units of 4.072e-3 µs + return 0.0; +} + int16_t get_prach_tx_power(NR_UE_MAC_INST_t *mac) { RA_config_t *ra = &mac->ra; @@ -580,13 +587,17 @@ void nr_Msg3_transmitted(NR_UE_MAC_INST_t *mac, uint8_t CC_id, frame_t frameP, s { RA_config_t *ra = &mac->ra; NR_RACH_ConfigCommon_t *nr_rach_ConfigCommon = mac->current_UL_BWP->rach_ConfigCommon; - long mu = mac->current_UL_BWP->scs; - int subframes_per_slot = nr_slots_per_frame[mu] / 10; + const double ta_Common_ms = get_ta_Common_ms(mac->sc_info.ntn_Config_r17); + const int mu = mac->current_UL_BWP->scs; + const int slots_per_ms = nr_slots_per_frame[mu] / 10; // start contention resolution timer - int RA_contention_resolution_timer_subframes = (nr_rach_ConfigCommon->ra_ContentionResolutionTimer + 1) << 3; - // timer step 1 slot and timer target given by ra_ContentionResolutionTimer - nr_timer_setup(&ra->contention_resolution_timer, RA_contention_resolution_timer_subframes * subframes_per_slot, 1); + const int RA_contention_resolution_timer_ms = (nr_rach_ConfigCommon->ra_ContentionResolutionTimer + 1) << 3; + const int RA_contention_resolution_timer_slots = RA_contention_resolution_timer_ms * slots_per_ms; + const int ta_Common_slots = (int)ceil(ta_Common_ms * slots_per_ms); + + // timer step 1 slot and timer target given by ra_ContentionResolutionTimer + ta-Common-r17 + nr_timer_setup(&ra->contention_resolution_timer, RA_contention_resolution_timer_slots + ta_Common_slots, 1); nr_timer_start(&ra->contention_resolution_timer); ra->ra_state = nrRA_WAIT_CONTENTION_RESOLUTION; @@ -788,11 +799,16 @@ void nr_get_RA_window(NR_UE_MAC_INST_t *mac) NR_RACH_ConfigCommon_t *setup = mac->current_UL_BWP->rach_ConfigCommon; AssertFatal(&setup->rach_ConfigGeneric != NULL, "In %s: FATAL! rach_ConfigGeneric is NULL...\n", __FUNCTION__); NR_RACH_ConfigGeneric_t *rach_ConfigGeneric = &setup->rach_ConfigGeneric; + const double ta_Common_ms = get_ta_Common_ms(mac->sc_info.ntn_Config_r17); + const int mu = mac->current_DL_BWP->scs; + const int slots_per_ms = nr_slots_per_frame[mu] / 10; - int ra_ResponseWindow = rach_ConfigGeneric->ra_ResponseWindow; - int mu = mac->current_DL_BWP->scs; + const int ra_Offset_slots = ra->RA_offset * nr_slots_per_frame[mu]; + const int ta_Common_slots = (int)ceil(ta_Common_ms * slots_per_ms); - ra->RA_window_cnt = ra->RA_offset * nr_slots_per_frame[mu]; // taking into account the 2 frames gap introduced by OAI gNB + ra->RA_window_cnt = ra_Offset_slots + ta_Common_slots; // taking into account the 2 frames gap introduced by OAI gNB + + int ra_ResponseWindow = rach_ConfigGeneric->ra_ResponseWindow; switch (ra_ResponseWindow) { case NR_RACH_ConfigGeneric__ra_ResponseWindow_sl1: From 1e473112597cf4f87cfb76256ac4c1306ba1be26 Mon Sep 17 00:00:00 2001 From: Thomas Schlichter Date: Mon, 27 May 2024 16:53:01 +0200 Subject: [PATCH 4/7] NR UE: use sr_ProhibitTimer_v1700 if present --- openair2/LAYER2/NR_MAC_UE/config_ue.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/openair2/LAYER2/NR_MAC_UE/config_ue.c b/openair2/LAYER2/NR_MAC_UE/config_ue.c index ccff0020c3..f723ab2378 100644 --- a/openair2/LAYER2/NR_MAC_UE/config_ue.c +++ b/openair2/LAYER2/NR_MAC_UE/config_ue.c @@ -1820,6 +1820,17 @@ static void configure_maccellgroup(NR_UE_MAC_INST_t *mac, const NR_MAC_CellGroup int target_ms = 0; if (sr->sr_ProhibitTimer) target_ms = 1 << *sr->sr_ProhibitTimer; + if (mcg->ext4 && mcg->ext4->schedulingRequestConfig_v1700) { + const NR_SchedulingRequestConfig_v1700_t *src_v1700 = mcg->ext4->schedulingRequestConfig_v1700; + if (src_v1700->schedulingRequestToAddModListExt_v1700) { + if (i < src_v1700->schedulingRequestToAddModListExt_v1700->list.count) { + const NR_SchedulingRequestToAddModExt_v1700_t *sr_v1700 = src_v1700->schedulingRequestToAddModListExt_v1700->list.array[i]; + if (sr_v1700->sr_ProhibitTimer_v1700) { + target_ms = 192 + 64 * *sr_v1700->sr_ProhibitTimer_v1700; + } + } + } + } // length of slot is (1/2^scs)ms nr_timer_setup(&sr_info->prohibitTimer, target_ms << scs, 1); // 1 slot update rate } From 4ddb2d3bac97973a8f289e9e5ba70b16ae12cda3 Mon Sep 17 00:00:00 2001 From: Thomas Schlichter Date: Tue, 7 May 2024 20:35:22 +0200 Subject: [PATCH 5/7] add section with NR UE NTN example to doc/RUNMODEM.md --- doc/RUNMODEM.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/doc/RUNMODEM.md b/doc/RUNMODEM.md index 753efdadaf..9ee9083e6d 100644 --- a/doc/RUNMODEM.md +++ b/doc/RUNMODEM.md @@ -188,6 +188,18 @@ cd cmake_targets sudo ./ran_build/build/nr-softmodem -O ../targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band66.fr1.25PRB.usrpx300.conf --sa --rfsim --rfsimulator.prop_delay 238.74 ``` +### NR UE + +At UE side, there are two main parameters to cope with the large NTN propagation delay, cellSpecificKoffset and ta-Common. +`cellSpecificKoffset` is the same as for gNB and can be provided to the UE via command line parameter `--ntn-koffset`. +`ta-Common` is a common timong advance and can be provided to the UE via command line parameter `--ntn-ta-common` in milliseconds. + +So an example NR UE command for FDD, 5MHz BW, 15 kHz SCS, GEO satellite 5G NR NTN is this: +``` +cd cmake_targets +sudo ./ran_build/build/nr-uesoftmodem --band 66 -C 2152680000 --CO -400000000 -r 25 --numerology 0 --ssb 48 --sa --rfsim --rfsimulator.prop_delay 238.74 --ntn-koffset 478 --ntn-ta-common 477.48 +``` + # Specific OAI modes ## phy-test setup with OAI UE From 9dc0dc5ffe756815fa4a8e0842cc061c8d1bb0ed Mon Sep 17 00:00:00 2001 From: Thomas Schlichter Date: Thu, 11 Jul 2024 14:43:13 +0200 Subject: [PATCH 6/7] NR UE: improve PSS detection by reducing the detection step size from 8 to 4 Until commit d74b2bd19fc7a34741822fdbcc537cd2c2b0d4ae, the PSS detection step size was 4, anyways. The PSS detection step size is a compromise between detection duration and accuracy. The most accurate detection step size would be 1, but this would lead to even longer initial sync time. --- openair1/PHY/NR_UE_TRANSPORT/pss_nr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair1/PHY/NR_UE_TRANSPORT/pss_nr.c b/openair1/PHY/NR_UE_TRANSPORT/pss_nr.c index 6d9aaf7f9a..54d9022e87 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/pss_nr.c +++ b/openair1/PHY/NR_UE_TRANSPORT/pss_nr.c @@ -560,7 +560,7 @@ static int pss_search_time_nr(const c16_t **rxdata, } for (int pss_index = pss_index_start; pss_index < pss_index_end; pss_index++) { - for (n = 0; n < length; n += 8) { // + for (n = 0; n < length; n += 4) { // int64_t pss_corr_ue=0; /* calculate dot product of primary_synchro_time_nr and rxdata[ar][n] From 359880fa73ade9c2636d4fa917576f5815bf80d6 Mon Sep 17 00:00:00 2001 From: Thomas Schlichter Date: Thu, 11 Jul 2024 14:48:52 +0200 Subject: [PATCH 7/7] rfsimulator: use ceil() to calculate the integer number of chan_offset samples from the prop_delay_ms The actual propagation delay should not be smaller than the one specified. A too short propagation delay might result in too early reception of Msg1, and with that in a mis-detection of the RAPID. --- radio/rfsimulator/simulator.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/radio/rfsimulator/simulator.c b/radio/rfsimulator/simulator.c index e524097898..0a2ece7d21 100644 --- a/radio/rfsimulator/simulator.c +++ b/radio/rfsimulator/simulator.c @@ -983,7 +983,7 @@ int device_init(openair0_device *device, openair0_config_t *openair0_cfg) { rfsimulator->tx_bw=openair0_cfg->tx_bw; rfsimulator_readconfig(rfsimulator); if (rfsimulator->prop_delay_ms > 0.0) - rfsimulator->chan_offset = rfsimulator->sample_rate * rfsimulator->prop_delay_ms / 1000; + rfsimulator->chan_offset = ceil(rfsimulator->sample_rate * rfsimulator->prop_delay_ms / 1000); if (rfsimulator->chan_offset != 0) { if (CirSize < minCirSize + rfsimulator->chan_offset) { CirSize = minCirSize + rfsimulator->chan_offset;