Compare commits

...

16 Commits

Author SHA1 Message Date
Sakthivel Velumani
82507b0355 doc: update cell-search option
Signed-off-by: Sakthivel Velumani <s.velumani@northeastern.edu>
2026-05-02 04:25:24 +00:00
Sakthivel Velumani
30876f4f51 ue_init_sync: remove unnecessary freq compensation
samples are freshly read from radio for SIB1.

Signed-off-by: Sakthivel Velumani <s.velumani@northeastern.edu>
2026-05-02 04:25:17 +00:00
Sakthivel Velumani
0c11fb3d8a ue: set default center freq from nr band
if center frequency is not provided, the center of band is used for
  radio initialization.

Signed-off-by: Sakthivel Velumani <s.velumani@northeastern.edu>
2026-05-02 04:25:16 +00:00
Sakthivel Velumani
c77d0c8192 Workaround for n3xx usrp beaking samples stream
Don't assert if overflow happens. When reading samples before sync, we
can continue reading samples and ignore any overflow. With n3xx usrp,
overflow happens after turing freq maybe because tuning takes longer
than other types of usrps.

Move dummyWrite() and readFrame() definitions earlier. Make dummyWrite()
static.

Signed-off-by: Sakthivel Velumani <s.velumani@northeastern.edu>
2026-05-02 04:25:15 +00:00
Sakthivel Velumani
c38e7d1425 ue: USRP check LO lock after tuning
Signed-off-by: Sakthivel Velumani <s.velumani@northeastern.edu>
2026-05-02 04:25:14 +00:00
Raymond Knopp
5d37b5b758 added tracing of PLMN information
Signed-off-by: Sakthivel Velumani <s.velumani@northeastern.edu>
2026-05-02 04:25:07 +00:00
Raymond Knopp
4c79c9e299 minor changes for commercial cell detection
SSS detection threshold

Signed-off-by: Sakthivel Velumani <s.velumani@northeastern.edu>
2026-05-02 04:24:20 +00:00
Sakthivel Velumani
7bd5498738 Add error message in sync req handler
Sync request from MAC should either have SSB position that the PHY has to sync
with or instruct the PHY to do a scan. If in SA mode neither is provided, the
UE asserts because likely the MAC had encountered an error and in do-ra/phytest
mode where the RRC config loaded from file could have a configuration that
sends reconfig with sync during initialization and an error message is
displayed.

Signed-off-by: Sakthivel Velumani <s.velumani@northeastern.edu>
2026-05-02 04:06:43 +00:00
Sakthivel Velumani
684ff39727 Implement scanning of whole NR band
when command line option --ue-scan-carrier 2 is set, the UE will scan
all the GSCN in the configured NR band and the center frequency set with
-C is ignored. The bandwidth scan can be run with --ue-scan-carrier 1
and the UE will scan for GSCN only within configured center frequency
and bandwidth.

Signed-off-by: Sakthivel Velumani <s.velumani@northeastern.edu>
2026-05-02 04:06:42 +00:00
Sakthivel Velumani
c8d111e8a7 Modify cell search functions to work with integers
Change frequency representation from Hz to kHz in places related to cell
search because channel raster and synchronization raster are always
represented in kHz.

Signed-off-by: Sakthivel Velumani <s.velumani@northeastern.edu>
2026-05-02 04:06:41 +00:00
Sakthivel Velumani
6ce55845f0 Fix sync request hadling in PHY
After receiving sync request from MAC, the PHY can start and immediately
disable the sync request flag because sync process is started and will
finish only if synced.

Signed-off-by: Sakthivel Velumani <s.velumani@northeastern.edu>
2026-05-02 04:06:40 +00:00
Sakthivel Velumani
688828cd91 Fix log message to show correct gscn and ssref
When resync request is received with SSB offset, we calculate GSCN and
ssref from ssb arfcn and log the values.

Signed-off-by: Sakthivel Velumani <s.velumani@northeastern.edu>
2026-05-02 04:06:40 +00:00
Sakthivel Velumani
451c096ecb Set point A frequency according to SIB1
The UE and gNB could operate at different center frequency and bandwidth
but point A should be same. This commit sends sync request after
receiving SIB1 with correct point A to be set at PHY.

Signed-off-by: Sakthivel Velumani <s.velumani@northeastern.edu>
2026-05-02 04:06:39 +00:00
Sakthivel Velumani
f9ab227616 Improve UE SIB1 reception
During cell search, the UE could be at any center frequency for a given
bandwidth to perform a SSB scan. If a MIB is found and the PDCCH0 config
indicates that the SIB1 is outside of current bandwidth, a sync_request
indication is sent to PHY with new carrier config so the UE can sync
with SSB and receive SIB1.

To do this, the function get_type0_PDCCH_CSS_config_parameters() is
disaggregated to smaller functions to fill type0 PDCCH config. After MIB
is decoded, we check if type0 PDCCH config in MIB lies within current
bandwidth in function configure_ue_phy_for_sib1_reception().

Signed-off-by: Sakthivel Velumani <s.velumani@northeastern.edu>
2026-05-02 04:06:38 +00:00
Sakthivel Velumani
1c79c448cb Remove received_config_request global variable
Instead, use the config_mask variable within fapi_nr_config_request_t to
determine which configuration has been sent from MAC to PHY. This allows
to control PHY configurations at different states. For ex, the carrier
config can be used to set the frequency for receiving SIB1 from MIB
information.

Signed-off-by: Sakthivel Velumani <s.velumani@northeastern.edu>
2026-05-02 04:06:37 +00:00
Sakthivel Velumani
645e24cbbb Move PBCH indication out of nr_rx_pbch
Signed-off-by: Sakthivel Velumani <s.velumani@northeastern.edu>
2026-05-02 04:06:37 +00:00
27 changed files with 698 additions and 231 deletions

View File

