Add MeasGap Configuration in Radio config
Add some helper functions that will be used by the MAC handler to fill the right MeasGap configuration based on Measurement Configuration sent by the CU, in the next commit.
This commit is contained in:
@@ -4090,3 +4090,198 @@ NR_ReconfigurationWithSync_t *get_reconfiguration_with_sync(rnti_t rnti, uid_t u
|
||||
|
||||
return reconfigurationWithSync;
|
||||
}
|
||||
|
||||
static NR_MeasGapConfig_t *get_gap_config_from_smtc(const NR_SSB_MTC_t *ssb_mtc)
|
||||
{
|
||||
NR_MeasGapConfig_t *measGapConfig = calloc_or_fail(1, sizeof(*measGapConfig));
|
||||
measGapConfig->ext1 = calloc_or_fail(1, sizeof(*measGapConfig->ext1));
|
||||
measGapConfig->ext1->gapUE = calloc_or_fail(1, sizeof(*measGapConfig->ext1->gapUE));
|
||||
measGapConfig->ext1->gapUE->present = NR_SetupRelease_GapConfig_PR_setup;
|
||||
NR_GapConfig_t *gap_config = calloc_or_fail(1, sizeof(*gap_config));
|
||||
measGapConfig->ext1->gapUE->choice.setup = gap_config;
|
||||
|
||||
// mgta = Measurement Gap Timing Advance, to provide sufficient time for the UE to re-tune its transceiver
|
||||
// This allows the Measurement Gap to extend mgta ms either side of the SS/PBCH Measurement Window.
|
||||
gap_config->mgta = NR_GapConfig__mgta_ms0dot5;
|
||||
|
||||
// mgrp = Measurement Gap Repetition Period
|
||||
// gapOffset = It defines the start of the Measurement Gaps relative to the start of the radio frame with SFN = 0
|
||||
// The Measurement Gaps need to be synchronized with the SS/PBCH transmissions which are to be measured
|
||||
gap_config->mgrp = NR_GapConfig__mgrp_ms160;
|
||||
switch (ssb_mtc->periodicityAndOffset.present) {
|
||||
case NR_SSB_MTC__periodicityAndOffset_PR_sf20:
|
||||
gap_config->gapOffset = ssb_mtc->periodicityAndOffset.choice.sf20;
|
||||
break;
|
||||
case NR_SSB_MTC__periodicityAndOffset_PR_sf40:
|
||||
gap_config->gapOffset = ssb_mtc->periodicityAndOffset.choice.sf40;
|
||||
break;
|
||||
case NR_SSB_MTC__periodicityAndOffset_PR_sf80:
|
||||
gap_config->gapOffset = ssb_mtc->periodicityAndOffset.choice.sf80;
|
||||
break;
|
||||
case NR_SSB_MTC__periodicityAndOffset_PR_sf160:
|
||||
gap_config->gapOffset = ssb_mtc->periodicityAndOffset.choice.sf160;
|
||||
break;
|
||||
default:
|
||||
LOG_W(NR_RRC, "SMTC periodicity higher than MGRP\n");
|
||||
// With this configuration, not all SSBs belong to the Measurement Gap.
|
||||
if (ssb_mtc->periodicityAndOffset.present == NR_SSB_MTC__periodicityAndOffset_PR_sf5) {
|
||||
gap_config->gapOffset = ssb_mtc->periodicityAndOffset.choice.sf5;
|
||||
} else if (ssb_mtc->periodicityAndOffset.present == NR_SSB_MTC__periodicityAndOffset_PR_sf10) {
|
||||
gap_config->gapOffset = ssb_mtc->periodicityAndOffset.choice.sf10;
|
||||
}
|
||||
}
|
||||
|
||||
// mgl = Measurement Gap Length
|
||||
// FIXME: At least the duration of the SMTC plus 2 times the mgta should be enough,
|
||||
// however, at the moment it only works by setting the maximum value
|
||||
gap_config->mgl = NR_GapConfig__mgl_ms6;
|
||||
|
||||
return measGapConfig;
|
||||
}
|
||||
|
||||
NR_MeasurementTimingConfiguration_t *get_nr_mtc(uint8_t *buf, uint32_t len)
|
||||
{
|
||||
if (buf == NULL || len == 0)
|
||||
return NULL;
|
||||
|
||||
NR_MeasurementTimingConfiguration_t *mtc = NULL;
|
||||
asn_dec_rval_t dec_rval = uper_decode(NULL, &asn_DEF_NR_MeasurementTimingConfiguration, (void **)&mtc, buf, len, 0, 0);
|
||||
if (dec_rval.code != RC_OK) {
|
||||
LOG_E(NR_MAC, "cannot decode NR MeasurementTimingConfiguration, ignoring\n");
|
||||
ASN_STRUCT_FREE(asn_DEF_NR_MeasurementTimingConfiguration, mtc);
|
||||
return NULL;
|
||||
}
|
||||
return mtc;
|
||||
}
|
||||
|
||||
/** @brief return Measurement Gap Repetition Period from ASN.1 config */
|
||||
static int get_mgrp(long mgrp)
|
||||
{
|
||||
switch (mgrp) {
|
||||
case NR_GapConfig__mgrp_ms20:
|
||||
return 20;
|
||||
case NR_GapConfig__mgrp_ms40:
|
||||
return 40;
|
||||
case NR_GapConfig__mgrp_ms80:
|
||||
return 80;
|
||||
case NR_GapConfig__mgrp_ms160:
|
||||
return 160;
|
||||
default:
|
||||
LOG_E(NR_MAC, "Invalid MGRP %ld\n", mgrp);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/** @brief Return Measurement Gap Length from ASN.1 config */
|
||||
static float get_mgl(long mgl)
|
||||
{
|
||||
switch (mgl) {
|
||||
case NR_GapConfig__mgl_ms1dot5:
|
||||
return 1.5;
|
||||
case NR_GapConfig__mgl_ms3:
|
||||
return 3.0;
|
||||
case NR_GapConfig__mgl_ms3dot5:
|
||||
return 3.5;
|
||||
case NR_GapConfig__mgl_ms4:
|
||||
return 4;
|
||||
case NR_GapConfig__mgl_ms5dot5:
|
||||
return 5.5;
|
||||
case NR_GapConfig__mgl_ms6:
|
||||
return 6;
|
||||
default:
|
||||
LOG_E(NR_MAC, "Invalid MGL %ld\n", mgl);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/** @brief Return Measurement Gap Timing Advance, from ASN.1 config */
|
||||
static float get_mgta(long mgta)
|
||||
{
|
||||
switch (mgta) {
|
||||
case NR_GapConfig__mgta_ms0:
|
||||
return 0.0;
|
||||
case NR_GapConfig__mgta_ms0dot25:
|
||||
return 0.25;
|
||||
case NR_GapConfig__mgta_ms0dot5:
|
||||
return 0.5;
|
||||
default:
|
||||
LOG_E(NR_MAC, "Invalid MGTA %ld\n", mgta);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/** @brief Return Measurement Gap Configuration, from ASN.1 config */
|
||||
const NR_GapConfig_t *get_gap_config(const NR_MeasGapConfig_t *mgc)
|
||||
{
|
||||
if (mgc->gapFR2 && mgc->gapFR2->present == NR_SetupRelease_GapConfig_PR_setup)
|
||||
return mgc->gapFR2->choice.setup;
|
||||
|
||||
// FR1 case
|
||||
if (!mgc->ext1)
|
||||
return NULL;
|
||||
|
||||
const NR_SetupRelease_GapConfig_t *gapUE = mgc->ext1->gapUE;
|
||||
if (gapUE && gapUE->present == NR_SetupRelease_GapConfig_PR_setup)
|
||||
return gapUE->choice.setup;
|
||||
|
||||
const NR_SetupRelease_GapConfig_t *gapFR1 = mgc->ext1->gapFR1;
|
||||
if (gapFR1 && gapFR1->present == NR_SetupRelease_GapConfig_PR_setup)
|
||||
return gapFR1->choice.setup;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
measgap_config_t create_measgap_config(const NR_MeasurementTimingConfiguration_t *mtc, int scs, int min_rxtxtime)
|
||||
{
|
||||
measgap_config_t mgc = {0};
|
||||
const NR_MeasTimingList_t *mtlist = mtc->criticalExtensions.choice.c1->choice.measTimingConf->measTiming;
|
||||
const NR_MeasTiming_t *mt = mtlist->list.array[0];
|
||||
DevAssert(mt != NULL && mt->frequencyAndTiming != NULL);
|
||||
const struct NR_MeasTiming__frequencyAndTiming *ft = mt->frequencyAndTiming;
|
||||
const NR_SSB_MTC_t *ssb_mtc = &ft->ssb_MeasurementTimingConfiguration;
|
||||
NR_MeasGapConfig_t *measGapConfig = get_gap_config_from_smtc(ssb_mtc);
|
||||
const NR_GapConfig_t *gap_config = get_gap_config(measGapConfig);
|
||||
if (!gap_config)
|
||||
return mgc;
|
||||
|
||||
mgc.mgrp_ms = get_mgrp(gap_config->mgrp);
|
||||
DevAssert(mgc.mgrp_ms != -1);
|
||||
mgc.mgrp = gap_config->mgrp;
|
||||
|
||||
mgc.gapOffset = gap_config->gapOffset;
|
||||
mgc.mgta = gap_config->mgta;
|
||||
mgc.n_slots_mgta = ((int)(10 * get_mgta(gap_config->mgta)) << scs) / 10;
|
||||
|
||||
// We start the timer K2 slots earlier to avoid scheduling feedback PUCCHs inside measGap
|
||||
// or depending on the current min_rxtxtime earlier
|
||||
// TS 38.214 - Table 6.1.2.1.1.2
|
||||
const int max_k2 = max(3, min_rxtxtime);
|
||||
|
||||
mgc.n_slots_advance = mgc.n_slots_mgta + max_k2;
|
||||
|
||||
mgc.mgl_ms = get_mgl(gap_config->mgl);
|
||||
DevAssert(mgc.mgl_ms != -1);
|
||||
mgc.mgl = gap_config->mgl;
|
||||
mgc.mgl_slots = ((int)(10 * (mgc.mgl_ms + max_k2)) << scs) / 10;
|
||||
|
||||
mgc.enable = true;
|
||||
return mgc;
|
||||
}
|
||||
|
||||
int encode_measgap_config(const measgap_config_t *c, uint8_t *buf)
|
||||
{
|
||||
NR_MeasGapConfig_t *measGapConfig = calloc_or_fail(1, sizeof(*measGapConfig));
|
||||
measGapConfig->ext1 = calloc_or_fail(1, sizeof(*measGapConfig->ext1));
|
||||
measGapConfig->ext1->gapUE = calloc_or_fail(1, sizeof(*measGapConfig->ext1->gapUE));
|
||||
measGapConfig->ext1->gapUE->present = NR_SetupRelease_GapConfig_PR_setup;
|
||||
NR_GapConfig_t *gap_config = calloc_or_fail(1, sizeof(*gap_config));
|
||||
measGapConfig->ext1->gapUE->choice.setup = gap_config;
|
||||
gap_config->mgta = c->mgta;
|
||||
gap_config->mgrp = c->mgrp;
|
||||
gap_config->gapOffset = c->gapOffset;
|
||||
gap_config->mgl = c->mgl;
|
||||
asn_enc_rval_t enc_rval_mgc = uper_encode_to_buffer(&asn_DEF_NR_MeasGapConfig, NULL, measGapConfig, buf, 1024);
|
||||
AssertFatal(enc_rval_mgc.encoded > 0, "Could not encode CellGroup, failed element %s\n", enc_rval_mgc.failed_type->name);
|
||||
ASN_STRUCT_FREE(asn_DEF_NR_MeasGapConfig, measGapConfig);
|
||||
return (int)((enc_rval_mgc.encoded + 7) >> 3);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user