Merge remote-tracking branch 'origin/NR_NTN_ulsyncduration' into integration_2025_w25 (!3367)

Enabling usage of ulsyncvalidityDuration timer in SIB19

ntn-UlSyncValidityDuration in SIB19 from Spec 38.331 v17.12 A validity
duration configured by the network for assistance information which
indicates the maximum time duration (from epochTime) during which the UE
can apply assistance information without having acquired new assistance
information. The unit of ntn-UlSyncValidityDuration is second. Value s5
corresponds to 5 s, value s10 indicate 10 s and so on.

    ntn-UlSyncValidityDuration-r17 ENUMERATED{ s5, s10, s15, s20, s25, s30, s35,s40, s45, s50, s55, s60, s120, s180, s240, s900}

Implementation of epochtime is under discussion.

It can be configured in configuration file according to the above
enumeration. For GEO - 240s, MEO - 20s, LEO-5s can be used.
This commit is contained in:
Robert Schmidt
2025-06-19 08:25:28 +02:00
14 changed files with 318 additions and 35 deletions
@@ -149,6 +149,8 @@ gNBs =
#ext2
#ntn_Config_r17
# This can be of values {s5, s10, s15, s20, s25, s30, s35, s40, s45, s50, s55, s60, s120, s180, s240, s900}
ntn-UlSyncValidityDuration-r17 = 240;
cellSpecificKoffset_r17 = 478;
ta-Common-r17 = 58629666; # 238.74 ms
positionX-r17 = 0;
+3
View File
@@ -231,6 +231,9 @@ Or by providing this the the command line parameters:
The main parameters to cope with the large NTN propagation delay are cellSpecificKoffset, ta-Common, ta-CommonDrift and the ephemeris data (satellite position and velocity vectors).
The parameter `ntn-UlSyncValidityDuration-r17` indicates the maximum time duration from epochtime during which the UE can apply assistance information without having acquired new assistance information. i.e this enables UE to re-read SIB19 before timer with value ulSyncValidityDuration expires. The unit of the field is in seconds. Example values for GEO: 240s, MEO: 20s, LEO: 5s.
As epochtime is not implemented yet, UE starts the timer from the TTI where SIB19 is received with ntn-UlSyncValidityDuration-r17 IE.
The parameter `cellSpecificKoffset_r17` is the scheduling offset used for the timing relationships that are modified for NTN (see TS 38.213).
The unit of the field Koffset is number of slots for a given subcarrier spacing of 15 kHz.
+2
View File
@@ -124,6 +124,7 @@
#define GNB_CONFIG_STRING_NROFUPLINKSYMBOLS2 "nrofUplinkSymbols2"
#define GNB_CONFIG_STRING_SSPBCHBLOCKPOWER "ssPBCH_BlockPower"
#define GNB_CONFIG_STRING_ULSYNCVALIDITYDURATION "ntn-UlSyncValidityDuration-r17"
#define GNB_CONFIG_STRING_CELLSPECIFICKOFFSET "cellSpecificKoffset_r17"
#define GNB_CONFIG_STRING_EPHEMERIS_POSITION_X "positionX-r17"
#define GNB_CONFIG_STRING_EPHEMERIS_POSITION_Y "positionY-r17"
@@ -250,6 +251,7 @@
{GNB_CONFIG_STRING_NROFUPLINKSLOTS,NULL,0,.i64ptr=&scc->tdd_UL_DL_ConfigurationCommon->pattern1.nrofUplinkSlots,.defint64val=2,TYPE_INT64,0},\
{GNB_CONFIG_STRING_NROFUPLINKSYMBOLS,NULL,0,.i64ptr=&scc->tdd_UL_DL_ConfigurationCommon->pattern1.nrofUplinkSymbols,.defint64val=4,TYPE_INT64,0},\
{GNB_CONFIG_STRING_SSPBCHBLOCKPOWER,NULL,0,.i64ptr=&scc->ss_PBCH_BlockPower,.defint64val=20,TYPE_INT64,0}, \
{GNB_CONFIG_STRING_ULSYNCVALIDITYDURATION,NULL,0,.i64ptr=scc->ext2->ntn_Config_r17->ntn_UlSyncValidityDuration_r17,.defint64val=0,TYPE_INT64,0}, \
{GNB_CONFIG_STRING_CELLSPECIFICKOFFSET,NULL,0,.i64ptr=scc->ext2->ntn_Config_r17->cellSpecificKoffset_r17,.defint64val=0,TYPE_INT64,0}, \
{GNB_CONFIG_STRING_EPHEMERIS_POSITION_X,NULL,0,.i64ptr=&scc->ext2->ntn_Config_r17->ephemerisInfo_r17->choice.positionVelocity_r17->positionX_r17,.defint64val=LONG_MAX,TYPE_INT64,0}, \
{GNB_CONFIG_STRING_EPHEMERIS_POSITION_Y,NULL,0,.i64ptr=&scc->ext2->ntn_Config_r17->ephemerisInfo_r17->choice.positionVelocity_r17->positionY_r17,.defint64val=LONG_MAX,TYPE_INT64,0}, \
+46 -2
View File
@@ -216,6 +216,7 @@ void prepare_scc(NR_ServingCellConfigCommon_t *scc)
scc->ext2 = calloc_or_fail(1, sizeof(*scc->ext2));
scc->ext2->ntn_Config_r17 = calloc_or_fail(1, sizeof(*scc->ext2->ntn_Config_r17));
scc->ext2->ntn_Config_r17->ntn_UlSyncValidityDuration_r17 = calloc_or_fail(1, sizeof(long));
scc->ext2->ntn_Config_r17->cellSpecificKoffset_r17 = calloc_or_fail(1, sizeof(*scc->ext2->ntn_Config_r17->cellSpecificKoffset_r17));
scc->ext2->ntn_Config_r17->ephemerisInfo_r17 = calloc_or_fail(1, sizeof(*scc->ext2->ntn_Config_r17->ephemerisInfo_r17));
@@ -465,6 +466,40 @@ static void fix_tdd_pattern(NR_ServingCellConfigCommon_t *scc)
}
}
static int get_ulsyncvalidityduration_enum_value(int val)
{
int retval = -1;
switch (val) {
case 5:
case 10:
case 15:
case 20:
case 25:
case 30:
case 35:
case 40:
case 45:
case 50:
case 55:
retval = val / 5 - 1;
break;
case 60:
case 120:
case 180:
case 240:
retval = 10 + val / 60;
break;
case 900:
retval = 15;
break;
default:
AssertFatal(1 == 0, "ulsyncvalidityDuration in SIB19 set to invalid value in Conf file\n");
break;
}
return retval;
}
void fix_scc(NR_ServingCellConfigCommon_t *scc, uint64_t ssbmap)
{
scc->ssb_PositionsInBurst->present = get_ssb_len(scc);
@@ -572,6 +607,13 @@ void fix_scc(NR_ServingCellConfigCommon_t *scc, uint64_t ssbmap)
AssertFatal(*scc->uplinkConfigCommon->initialUplinkBWP->pucch_ConfigCommon->choice.setup->pucch_ResourceCommon < 2,
"pucch_ResourceConfig should be 0 or 1 for now\n");
if (*scc->ext2->ntn_Config_r17->ntn_UlSyncValidityDuration_r17 == 0) {
free(scc->ext2->ntn_Config_r17->ntn_UlSyncValidityDuration_r17);
scc->ext2->ntn_Config_r17->ntn_UlSyncValidityDuration_r17 = NULL;
} else {
int val = get_ulsyncvalidityduration_enum_value(*scc->ext2->ntn_Config_r17->ntn_UlSyncValidityDuration_r17);
*scc->ext2->ntn_Config_r17->ntn_UlSyncValidityDuration_r17 = val;
}
if (*scc->ext2->ntn_Config_r17->cellSpecificKoffset_r17 == 0) {
free(scc->ext2->ntn_Config_r17->cellSpecificKoffset_r17);
scc->ext2->ntn_Config_r17->cellSpecificKoffset_r17 = NULL;
@@ -596,8 +638,10 @@ void fix_scc(NR_ServingCellConfigCommon_t *scc, uint64_t ssbmap)
scc->ext2->ntn_Config_r17->ephemerisInfo_r17 = NULL;
}
if (!scc->ext2->ntn_Config_r17->cellSpecificKoffset_r17 && !scc->ext2->ntn_Config_r17->ta_Info_r17
&& !scc->ext2->ntn_Config_r17->ephemerisInfo_r17) {
if (!scc->ext2->ntn_Config_r17->ntn_UlSyncValidityDuration_r17 &&
!scc->ext2->ntn_Config_r17->cellSpecificKoffset_r17 &&
!scc->ext2->ntn_Config_r17->ta_Info_r17 &&
!scc->ext2->ntn_Config_r17->ephemerisInfo_r17) {
free(scc->ext2->ntn_Config_r17);
free(scc->ext2);
scc->ext2 = NULL;
+5
View File
@@ -1748,6 +1748,11 @@ void nr_rrc_mac_config_req_reset(module_id_t module_id, NR_UE_MAC_reset_cause_t
release_mac_configuration(mac, cause);
nr_ue_mac_default_configs(mac);
break;
case UL_SYNC_LOST_T430_EXPIRED:
// TS 38.331 Section 5.2.2.6, TS 38.321 Section 5.2a
// Flush all HARQ buffers and Stop UL transmissions
handle_ulsync_loss(mac);
break;
default:
AssertFatal(false, "Invalid MAC reset cause %d\n", cause);
}
+1
View File
@@ -198,6 +198,7 @@ typedef enum {
T300_EXPIRY,
RE_ESTABLISHMENT,
RRC_SETUP_REESTAB_RESUME,
UL_SYNC_LOST_T430_EXPIRED,
} NR_UE_MAC_reset_cause_t;
typedef struct {
+6 -2
View File
@@ -67,13 +67,16 @@ void release_common_ss_cset(NR_BWP_PDCCH_t *pdcch);
\param gNB_index gNB index
\param sibs_mask sibs mask
\param pduP pointer to pdu
\param pdu_length length of pdu */
\param pdu_length length of pdu
\param frame,slot Received TTI*/
void nr_ue_decode_BCCH_DL_SCH(NR_UE_MAC_INST_t *mac,
int cc_id,
unsigned int gNB_index,
uint8_t ack_nack,
uint8_t *pduP,
uint32_t pdu_len);
uint32_t pdu_len,
int frame,
int slot);
void release_dl_BWP(NR_UE_MAC_INST_t *mac, int index);
void release_ul_BWP(NR_UE_MAC_INST_t *mac, int index);
@@ -320,6 +323,7 @@ void nr_Msg3_transmitted(NR_UE_MAC_INST_t *mac, uint8_t CC_id, frame_t frameP, s
void trigger_MAC_UE_RA(NR_UE_MAC_INST_t *mac, dci_pdu_rel15_t *pdcch_order);
void nr_get_Msg3_MsgA_PUSCH_payload(NR_UE_MAC_INST_t *mac, uint8_t *buf, int TBS_max);
void handle_time_alignment_timer_expired(NR_UE_MAC_INST_t *mac);
void handle_ulsync_loss(NR_UE_MAC_INST_t *mac);
int8_t nr_ue_process_dci_freq_dom_resource_assignment(nfapi_nr_ue_pusch_pdu_t *pusch_config_pdu,
fapi_nr_dl_config_dlsch_pdu_rel15_t *dlsch_config_pdu,
NR_PDSCH_Config_t *pdsch_Config,
+5 -3
View File
@@ -305,11 +305,13 @@ void nr_ue_decode_BCCH_DL_SCH(NR_UE_MAC_INST_t *mac,
unsigned int gNB_index,
uint8_t ack_nack,
uint8_t *pduP,
uint32_t pdu_len)
uint32_t pdu_len,
int frame,
int slot)
{
if(ack_nack) {
LOG_D(NR_MAC, "Decoding NR-BCCH-DL-SCH-Message (SIB1 or SI)\n");
nr_mac_rrc_data_ind_ue(mac->ue_id, cc_id, gNB_index, 0, 0, 0, mac->physCellId, 0, NR_BCCH_DL_SCH, (uint8_t *) pduP, pdu_len);
nr_mac_rrc_data_ind_ue(mac->ue_id, cc_id, gNB_index, frame, slot, 0, mac->physCellId, 0, NR_BCCH_DL_SCH, (uint8_t *) pduP, pdu_len);
if (mac->get_sib1)
mac->get_sib1 = false;
for (int i = 0; i < MAX_SI_GROUPS; i++) {
@@ -325,7 +327,7 @@ void nr_ue_decode_BCCH_DL_SCH(NR_UE_MAC_INST_t *mac,
}
else {
LOG_E(NR_MAC, "Got NACK on NR-BCCH-DL-SCH-Message (%s)\n", mac->get_sib1 ? "SIB1" : "other SI");
nr_mac_rrc_data_ind_ue(mac->ue_id, cc_id, gNB_index, 0, 0, 0, mac->physCellId, 0, NR_BCCH_DL_SCH, NULL, 0);
nr_mac_rrc_data_ind_ue(mac->ue_id, cc_id, gNB_index, frame, slot, 0, mac->physCellId, 0, NR_BCCH_DL_SCH, NULL, 0);
}
}
@@ -182,6 +182,27 @@ void handle_time_alignment_timer_expired(NR_UE_MAC_INST_t *mac)
// TODO not sure what to do here
}
void handle_ulsync_loss(NR_UE_MAC_INST_t *mac)
{
// flush all HARQ buffers for all Serving Cells
for (int k = 0; k < NR_MAX_HARQ_PROCESSES; k++) {
memset(&mac->dl_harq_info[k], 0, sizeof(*mac->dl_harq_info));
memset(&mac->ul_harq_info[k], 0, sizeof(*mac->ul_harq_info));
mac->dl_harq_info[k].last_ndi = -1; // initialize to invalid value
mac->ul_harq_info[k].last_ndi = -1; // initialize to invalid value
}
// clear any configured downlink assignments and uplink grants;
if (mac->dl_config_request)
memset(mac->dl_config_request, 0, sizeof(*mac->dl_config_request));
if (mac->ul_config_request)
clear_ul_config_request(mac);
// Need to receive SIB19 again after loosing UL SYNC
mac->state = UE_RECEIVING_SIB;
// gNB needs to send PDCCH ORDER triggering RA after detecting ULSYNC LOSS
LOG_W(NR_MAC, "Wait for PDCCH ORDER, RACH needs to performed to obtain ULSYNC.\n");
}
void update_mac_dl_timers(NR_UE_MAC_INST_t *mac)
{
bool ra_window_expired = nr_timer_tick(&mac->ra.response_window_timer);
+9 -4
View File
@@ -1113,9 +1113,11 @@ static int handle_bcch_dlsch(NR_UE_MAC_INST_t *mac,
unsigned int gNB_index,
uint8_t ack_nack,
uint8_t *pduP,
uint32_t pdu_len)
uint32_t pdu_len,
int frame,
int slot)
{
nr_ue_decode_BCCH_DL_SCH(mac, cc_id, gNB_index, ack_nack, pduP, pdu_len);
nr_ue_decode_BCCH_DL_SCH(mac, cc_id, gNB_index, ack_nack, pduP, pdu_len, frame, slot);
return 0;
}
@@ -1297,10 +1299,13 @@ static uint32_t nr_ue_dl_processing(NR_UE_MAC_INST_t *mac, nr_downlink_indicatio
break;
case FAPI_NR_RX_PDU_TYPE_SIB:
ret_mask |= (handle_bcch_dlsch(mac,
dl_info->cc_id, dl_info->gNB_index,
dl_info->cc_id,
dl_info->gNB_index,
rx_indication_body.pdsch_pdu.ack_nack,
rx_indication_body.pdsch_pdu.pdu,
rx_indication_body.pdsch_pdu.pdu_length)) << FAPI_NR_RX_PDU_TYPE_SIB;
rx_indication_body.pdsch_pdu.pdu_length,
dl_info->frame,
dl_info->slot)) << FAPI_NR_RX_PDU_TYPE_SIB;
break;
case FAPI_NR_RX_PDU_TYPE_DLSCH:
ret_mask |= (handle_dlsch(mac, dl_info, i)) << FAPI_NR_RX_PDU_TYPE_DLSCH;
+199 -23
View File
@@ -144,7 +144,8 @@ static void process_lte_nsa_msg(NR_UE_RRC_INST_t *rrc, nsa_msg_t *msg, int msg_l
static void nr_rrc_ue_process_ueCapabilityEnquiry(NR_UE_RRC_INST_t *rrc, NR_UECapabilityEnquiry_t *UECapabilityEnquiry);
static void nr_rrc_ue_process_masterCellGroup(NR_UE_RRC_INST_t *rrc,
OCTET_STRING_t *masterCellGroup,
long *fullConfig);
long *fullConfig,
int gNB_index);
static void nr_rrc_ue_process_measConfig(rrcPerNB_t *rrc, NR_MeasConfig_t *const measConfig, NR_UE_Timers_Constants_t *timers);
@@ -165,7 +166,120 @@ static void set_DRB_status(NR_UE_RRC_INST_t *rrc, NR_DRB_Identity_t drb_id, NR_R
rrc->status_DRBs[drb_id - 1] = status;
}
static void nr_decode_SI(NR_UE_RRC_SI_INFO *SI_info, NR_SystemInformation_t *si, NR_UE_RRC_INST_t *rrc)
static int get_ulsyncvalidityduration_timer_value(NR_NTN_Config_r17_t *ntncfg)
{
int retval = 0;
AssertFatal(ntncfg, "NTN-Config IE not present\n");
if (ntncfg->ntn_UlSyncValidityDuration_r17) {
const int values[] = {5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 120, 180, 240, 900};
retval = values[*ntncfg->ntn_UlSyncValidityDuration_r17];
}
return retval;
}
static void get_epochtime_from_sib19scheduling(NR_UE_RRC_SI_INFO *SI_info, int *frame, int *subframe)
{
// TS 38.331 section 5.2.2.3.2
// SI-window starts at the slot #a, where a = x mod N
// x = (si-WindowPosition -1) × w, where w is the si-WindowLength;
// N is the number of slots in a radio frame
int wl_slots = 5 << SI_info->si_windowlength;
int x = (SI_info->sib19_windowposition - 1) * wl_slots;
int slots_per_subframe = 1 << SI_info->scs;
int N = slots_per_subframe * 10;
int slot_end_sib19_window = (x % N) + wl_slots;
*frame += (slot_end_sib19_window / N);
int slot = slot_end_sib19_window % N;
*subframe = ceil(slot / slots_per_subframe);
LOG_D(NR_RRC,
"Get EPOCHTIME: x:%d, N:%d, slot_endw:%d, frame:%d, subframe:%d , slot:%d\n",
x,
N,
slot_end_sib19_window,
*frame,
*subframe,
slot);
}
static int eval_epoch_time(NR_UE_RRC_SI_INFO *SI_info, NR_NTN_Config_r17_t *ntncfg, int frame)
{
int epoch_frame = 0, epoch_subframe = 0;
int diff_frames = 0;
AssertFatal(frame >= 0, "Frame Incorrect, results in incorrect EPOCH time evaluation\n");
if (ntncfg->epochTime_r17) {
epoch_frame = ntncfg->epochTime_r17->sfn_r17;
epoch_subframe = ntncfg->epochTime_r17->subFrameNR_r17;
} else {
// EPOCH time is optional in case of SIB19. This case happens only in case of SIB19 NTN config
// If no EPOCH time is sent, epochtime points to SIB19 window end slot in the current scheduling window
epoch_frame = frame;
epoch_subframe = 0;
get_epochtime_from_sib19scheduling(SI_info, &epoch_frame, &epoch_subframe);
// Adding epochTime IE in SIB19, later MAC will use it.
ntncfg->epochTime_r17 = CALLOC(1, sizeof(NR_EpochTime_r17_t));
ntncfg->epochTime_r17->sfn_r17 = epoch_frame;
ntncfg->epochTime_r17->subFrameNR_r17 = epoch_subframe;
}
// For serving cell, the field sfn indicates the current SFN or the next upcoming SFN
// after the frame where the message indicating the epochTime is received
// i.e. Epochframe can be present or future SFN
diff_frames = (epoch_frame - frame + 1024) % 1024; // According to 38.331 Epochtime is defined for serving cell like this
LOG_D(NR_RRC, "Epoch frame %d, ahead by %d frames\n", epoch_frame, diff_frames);
return diff_frames;
}
static int get_ntn_timervalues(NR_UE_RRC_SI_INFO *SI_info, NR_NTN_Config_r17_t *ntncfg, int diff_frames, int *val430_ms)
{
int val430 = get_ulsyncvalidityduration_timer_value(ntncfg);
int sib19_periodicity_ms = (SI_info->sib19_periodicity + 1) * 10;
*val430_ms = val430 * 1000 + diff_frames * 10; // in ms
if (*val430_ms <= sib19_periodicity_ms)
LOG_E(NR_RRC, "Too small T430 value. Might result in frequent ULSYNC failure\n");
// Depending on ulsyncvalidity duration, SIB19 timer expires 15secs/2secs before T430
// LArger values might be used for GEO and epoch time interval can be around 10 secs
// Lower values will be used for NGSO (LEO/MEO), epoch time interval can be between 2-3 secs.
// TODO remove the hardoded values and define a better strategy to determine the time of expiry
// with real GEO/LEO/MEO SATs.
int expire_before_ms = ((val430 >= 120) ? 10000 : 2000);
int diff = *val430_ms - expire_before_ms;
int sib19_timer_ms = (diff > 0) ? diff : ((*val430_ms - sib19_periodicity_ms) > 0) ? (*val430_ms - sib19_periodicity_ms) : 0;
LOG_D(NR_RRC, "val430:%d s, T430:%d ms, sib19_timer:%d ms\n", val430, *val430_ms, sib19_timer_ms);
return sib19_timer_ms;
}
static void nr_rrc_process_ntnconfig(NR_UE_RRC_INST_t *rrc, NR_UE_RRC_SI_INFO *SI_info, NR_NTN_Config_r17_t *ntncfg, int frame)
{
SI_info->SInfo_r17.sib19_validity = true;
// Check if Epochtime is sent or not
int diff_frames = eval_epoch_time(SI_info, ntncfg, frame);
if (ntncfg->ntn_UlSyncValidityDuration_r17) { // ulsyncvalidity duration configured
int val430_ms = 0, sib19_timer_ms = 0;
sib19_timer_ms = get_ntn_timervalues(SI_info, ntncfg, diff_frames, &val430_ms);
// T430 should be started only in connected mode.
// Inorder to avoid starting T430 when entering connected mode, T430 is started as soon as
// SIB19 is received, and if UE enters connected mode T430 will be in running.
// T430 expiry in RRC idle or inactive states does nothing.
nr_timer_setup(&rrc->timers_and_constants.T430, val430_ms, 10);
nr_timer_start(&rrc->timers_and_constants.T430);
// SIB19 should be received before T430 expires
// SIB19 validity timer should expire before T430 expiry such that new SIB19 is read
if (sib19_timer_ms > 0) {
nr_timer_setup(&SI_info->SInfo_r17.sib19_timer, sib19_timer_ms, 10);
nr_timer_start(&SI_info->SInfo_r17.sib19_timer);
} else
// This makes sure that SIB19 is read again in the next window
SI_info->SInfo_r17.sib19_validity = false;
} else
nr_timer_start(&SI_info->SInfo_r17.sib19_timer);
}
static void nr_decode_SI(NR_UE_RRC_SI_INFO *SI_info, NR_SystemInformation_t *si, NR_UE_RRC_INST_t *rrc, int frame)
{
instance_t ue_id = rrc->ue_id;
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RRC_UE_DECODE_SI, VCD_FUNCTION_IN);
@@ -240,11 +354,10 @@ static void nr_decode_SI(NR_UE_RRC_SI_INFO *SI_info, NR_SystemInformation_t *si,
nr_timer_start(&SI_info->sib14_timer);
break;
case NR_SystemInformation_IEs__sib_TypeAndInfo__Member_PR_sib19_v1700:
SI_info->SInfo_r17.sib19_validity = true;
if (g_log->log_component[NR_RRC].level >= OAILOG_DEBUG)
xer_fprint(stdout, &asn_DEF_NR_SIB19_r17, (const void *)typeandinfo->choice.sib19_v1700);
sib19 = typeandinfo->choice.sib19_v1700;
nr_timer_start(&SI_info->SInfo_r17.sib19_timer);
if (g_log->log_component[NR_RRC].level >= OAILOG_DEBUG)
xer_fprint(stdout, &asn_DEF_NR_SIB19_r17, (const void *)sib19);
nr_rrc_process_ntnconfig(rrc, SI_info, sib19->ntn_Config_r17, frame);
break;
default:
break;
@@ -335,6 +448,27 @@ static bool verify_NTN_access(const NR_UE_RRC_SI_INFO *SI_info, const NR_SIB1_v1
return ntn_access && sib19_present;
}
static void get_sib19_schedinfo(NR_UE_RRC_SI_INFO *SI_info, NR_SI_SchedulingInfo_v1700_t *si_SchedInfo_v1700)
{
// Find the SIB19 periodicity configured in the scheduling info
if (si_SchedInfo_v1700) {
int count_v17 = si_SchedInfo_v1700->schedulingInfoList2_r17.list.count;
for (int i = 0; i < count_v17; i++) {
struct NR_SchedulingInfo2_r17 *schedulingInfo2 = si_SchedInfo_v1700->schedulingInfoList2_r17.list.array[i];
for (int j = 0; j < schedulingInfo2->sib_MappingInfo_r17.list.count; j++) {
struct NR_SIB_TypeInfo_v1700 *sib_TypeInfo_v1700 = schedulingInfo2->sib_MappingInfo_r17.list.array[j];
if (sib_TypeInfo_v1700->sibType_r17.present == NR_SIB_TypeInfo_v1700__sibType_r17_PR_type1_r17) {
if (sib_TypeInfo_v1700->sibType_r17.choice.type1_r17 == NR_SIB_TypeInfo_v1700__sibType_r17__type1_r17_sibType19) {
SI_info->sib19_periodicity = 8 << schedulingInfo2->si_Periodicity_r17;
SI_info->sib19_windowposition = schedulingInfo2->si_WindowPosition_r17;
return;
}
}
}
}
}
}
static void nr_rrc_process_sib1(NR_UE_RRC_INST_t *rrc, NR_UE_RRC_SI_INFO *SI_info, NR_SIB1_t *sib1)
{
if(g_log->log_component[NR_RRC].level >= OAILOG_DEBUG)
@@ -355,9 +489,14 @@ static void nr_rrc_process_sib1(NR_UE_RRC_INST_t *rrc, NR_UE_RRC_SI_INFO *SI_inf
si_SchedInfo_v1700 = sib1_v1700->si_SchedulingInfo_v1700;
}
AssertFatal(sib1->servingCellConfigCommon, "configuration issue in SIB1\n");
SI_info->scs = sib1->servingCellConfigCommon->downlinkConfigCommon.initialDownlinkBWP.genericParameters.subcarrierSpacing;
SI_info->si_windowlength = (sib1->si_SchedulingInfo) ? sib1->si_SchedulingInfo->si_WindowLength : 0;
// configure default SI
nr_rrc_configure_default_SI(SI_info, sib1->si_SchedulingInfo, si_SchedInfo_v1700);
rrc->is_NTN_UE = verify_NTN_access(SI_info, sib1_v1700);
if (rrc->is_NTN_UE)
get_sib19_schedinfo(SI_info, si_SchedInfo_v1700);
// configure timers and constant
nr_rrc_set_sib1_timers_and_constants(&rrc->timers_and_constants, sib1);
@@ -376,7 +515,7 @@ static void nr_rrc_process_reconfiguration_v1530(NR_UE_RRC_INST_t *rrc, NR_RRCRe
LOG_E(NR_RRC, "RRCReconfiguration includes fullConfig but this is not implemented yet\n");
}
if (rec_1530->masterCellGroup)
nr_rrc_ue_process_masterCellGroup(rrc, rec_1530->masterCellGroup, rec_1530->fullConfig);
nr_rrc_ue_process_masterCellGroup(rrc, rec_1530->masterCellGroup, rec_1530->fullConfig, gNB_index);
if (rec_1530->masterKeyUpdate) {
// TODO perform AS security key update procedure as specified in 5.3.5.7
LOG_E(NR_RRC, "RRCReconfiguration includes masterKeyUpdate but this is not implemented yet\n");
@@ -426,7 +565,7 @@ static void nr_rrc_process_reconfiguration_v1530(NR_UE_RRC_INST_t *rrc, NR_RRCRe
SEQUENCE_free(&asn_DEF_NR_SystemInformation, si, 1);
} else {
LOG_I(NR_RRC, "[UE %ld] Decoding dedicatedSystemInformationDelivery\n", rrc->ue_id);
nr_decode_SI(SI_info, si, rrc);
nr_decode_SI(SI_info, si, rrc, rrc->current_frame);
}
}
if (rec_1530->otherConfig) {
@@ -502,7 +641,7 @@ static void nr_rrc_ue_process_rrcReconfiguration(NR_UE_RRC_INST_t *rrc, int gNB_
if (LOG_DEBUGFLAG(DEBUG_ASN1))
xer_fprint(stdout, &asn_DEF_NR_CellGroupConfig, (const void *) cellGroupConfig);
nr_rrc_cellgroup_configuration(rrc, cellGroupConfig);
nr_rrc_cellgroup_configuration(rrc, cellGroupConfig, gNB_index);
AssertFatal(!IS_SA_MODE(get_softmodem_params()), "secondaryCellGroup only used in NSA for now\n");
MessageDef *msg = itti_alloc_new_message(TASK_RRC_NRUE, 0, NR_MAC_RRC_CONFIG_CG);
@@ -928,7 +1067,9 @@ static void nr_rrc_ue_decode_NR_BCCH_DL_SCH_Message(NR_UE_RRC_INST_t *rrc,
uint8_t *const Sdu,
const uint8_t Sdu_len,
const uint8_t rsrq,
const uint8_t rsrp)
const uint8_t rsrp,
int frame,
int slot)
{
NR_UE_RRC_SI_INFO *SI_info = &rrc->perNB[gNB_index].SInfo;
SI_info->sib_pending = false;
@@ -964,9 +1105,9 @@ static void nr_rrc_ue_decode_NR_BCCH_DL_SCH_Message(NR_UE_RRC_INST_t *rrc,
bcch_message->message.choice.c1->choice.systemInformationBlockType1 = NULL;
break;
case NR_BCCH_DL_SCH_MessageType__c1_PR_systemInformation:
LOG_I(NR_RRC, "[UE %ld] Decoding SI\n", rrc->ue_id);
LOG_I(NR_RRC, "[UE %ld] %d:%d Decoding SI\n", rrc->ue_id, frame, slot);
NR_SystemInformation_t *si = bcch_message->message.choice.c1->choice.systemInformation;
nr_decode_SI(SI_info, si, rrc);
nr_decode_SI(SI_info, si, rrc, frame);
break;
case NR_BCCH_DL_SCH_MessageType__c1_PR_NOTHING:
default:
@@ -1023,7 +1164,9 @@ static void nr_rrc_manage_rlc_bearers(NR_UE_RRC_INST_t *rrc,
}
}
static void nr_rrc_process_reconfigurationWithSync(NR_UE_RRC_INST_t *rrc, NR_ReconfigurationWithSync_t *reconfigurationWithSync)
static void nr_rrc_process_reconfigurationWithSync(NR_UE_RRC_INST_t *rrc,
NR_ReconfigurationWithSync_t *reconfigurationWithSync,
int gNB_index)
{
// perform Reconfiguration with sync according to 5.3.5.5.2
if (!rrc->as_security_activated && !(get_softmodem_params()->phy_test || get_softmodem_params()->do_ra)) {
@@ -1055,15 +1198,26 @@ static void nr_rrc_process_reconfigurationWithSync(NR_UE_RRC_INST_t *rrc, NR_Rec
}
rrc->rnti = reconfigurationWithSync->newUE_Identity;
// reset the MAC entity of this cell group (done at MAC in handle_reconfiguration_with_sync)
// 3GPP TS38.331 section 5.3.5.5.2
nr_timer_stop(&tac->T430);
if (reconfigurationWithSync->spCellConfigCommon &&
reconfigurationWithSync->spCellConfigCommon->ext2 &&
reconfigurationWithSync->spCellConfigCommon->ext2->ntn_Config_r17) {
NR_NTN_Config_r17_t *ntncfg = reconfigurationWithSync->spCellConfigCommon->ext2->ntn_Config_r17;
// EPOCH time is always sent if NTN config is sent through DCCH
AssertFatal(ntncfg->epochTime_r17, "NTN-CONFIG sent in dedicated mode should have EPOCHTIME\n");
nr_rrc_process_ntnconfig(rrc, &rrc->perNB[gNB_index].SInfo, ntncfg, rrc->current_frame);
}
}
void nr_rrc_cellgroup_configuration(NR_UE_RRC_INST_t *rrc, NR_CellGroupConfig_t *cellGroupConfig)
void nr_rrc_cellgroup_configuration(NR_UE_RRC_INST_t *rrc, NR_CellGroupConfig_t *cellGroupConfig, int gNB_index)
{
NR_SpCellConfig_t *spCellConfig = cellGroupConfig->spCellConfig;
if(spCellConfig) {
if (spCellConfig->reconfigurationWithSync) {
LOG_I(NR_RRC, "Processing reconfigurationWithSync\n");
nr_rrc_process_reconfigurationWithSync(rrc, spCellConfig->reconfigurationWithSync);
nr_rrc_process_reconfigurationWithSync(rrc, spCellConfig->reconfigurationWithSync, gNB_index);
}
nr_rrc_handle_SetupRelease_RLF_TimersAndConstants(rrc, spCellConfig->rlf_TimersAndConstants);
if (spCellConfig->spCellConfigDedicated) {
@@ -1083,10 +1237,10 @@ void nr_rrc_cellgroup_configuration(NR_UE_RRC_INST_t *rrc, NR_CellGroupConfig_t
AssertFatal(cellGroupConfig->sCellToAddModList == NULL, "Secondary serving cell addition not implemented\n");
}
static void nr_rrc_ue_process_masterCellGroup(NR_UE_RRC_INST_t *rrc,
OCTET_STRING_t *masterCellGroup,
long *fullConfig)
long *fullConfig,
int gNB_index)
{
AssertFatal(!fullConfig, "fullConfig not supported yet\n");
NR_CellGroupConfig_t *cellGroupConfig = NULL;
@@ -1100,7 +1254,7 @@ static void nr_rrc_ue_process_masterCellGroup(NR_UE_RRC_INST_t *rrc,
xer_fprint(stdout, &asn_DEF_NR_CellGroupConfig, (const void *) cellGroupConfig);
}
nr_rrc_cellgroup_configuration(rrc, cellGroupConfig);
nr_rrc_cellgroup_configuration(rrc, cellGroupConfig, gNB_index);
LOG_D(RRC, "Sending CellGroupConfig to MAC the pointer will be managed by mac\n");
MessageDef *msg = itti_alloc_new_message(TASK_RRC_NRUE, 0, NR_MAC_RRC_CONFIG_CG);
@@ -1207,9 +1361,7 @@ static void nr_rrc_process_rrcsetup(NR_UE_RRC_INST_t *rrc, const NR_RRCSetup_t *
nr_rrc_rrcsetup_fallback(rrc);
// perform the cell group configuration procedure in accordance with the received masterCellGroup
nr_rrc_ue_process_masterCellGroup(rrc,
&rrcSetup->criticalExtensions.choice.rrcSetup->masterCellGroup,
NULL);
nr_rrc_ue_process_masterCellGroup(rrc, &rrcSetup->criticalExtensions.choice.rrcSetup->masterCellGroup, NULL, 0);
// perform the radio bearer configuration procedure in accordance with the received radioBearerConfig
nr_rrc_ue_process_RadioBearerConfig(rrc,
&rrcSetup->criticalExtensions.choice.rrcSetup->radioBearerConfig);
@@ -2069,7 +2221,8 @@ void *rrc_nrue(void *notUsed)
} break;
case NRRRC_FRAME_PROCESS:
LOG_D(NR_RRC, "Received %s: frame %d\n", ITTI_MSG_NAME(msg_p), NRRRC_FRAME_PROCESS(msg_p).frame);
rrc->current_frame = NRRRC_FRAME_PROCESS(msg_p).frame;
LOG_D(NR_RRC, "Received %s: frame %d\n", ITTI_MSG_NAME(msg_p), rrc->current_frame);
// increase the timers every 10ms (every new frame)
nr_rrc_handle_timers(rrc);
NR_UE_RRC_SI_INFO *SInfo = &rrc->perNB[NRRRC_FRAME_PROCESS(msg_p).gnb_id].SInfo;
@@ -2113,7 +2266,14 @@ void *rrc_nrue(void *notUsed)
if (bcch->is_bch)
nr_rrc_ue_decode_NR_BCCH_BCH_Message(rrc, bcch->gnb_index, bcch->phycellid, bcch->ssb_arfcn, bcch->sdu, bcch->sdu_size);
else
nr_rrc_ue_decode_NR_BCCH_DL_SCH_Message(rrc, bcch->gnb_index, bcch->sdu, bcch->sdu_size, bcch->rsrq, bcch->rsrp);
nr_rrc_ue_decode_NR_BCCH_DL_SCH_Message(rrc,
bcch->gnb_index,
bcch->sdu,
bcch->sdu_size,
bcch->rsrq,
bcch->rsrp,
bcch->frame,
bcch->slot);
break;
case NR_RRC_MAC_SBCCH_DATA_IND:
@@ -2714,6 +2874,22 @@ void handle_t300_expiry(NR_UE_RRC_INST_t *rrc)
// TODO inform upper layers about the failure to establish the RRC connection
}
void handle_t430_expiry(NR_UE_RRC_INST_t *rrc)
{
// SPEC 38.331 section 5.2.2.6
// Reacquire SIB19 after T430 expiry
for (int i = 0; i < NB_CNX_UE; i++) {
rrcPerNB_t *nb = &rrc->perNB[i];
NR_UE_RRC_SI_INFO *SI_info = &nb->SInfo;
SI_info->SInfo_r17.sib19_validity = false;
}
// Indicate MAC that UL SYNC is LOST
NR_UE_MAC_reset_cause_t cause = UL_SYNC_LOST_T430_EXPIRED;
MessageDef *msg = itti_alloc_new_message(TASK_RRC_NRUE, 0, NR_MAC_RRC_CONFIG_RESET);
NR_MAC_RRC_CONFIG_RESET(msg).cause = cause;
itti_send_msg_to_task(TASK_MAC_UE, rrc->ue_id, msg);
}
//This calls the sidelink preconf message after RRC, MAC instances are created.
void start_sidelink(int instance)
{
+9
View File
@@ -152,6 +152,11 @@ typedef struct UE_RRC_SI_INFO_NR_s {
bool sib14_validity;
NR_timer_t sib14_timer;
NR_UE_RRC_SI_INFO_r17 SInfo_r17;
// Extracted from SIB1
int scs;
int sib19_periodicity;
int sib19_windowposition;
int si_windowlength;
} NR_UE_RRC_SI_INFO;
typedef struct NR_UE_Timers_Constants_s {
@@ -168,6 +173,8 @@ typedef struct NR_UE_Timers_Constants_s {
NR_timer_t T325;
NR_timer_t T380;
NR_timer_t T390;
// NTN timer T430 which guards UL SYNC
NR_timer_t T430;
// counters
uint32_t N310_cnt;
uint32_t N311_cnt;
@@ -234,6 +241,8 @@ typedef struct NR_UE_RRC_INST_s {
bool reconfig_after_reestab;
// 5G-S-TMSI
uint64_t fiveG_S_TMSI;
// Frame timing received from MAC
int current_frame;
//Sidelink params
NR_SL_PreconfigurationNR_r16_t *sl_preconfig;
+2 -1
View File
@@ -47,7 +47,7 @@ void init_nsa_message (NR_UE_RRC_INST_t *rrc, char* reconfig_file, char* rbconfi
void process_nsa_message(NR_UE_RRC_INST_t *rrc, nsa_message_t nsa_message_type, void *message, int msg_len);
void nr_rrc_cellgroup_configuration(NR_UE_RRC_INST_t *rrc, NR_CellGroupConfig_t *cellGroupConfig);
void nr_rrc_cellgroup_configuration(NR_UE_RRC_INST_t *rrc, NR_CellGroupConfig_t *cellGroupConfig, int gNB_index);
void nr_rrc_going_to_IDLE(NR_UE_RRC_INST_t *rrc,
NR_Release_Cause_t release_cause,
@@ -80,6 +80,7 @@ void init_SI_timers(NR_UE_RRC_SI_INFO *SInfo);
void nr_ue_rrc_timer_trigger(int module_id, int frame, int gnb_id);
void handle_t300_expiry(NR_UE_RRC_INST_t *rrc);
void handle_t430_expiry(NR_UE_RRC_INST_t *rrc);
void reset_rlf_timers_and_constants(NR_UE_Timers_Constants_t *tac);
void set_default_timers_and_constants(NR_UE_Timers_Constants_t *tac);
@@ -169,6 +169,14 @@ void nr_rrc_handle_timers(NR_UE_RRC_INST_t *rrc)
// with release cause 'RRC connection failure'
nr_rrc_going_to_IDLE(rrc, RRC_CONNECTION_FAILURE, NULL);
}
bool t430_expired = nr_timer_tick(&rrc->timers_and_constants.T430);
if (t430_expired && rrc->nrRrcState == RRC_STATE_CONNECTED_NR && rrc->is_NTN_UE) {
LOG_W(NR_RRC, "Timer T430 expired! Indicate UL SYNC LOSS to MAC\n");
// Upon T430 expiry, the UE shall reacquire SIB19 and re-obtain UL-SYNC
// Spec 38.331 Section 5.2.2.6
handle_t430_expiry(rrc);
}
}
int nr_rrc_get_T304(long t304)