@@ -683,6 +683,11 @@ int get_nr_table_idx(int nr_bandP, uint8_t scs_index)
return i;
}
nr_bandentry_t get_band_entry(int nr_band, uint8_t scs)
{
return nr_bandtable[get_nr_table_idx(nr_band, scs)];
}
int get_subband_size(int NPRB,int size) {
// implements table 5.2.1.4-2 from 36.214
//
@@ -1027,16 +1032,16 @@ uint32_t get_ssb_offset_to_pointA(uint32_t absoluteFrequencySSB,
return ssb_offset_point_a;
}
static double get_start_freq(const double fc, const int nbRB, const int mu)
static uint32_t get_start_freq(const uint32_t fc_khz, const int nbRB, const int mu)
{
const int scs = MU_SCS(mu) * 1000;
return fc - ((double)nbRB / 2 * NR_NB_SC_PER_RB * scs);
const int scs = MU_SCS(mu);
return fc_khz - (nbRB * NR_NB_SC_PER_RB / 2 * scs);
}
static double get_stop_freq(const double fc, const int nbRB, const int mu)
static uint32_t get_stop_freq(const uint32_t fc_khz, const int nbRB, const int mu)
{
int scs = MU_SCS(mu) * 1000;
return fc + ((double)nbRB / 2 * NR_NB_SC_PER_RB * scs);
const int scs = MU_SCS(mu);
return fc_khz + (nbRB * NR_NB_SC_PER_RB / 2 * scs);
}
static void compute_M_and_N(const int gscn, int *rM, int *rN)
@@ -1063,38 +1068,78 @@ static void compute_M_and_N(const int gscn, int *rM, int *rN)
}
// Section 5.4.3 of 38.101-1 and -2
static double get_ssref_from_gscn(const int gscn)
// Returns SSRef in kHz
uint32_t get_ssref_from_gscn(const int gscn)
{
int M, N = -1;
compute_M_and_N(gscn, &M, &N);
if (gscn > 1 && gscn < 7499) { // Sub 3GHz
AssertFatal(N > 0 && N < 2500, "Invalid N\n");
AssertFatal(M > 0 && M < 6 && (M & 0x1), "Invalid M\n");
return (N * 1200e3 + M * 50e3);
return (N * 1200 + M * 50);
} else if (gscn > 7498 && gscn < 22256) {
AssertFatal(N > -1 && N < 14757, "Invalid N\n");
return (3000e6 + N * 1.44e6);
return (3000000 + N * 1440);
} else if (gscn > 22255 && gscn < 26638) {
AssertFatal(N > -1 && N < 4382, "Invalid N\n");
return (24250.08e6 + N * 17.28e6);
return (24250080 + N * 17280);
} else {
LOG_E(NR_PHY, "Invalid GSCN\n");
abort();
}
}
static void find_gscn_to_scan(const double startFreq,
const double stopFreq,
static void compute_M_and_N_from_ssref(const uint32_t ssref, int *rM, int *rN)
{
if (ssref < 3000000) {
for (int M = 1; M < 6; M += 2) {
if (((ssref - M * 50) % 1200) == 0) {
*rM = M;
*rN = (ssref - M * 50) / 1200;
break;
}
}
} else if (ssref >= 3000000 && ssref < 24250000) {
*rN = (ssref - 3000000) / 1440;
} else if (ssref >= 24250000 && ssref < 100000000) {
*rN = (ssref - 24250080) / 17280;
} else {
AssertFatal(0, "Invalid ssref %u kHz\n", ssref);
}
}
int get_gscn_from_nrarfcn(const int band, const int scs, const uint32_t arfcn)
{
int M, N = -1;
const uint32_t ssref = from_nrarfcn(band, scs, arfcn) / 1000;
compute_M_and_N_from_ssref(ssref, &M, &N);
if (ssref < 3000000) {
AssertFatal(N > 0 && N < 2500, "Invalid N\n");
AssertFatal(M > 0 && M < 6 && (M & 0x1), "Invalid M\n");
return 3 * N + (M - 3) / 2;
} else if (ssref >= 3000000 && ssref < 24250000) {
AssertFatal(N > -1 && N < 14757, "Invalid N\n");
return 7499 + N;
} else if (ssref >= 24250000 && ssref < 100000000) {
AssertFatal(N > -1 && N < 4382, "Invalid N\n");
return 22256 + N;
}
AssertFatal(0, "Invalid ssref %u kHz\n", ssref);
return -1;
}
static void find_gscn_to_scan(const uint32_t startFreq,
const uint32_t stopFreq,
const sync_raster_t gscn,
int *scanGscnStart,
int *scanGscnStop)
{
const double scs = MU_SCS(gscn.scs_index) * 1e3;
const double ssbBW = 20 * NR_NB_SC_PER_RB * scs;
const int scs = MU_SCS(gscn.scs_index);
const uint32_t ssbBW = 20 * NR_NB_SC_PER_RB * scs;
for (int g = gscn.first_gscn; g < gscn.last_gscn; g += gscn.step_gscn) {
const double centerSSBFreq = get_ssref_from_gscn(g);
const double startSSBFreq = centerSSBFreq - ssbBW / 2;
const uint32_t centerSSBFreq = get_ssref_from_gscn(g);
const uint32_t startSSBFreq = centerSSBFreq - ssbBW / 2;
if (startSSBFreq < startFreq)
continue;
@@ -1104,8 +1149,8 @@ static void find_gscn_to_scan(const double startFreq,
*scanGscnStop = *scanGscnStart;
for (int g = gscn.last_gscn; g > gscn.first_gscn; g -= gscn.step_gscn) {
const double centerSSBFreq = get_ssref_from_gscn(g);
const double stopSSBFreq = centerSSBFreq + ssbBW / 2 - 1;
const uint32_t centerSSBFreq = get_ssref_from_gscn(g);
const uint32_t stopSSBFreq = centerSSBFreq + ssbBW / 2 - scs;
if (stopSSBFreq > stopFreq)
continue;
@@ -1114,23 +1159,32 @@ static void find_gscn_to_scan(const double startFreq,
}
}
static int get_ssb_first_sc(const double pointA, const double ssbCenter, const int mu)
int get_ssb_first_sc(const uint32_t pointA_kHz, const uint32_t ssbCenter_kHz, const int mu)
{
const double scs = MU_SCS(mu) * 1e3;
const uint32_t scs = MU_SCS(mu);
const int ssbRBs = 20;
return (int)((ssbCenter - pointA) / scs - (ssbRBs / 2 * NR_NB_SC_PER_RB));
return ((ssbCenter_kHz - pointA_kHz) / scs - (ssbRBs * NR_NB_SC_PER_RB / 2));
}
static int get_neigh_gscn_offset(const int gscn, const int gscn2, const int scs_khz)
{
const uint32_t firstSSRef = get_ssref_from_gscn(gscn);
const uint32_t nextSSRef = get_ssref_from_gscn(gscn2);
return ((nextSSRef - firstSSRef) % scs_khz);
}
/* Returns array of first SCS offset in the scanning window */
int get_scan_ssb_first_sc(const double fc, const int nbRB, const int nrBand, const int mu, nr_gscn_info_t ssbInfo[MAX_GSCN_BAND])
int get_scan_ssb_first_sc(uint32_t *fc_khz_p,
const int nbRB,
const int nrBand,
const int mu,
const int numScans,
const int firstScannedGscn,
const int lastScannedGscn,
nr_gscn_info_t ssbInfo[MAX_GSCN_BAND])
{
const double startFreq = get_start_freq(fc, nbRB, mu);
const double stopFreq = get_stop_freq(fc, nbRB, mu);
int scanGscnStart = 0;
int scanGscnStop = 0;
const sync_raster_t *tmpRaster = sync_raster;
const sync_raster_t * end=sync_raster + sizeofArray(sync_raster);
const sync_raster_t *end = sync_raster + sizeofArray(sync_raster);
while (tmpRaster < end && (tmpRaster->band != nrBand || tmpRaster->scs_index != mu))
tmpRaster++;
if (tmpRaster >= end) {
@@ -1138,18 +1192,69 @@ int get_scan_ssb_first_sc(const double fc, const int nbRB, const int nrBand, con
return 0;
}
// for sub 3GHz SSRef = N * 1200kHz + M * 50kHz. So one value of M for each scan
/*
GSCN First scan Second scan Third scan
0 x
1 x
2 x
3 x
... x
... x
...
N-3 x
N-2 x
N-1 x
*/
bool sub3 = (tmpRaster->last_gscn < 7499 && tmpRaster->step_gscn == 1); // GSCN granularity not consistent with SCS
const uint32_t scs = MU_SCS(mu);
uint32_t fc_khz = *fc_khz_p;
uint32_t startFreq;
if (fc_khz != 0) {
// center freq provided, return list of GSCN in current bandwidth
startFreq = get_start_freq(fc_khz, nbRB, mu);
} else {
// center freq not provided
// compute startFreq from first GSCN to be scanned in this run
int first_gscn;
if (sub3 && (numScans % 3))
first_gscn = firstScannedGscn + 1;
else
first_gscn = (lastScannedGscn == -1) ? tmpRaster->first_gscn : lastScannedGscn + tmpRaster->step_gscn;
if (first_gscn > tmpRaster->last_gscn) {
// Repeat search
first_gscn = tmpRaster->first_gscn;
}
const uint32_t firstSSRef = get_ssref_from_gscn(first_gscn);
const int ssbRBs = 20;
startFreq = firstSSRef - (ssbRBs * NR_NB_SC_PER_RB / 2 * scs);
fc_khz = startFreq + (nbRB * NR_NB_SC_PER_RB / 2 * scs);
// return new center frequency
*fc_khz_p = fc_khz;
}
const uint32_t stopFreq = get_stop_freq(fc_khz, nbRB, mu);
int scanGscnStart = 0;
int scanGscnStop = 0;
find_gscn_to_scan(startFreq, stopFreq, *tmpRaster, &scanGscnStart, &scanGscnStop);
const double scs = MU_SCS(mu) * 1e3;
const double pointA = fc - ((double)nbRB / 2 * scs * NR_NB_SC_PER_RB);
const uint32_t pointA = fc_khz - (nbRB * NR_NB_SC_PER_RB / 2 * scs);
int numGscn = 0;
for (int g = scanGscnStart; (g <= scanGscnStop) && (numGscn < MAX_GSCN_BAND); g += tmpRaster->step_gscn) {
const int step_gscn = sub3 ? 3 : tmpRaster->step_gscn;
for (int g = scanGscnStart; (g <= scanGscnStop) && (numGscn < MAX_GSCN_BAND); g += step_gscn) {
ssbInfo[numGscn].ssRef = get_ssref_from_gscn(g);
ssbInfo[numGscn].ssbFirstSC = get_ssb_first_sc(pointA, ssbInfo[numGscn].ssRef, mu);
ssbInfo[numGscn].gscn = g;
numGscn++;
}
if (numGscn > 2) {
// Check if GSCNs to be scanned are aligned with current freq and SCS
const int sync_raster_granu = get_neigh_gscn_offset(ssbInfo[0].gscn, ssbInfo[1].gscn, scs);
if (sync_raster_granu)
LOG_E(NR_PHY, "Sync raster granularity %d unaligned with SCS %d\n", sync_raster_granu, scs);
}
return numGscn;
}

View File

@@ -108,6 +108,14 @@ typedef struct {
nr_sib_type_t SIB_type;
} nr_SIBs_t;
typedef enum {
PHY_CONFIG_BIT_MASK_CARRIER = 0,
PHY_CONFIG_BIT_MASK_CELL,
PHY_CONFIG_BIT_MASK_SSB,
PHY_CONFIG_BIT_MASK_TDD,
PHY_CONFIG_BIT_MASK_PRACH
} nr_phy_config_mask_t;
typedef struct nr_bandentry_s {
int16_t band;
uint64_t ul_min;
@@ -131,7 +139,7 @@ typedef struct {
typedef struct {
int gscn;
double ssRef;
uint32_t ssRef;
int ssbFirstSC;
} nr_gscn_info_t;
@@ -277,7 +285,8 @@ int NRRIV2BW(int locationAndBandwidth,int N_RB);
int NRRIV2PRBOFFSET(int locationAndBandwidth,int N_RB);
int PRBalloc_to_locationandbandwidth0(int NPRB,int RBstart,int BWPsize);
int PRBalloc_to_locationandbandwidth(int NPRB,int RBstart);
int get_subband_size(int NPRB,int size);
nr_bandentry_t get_band_entry(int nr_band, uint8_t scs);
int get_subband_size(int NPRB, int size);
void SLIV2SL(int SLIV,int *S,int *L);
int get_dmrs_port(int nl, uint16_t dmrs_ports);
uint16_t SL_to_bitmap(int startSymbolIndex, int nrOfSymbols);
@@ -299,11 +308,14 @@ uint32_t get_ssb_offset_to_pointA(uint32_t absoluteFrequencySSB,
int get_ssb_subcarrier_offset(uint32_t absoluteFrequencySSB, uint32_t absoluteFrequencyPointA, int scs);
int get_delay_idx(int delay, int max_delay_comp);
int get_scan_ssb_first_sc(const double fc,
int get_scan_ssb_first_sc(uint32_t *fc_khz_p,
const int nbRB,
const int nrBand,
const int mu,
nr_gscn_info_t ssbStartSC[MAX_GSCN_BAND]);
const int numScans,
const int firstScannedGscn,
const int lastScannedGscn,
nr_gscn_info_t ssbInfo[MAX_GSCN_BAND]);
void check_ssb_raster(uint64_t freq, int band, int scs);
int get_smallest_supported_bandwidth_index(int scs, frequency_range_t frequency_range, int n_rbs);
@@ -314,6 +326,9 @@ uint8_t get_PRACH_k_bar(unsigned int delta_f_RA_PRACH, unsigned int delta_f_PUSC
unsigned int get_prach_K(int prach_sequence_length, int prach_fmt_id, int pusch_mu, int prach_mu);
int get_slot_idx_in_period(const int slot, const frame_structure_t *fs);
int get_ssb_first_sc(const uint32_t pointA, const uint32_t ssbCenter, const int mu);
int get_gscn_from_nrarfcn(const int band, const int scs, const uint32_t arfcn);
uint32_t get_ssref_from_gscn(const int gscn);
frequency_range_t get_freq_range_from_freq(uint64_t freq);
frequency_range_t get_freq_range_from_arfcn(uint32_t arfcn);
@@ -358,6 +373,12 @@ void nr_deconstruct_5g_s_tmsi(const uint64_t fiveg_s_tmsi, uint16_t *amf_set_id,
static const char *const duplex_mode_txt[] = {"FDD", "TDD"};
#define SETBIT(a, b) ((a) |= (1 << (b)))
#define GETBIT(a, b) (((a) >> (b)) & 1)
// Align up to a multiple of 16
#define ALIGN_UP_16(a) ((a + 15) & ~15)
#ifdef __cplusplus
#ifdef min
#undef min

View File

@@ -91,7 +91,7 @@ Here are some useful command line options for the NR UE:
| Parameter | Description |
|--------------------------|---------------------------------------------------------------------------------------------------------------|
| `--ue-scan-carrier` | Scan for cells in current bandwidth. This option can be used if the SSB position of the gNB is unknown. If multiple cells are detected, the UE will try to connect to the first cell. By default, this option is disabled and the UE attempts to only decode SSB given by `--ssb`. |
| `--ue-scan-carrier` | Value range: [0 - 2]. 0: Scan disabled and UE attempts to only decode SSB given be `--ssb`. This is the default behavior. 1: Scan for cells in current bandwidth. This option can be used if the SSB position of the gNB is unknown. If multiple cells are detected, the UE will try to connect to the first cell. 2: Scan for cells in NR band given by `--band`. This option can be used to scan cells in an NR band. Like option 1, the UE will try to connect to the fist cell. There is ongoing work to improve this and have a scan only mode to report all cells in the band. |
| `--ue-fo-compensation` | Enables the initial frequency offset compensation at the UE. Useful when running over the air and/or without an external clock/time source. |
| `--cont-fo-comp` | Enables the continuous frequency offset (FO) estimation and compensation. Parameter value `1` specifies that the main FO contribution comes from the local oscillator's (LO) accuracy. Parameter value `2` specifies that the main FO contribution comes from Doppler shift. Parameter value `3` specifies that no measured residual DL FO is considered for UL FO pre-compensation. |
| `--initial-fo` | Sets the known initial frequency offset. Useful especially with large Doppler frequency, e.g. LEO satellite. |
@@ -112,6 +112,10 @@ You can view all available options by typing:
./nr-uesoftmodem --help
```
### Cell Search Limitation
The cell search feature in the UE (`--ue-scan-carrier`) works only with real RF devices and not in rfsim. It is because the NR waveform has phase pre-compensation to have different center frequencies at gNB and UE. In real RF the phase offset produced by difference in center frequencies are cancelled by the pre-compensation in OFDM signal generation and Up/Down conversion. But it is not the case in rfsim. However, `--ue-scan-carrier 1` can be used in rfsim when gNB and UE have the same center frequency.
### UE Capabilities
The `--uecap_file` option can be used to pass the UE Capabilities input file (path location + filename), e.g.`--uecap_file ../../../targets/PROJECTS/GENERIC-NR-5GC/CONF/uecap_ports1.xml` for 1 layer or e.g. `--uecap_file ../../../targets/PROJECTS/GENERIC-NR-5GC/CONF/uecap_ports2.xml` for 2 layers.

View File

@@ -48,7 +48,10 @@
#define CONFIG_HLP_UETXG "set UE TX gain\n"
#define CONFIG_HLP_UENANTR "set UE number of rx antennas\n"
#define CONFIG_HLP_UENANTT "set UE number of tx antennas\n"
#define CONFIG_HLP_UESCAN "set UE to scan all possible GSCN in current bandwidth\n"
#define CONFIG_HLP_UESCAN \
"0: UE will decode SSB based on --ssb parameter,\n" \
"1: UE will scan all possible GSCN in given center frequency & bandwidth,\n" \
"2: UE will scan the whole NR band and connects to first found cell.\n"
#define CONFIG_HLP_UEFO "set UE to enable estimation and compensation of frequency offset\n"
#define CONFIG_HLP_PRB_SA "Set the number of PRBs for SA\n"
#define CONFIG_HLP_SSC "Set the start subcarrier \n"

View File

@@ -290,7 +290,7 @@ static void RU_write(nr_rxtx_thread_data_t *rxtxD, bool sl_tx_action, c16_t **tx
radio_tx_burst_flag_t flags = TX_BURST_INVALID;
if (UE->received_config_request) {
if (GETBIT(cfg->config_mask, PHY_CONFIG_BIT_MASK_TDD)) {
if (fp->frame_type == FDD || get_softmodem_params()->continuous_tx) {
flags = TX_BURST_MIDDLE;
// In case of Sidelink, USRP write needed only in case transmission
@@ -453,21 +453,103 @@ static uint64_t get_carrier_frequency(const int N_RB, const int mu, const uint32
return carrier_freq;
}
static int handle_sync_req_from_mac(PHY_VARS_NR_UE *UE)
static void dummyWrite(PHY_VARS_NR_UE *UE, openair0_timestamp_t timestamp, int writeBlockSize)
{
const NR_DL_FRAME_PARMS *fp = &UE->frame_parms;
if (UE->sl_mode == 2)
fp = &UE->SL_UE_PHY_PARAMS.sl_frame_params;
c16_t *dummy_tx[fp->nb_antennas_tx];
c16_t dummy_tx_data[writeBlockSize];
memset(dummy_tx_data, 0, sizeof(dummy_tx_data));
for (int i = 0; i < fp->nb_antennas_tx; i++)
dummy_tx[i] = dummy_tx_data;
int tmp = nrue_ru_write(UE, timestamp, (void **)dummy_tx, writeBlockSize, fp->nb_antennas_tx, 4);
AssertFatal(writeBlockSize == tmp, "");
}
static int readFrame(PHY_VARS_NR_UE *UE, openair0_timestamp_t *timestamp, int duration_rx_to_tx, bool toTrash)
{
const NR_DL_FRAME_PARMS *fp = &UE->frame_parms;
// two frames for initial sync
int num_frames = 2;
// In Sidelink worst case SL-SSB can be sent once in 16 frames
if (UE->sl_mode == 2) {
fp = &UE->SL_UE_PHY_PARAMS.sl_frame_params;
num_frames = SL_NR_PSBCH_REPETITION_IN_FRAMES;
}
c16_t *rxp[fp->nb_antennas_rx];
if (toTrash) {
rxp[0] = malloc16(get_samples_per_slot(0, fp) * sizeof(c16_t));
for (int i = 1; i < fp->nb_antennas_rx; i++)
rxp[i] = rxp[0];
}
for (int x = 0; x < num_frames * NR_NUMBER_OF_SUBFRAMES_PER_FRAME; x++) { // two frames for initial sync
for (int slot_rx = 0; slot_rx < fp->slots_per_subframe; slot_rx++) {
if (!toTrash)
for (int i = 0; i < fp->nb_antennas_rx; i++)
rxp[i] = &UE->common_vars.rxdata[i][x * fp->samples_per_subframe + get_samples_slot_timestamp(fp, slot_rx)];
int readBlockSize = get_samples_per_slot(slot_rx, fp);
int tmp = nrue_ru_read(UE, timestamp, (void **)rxp, readBlockSize, fp->nb_antennas_rx);
UEscopeCopy(UE, ueTimeDomainSamplesBeforeSync, rxp[0], sizeof(c16_t), 1, readBlockSize, 0);
if (readBlockSize != tmp) {
if (toTrash)
free(rxp[0]);
return 1;
}
if (IS_SOFTMODEM_RFSIM) {
int slot_tx = (slot_rx + duration_rx_to_tx) % fp->slots_per_frame;
int writeBlockSize = get_samples_per_slot(slot_tx, fp);
int ta = UE->timing_advance + UE->timing_advance_ntn;
const openair0_timestamp_t writeTimestamp =
*timestamp + get_samples_slot_duration(fp, slot_rx, duration_rx_to_tx) - UE->N_TA_offset - ta;
dummyWrite(UE, writeTimestamp, writeBlockSize);
}
}
}
if (toTrash)
free(rxp[0]);
return 0;
}
static int handle_sync_req_from_mac(PHY_VARS_NR_UE *UE, uint32_t *ssb_arfcn)
{
NR_DL_FRAME_PARMS *fp = &UE->frame_parms;
const fapi_nr_config_request_t *config = &UE->nrUE_config;
const fapi_nr_ue_carrier_config_t *cfg = &config->carrier_config;
// Start synchronization with a target gNB
if (UE->synch_request.received_synch_request == 1) {
// if upper layers signal BW scan we do as instructed by command line parameter
// if upper layers disable BW scan we set it to false
if (UE->synch_request.synch_req.ssb_bw_scan)
const fapi_nr_synch_request_t *s = &UE->synch_request.synch_req;
if (s->ssb_bw_scan)
UE->UE_scan_carrier = get_nrUE_params()->UE_scan_carrier;
else
UE->UE_scan_carrier = false;
else {
UE->UE_scan_carrier = NO_SCAN;
if (s->ssb_arfcn == 0) {
if (get_softmodem_params()->do_ra || get_softmodem_params()->phy_test)
LOG_E(PHY,
"Received sync request without BW scan and no SSB position. Either one should be provided. Attempting sync with "
"default SSB position\n");
else
AssertFatal(0, "Sync request in SA mode must have SSB position or BW scan command\n");
} else {
fp->ssb_start_subcarrier = get_ssb_first_sc(cfg->dl_frequency,
from_nrarfcn(nrue_get_band(UE), fp->numerology_index, s->ssb_arfcn) / 1000,
fp->numerology_index);
*ssb_arfcn = s->ssb_arfcn;
}
}
UE->target_Nid_cell = UE->synch_request.synch_req.target_Nid_cell;
const fapi_nr_config_request_t *config = &UE->nrUE_config;
const fapi_nr_ue_carrier_config_t *cfg = &config->carrier_config;
uint64_t dl_CarrierFreq = get_carrier_frequency(fp->N_RB_DL, fp->numerology_index, cfg->dl_frequency);
uint64_t ul_CarrierFreq = get_carrier_frequency(fp->N_RB_UL, fp->numerology_index, cfg->uplink_frequency);
if (dl_CarrierFreq != fp->dl_CarrierFreq || ul_CarrierFreq != fp->ul_CarrierFreq) {
@@ -484,6 +566,10 @@ static int handle_sync_req_from_mac(PHY_VARS_NR_UE *UE)
fp->dl_CarrierFreq = dl_CarrierFreq;
fp->ul_CarrierFreq = ul_CarrierFreq;
init_symbol_rotation(fp);
// warm up the RF board after changing frequency
int64_t tmp;
for (int i = 0; i < 50; i++)
readFrame(UE, &tmp, NR_UE_CAPABILITY_SLOT_RX_TO_TX, true);
}
int ssb_start_subcarrier = nr_get_ssb_start_sc(fp->numerology_index,
@@ -613,66 +699,6 @@ void UE_dl_processing(void *arg) {
TracyCZoneEnd(ctx);
}
void dummyWrite(PHY_VARS_NR_UE *UE, openair0_timestamp_t timestamp, int writeBlockSize)
{
const NR_DL_FRAME_PARMS *fp = &UE->frame_parms;
if (UE->sl_mode == 2)
fp = &UE->SL_UE_PHY_PARAMS.sl_frame_params;
c16_t *dummy_tx[fp->nb_antennas_tx];
c16_t dummy_tx_data[writeBlockSize];
memset(dummy_tx_data, 0, sizeof(dummy_tx_data));
for (int i = 0; i < fp->nb_antennas_tx; i++)
dummy_tx[i] = dummy_tx_data;
int tmp = nrue_ru_write(UE, timestamp, (void **)dummy_tx, writeBlockSize, fp->nb_antennas_tx, 4);
AssertFatal(writeBlockSize == tmp, "");
}
void readFrame(PHY_VARS_NR_UE *UE, openair0_timestamp_t *timestamp, int duration_rx_to_tx, bool toTrash)
{
const NR_DL_FRAME_PARMS *fp = &UE->frame_parms;
// two frames for initial sync
int num_frames = 2;
// In Sidelink worst case SL-SSB can be sent once in 16 frames
if (UE->sl_mode == 2) {
fp = &UE->SL_UE_PHY_PARAMS.sl_frame_params;
num_frames = SL_NR_PSBCH_REPETITION_IN_FRAMES;
}
c16_t *rxp[fp->nb_antennas_rx];
if (toTrash) {
rxp[0] = malloc16(get_samples_per_slot(0, fp) * sizeof(c16_t));
for (int i = 1; i < fp->nb_antennas_rx; i++)
rxp[i] = rxp[0];
}
for (int x = 0; x < num_frames * NR_NUMBER_OF_SUBFRAMES_PER_FRAME; x++) { // two frames for initial sync
for (int slot_rx = 0; slot_rx < fp->slots_per_subframe; slot_rx++) {
if (!toTrash)
for (int i = 0; i < fp->nb_antennas_rx; i++)
rxp[i] = &UE->common_vars.rxdata[i][x * fp->samples_per_subframe + get_samples_slot_timestamp(fp, slot_rx)];
int readBlockSize = get_samples_per_slot(slot_rx, fp);
int tmp = nrue_ru_read(UE, timestamp, (void **)rxp, readBlockSize, fp->nb_antennas_rx);
UEscopeCopy(UE, ueTimeDomainSamplesBeforeSync, rxp[0], sizeof(c16_t), 1, readBlockSize, 0);
AssertFatal(readBlockSize == tmp, "");
if (IS_SOFTMODEM_RFSIM) {
int slot_tx = (slot_rx + duration_rx_to_tx) % fp->slots_per_frame;
int writeBlockSize = get_samples_per_slot(slot_tx, fp);
int ta = UE->timing_advance + UE->timing_advance_ntn;
const openair0_timestamp_t writeTimestamp =
*timestamp + get_samples_slot_duration(fp, slot_rx, duration_rx_to_tx) - UE->N_TA_offset - ta;
dummyWrite(UE, writeTimestamp, writeBlockSize);
}
}
}
if (toTrash)
free(rxp[0]);
}
static void syncInFrame(PHY_VARS_NR_UE *UE, openair0_timestamp_t *timestamp, int duration_rx_to_tx, openair0_timestamp_t rx_offset)
{
const NR_DL_FRAME_PARMS *fp = &UE->frame_parms;
@@ -760,6 +786,7 @@ void *UE_thread(void *arg)
int intialSyncOffset = 0;
openair0_timestamp_t sync_timestamp;
bool stats_printed = false;
uint32_t sync_ssb_arfcn = 0;
if (get_softmodem_params()->sync_ref && UE->sl_mode == 2) {
UE->is_synchronized = 1;
@@ -771,6 +798,10 @@ void *UE_thread(void *arg)
}
c16_t *rxp[fp->nb_antennas_rx];
int first_scanned_gscn = -1;
int last_scanned_gscn = -1;
int num_scans = 0;
while (!oai_exit) {
if (syncRunning) {
notifiedFIFO_elt_t *res = pollNotifiedFIFO(&nf);
@@ -778,7 +809,6 @@ void *UE_thread(void *arg)
if (res) {
syncRunning = false;
if (UE->is_synchronized) {
UE->synch_request.received_synch_request = 0;
if (UE->sl_mode == SL_MODE2_SUPPORTED)
decoded_frame_rx = UE->SL_UE_PHY_PARAMS.sync_params.DFN;
else {
@@ -824,20 +854,68 @@ void *UE_thread(void *arg)
AssertFatal(!syncRunning, "At this point synchronization can't be running\n");
if (!UE->is_synchronized) {
readFrame(UE, &sync_timestamp, duration_rx_to_tx, false);
notifiedFIFO_elt_t *Msg = newNotifiedFIFO_elt(sizeof(syncData_t), 0, &nf, UE_synch);
syncData_t *syncMsg = (syncData_t *)NotifiedFifoData(Msg);
*syncMsg = (syncData_t){0};
if (UE->UE_scan_carrier) {
NR_DL_FRAME_PARMS *fp = &UE->frame_parms;
const int nr_band = nrue_get_band(UE);
if (fp->dl_CarrierFreq % 1000)
LOG_E(PHY, "Center frequency %lu is not multiple of kHz\n", fp->dl_CarrierFreq);
if (UE->UE_scan_carrier == SCAN_BW) {
// Get list of GSCN in this band for UE's bandwidth and center frequency.
LOG_W(PHY, "UE set to scan all GSCN in current bandwidth\n");
syncMsg->numGscn =
get_scan_ssb_first_sc(fp->dl_CarrierFreq, fp->N_RB_DL, nrue_get_band(UE), fp->numerology_index, syncMsg->gscnInfo);
uint32_t dl_freq_khz = fp->dl_CarrierFreq / 1000;
syncMsg->numGscn = get_scan_ssb_first_sc(&dl_freq_khz,
fp->N_RB_DL,
nr_band,
fp->numerology_index,
0,
0,
0 /*not used*/,
syncMsg->gscnInfo);
} else if (UE->UE_scan_carrier == SCAN_BAND) {
// Get list of GSCN after last scanned GSCN in this band
LOG_W(PHY, "UE set to scan full NR band\n");
uint32_t dlFreq = 0;
syncMsg->numGscn = get_scan_ssb_first_sc(&dlFreq,
fp->N_RB_DL,
nr_band,
fp->numerology_index,
num_scans,
first_scanned_gscn,
last_scanned_gscn,
syncMsg->gscnInfo);
num_scans++;
// save last gscn from current list to continune in next scan
first_scanned_gscn = syncMsg->gscnInfo[0].gscn;
last_scanned_gscn = syncMsg->gscnInfo[syncMsg->numGscn - 1].gscn;
// set dl freqeuncy for current scan
fp->dl_CarrierFreq = dlFreq * 1000;
nrue_ru_set_freq(UE, fp->dl_CarrierFreq, fp->dl_CarrierFreq, 0);
init_symbol_rotation(fp);
} else {
LOG_W(PHY, "SSB position provided\n");
syncMsg->gscnInfo[0] = (nr_gscn_info_t){.ssbFirstSC = fp->ssb_start_subcarrier};
nr_gscn_info_t *g = syncMsg->gscnInfo;
g->ssbFirstSC = fp->ssb_start_subcarrier;
if (sync_ssb_arfcn) {
g->gscn = get_gscn_from_nrarfcn(nr_band, fp->numerology_index, sync_ssb_arfcn);
g->ssRef = get_ssref_from_gscn(g->gscn);
} else {
g->gscn = g->ssRef = 0;
}
syncMsg->numGscn = 1;
}
// warm up the RF board after changing frequency
int64_t tmp;
for (int i = 0; i < 50; i++)
readFrame(UE, &tmp, duration_rx_to_tx, true);
// read 2 frames to do initial sync
while (true) {
if (readFrame(UE, &sync_timestamp, duration_rx_to_tx, false) == 0)
break;
}
syncMsg->UE = UE;
memset(&syncMsg->proc, 0, sizeof(syncMsg->proc));
pushNotifiedFIFO(&UE->sync_actor.fifo, Msg);
@@ -901,7 +979,7 @@ void *UE_thread(void *arg)
}
/* check if MAC has sent sync request */
if (handle_sync_req_from_mac(UE) == 0)
if (handle_sync_req_from_mac(UE, &sync_ssb_arfcn) == 0)
continue;
// start of normal case, the UE is in sync
@@ -922,16 +1000,15 @@ void *UE_thread(void *arg)
curMsg.proc.frame_tx = ((absolute_slot + duration_rx_to_tx) / nb_slot_frame) % MAX_FRAME_NUMBER;
curMsg.proc.hfn_rx = (absolute_slot / nb_slot_frame) / MAX_FRAME_NUMBER;
curMsg.proc.hfn_tx = ((absolute_slot + duration_rx_to_tx) / nb_slot_frame) / MAX_FRAME_NUMBER;
if (UE->received_config_request) {
if (UE->sl_mode) {
if (sl_cfg) {
if (sl_cfg->config_mask == 0xf && UE->sl_mode) {
curMsg.proc.rx_slot_type = sl_nr_ue_slot_select(sl_cfg, curMsg.proc.nr_slot_rx, TDD);
curMsg.proc.tx_slot_type = sl_nr_ue_slot_select(sl_cfg, curMsg.proc.nr_slot_tx, TDD);
} else {
curMsg.proc.rx_slot_type = nr_ue_slot_select(cfg, curMsg.proc.nr_slot_rx);
curMsg.proc.tx_slot_type = nr_ue_slot_select(cfg, curMsg.proc.nr_slot_tx);
}
}
else {
} else if (GETBIT(cfg->config_mask, PHY_CONFIG_BIT_MASK_TDD)) {
curMsg.proc.rx_slot_type = nr_ue_slot_select(cfg, curMsg.proc.nr_slot_rx);
curMsg.proc.tx_slot_type = nr_ue_slot_select(cfg, curMsg.proc.nr_slot_tx);
} else {
curMsg.proc.rx_slot_type = NR_DOWNLINK_SLOT;
curMsg.proc.tx_slot_type = NR_DOWNLINK_SLOT;
}

View File

@@ -380,6 +380,7 @@ int main(int argc, char **argv)
mac->nr_band = cell.band;
mac->ssb_start_subcarrier = cell.ssb_start;
mac->dl_frequency = cell.rf_frequency;
mac->N_RB_DL = cell.N_RB_DL;
UE_CC->sl_mode = get_softmodem_params()->sl_mode;
init_actor(&UE_CC->sync_actor, "SYNC_", -1);

View File

@@ -55,7 +55,7 @@ extern uint16_t ue_id_g;
{"ue-txgain", CONFIG_HLP_UETXG, 0, .dblptr=&nrUE_params.tx_gain, .defdblval=0, TYPE_DOUBLE, 0}, \
{"ue-nb-ant-rx", CONFIG_HLP_UENANTR, 0, .iptr=&(nrUE_params.nb_antennas_rx), .defuintval=1, TYPE_UINT8, 0}, \
{"ue-nb-ant-tx", CONFIG_HLP_UENANTT, 0, .iptr=&(nrUE_params.nb_antennas_tx), .defuintval=1, TYPE_UINT8, 0}, \
{"ue-scan-carrier", CONFIG_HLP_UESCAN, PARAMFLAG_BOOL, .iptr=&(nrUE_params.UE_scan_carrier), .defintval=0, TYPE_INT, 0}, \
{"ue-scan-carrier", CONFIG_HLP_UESCAN, 0, .iptr=&(nrUE_params.UE_scan_carrier), .defintval=0, TYPE_INT, 0}, \
{"ue-fo-compensation", CONFIG_HLP_UEFO, PARAMFLAG_BOOL, .iptr=&(nrUE_params.UE_fo_compensation), .defintval=0, TYPE_INT, 0}, \
{"ue-max-power", NULL, 0, .iptr=&(nrUE_params.tx_max_power), .defintval=90, TYPE_INT, 0}, \
{"r" , CONFIG_HLP_PRB_SA, 0, .iptr=&(nrUE_params.N_RB_DL), .defintval=106, TYPE_UINT, 0}, \

View File

@@ -727,6 +727,7 @@ typedef struct {
typedef struct {
int16_t target_Nid_cell;
uint32_t ssb_arfcn;
bool ssb_bw_scan;
} fapi_nr_synch_request_t;

View File

@@ -257,10 +257,6 @@ int init_nr_ue_signal(PHY_VARS_NR_UE *ue, int nb_connected_gNB)
init_symbol_rotation(fp);
init_timeshift_rotation(fp);
// initialize to false only for SA since in do-ra and phy-test it is already set to true before getting here
if (IS_SA_MODE(get_softmodem_params()))
ue->received_config_request = false;
return 0;
}

View File

@@ -423,13 +423,20 @@ int nr_init_frame_parms_ue(NR_DL_FRAME_PARMS *fp, fapi_nr_config_request_t* conf
void nr_init_frame_parms_ue_sa(NR_DL_FRAME_PARMS *frame_parms, const nrUE_cell_params_t *cell)
{
const uint64_t downlink_frequency = cell->rf_frequency;
const int64_t delta_duplex = cell->rf_freq_offset;
const uint8_t mu = cell->numerology;
const int N_RB_DL = cell->N_RB_DL;
const int ssb_start_subcarrier = cell->ssb_start;
const uint16_t nr_band = cell->band;
// Set DL freq from band if center freq not provided
uint64_t downlink_frequency = cell->rf_frequency;
if (downlink_frequency == 0) {
const nr_bandentry_t b = get_band_entry(nr_band, mu);
/* Set center of the band for radio initialization. Center will be reconfigured
during cell search and after SIB1 reception */
downlink_frequency = (b.dl_min + (b.dl_max - b.dl_min) / 2) * 1000;
}
LOG_I(PHY,"SA init parameters. DL freq %lu UL offset %ld SSB numerology %d N_RB_DL %d\n",
downlink_frequency,
delta_duplex,

View File

@@ -41,7 +41,7 @@
#define SSS_START_IDX (3) /* [0:PSBCH 1:PSS0 2:PSS1 3:SSS0 4:SSS1] */
#define NUM_SSS_SYMBOLS (2)
#define SSS_METRIC_FLOOR_NR (30000)
#define SSS_METRIC_FLOOR_NR (20000)
void init_context_sss_nr(int amp);
void free_context_sss_nr(void);

View File

@@ -394,7 +394,7 @@ nr_initial_sync_t nr_initial_sync(UE_nr_rxtx_proc_t *proc,
memset(ssbInfo->rxdata[ant] + fp->samples_per_frame * 2, 0, fp->ofdm_symbol_size * sizeof(c16_t));
}
LOG_I(NR_PHY,
"Scanning GSCN: %d, with SSB offset: %d, SSB Freq: %lf\n",
"Scanning GSCN: %d, with SSB offset: %d, SSB Freq: %u kHz\n",
ssbInfo->gscnInfo.gscn,
ssbInfo->gscnInfo.ssbFirstSC,
ssbInfo->gscnInfo.ssRef);
@@ -410,7 +410,7 @@ nr_initial_sync_t nr_initial_sync(UE_nr_rxtx_proc_t *proc,
nr_ue_ssb_scan_t *ssbInfo = &ssb_info[i];
if (ssbInfo->syncRes.cell_detected) {
LOG_I(NR_PHY,
"Cell Detected with GSCN: %d, SSB SC offset: %d, SSB Ref: %lf, PSS Corr peak: %d dB, PSS Corr Average: %d\n",
"Cell Detected with GSCN: %d, SSB SC offset: %d, SSB Ref: %u kHz, PSS Corr peak: %d dB, PSS Corr Average: %d\n",
ssbInfo->gscnInfo.gscn,
ssbInfo->gscnInfo.ssbFirstSC,
ssbInfo->gscnInfo.ssRef,
@@ -459,12 +459,6 @@ nr_initial_sync_t nr_initial_sync(UE_nr_rxtx_proc_t *proc,
LOG_D(PHY, "nr_initial sync ue RB_DL %d\n", fp->N_RB_DL);
if (res) {
// digital compensation of FFO for SSB symbols
if (res->freqOffset && ue->UE_fo_compensation) {
// In SA we need to perform frequency offset correction until the end of buffer because we need to decode SIB1
// and we do not know yet in which slot it goes.
compensate_freq_offset(ue->common_vars.rxdata, fp, res->freqOffset, res->syncRes.frame_id);
}
// sync at symbol ue->symbol_offset
// computing the offset wrt the beginning of the frame
int mu = fp->numerology_index;

View File

@@ -397,19 +397,9 @@ int nr_rx_pbch(PHY_VARS_NR_UE *ue,
NR_POLAR_PBCH_AGGREGATION_LEVEL);
pbch_a_prime = tmp;
nr_downlink_indication_t dl_indication;
fapi_nr_rx_indication_t rx_ind = {0};
uint16_t number_pdus = 1;
if (decoderState)
return decoderState;
if (decoderState) {
if (ue) { // decoding failed in synced state
nr_fill_dl_indication(&dl_indication, NULL, &rx_ind, proc, ue, NULL);
nr_fill_rx_indication(&rx_ind, FAPI_NR_RX_PDU_TYPE_SSB, ue, NULL, NULL, number_pdus, proc, NULL, NULL);
if (ue->if_inst && ue->if_inst->dl_indication)
ue->if_inst->dl_indication(&dl_indication);
}
return(decoderState);
}
// printf("polar decoder output 0x%08x\n",pbch_a_prime);
// Decoder reversal
pbch_a_prime = (uint32_t)reverse_bits(pbch_a_prime, NR_POLAR_PBCH_PAYLOAD_BITS);
@@ -462,14 +452,6 @@ int nr_rx_pbch(PHY_VARS_NR_UE *ue,
#endif
if (ue) {
nr_fill_dl_indication(&dl_indication, NULL, &rx_ind, proc, ue, NULL);
nr_fill_rx_indication(&rx_ind, FAPI_NR_RX_PDU_TYPE_SSB, ue, NULL, NULL, number_pdus, proc, (void *)result, NULL);
if (ue->if_inst && ue->if_inst->dl_indication)
ue->if_inst->dl_indication(&dl_indication);
}
TracyCZoneEnd(ctx);
return 0;
}

View File

@@ -267,6 +267,12 @@ typedef struct {
int used_by_ue;
} nrUE_cell_params_t;
typedef enum {
NO_SCAN = 0,
SCAN_BW,
SCAN_BAND,
} nr_ue_scan_enum_t;
/// Top-level PHY Data Structure for UE
typedef struct PHY_VARS_NR_UE_s {
/// \brief Module ID indicator for this instance
@@ -278,7 +284,7 @@ typedef struct PHY_VARS_NR_UE_s {
/// \brief Indicator that UE should perform band scanning
int UE_scan;
/// \brief Indicator that UE should perform coarse scanning around carrier
int UE_scan_carrier;
nr_ue_scan_enum_t UE_scan_carrier;
/// \brief Indicator that UE should enable estimation and compensation of frequency offset
int UE_fo_compensation;
/// IF frequency for RF
@@ -329,7 +335,6 @@ typedef struct PHY_VARS_NR_UE_s {
NR_UE_COMMON common_vars;
nr_ue_if_module_t *if_inst;
bool received_config_request;
fapi_nr_config_request_t nrUE_config;
nr_synch_request_t synch_request;

View File

@@ -378,8 +378,7 @@ void nr_ue_phy_config_request(nr_phy_config_t *phy_config)
{
PHY_VARS_NR_UE *phy = PHY_vars_UE_g[phy_config->Mod_id][phy_config->CC_id];
fapi_nr_config_request_t *nrUE_config = &phy->nrUE_config;
if(phy_config != NULL) {
phy->received_config_request = true;
if (phy_config != NULL) {
memcpy(nrUE_config, &phy_config->config_req, sizeof(fapi_nr_config_request_t));
}
}
@@ -396,7 +395,6 @@ void nr_ue_sl_phy_config_request(nr_sl_phy_config_t *phy_config)
PHY_VARS_NR_UE *phy = PHY_vars_UE_g[phy_config->Mod_id][phy_config->CC_id];
sl_nr_phy_config_request_t *sl_config = &phy->SL_UE_PHY_PARAMS.sl_config;
if (phy_config != NULL) {
phy->received_config_request = true;
memcpy(sl_config, &phy_config->sl_config_req, sizeof(sl_nr_phy_config_request_t));
}
}

View File

@@ -465,6 +465,17 @@ static int nr_ue_pbch_procedures(PHY_VARS_NR_UE *ue,
ue->frame_parms.samples_per_frame_wCP,
rxdataF);
nr_downlink_indication_t dl_indication;
fapi_nr_rx_indication_t rx_ind = {0};
const uint16_t number_pdus = 1;
void *pbch_result = ret ? NULL : &result;
nr_fill_dl_indication(&dl_indication, NULL, &rx_ind, proc, ue, NULL);
nr_fill_rx_indication(&rx_ind, FAPI_NR_RX_PDU_TYPE_SSB, ue, NULL, NULL, number_pdus, proc, pbch_result, NULL);
if (ue->if_inst && ue->if_inst->dl_indication)
ue->if_inst->dl_indication(&dl_indication);
if (ret==0) {
T(T_NRUE_PHY_MIB, T_INT(frame_rx), T_INT(nr_slot_rx),
T_INT(ssb_index), T_BUFFER(result.decoded_output, 3));
@@ -909,10 +920,10 @@ static bool check_meas_to_perform(PHY_VARS_NR_UE *ue, int nr_slot_rx)
static bool is_ssb_index_transmitted(const PHY_VARS_NR_UE *ue, const int index)
{
if (ue->received_config_request) {
const fapi_nr_config_request_t *cfg = &ue->nrUE_config;
const fapi_nr_config_request_t *cfg = &ue->nrUE_config;
if (GETBIT(cfg->config_mask, PHY_CONFIG_BIT_MASK_SSB)) {
const uint32_t curr_mask = cfg->ssb_table.ssb_mask_list[index / 32].ssb_mask;
return ((curr_mask >> (31 - (index % 32))) & 0x01);
return GETBIT(curr_mask, (31 - (index % 32)));
} else
return ue->frame_parms.ssb_index == index;
}
@@ -1004,7 +1015,8 @@ int pbch_processing(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, nr_phy_da
// checking if current frame is compatible with SSB periodicity
const int default_ssb_period = 2;
const int ssb_period = ue->received_config_request ? ue->nrUE_config.ssb_table.ssb_period : default_ssb_period;
const fapi_nr_config_request_t *cfg = &ue->nrUE_config;
const int ssb_period = GETBIT(cfg->config_mask, PHY_CONFIG_BIT_MASK_SSB) ? cfg->ssb_table.ssb_period : default_ssb_period;
if (ssb_period == 0 || !(frame_rx % (1 << (ssb_period - 1)))) {
const int estimateSz = fp->symbols_per_slot * fp->ofdm_symbol_size;
// loop over SSB blocks

View File

@@ -449,6 +449,7 @@ typedef struct {
typedef struct {
NR_SIB1_t *sib1;
bool can_start_ra;
int ssb_arfcn;
} nr_mac_rrc_config_sib1_t;
typedef struct {
NR_SIB19_r17_t *sib19;
@@ -458,6 +459,7 @@ typedef struct {
} nr_mac_rrc_config_other_sib_t;
typedef struct {
int get_sib;
int ssb_arfcn;
} nr_mac_rrc_sched_sib_t;

View File

@@ -3518,52 +3518,14 @@ uint32_t get_Y(const NR_SearchSpace_t *ss, int slot, rnti_t rnti) {
return Y;
}
void get_type0_PDCCH_CSS_config_parameters(NR_Type0_PDCCH_CSS_config_t *type0_PDCCH_CSS_config,
frame_t frameP,
const NR_MIB_t *mib,
uint8_t num_slot_per_frame,
uint8_t ssb_subcarrier_offset,
uint16_t ssb_start_symbol,
NR_SubcarrierSpacing_t scs_ssb,
frequency_range_t frequency_range,
int nr_band,
int grid_size,
uint32_t ssb_index,
uint32_t ssb_period,
uint32_t ssb_offset_point_a)
void fill_type0_PDCCH_coreset_config(NR_Type0_PDCCH_CSS_config_t *type0_PDCCH_CSS_config,
const uint32_t scs_ssb,
const uint32_t scs_pdcch,
const uint32_t index_4msb,
const channel_bandwidth_t min_channel_bw,
const bool is_condition_A,
const uint32_t ssb_offset_point_a)
{
// according to Table 5.3.5-1 in 38.104
// band 79 is the only one which minimum is 40
// for all the other channels it is either 10 or 5
// and there is no difference between the two for this implementation so it is set it to 10
channel_bandwidth_t min_channel_bw;
if (nr_band == 79)
min_channel_bw = bw_40MHz;
else
min_channel_bw = bw_10MHz;
NR_SubcarrierSpacing_t scs_pdcch;
if (frequency_range == FR2) {
if(mib->subCarrierSpacingCommon == NR_MIB__subCarrierSpacingCommon_scs15or60)
scs_pdcch = NR_SubcarrierSpacing_kHz60;
else
scs_pdcch = NR_SubcarrierSpacing_kHz120;
} else {
frequency_range = FR1;
if(mib->subCarrierSpacingCommon == NR_MIB__subCarrierSpacingCommon_scs15or60)
scs_pdcch = NR_SubcarrierSpacing_kHz15;
else
scs_pdcch = NR_SubcarrierSpacing_kHz30;
}
type0_PDCCH_CSS_config->scs_pdcch = scs_pdcch;
type0_PDCCH_CSS_config->ssb_index = ssb_index;
type0_PDCCH_CSS_config->frame = frameP;
uint8_t ssb_slot = ssb_start_symbol / 14;
uint32_t is_condition_A = (ssb_subcarrier_offset == 0); // 38.213 ch.13
uint32_t index_4msb = (mib->pdcch_ConfigSIB1.controlResourceSetZero);
uint32_t index_4lsb = (mib->pdcch_ConfigSIB1.searchSpaceZero);
type0_PDCCH_CSS_config->num_rbs = -1;
type0_PDCCH_CSS_config->num_symbols = -1;
type0_PDCCH_CSS_config->rb_offset = -1;
@@ -3683,22 +3645,25 @@ void get_type0_PDCCH_CSS_config_parameters(NR_Type0_PDCCH_CSS_config_t *type0_PD
min_channel_bw);
break;
}
type0_PDCCH_CSS_config->cset_start_rb = ssb_offset_point_a - type0_PDCCH_CSS_config->rb_offset;
LOG_D(NR_MAC,
"Coreset0: index_4msb=%d, num_rbs=%d, num_symb=%d, rb_offset=%d\n",
index_4msb,
type0_PDCCH_CSS_config->num_rbs,
type0_PDCCH_CSS_config->num_symbols,
type0_PDCCH_CSS_config->rb_offset);
}
AssertFatal(type0_PDCCH_CSS_config->num_rbs != -1,
"Type0 PDCCH coreset num_rbs undefined, index_4msb=%d, min_channel_bw %d, scs_ssb %d, scs_pdcch %d\n",
index_4msb,
min_channel_bw,
(int)scs_ssb,
(int)scs_pdcch);
AssertFatal(type0_PDCCH_CSS_config->num_symbols != -1, "Type0 PDCCH coreset num_symbols undefined");
AssertFatal(type0_PDCCH_CSS_config->rb_offset != -1, "Type0 PDCCH coreset rb_offset undefined");
void fill_type0_PDCCH_search_space_config(NR_Type0_PDCCH_CSS_config_t *type0_PDCCH_CSS_config,
const uint32_t index_4lsb,
const uint32_t scs_ssb,
const uint32_t scs_pdcch,
const uint32_t ssb_start_symbol,
const frequency_range_t frequency_range,
const uint32_t num_slot_per_frame,
const uint32_t ssb_period)
{
const uint8_t ssb_slot = ssb_start_symbol / 14;
// type0-pdcch search space
float big_o = 0.0f;
@@ -3850,8 +3815,87 @@ void get_type0_PDCCH_CSS_config_parameters(NR_Type0_PDCCH_CSS_config_t *type0_PD
type0_PDCCH_CSS_config->search_space_frame_period = ssb_period * slots_per_frame;
}
AssertFatal(type0_PDCCH_CSS_config->slot != UINT_MAX, "type0_PDCCH_CSS_config slot not configured");
}
channel_bandwidth_t get_type0_PDCCH_min_channel_bw(const int nr_band)
{
// according to Table 5.3.5-1 in 38.104
// band 79 is the only one which minimum is 40
// for all the other channels it is either 10 or 5
// and there is no difference between the two for this implementation so it is set it to 10
if (nr_band == 79)
return bw_40MHz;
else
return bw_10MHz;
}
NR_SubcarrierSpacing_t get_type0_PDCCH_scs(const frequency_range_t frequency_range, const long scs_common)
{
if (frequency_range == FR2) {
if (scs_common == NR_MIB__subCarrierSpacingCommon_scs15or60)
return NR_SubcarrierSpacing_kHz60;
else
return NR_SubcarrierSpacing_kHz120;
} else if (frequency_range == FR1) {
if (scs_common == NR_MIB__subCarrierSpacingCommon_scs15or60)
return NR_SubcarrierSpacing_kHz15;
else
return NR_SubcarrierSpacing_kHz30;
} else
AssertFatal(false, "Invalid frequency range %d\n", frequency_range);
}
void get_type0_PDCCH_CSS_config_parameters(NR_Type0_PDCCH_CSS_config_t *type0_PDCCH_CSS_config,
frame_t frameP,
const NR_MIB_t *mib,
uint8_t num_slot_per_frame,
uint8_t ssb_subcarrier_offset,
uint16_t ssb_start_symbol,
NR_SubcarrierSpacing_t scs_ssb,
frequency_range_t frequency_range,
int nr_band,
int grid_size,
uint32_t ssb_index,
uint32_t ssb_period,
uint32_t ssb_offset_point_a)
{
const NR_SubcarrierSpacing_t scs_pdcch = get_type0_PDCCH_scs(frequency_range, mib->subCarrierSpacingCommon);
const channel_bandwidth_t min_channel_bw = get_type0_PDCCH_min_channel_bw(nr_band);
type0_PDCCH_CSS_config->scs_pdcch = scs_pdcch;
type0_PDCCH_CSS_config->ssb_index = ssb_index;
type0_PDCCH_CSS_config->frame = frameP;
bool is_condition_A = (ssb_subcarrier_offset == 0); // 38.213 ch.13
uint32_t index_4msb = (mib->pdcch_ConfigSIB1.controlResourceSetZero);
uint32_t index_4lsb = (mib->pdcch_ConfigSIB1.searchSpaceZero);
fill_type0_PDCCH_coreset_config(type0_PDCCH_CSS_config,
scs_ssb,
scs_pdcch,
index_4msb,
min_channel_bw,
is_condition_A,
ssb_offset_point_a);
AssertFatal(type0_PDCCH_CSS_config->num_rbs != -1,
"Type0 PDCCH coreset num_rbs undefined, index_4msb=%d, min_channel_bw %d, scs_ssb %d, scs_pdcch %d\n",
index_4msb,
min_channel_bw,
(int)scs_ssb,
(int)scs_pdcch);
AssertFatal(type0_PDCCH_CSS_config->num_symbols != -1, "Type0 PDCCH coreset num_symbols undefined");
AssertFatal(type0_PDCCH_CSS_config->rb_offset != -1, "Type0 PDCCH coreset rb_offset undefined");
fill_type0_PDCCH_search_space_config(type0_PDCCH_CSS_config,
index_4lsb,
scs_ssb,
scs_pdcch,
ssb_start_symbol,
frequency_range,
num_slot_per_frame,
ssb_period);
type0_PDCCH_CSS_config->cset_start_rb = ssb_offset_point_a - type0_PDCCH_CSS_config->rb_offset;
AssertFatal(type0_PDCCH_CSS_config->cset_start_rb >= 0,
"Invalid CSET0 start PRB %d SSB offset point A %d RB offset %d\n",
type0_PDCCH_CSS_config->cset_start_rb,

View File

@@ -207,6 +207,18 @@ uint32_t nr_compute_tbslbrm(uint16_t table,
uint16_t nb_rb,
uint8_t Nl);
channel_bandwidth_t get_type0_PDCCH_min_channel_bw(const int nr_band);
NR_SubcarrierSpacing_t get_type0_PDCCH_scs(const frequency_range_t frequency_range, const long scs_common);
void fill_type0_PDCCH_coreset_config(NR_Type0_PDCCH_CSS_config_t *type0_PDCCH_CSS_config,
const uint32_t scs_ssb,
const uint32_t scs_pdcch,
const uint32_t index_4msb,
const channel_bandwidth_t min_channel_bw,
const bool is_condition_A,
const uint32_t ssb_offset_point_a);
void get_type0_PDCCH_CSS_config_parameters(NR_Type0_PDCCH_CSS_config_t *type0_PDCCH_CSS_config,
frame_t frameP,
const NR_MIB_t *mib,

View File

@@ -102,7 +102,33 @@ static void set_tdd_config_nr_ue(fapi_nr_tdd_table_t *tdd_table, const frame_str
}
}
static void config_common_ue_sa(NR_UE_MAC_INST_t *mac, NR_ServingCellConfigCommonSIB_t *scc, int cc_idP)
static uint32_t get_pointA_frequency(const int arfcn_ssb,
const int k_ssb,
const int offsetToPointA,
const int system_mu,
const int scc_common,
const int nr_band,
const frequency_range_t fr)
{
const uint32_t ssb_center = from_nrarfcn(nr_band, system_mu, arfcn_ssb) / 1000;
const uint32_t ssb_prbs = 20;
const uint32_t scs_khz = MU_SCS(system_mu);
const uint32_t ssb_start = ssb_center - (ssb_prbs / 2 * NR_NB_SC_PER_RB * scs_khz);
uint32_t pointA;
if (fr == FR1) {
const uint32_t ssb_crb_start = ssb_start - ((k_ssb >> system_mu) * scs_khz);
pointA = ssb_crb_start - (((offsetToPointA * NR_NB_SC_PER_RB) >> system_mu) * scs_khz);
} else {
AssertFatal(system_mu >= 2, "Invalid numerology %d for FR2\n", system_mu);
/* for FR2, mu of k_ssb is subCarrierSpacingCommon as specified in 38.211 7.4.3.1 */
const uint32_t ssb_crb_start = ssb_start - ((k_ssb >> (system_mu - scc_common)) * scs_khz);
/* FR2, offsetToPointA represented as 60kHz SCS */
pointA = ssb_crb_start - (((offsetToPointA * NR_NB_SC_PER_RB) >> (system_mu - 2)) * scs_khz);
}
return pointA;
}
static void config_common_ue_sa(NR_UE_MAC_INST_t *mac, NR_ServingCellConfigCommonSIB_t *scc, int cc_idP, const int arfcn_ssb)
{
fapi_nr_config_request_t *cfg = &mac->phy_config.config_req;
mac->phy_config.Mod_id = mac->ue_id;
@@ -119,18 +145,31 @@ static void config_common_ue_sa(NR_UE_MAC_INST_t *mac, NR_ServingCellConfigCommo
int bw_index = get_supported_band_index(frequencyInfoDL->scs_SpecificCarrierList.list.array[0]->subcarrierSpacing,
mac->frequency_range,
frequencyInfoDL->scs_SpecificCarrierList.list.array[0]->carrierBandwidth);
SETBIT(cfg->config_mask, PHY_CONFIG_BIT_MASK_CARRIER);
cfg->carrier_config.dl_bandwidth = get_supported_bw_mhz(mac->frequency_range, bw_index);
/** Only set frequency if not already initialized (e.g., from handover reconfigurationWithSync)
* MAC maintains its own frequency state, don't overwrite it with command-line parameter which
* is related to the initial cell selection. */
if (cfg->carrier_config.dl_frequency == 0) {
// Initial cell selection: derive from command-line parameter
uint64_t dl_bw_khz = (12 * frequencyInfoDL->scs_SpecificCarrierList.list.array[0]->carrierBandwidth) *
(15 << frequencyInfoDL->scs_SpecificCarrierList.list.array[0]->subcarrierSpacing);
cfg->carrier_config.dl_frequency = mac->dl_frequency / 1000 - (dl_bw_khz >> 1);
// Initial cell selection: derive from SIB1 parameter
const frequency_range_t fr = mac->frequency_range;
const int sccCommon = (fr == FR2) ? (2 + mac->mib->subCarrierSpacingCommon) : mac->mib->subCarrierSpacingCommon;
const uint32_t pointA = get_pointA_frequency(arfcn_ssb,
mac->ssb_subcarrier_offset,
frequencyInfoDL->offsetToPointA,
mac->numerology,
sccCommon,
mac->nr_band,
fr);
cfg->carrier_config.dl_frequency = pointA;
// Update cset0 start RB
NR_Type0_PDCCH_CSS_config_t *cset0 = &mac->type0_PDCCH_CSS_config;
// FR2, offsetToPointA represented as 60kHz SCS
const int offsetToPointA_mu = (fr == FR2) ? mac->numerology - 2 : mac->numerology;
cset0->cset_start_rb = (frequencyInfoDL->offsetToPointA >> offsetToPointA_mu) - cset0->rb_offset;
LOG_I(NR_MAC,
"[UE %d] Initial cell selection: dl_frequency=%u kHz (from command-line, band=%d, scs=%ld)\n",
"[UE %d] Initial cell selection: dl_frequency=%u kHz (from SIB1, band=%d, scs=%ld)\n",
mac->ue_id,
cfg->carrier_config.dl_frequency,
mac->nr_band,
@@ -195,11 +234,13 @@ static void config_common_ue_sa(NR_UE_MAC_INST_t *mac, NR_ServingCellConfigCommo
frame_type_t frame_type = get_frame_type(mac->nr_band, mac->numerology);
// cell config
SETBIT(cfg->config_mask, PHY_CONFIG_BIT_MASK_CELL);
cfg->cell_config.phy_cell_id = mac->physCellId;
cfg->cell_config.frame_duplex_type = frame_type;
cfg->cell_config.N_TA_offset = get_ta_offset(scc->n_TimingAdvanceOffset);
// SSB config
SETBIT(cfg->config_mask, PHY_CONFIG_BIT_MASK_SSB);
cfg->ssb_config.ss_pbch_power = scc->ss_PBCH_BlockPower;
cfg->ssb_config.scs_common = mac->numerology;
@@ -228,10 +269,12 @@ static void config_common_ue_sa(NR_UE_MAC_INST_t *mac, NR_ServingCellConfigCommo
&mac->frame_structure);
// TDD Table Configuration
SETBIT(cfg->config_mask, PHY_CONFIG_BIT_MASK_TDD);
if (cfg->cell_config.frame_duplex_type == TDD)
set_tdd_config_nr_ue(&cfg->tdd_table, &mac->frame_structure);
// PRACH configuration
SETBIT(cfg->config_mask, PHY_CONFIG_BIT_MASK_PRACH);
uint8_t nb_preambles = 64;
NR_RACH_ConfigCommon_t *rach_ConfigCommon = scc->uplinkConfigCommon->initialUplinkBWP.rach_ConfigCommon->choice.setup;
if(rach_ConfigCommon->totalNumberOfRA_Preambles != NULL)
@@ -437,6 +480,7 @@ static void config_common_ue(NR_UE_MAC_INST_t *mac, NR_ServingCellConfigCommon_t
AssertFatal(scc->downlinkConfigCommon, "Not expecting downlinkConfigCommon to be NULL here\n");
NR_FrequencyInfoDL_t *frequencyInfoDL = scc->downlinkConfigCommon->frequencyInfoDL;
SETBIT(cfg->config_mask, PHY_CONFIG_BIT_MASK_CARRIER);
if (frequencyInfoDL) { // NeedM for inter-freq handover
mac->nr_band = *frequencyInfoDL->frequencyBandList.list.array[0];
frame_type = get_frame_type(mac->nr_band, mac->numerology);
@@ -505,11 +549,13 @@ static void config_common_ue(NR_UE_MAC_INST_t *mac, NR_ServingCellConfigCommon_t
}
// cell config
SETBIT(cfg->config_mask, PHY_CONFIG_BIT_MASK_CELL);
cfg->cell_config.phy_cell_id = *scc->physCellId;
cfg->cell_config.frame_duplex_type = frame_type;
cfg->cell_config.N_TA_offset = get_ta_offset(scc->n_TimingAdvanceOffset);
// SSB config
SETBIT(cfg->config_mask, PHY_CONFIG_BIT_MASK_SSB);
cfg->ssb_config.ss_pbch_power = scc->ss_PBCH_BlockPower;
cfg->ssb_config.scs_common = *scc->ssbSubcarrierSpacing;
@@ -556,10 +602,12 @@ static void config_common_ue(NR_UE_MAC_INST_t *mac, NR_ServingCellConfigCommon_t
&mac->frame_structure);
// TDD Table Configuration
SETBIT(cfg->config_mask, PHY_CONFIG_BIT_MASK_TDD);
if (cfg->cell_config.frame_duplex_type == TDD)
set_tdd_config_nr_ue(&cfg->tdd_table, &mac->frame_structure);
// PRACH configuration
SETBIT(cfg->config_mask, PHY_CONFIG_BIT_MASK_PRACH);
uint8_t nb_preambles = 64;
if (scc->uplinkConfigCommon && scc->uplinkConfigCommon->initialUplinkBWP
&& scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon) { // all NeedM
@@ -1082,13 +1130,77 @@ static void update_mib_conf(NR_MIB_t *target, NR_MIB_t *source)
target->intraFreqReselection = source->intraFreqReselection;
}
void configure_ue_phy_for_sib1_reception(NR_UE_MAC_INST_t *mac, const int cc_id, const long ssb_arfcn)
{
const int ssb_scs = mac->numerology;
int ssb_sc_offset_norm;
if (mac->ssb_subcarrier_offset < 24 && mac->frequency_range == FR1)
ssb_sc_offset_norm = mac->ssb_subcarrier_offset >> ssb_scs;
else
ssb_sc_offset_norm = mac->ssb_subcarrier_offset;
const NR_SubcarrierSpacing_t scs_pdcch = get_type0_PDCCH_scs(mac->frequency_range, mac->mib->subCarrierSpacingCommon);
const channel_bandwidth_t min_ch_bw = get_type0_PDCCH_min_channel_bw(mac->nr_band);
const uint32_t index_4msb = (mac->mib->pdcch_ConfigSIB1.controlResourceSetZero);
NR_Type0_PDCCH_CSS_config_t dummy_cset0 = {0};
/* first we obtain RB offset of type 0 PDCCH from MIB */
fill_type0_PDCCH_coreset_config(&dummy_cset0, ssb_scs, scs_pdcch, index_4msb, min_ch_bw, (ssb_sc_offset_norm == 0), 0);
/* SC offset from current point A to CRB SSB start */
const int ssb_sc_crb_offset_point_a = mac->ssb_start_subcarrier - ssb_sc_offset_norm;
/* check if type0 PDCCH is within current bandwidth */
/* Here we don't consider cset_start_rb from NR_Type0_PDCCH_CSS_config_t becuase the varialbe has PRB granularity but
the UE could have arbitrary SC as the start RB. This is because the UE can start with a center frequency that is
not PRB aligned wrt the gNB. Hence, the following code uses type0 coreset start SC computed from current point A. */
int type0cset_start_sc = ssb_sc_crb_offset_point_a - dummy_cset0.rb_offset * NR_NB_SC_PER_RB;
int pointA_adj = 0;
if (type0cset_start_sc < 0) { // type 0 PDCCH coreset starts below current point A
pointA_adj = type0cset_start_sc;
type0cset_start_sc = 0; // adjusted start SC
} else {
/* check if cset0 start is PRB aligned with current point A. PHY can only handle PDCCH config with RB start wrt point A. */
pointA_adj = type0cset_start_sc % NR_NB_SC_PER_RB;
type0cset_start_sc -= pointA_adj;
}
AssertFatal(dummy_cset0.num_rbs <= mac->N_RB_DL, "Cannot receive SIB1 with current configured bandwidth %d\n", mac->N_RB_DL);
const int type0cset_stop_sc = type0cset_start_sc + dummy_cset0.num_rbs * NR_NB_SC_PER_RB;
if (type0cset_stop_sc > mac->N_RB_DL * NR_NB_SC_PER_RB) // type 0 PDCCH coreset goes beyond current bw
pointA_adj += type0cset_stop_sc - mac->N_RB_DL * NR_NB_SC_PER_RB;
if (pointA_adj == 0) // no need to change carrier freq
return;
LOG_I(NR_MAC, "Current SSB ARFCN %ld\n", ssb_arfcn);
LOG_I(NR_MAC, "Adjusting center frequency by %d sub carriers\n", pointA_adj);
const uint32_t ssb_abs_freq = from_nrarfcn(mac->nr_band, ssb_scs, ssb_arfcn) / 1000; // in khz
const uint32_t ssb_rbs = 20;
const uint32_t scs_khz = MU_SCS(ssb_scs);
const uint32_t ssb_start_abs_freq = ssb_abs_freq - ssb_rbs / 2 * NR_NB_SC_PER_RB * scs_khz;
const uint32_t pointA_abs_current = ssb_start_abs_freq - mac->ssb_start_subcarrier * scs_khz;
const uint32_t pointA_abs_new = pointA_abs_current + pointA_adj * scs_khz;
/* set new center frequency to receive SIB1 */
fapi_nr_config_request_t *cfg = &mac->phy_config.config_req;
cfg->carrier_config.dl_frequency = pointA_abs_new;
cfg->carrier_config.uplink_frequency = cfg->carrier_config.dl_frequency;
/* send sync request so PHY can sync again with new carrier freq */
mac->synch_request.Mod_id = mac->ue_id;
mac->synch_request.CC_id = cc_id;
fapi_nr_synch_request_t s = {.target_Nid_cell = mac->physCellId, .ssb_bw_scan = false, .ssb_arfcn = ssb_arfcn};
mac->synch_request.synch_req = s;
mac->if_module->synch_request(&mac->synch_request);
mac->if_module->phy_config_request(&mac->phy_config);
}
static bool is_cset0_present(frequency_range_t const fr, uint8_t const kssb)
{
// TS 38.213 4.1 defines if CORESET 0 is present or not based on Kssb
return (fr == FR1) ? (kssb < 24) : (kssb < 12);
}
void nr_rrc_mac_sched_sib(module_id_t module_id, int sched_sib)
void nr_rrc_mac_sched_sib(module_id_t module_id, int cc_idP, int sched_sib, const long ssb_arfcn)
{
NR_UE_MAC_INST_t *mac = get_mac_inst(module_id);
if (sched_sib == 1) {
@@ -1098,6 +1210,8 @@ void nr_rrc_mac_sched_sib(module_id_t module_id, int sched_sib)
} else if (sched_sib > 1)
mac->get_otherSI[sched_sib - 2] = true;
if (mac->get_sib1)
configure_ue_phy_for_sib1_reception(mac, cc_idP, ssb_arfcn);
if (mac->state == UE_NOT_SYNC && mac->get_sib1)
mac->state = UE_RECEIVING_SIB;
}
@@ -1973,7 +2087,7 @@ static void configure_si_schedulingInfo(NR_UE_MAC_INST_t *mac,
}
}
void nr_rrc_mac_config_req_sib1(module_id_t module_id, int cc_idP, NR_SIB1_t *sib1, bool can_start_ra)
void nr_rrc_mac_config_req_sib1(module_id_t module_id, int cc_idP, NR_SIB1_t *sib1, bool can_start_ra, int ssb_arfcn)
{
NR_UE_MAC_INST_t *mac = get_mac_inst(module_id);
int ret = pthread_mutex_lock(&mac->if_mutex);
@@ -1989,7 +2103,7 @@ void nr_rrc_mac_config_req_sib1(module_id_t module_id, int cc_idP, NR_SIB1_t *si
UPDATE_IE(mac->tdd_UL_DL_ConfigurationCommon, scc->tdd_UL_DL_ConfigurationCommon, NR_TDD_UL_DL_ConfigCommon_t);
configure_si_schedulingInfo(mac, si_SchedulingInfo, si_SchedulingInfo_v1700);
config_common_ue_sa(mac, scc, cc_idP);
config_common_ue_sa(mac, scc, cc_idP, ssb_arfcn);
// Build the list of all the valid/transmitted SSBs according to the config
LOG_D(NR_MAC, "Build SSB list\n");
@@ -2013,6 +2127,17 @@ void nr_rrc_mac_config_req_sib1(module_id_t module_id, int cc_idP, NR_SIB1_t *si
if (mac->state == UE_RECEIVING_SIB && can_start_ra)
mac->state = UE_PERFORMING_RA;
const int new_ssb_start_sc = get_ssb_first_sc(mac->phy_config.config_req.carrier_config.dl_frequency,
from_nrarfcn(mac->nr_band, mac->numerology, ssb_arfcn) / 1000,
mac->numerology);
/* send sync request only if center frequency changes */
if (new_ssb_start_sc != mac->ssb_start_subcarrier) {
mac->synch_request.Mod_id = mac->ue_id;
mac->synch_request.CC_id = cc_idP;
fapi_nr_synch_request_t s = {.target_Nid_cell = mac->physCellId, .ssb_bw_scan = false, .ssb_arfcn = ssb_arfcn};
mac->synch_request.synch_req = s;
mac->if_module->synch_request(&mac->synch_request);
}
mac->if_module->phy_config_request(&mac->phy_config);
mac->phy_config.config_req.ntn_config.params_changed = false;
ret = pthread_mutex_unlock(&mac->if_mutex);

View File

@@ -586,6 +586,8 @@ typedef struct NR_UE_MAC_INST_s {
int ssb_start_subcarrier;
uint64_t dl_frequency;
int numerology;
/// Initial bandwidth set in PHY
uint16_t N_RB_DL;
NR_SSB_meas_t ssb_measurements[MAX_NB_SSB];
NR_CSIRS_meas_t csirs_measurements;

View File

@@ -63,8 +63,8 @@ void nr_rrc_mac_config_req_cg(module_id_t module_id,
NR_UE_NR_Capability_t *ue_Capability);
void nr_rrc_mac_config_req_mib(module_id_t module_id, int cc_idP, NR_MIB_t *mibP, bool barred);
void nr_rrc_mac_sched_sib(module_id_t module_id, int sched_sib);
void nr_rrc_mac_config_req_sib1(module_id_t module_id, int cc_idP, NR_SIB1_t *sib1, bool can_start_ra);
void nr_rrc_mac_sched_sib(module_id_t module_id, int cc_idP, int sched_sib, long ssb_arfcn);
void nr_rrc_mac_config_req_sib1(module_id_t module_id, int cc_idP, NR_SIB1_t *sib1, bool can_start_ra, int ssb_arfcn);
struct position; /* forward declaration */
void nr_rrc_mac_config_other_sib(module_id_t module_id, NR_SIB19_r17_t *sib19_r17, int hfn, int frame, bool can_start_ra);

View File

@@ -155,6 +155,7 @@ void nr_ue_decode_mib(NR_UE_MAC_INST_t *mac, int cc_id)
mac->synch_request.Mod_id = mac->ue_id;
mac->synch_request.CC_id = cc_id;
mac->synch_request.synch_req.target_Nid_cell = -1;
mac->synch_request.synch_req.ssb_bw_scan = true; // scan according to cmd line option
mac->if_module->synch_request(&mac->synch_request);
return;
}

View File

@@ -549,6 +549,7 @@ static const plmn_data_t plmn_data[] = {
{208, 13, "Vivendi", "SFR FR"},
{208, 14, "Iliad", "Free Mobile FR"},
{208, 15, "Iliad", "Free Mobile FR"},
{208, 16, "Iliad", "Free Mobile FR"},
{208, 20, "Bouygues Telecom", "Bouygues FR"},
{208, 21, "Bouygues Telecom", "Bouygues FR"},
{208, 88, "Bouygues Telecom (Zones Blanches)", "Bouygues FR"},

View File

@@ -134,7 +134,8 @@ void process_msg_rcc_to_mac(nr_mac_rrc_message_t *msg, int instance_id)
case NR_MAC_RRC_CONFIG_SIB1: {
NR_SIB1_t *sib1 = msg->payload.config_sib1.sib1;
bool can_start_ra = msg->payload.config_sib1.can_start_ra;
nr_rrc_mac_config_req_sib1(instance_id, 0, sib1, can_start_ra);
int ssb_arfcn = msg->payload.config_sib1.ssb_arfcn;
nr_rrc_mac_config_req_sib1(instance_id, 0, sib1, can_start_ra, ssb_arfcn);
SEQUENCE_free(&asn_DEF_NR_SIB1, msg->payload.config_sib1.sib1, ASFM_FREE_EVERYTHING);
} break;
case NR_MAC_RRC_CONFIG_OTHER_SIB: {
@@ -145,7 +146,7 @@ void process_msg_rcc_to_mac(nr_mac_rrc_message_t *msg, int instance_id)
msg->payload.config_other_sib.can_start_ra);
} break;
case NR_MAC_RRC_SCHED_SIB:
nr_rrc_mac_sched_sib(instance_id, msg->payload.sched_sib.get_sib);
nr_rrc_mac_sched_sib(instance_id, 0, msg->payload.sched_sib.get_sib, msg->payload.sched_sib.ssb_arfcn);
break;
case NR_MAC_RRC_RESUME_RB:
nr_rrc_mac_resume_rb(instance_id, msg->payload.resume_rb.is_srb, msg->payload.resume_rb.rb_id);

View File

@@ -21,6 +21,7 @@
#include "NR_UL-DCCH-Message.h"
#include "uper_encoder.h"
#include "uper_decoder.h"
#include "NR_PLMN-Identity.h"
#include "rrc_defs.h"
#include "rrc_proto.h"
@@ -364,7 +365,7 @@ static void nr_decode_SI(NR_UE_RRC_SI_INFO *SI_info, NR_SystemInformation_t *si,
static void nr_rrc_ue_prepare_RRCSetupRequest(NR_UE_RRC_INST_t *rrc)
{
LOG_D(NR_RRC, "Generation of RRCSetupRequest\n");
LOG_A(NR_RRC, "Generation of RRCSetupRequest\n");
uint8_t rv[6];
// Get RRCConnectionRequest, fill random for now
// Generate random byte stream for contention resolution
@@ -464,6 +465,46 @@ static void nr_rrc_process_sib1(NR_UE_RRC_INST_t *rrc, NR_UE_RRC_SI_INFO *SI_inf
xer_fprint(stdout, &asn_DEF_NR_SIB1, (const void *) sib1);
LOG_A(NR_RRC, "SIB1 decoded\n");
// Print all PLMN in SIB1.
const int n = sib1->cellAccessRelatedInfo.plmn_IdentityInfoList.list.count;
for (int i = 0; i < n; ++i) {
struct NR_PLMN_IdentityInfo__plmn_IdentityList *PLMN_identityInfoList =
&sib1->cellAccessRelatedInfo.plmn_IdentityInfoList.list.array[i]->plmn_IdentityList;
for (int i2 = 0; i2 < PLMN_identityInfoList->list.count; i2++) {
NR_PLMN_Identity_t *PLMN_id = PLMN_identityInfoList->list.array[i2];
int mccdigits = PLMN_id->mcc->list.count;
int mncdigits = PLMN_id->mnc.list.count;
int mcc;
if (mccdigits == 2) {
mcc = *PLMN_id->mcc->list.array[0] * 10 + *PLMN_id->mcc->list.array[1];
} else {
mcc = *PLMN_id->mcc->list.array[0] * 100 + *PLMN_id->mcc->list.array[1] * 10 + *PLMN_id->mcc->list.array[2];
}
int mnc;
if (mncdigits == 2) {
mnc = *PLMN_id->mnc.list.array[0] * 10 + *PLMN_id->mnc.list.array[1];
} else {
mnc = *PLMN_id->mnc.list.array[0] * 100 + *PLMN_id->mnc.list.array[1] * 10 + *PLMN_id->mnc.list.array[2];
}
LOG_A(NR_RRC, "PLMN %d.%d MCC %0*d, MNC %0*d\n", i + 1, i2 + 1, mccdigits, mcc, mncdigits, mnc);
// search internal table for provider name
const size_t num_plmn_data = sizeof(plmn_data) / sizeof(plmn_data[0]);
for (size_t plmn_ind = 0;; ++plmn_ind) {
if (plmn_ind == num_plmn_data) {
LOG_W(NR_RRC, "Did not find operator name from internal table for MCC %0*d, MNC %0*d\n", mccdigits, mcc, mncdigits, mnc);
break;
}
if ((plmn_data[plmn_ind].mcc == mcc) && (plmn_data[plmn_ind].mnc == mnc)) {
LOG_A(NR_RRC, "Found %s (name from internal table)\n", plmn_data[plmn_ind].oper_short);
break;
}
}
}
}
plmn_id_t *plmn_id = malloc_or_fail(sizeof(plmn_id_t));
/* selected_plmn_identity is one-indexed */
@@ -521,6 +562,7 @@ static void nr_rrc_process_sib1(NR_UE_RRC_INST_t *rrc, NR_UE_RRC_SI_INFO *SI_inf
nr_mac_rrc_config_sib1_t *config_sib1 = &rrc_msg.payload.config_sib1;
config_sib1->sib1 = sib1;
config_sib1->can_start_ra = !rrc->is_NTN_UE;
config_sib1->ssb_arfcn = rrc->arfcn_ssb;
nr_rrc_send_msg_to_mac(rrc, &rrc_msg);
}
@@ -1922,6 +1964,7 @@ static void nr_rrc_ue_decode_NR_BCCH_BCH_Message(NR_UE_RRC_INST_t *rrc,
nr_mac_rrc_message_t sib_msg = {0};
sib_msg.payload_type = NR_MAC_RRC_SCHED_SIB;
sib_msg.payload.sched_sib.get_sib = get_sib;
sib_msg.payload.sched_sib.ssb_arfcn = ssb_arfcn;
nr_rrc_send_msg_to_mac(rrc, &sib_msg);
}
} else {

View File

@@ -124,6 +124,29 @@ int check_ref_locked(usrp_state_t *s,size_t mboard) {
return ref_locked;
}
static int check_lo_locked(usrp_state_t *s, size_t channel)
{
std::vector<std::string> sensor_names = s->usrp->get_rx_sensor_names(channel);
bool lo_locked = false;
if (std::find(sensor_names.begin(), sensor_names.end(), "lo_locked") != sensor_names.end()) {
LOG_W(HW, "lo_locked sensor not present on this board\n");
return false;
}
for (int i = 0; i < 30; i++) {
lo_locked = s->usrp->get_rx_sensor("lo_locked", channel).to_bool();
if (lo_locked) {
LOG_I(HW, "LO Lock successful\n");
return true;
}
boost::this_thread::sleep(boost::posix_time::milliseconds(5));
}
LOG_W(HW, "LO Lock failed\n");
return false;
}
static int sync_to_gps(openair0_device_t *device)
{
//uhd::set_thread_priority_safe();
@@ -828,6 +851,13 @@ int trx_usrp_set_freq(openair0_device_t *device, openair0_config_t *openair0_cfg
s->usrp->set_tx_freq(tx_tune_req);
s->usrp->set_rx_freq(rx_tune_req);
for(int i=0; i<((int) s->usrp->get_rx_num_channels()); i++) {
openair0_config_t *cfg = device->openair0_cfg;
if (i < cfg->rx_num_channels) {
check_lo_locked(s, i);
}
}
return(0);
}