Merge branch 'integration_2025_w50' into 'develop'
Integration `2025.w50` * !3638 NR UE: calculate TA based on SIB19 information in NTN mode, if autonomous TA is not enabled * !3624 NR UE: improve handling of Handover procedures * !3807 doc: Update doc for IF setup * !3741 Update documenation for handover * !3798 Fix for computation of PRACH occasions and association period * !3808 Add symbol timing functions for NR_DL_FRAME_PARMS + optimization for slot timing counterparts Closes #981 See merge request oai/openairinterface5g!3806
This commit is contained in:
@@ -123,7 +123,7 @@ services:
|
||||
--rfsim --rfsimulator.prop_delay 20 --rfsimulator.options chanmod
|
||||
--rfsimulator.serveraddr 192.168.71.140
|
||||
--time-sync-I 0.1 --ntn-initial-time-drift -46
|
||||
--autonomous-ta --initial-fo 57340 --cont-fo-comp 2
|
||||
--initial-fo 57340 --cont-fo-comp 2
|
||||
--log_config.global_log_options level,nocolor,time
|
||||
--num-ul-actors 1
|
||||
depends_on:
|
||||
|
||||
+3
-1
@@ -352,7 +352,9 @@ These modes of operation are supported:
|
||||
- Formats 0,1,2,3, A1-A3, B1-B3
|
||||
* NTN
|
||||
- TA adjustemt based on ntn-Config-r17 information
|
||||
- Autonomous TA adjustemt between SIB19 receptions based on DL time tracking
|
||||
- Different TA adjustemt algorithms between SIB19 receptions:
|
||||
- Autonomous TA adjustemt based on DL time tracking
|
||||
- Standard compliant epoch time based TA adjustment including orbital propagation
|
||||
- UL Doppler pre-compensation based on continuous DL FO estimation
|
||||
* Highly efficient 3GPP compliant LDPC encoder and decoder (BG1 and BG2 are supported)
|
||||
* Highly efficient 3GPP compliant polar encoder and decoder
|
||||
|
||||
+23
-10
@@ -356,7 +356,9 @@ sudo ./ran_build/build/nr-uesoftmodem -O ../targets/PROJECTS/GENERIC-NR-5GC/CONF
|
||||
|
||||
For LEO satellite scenarios, the parameter `--ntn-initial-time-drift` must be provided via command line, as the UE needs this value to compensate for the time drift during initial sync, before SIB19 was received.
|
||||
This parameter provides the drift rate of the complete DL timing (incl. feeder link and service link) in µs/s.
|
||||
Also, to perform an autonomous TA update based on the DL drift, the boolean parameter `--autonomous-ta` should be added in case of a LEO satellite scenario.
|
||||
|
||||
To perform an autonomous TA update based on the DL drift, the boolean parameter `--autonomous-ta` can be added.
|
||||
If that parameter is omitted, the TA is continuously computed based on the SIB19 information.
|
||||
|
||||
For LEO satellite scenario we assume the LO to be very accurate and the main FO contribution comes from Doppler shift.
|
||||
Therefore, we use the command line parameter `--cont-fo-comp 2` to continuously compensate the DL Doppler and pre-compensate the UL Doppler.
|
||||
@@ -367,7 +369,7 @@ For other information on optional NR UE command line options, please refer [here
|
||||
So an example NR UE command for FDD, 5MHz BW, 15 kHz SCS, transparent LEO satellite 5G NR NTN is this:
|
||||
```
|
||||
cd cmake_targets
|
||||
sudo ./ran_build/build/nr-uesoftmodem -O ../targets/PROJECTS/GENERIC-NR-5GC/CONF/ue.conf --band 254 -C 2488400000 --CO -873500000 -r 25 --numerology 0 --ssb 60 --rfsim --rfsimulator.prop_delay 20 --rfsimulator.options chanmod --time-sync-I 0.1 --ntn-initial-time-drift -46 --autonomous-ta --initial-fo 57340 --cont-fo-comp 2
|
||||
sudo ./ran_build/build/nr-uesoftmodem -O ../targets/PROJECTS/GENERIC-NR-5GC/CONF/ue.conf --band 254 -C 2488400000 --CO -873500000 -r 25 --numerology 0 --ssb 60 --rfsim --rfsimulator.prop_delay 20 --rfsimulator.options chanmod --time-sync-I 0.1 --ntn-initial-time-drift -46 --initial-fo 57340 --cont-fo-comp 2
|
||||
```
|
||||
|
||||
# Specific OAI modes
|
||||
@@ -468,19 +470,30 @@ The hardcoded DRBs will be treated like GBR Flows. Due to code limitations at th
|
||||
|
||||
## IF setup with OAI
|
||||
|
||||
OAI is also compatible with Intermediate Frequency (IF) equipment. This allows to use RF front-end that with arbitrary frequencies bands that do not comply with the standardised 3GPP NR bands.
|
||||
OAI is also compatible with Intermediate Frequency (IF) equipment, allowing the
|
||||
use of RF front-ends operating on arbitrary frequency bands that do not conform
|
||||
to the standardized 3GPP NR bands.
|
||||
|
||||
To configure the IF frequencies it is necessary to use two command-line options at UE side:
|
||||
- `if_freq`, downlink frequency in Hz
|
||||
- `if_freq_off`, uplink frequency offset in Hz
|
||||
### OAIUE configuration
|
||||
To configure IF frequencies on the UE side, provide the following command-line
|
||||
options:
|
||||
- `if_freq`: DL frequency in Hz
|
||||
- `if_freq_off`: UL frequency offset in Hz
|
||||
|
||||
Accordingly, the following parameters must be configured in the RUs section of the gNB configuration file:
|
||||
- `if_freq`
|
||||
- `if_offset`
|
||||
### gNB configuration
|
||||
On the gNB side, the corresponding parameters must be set in the RUs section of
|
||||
the configuration file:
|
||||
- `if_freq`: DL frequency in Hz
|
||||
- `if_offset`: UL frequency offset in Hz
|
||||
|
||||
> Note: When using a libconfig-based configuration file for the gNB, ensure that
|
||||
> `if_freq` numeric value is suffixed with "L" so it is correctly parsed as
|
||||
> 64-bit integer.
|
||||
|
||||
### Run OAI with custom DL/UL arbitrary frequencies
|
||||
|
||||
The following example uses DL frequency 2169.080 MHz and UL frequency offset -400 MHz, with a configuration file for band 66 (FDD) at gNB side.
|
||||
The following example uses DL frequency 2169.080 MHz and UL frequency offset
|
||||
-400 MHz, with a configuration file for band 66 (FDD) at gNB side.
|
||||
|
||||
On two separate machines with USRPs, run:
|
||||
|
||||
|
||||
+150
-164
@@ -1,6 +1,15 @@
|
||||
This tutorial explains how to perform handovers. It covers both F1 handovers
|
||||
(intra-gNB, within a single gNB between DUs) and N2 handovers (inter-gNB).
|
||||
|
||||
This document assumes familiarity with the F1 split architecture and basic
|
||||
OAI knowledge. Please refer to the prerequisite documentation listed below:
|
||||
|
||||
- To run the [Core Network](https://gitlab.eurecom.fr/oai/openairinterface5g/-/blob/develop/doc/NR_SA_Tutorial_OAI_CN5G.md)
|
||||
- To run [OAI full stack with COTS UE](https://gitlab.eurecom.fr/oai/openairinterface5g/-/blob/develop/doc/NR_SA_Tutorial_COTS_UE.md)
|
||||
- [F1 split design document](https://gitlab.eurecom.fr/oai/openairinterface5g/-/blob/develop/doc/F1AP/F1-design.md?ref_type=heads)
|
||||
for details on the F1 architecture and the networking relationships between
|
||||
the CU and the associated DUs.
|
||||
|
||||
[[_TOC_]]
|
||||
|
||||
# Considered setup for F1 handover
|
||||
@@ -13,22 +22,22 @@ same.
|
||||
|
||||

|
||||
|
||||
# What is a gNB neighbor?
|
||||
# gNB neighbour definition
|
||||
|
||||
Network continuity is a key aspect of 5G. In the 5G architecture, gNB neighbors
|
||||
Network continuity is a key aspect of 5G. In the 5G architecture, gNB neighbours
|
||||
play a central role in maintaining service continuity through mechanisms such
|
||||
as handover and load balancing. By definition, a gNB neighbor is another gNB
|
||||
as handover and load balancing. By definition, a gNB neighbour is another gNB
|
||||
that can be measured and linked by the UE. If the current serving gNB is no
|
||||
longer optimal, the UE may connect to a neighbor gNB.
|
||||
longer optimal, the UE may connect to a neighbour gNB.
|
||||
|
||||
To support this behavior, the network configuration specifies additional frequencies
|
||||
and cells that the UE should measure. The UE reports these measurements to the
|
||||
network, which then decides whether or not to initiate a handover.
|
||||
|
||||
Neighbor types include:
|
||||
- **Intra-gNB neighbors** - cells belonging to the same gNB
|
||||
- **Inter-gNB neighbors** - cells belonging to different gNBs
|
||||
- **Inter-RAT neighbors** - cells belonging to another RAT (e.g., LTE)
|
||||
Neighbour types include:
|
||||
- **Intra-gNB neighbours** - cells belonging to the same gNB
|
||||
- **Inter-gNB neighbours** - cells belonging to different gNBs
|
||||
- **Inter-RAT neighbours** - cells belonging to another RAT (e.g., LTE)
|
||||
|
||||
# Steps to run F1 handover with OAI UE
|
||||
|
||||
@@ -46,10 +55,6 @@ build both gNB and UE as well as activate the build of telnet to that purpose:
|
||||
|
||||
## Run the setup
|
||||
|
||||
This tutorial assumes you have a core network running; [refer to the
|
||||
corresponding tutorial](./NR_SA_Tutorial_OAI_CN5G.md) if this is not the case
|
||||
yet.
|
||||
|
||||
We will use the TDD configuration files in the repository for the
|
||||
[CU](../targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-cu.sa.f1.conf) as well for
|
||||
[DU0](../targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-du.sa.band78.106prb.rfsim.pci0.conf)
|
||||
@@ -139,19 +144,23 @@ directory of the CU.
|
||||
You can do handover across DUs with a COTS UE. Note that these DUs should be
|
||||
separated by at least multiple meters to ensure that the UE will receive
|
||||
different signal strengths when moving between cells.
|
||||
In the CI setup we use a digital 4 channel attenuator that allows us to "control"
|
||||
the transmitted signal from both RUs. This allows us to create a setup in
|
||||
which the UE thinks it's changing positions between 2 cells, but in reality
|
||||
it's not moving.
|
||||
|
||||
We support both intra-frequency and inter-frequency handovers. We have verified with USRPs
|
||||
only, although other radios should work as well.
|
||||
We support both intra-frequency and inter-frequency handovers. We have verified
|
||||
with USRPs only, although other radios should work as well.
|
||||
|
||||
For UEs, we verified Quectel modules and iPhones. Note, though, that not all
|
||||
phones might work; for instance, we did not achieve handovers with a OnePlus
|
||||
Nord, yet.
|
||||
For UEs, we verified Quectel modules, iPhones and Samsung S23 Ultra. Note,
|
||||
though, that not all phones might work; for instance, we did not achieve
|
||||
handovers with a OnePlus Nord, yet.
|
||||
|
||||
## Steps
|
||||
|
||||
First, make sure that you can run both DUs with the CU independently. Use the
|
||||
same radio hardware for both radios to ensure that both cells can be received
|
||||
equally good by the UE.
|
||||
First, make sure that you can run both DUs with the CU independently.
|
||||
Use the same radio hardware for both radios to ensure that both cells can be
|
||||
received equally good by the UE.
|
||||
|
||||
In order to enable handovers (triggered by the UE), you have to configure the
|
||||
neighbour relation of the DUs at the CU. To do so, proceed as follows:
|
||||
@@ -163,11 +172,13 @@ neighbour relation of the DUs at the CU. To do so, proceed as follows:
|
||||
```
|
||||
cat nrRRC_stats.log
|
||||
```
|
||||
1. Fill in the [`neighbour-config.conf`](../ci-scripts/conf_files/neighbour-config.conf) configuration file as shown below, and
|
||||
`@include` it in the CU file.
|
||||
1. Start the CU and both DUs.
|
||||
1. Fill in the [`neighbour-config.conf`](../ci-scripts/conf_files/neighbour-config.conf)
|
||||
configuration file as shown below, and `@include` it in the CU file.
|
||||
1. Start the CU and both DUs. If you are using an attenuator, make sure that
|
||||
the signal on one DU is stronger than the other.
|
||||
|
||||
1. Bring the phone close to one cell, and leave flight mode. It should connect
|
||||
to the DU to which it is closer.
|
||||
to the DU to which it is closer/stronger signal.
|
||||
1. Move the UE towards the other DU; it should trigger an "A3 event" (Neighbour
|
||||
Becomes Better than Serving), and the CU will trigger the handover to the
|
||||
other DU.
|
||||
@@ -175,7 +186,14 @@ neighbour relation of the DUs at the CU. To do so, proceed as follows:
|
||||
The output on the terminal should be the same as with RFsim. If no handover is
|
||||
triggered:
|
||||
|
||||
- Make sure that both DUs use the same hardware.
|
||||
- Make sure that both DUs use the same hardware. In case of USRPs, make sure that
|
||||
they are synched:
|
||||
- By connecting them to a GPS or an Octoclock to provide a common time and clock
|
||||
reference.
|
||||
- By synchronizing the RU hosts.
|
||||
- By using Openairinterface starting tag [2025.w42](https://gitlab.eurecom.fr/oai/openairinterface5g/-/tree/2025.w42?ref_type=tags)
|
||||
(A fix was added to force the USRP to "use" the time/clock provided by the
|
||||
external source instead to its own master clock. for more info see [MR](https://gitlab.eurecom.fr/oai/openairinterface5g/-/merge_requests/3693)).
|
||||
- Make sure that the UE sees both cells. For instance, you can switch to flight
|
||||
mode, go closer to the other DU, and switch off flight mode -- the UE should
|
||||
connect to that second DU.
|
||||
@@ -187,6 +205,17 @@ decision about a handover is always at the network-side, the UE only "assists"
|
||||
through measurements telling the CU that one DU is stronger than others.
|
||||
Hence, "forcing" a handover just means that you manually trigger the handover,
|
||||
instead of waiting for UE measurement report.)
|
||||
|
||||
Our CI setup consists of:
|
||||
- 2 USRPs B210 that are synchronized by connecting them to an Octoclock over
|
||||
10MHz refrence and a PPS signal. The RU hosts are synchronized via NTP.
|
||||
- Mini-Circuits RC4DAT-6G-60 programmable attenuator. To control the digital attenuator,
|
||||
a Python script was developed `ci-scripts/attenuatorctl.py`.
|
||||
- Quectel RM520 as a UE.
|
||||
- The setup is run using Docker `ci-scripts/yaml_files/5g_sa_f1_b210_ho`.
|
||||
|
||||
To run the setup using Docker:
|
||||
- We consider 2 synchronized servers. One for each DU.
|
||||
|
||||
## Example neighbour configuration
|
||||
|
||||
@@ -209,70 +238,100 @@ Concretely, the first cell is `12345678` (on DU `[2]`), and it has `11111111`
|
||||
|
||||
The below configuration further enables periodic measurements, A2 event
|
||||
("Serving becomes worse than threshold"), and A3 events ("Neighbour Becomes
|
||||
Better than Serving"). The A2 event can be disabled by setting `enable = 0`. A3
|
||||
events cannot be disabled as of now. Further, the A3 events can be made
|
||||
specific to cells; `cell_id = -1` means "any cell".
|
||||
Better than Serving").
|
||||
The A2 event can be disabled by setting `enable = 0`.
|
||||
The A3 event cannot be disabled as of now. It can be made
|
||||
specific to cells or set to `cell_id = -1` which means "any cell".
|
||||
|
||||
`hysteresis` is a margin added to the serving cell measurements to
|
||||
prevent unnecessary or frequent handovers. It ensures that the neighbouring
|
||||
cell must show sufficiently better signal quality before a handover is
|
||||
triggered. It is an integer between 0 and 30.
|
||||
|
||||
`timeToTrigger` the time during which specific criteria for the event
|
||||
needs to be met in order to trigger a measurement report. It is an enumerated
|
||||
parameter and in the configuration below it is set to 1 which corresponds to
|
||||
`ms40` or 40 milliseconds.
|
||||
|
||||
*Note*: For more information please refer to 3GPP TS 38.331 specifications.
|
||||
```
|
||||
neighbour_list = (
|
||||
{
|
||||
nr_cellid = 12345678;
|
||||
neighbour_cell_configuration = (
|
||||
{
|
||||
gNB_ID = 0xe01;
|
||||
nr_cellid = 11111111;
|
||||
physical_cellId = 1;
|
||||
absoluteFrequencySSB = 643296;
|
||||
subcarrierSpacing = 1; #30 KHz
|
||||
band = 78;
|
||||
plmn = { mcc = 001; mnc = 01; mnc_length = 2};
|
||||
tracking_area_code = 1;
|
||||
}
|
||||
)
|
||||
},
|
||||
{
|
||||
nr_cellid = 11111111;
|
||||
neighbour_cell_configuration = (
|
||||
{
|
||||
gNB_ID = 0xe00;
|
||||
nr_cellid = 12345678;
|
||||
physical_cellId = 0;
|
||||
absoluteFrequencySSB = 643296;
|
||||
subcarrierSpacing = 1; #30 KHz
|
||||
band = 78;
|
||||
plmn = { mcc = 001; mnc = 01; mnc_length = 2};
|
||||
tracking_area_code = 1;
|
||||
}
|
||||
)
|
||||
}
|
||||
);
|
||||
############################################################
|
||||
# gNB-to-gNB neighbour list + measurement configuration #
|
||||
# for the 2-cell rfsim setup (gNB_ID 0xe00 & 0xb00) #
|
||||
############################################################
|
||||
|
||||
neighbour_list = (
|
||||
##########################################################
|
||||
# Entry USED BY gNB_ID = 0xe00 (nr_cellid = 12345678L) #
|
||||
##########################################################
|
||||
{
|
||||
nr_cellid = 12345678; # Serving cell of gNB 0xe00
|
||||
neighbour_cell_configuration = (
|
||||
{
|
||||
gNB_ID = 0xe01;
|
||||
nr_cellid = 11111111; # Cell served by gNB 0xe01
|
||||
physical_cellId = 1;
|
||||
absoluteFrequencySSB = 643296;
|
||||
subcarrierSpacing = 1; # 30 kHz
|
||||
band = 77;
|
||||
plmn = { mcc = 001; mnc = 01; mnc_length = 2 };
|
||||
tracking_area_code = 1;
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
##########################################################
|
||||
# Entry USED BY gNB_ID = 0xe01 (nr_cellid = 11111111) #
|
||||
##########################################################
|
||||
{
|
||||
nr_cellid = 11111111; # Serving cell of gNB 0xe01
|
||||
neighbour_cell_configuration = (
|
||||
{
|
||||
gNB_ID = 0xe00;
|
||||
nr_cellid = 12345678L; # Cell served by gNB 0xe00
|
||||
physical_cellId = 0;
|
||||
absoluteFrequencySSB = 643296;
|
||||
subcarrierSpacing = 1; # 30 kHz
|
||||
band = 77;
|
||||
plmn = { mcc = 001; mnc = 01; mnc_length = 2 };
|
||||
tracking_area_code = 1;
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
############################################################
|
||||
# Common NR measurement-event configuration #
|
||||
############################################################
|
||||
|
||||
nr_measurement_configuration = {
|
||||
Periodical = {
|
||||
enable = 1;
|
||||
includeBeamMeasurements = 1;
|
||||
maxNrofRS_IndexesToReport = 4;
|
||||
enable = 1;
|
||||
includeBeamMeasurements = 1;
|
||||
maxNrofRS_IndexesToReport = 4;
|
||||
};
|
||||
|
||||
A2 = {
|
||||
enable = 1;
|
||||
threshold = 60;
|
||||
enable = 1;
|
||||
threshold = 60;
|
||||
timeToTrigger = 1;
|
||||
};
|
||||
|
||||
A3 = ({
|
||||
cell_id = -1; #Default
|
||||
offset = 10;
|
||||
hysteresis = 0;
|
||||
timeToTrigger = 1
|
||||
})
|
||||
A3 = (
|
||||
{
|
||||
cell_id = -1;
|
||||
offset = 10;
|
||||
hysteresis = 0;
|
||||
timeToTrigger = 1;
|
||||
}
|
||||
)
|
||||
};
|
||||
```
|
||||
|
||||
`@include` this configuration file inside the gNB section of CU file as shown below.
|
||||
|
||||
```
|
||||
plmn_list = ({ mcc = 222; mnc = 01; mnc_length = 2; snssaiList = ({ sst = 1, sd = 0xffffff })});
|
||||
plmn_list = ({ mcc = 001; mnc = 01; mnc_length = 2; snssaiList = ({ sst = 1, sd = 0xffffff })});
|
||||
|
||||
|
||||
@include "neighbour-config.conf"
|
||||
@@ -364,30 +423,37 @@ done
|
||||
|
||||
## Run the setup
|
||||
|
||||
An N2 handover involves the transfer of a UE from one gNB to another via the 5G core network. Unlike F1 handover, where the CU handles the process internally between its DUs, N2 handover requires signaling through the AMF, making it a core-network-based handover.
|
||||
An N2 handover involves the transfer of a UE from one gNB to another via the
|
||||
5G core network. Unlike F1 handover, where the CU handles the process internally
|
||||
between its DUs, N2 handover requires signaling through the AMF, making it
|
||||
a core-network-based handover.
|
||||
|
||||
We assume:
|
||||
|
||||
* Two independent gNBs connected to the same 5GC via N2 interface.
|
||||
* A UE initially connected to gNB-PCI0, which will be handed over to gNB-PCI1.
|
||||
* Handover is triggered by either a decision based measurement event (e.g. A3) or telnet command.
|
||||
* Handover is triggered by either a decision based measurement event (e.g. A3) or
|
||||
telnet command.
|
||||
|
||||
## Steps to run N2 handover with OAI UE
|
||||
|
||||
**Note for same-machine setup:** When running both gNBs on the same machine, you need to assign a unique IP address to the second gNB to avoid network conflicts. For example:
|
||||
**Note for same-machine setup:** When running both gNBs on the same machine,
|
||||
you need to assign a unique IP address to the second gNB to avoid network conflicts.
|
||||
For example:
|
||||
|
||||
```sh
|
||||
sudo ip addr add 192.168.71.180/24 dev rfsim5g-public
|
||||
```
|
||||
|
||||
1. Similarly to F1 handover, UE does not support any measurement reporting and handover is triggered by
|
||||
telnet command. Therefore, ensure that both gNBs and UE are built with telnet support:
|
||||
1. Similarly to F1 handover, UE does not support any measurement reporting and
|
||||
handover is triggered by telnet command. Therefore, ensure that both gNBs and
|
||||
UE are built with telnet support:
|
||||
|
||||
```sh
|
||||
./build_oai --ninja --nrUE --gNB --build-lib telnetsrv
|
||||
```
|
||||
|
||||
Run the 5G Core Network if not already running. See [OAI CN5G tutorial](./NR_SA_Tutorial_OAI_CN5G.md).
|
||||
Run the 5G Core Network if not already running.
|
||||
|
||||
2. Start the source gNB (gNB-PCI0) e.g.
|
||||
|
||||
@@ -409,7 +475,8 @@ Ensure the UE successfully registers with the network.
|
||||
sudo ./nr-softmodem -O ../../../targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.pci1.rfsim.conf --rfsim --telnetsrv --telnetsrv.shrmod ci --gNBs.[0].min_rxtxtime 6 --rfsimulator.serveraddr 127.0.0.1
|
||||
```
|
||||
|
||||
**Note for same-machine setup:** When running both gNBs on the same machine, add the following network interface options to the target gNB command, e.g.:
|
||||
**Note for same-machine setup:** When running both gNBs on the same machine,
|
||||
add the following network interface options to the target gNB command, e.g.:
|
||||
|
||||
```sh
|
||||
--gNBs.[0].NETWORK_INTERFACES.GNB_IPV4_ADDRESS_FOR_NG_AMF 192.168.71.180
|
||||
@@ -423,96 +490,15 @@ From gNB-PCI0, trigger handover on target gNB with PCI 1 for UE ID 1:
|
||||
```sh
|
||||
echo ci trigger_n2_ho 1,1 | nc 127.0.0.1 9090 && echo
|
||||
```
|
||||
where the input parameters correspond to the PCI of the neighbor cell and the RRC ID of the UE.
|
||||
where the input parameters correspond to the PCI of the neighbour cell and the RRC ID of the UE.
|
||||
|
||||
This will initiate the N2 handover on the source gNB.
|
||||
|
||||
## Neighbour list and measurement configuration
|
||||
|
||||
Make sure the configuration file contains a neighbour list and measurement configuration, e.g. [neighbour-config-rfsim.conf](../../ci-scripts/conf_files/neighbour-config.conf). This configuration can also be present in a different file and included in the gNB configuration file with `@include "neighbour-config-rfsim.conf"`.
|
||||
Make sure the configuration file contains a neighbour list and measurement configuration, e.g. [neighbour-config-rfsim.conf](../../ci-scripts/conf_files/neighbour-config.conf).
|
||||
This configuration can also be present in a different file and included in the gNB configuration file with `@include "neighbour-config-rfsim.conf"`.
|
||||
|
||||
For each gNB there is a `neighbour_cell_configuration` linked to its serving cell ID.
|
||||
|
||||
The measurement configuration is based on A2 and A3 measurement events in 5G NR. These events are used by the UE to report radio conditions to the gNB. The A2 Measurement Event indicates that the serving cell’s signal quality has degraded below a defined threshold and the UE shall initiate measurement of neighboring cells. The A3 Measurement Event indicates that a neighboring cell’s signal quality is better than that of the serving cell by a certain offset and the UE shall trigger handover to a stronger neighboring cell
|
||||
|
||||
This is an example with comments on how to use the configuration file:
|
||||
|
||||
```
|
||||
############################################################
|
||||
# gNB-to-gNB neighbour list + measurement configuration #
|
||||
# for the 2-cell rfsim setup (gNB_ID 0xe00 & 0xb00) #
|
||||
############################################################
|
||||
|
||||
neighbour_list = (
|
||||
##########################################################
|
||||
# Entry USED BY gNB_ID = 0xe00 (nr_cellid = 12345678L) #
|
||||
##########################################################
|
||||
{
|
||||
nr_cellid = 12345678L; # Serving cell of gNB 0xe00
|
||||
neighbour_cell_configuration = (
|
||||
{
|
||||
gNB_ID = 0xb00;
|
||||
nr_cellid = 720898; # Cell served by gNB 0xb00
|
||||
physical_cellId = 1;
|
||||
absoluteFrequencySSB= 621312;
|
||||
subcarrierSpacing = 1; # 30 kHz
|
||||
band = 78;
|
||||
plmn = { mcc = 208; mnc = 99; mnc_length = 2 };
|
||||
tracking_area_code = 1;
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
##########################################################
|
||||
# Entry USED BY gNB_ID = 0xb00 (nr_cellid = 720898) #
|
||||
##########################################################
|
||||
{
|
||||
nr_cellid = 720898; # Serving cell of gNB 0xb00
|
||||
neighbour_cell_configuration = (
|
||||
{
|
||||
gNB_ID = 0xe00;
|
||||
nr_cellid = 12345678L; # Cell served by gNB 0xe00
|
||||
physical_cellId = 0;
|
||||
absoluteFrequencySSB= 641280;
|
||||
subcarrierSpacing = 1; # 30 kHz
|
||||
band = 78;
|
||||
plmn = { mcc = 208; mnc = 99; mnc_length = 2 };
|
||||
tracking_area_code = 1;
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
############################################################
|
||||
# Common NR measurement-event configuration #
|
||||
############################################################
|
||||
|
||||
nr_measurement_configuration = {
|
||||
Periodical = {
|
||||
enable = 1;
|
||||
includeBeamMeasurements = 1;
|
||||
maxNrofRS_IndexesToReport = 4;
|
||||
};
|
||||
|
||||
A2 = {
|
||||
enable = 1;
|
||||
threshold = 60;
|
||||
timeToTrigger = 1;
|
||||
};
|
||||
|
||||
A3 = (
|
||||
{
|
||||
cell_id = 720898; # neighbour of gNB 0xe00
|
||||
offset = 10;
|
||||
hysteresis = 0;
|
||||
timeToTrigger = 1;
|
||||
},
|
||||
{
|
||||
cell_id = 12345678; # neighbour of gNB 0xb00
|
||||
offset = 5;
|
||||
hysteresis = 1;
|
||||
timeToTrigger = 2;
|
||||
}
|
||||
);
|
||||
};
|
||||
```
|
||||
See the example above for `neighbour-config-ho.conf`. The same configuration is for both F1 and N2 handover.
|
||||
|
||||
+15
-21
@@ -247,7 +247,7 @@ int connect_rau(RU_t *ru) {
|
||||
void fh_if5_south_out(RU_t *ru, int frame, int slot, uint64_t timestamp) {
|
||||
if (ru == RC.ru[0])
|
||||
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_TRX_TST, ru->proc.timestamp_tx & 0xffffffff);
|
||||
int offset = ru->nr_frame_parms->get_samples_slot_timestamp(slot,ru->nr_frame_parms,0);
|
||||
int offset = get_samples_slot_timestamp(ru->nr_frame_parms, slot);
|
||||
void *buffs[ru->nb_tx];
|
||||
for (int aid = 0; aid < ru->nb_tx; aid++)
|
||||
buffs[aid] = (void*)&ru->common.txdata[aid][offset];
|
||||
@@ -260,15 +260,9 @@ void fh_if5_south_out(RU_t *ru, int frame, int slot, uint64_t timestamp) {
|
||||
timestamp,
|
||||
buffs[0],
|
||||
buffs[1],
|
||||
10 * log10((double)signal_energy(buffs[0], ru->nr_frame_parms->get_samples_per_slot(slot, ru->nr_frame_parms))),
|
||||
10 * log10((double)signal_energy(buffs[0], get_samples_per_slot(slot, ru->nr_frame_parms))),
|
||||
(int)txmeas.tv_nsec);
|
||||
ru->ifdevice.trx_write_func2(&ru->ifdevice,
|
||||
timestamp,
|
||||
buffs,
|
||||
0,
|
||||
ru->nr_frame_parms->get_samples_per_slot(slot,ru->nr_frame_parms),
|
||||
0,
|
||||
ru->nb_tx);
|
||||
ru->ifdevice.trx_write_func2(&ru->ifdevice, timestamp, buffs, 0, get_samples_per_slot(slot, ru->nr_frame_parms), 0, ru->nb_tx);
|
||||
}
|
||||
|
||||
// southbound IF4p5 fronthaul
|
||||
@@ -295,11 +289,11 @@ void fh_if5_south_in(RU_t *ru,
|
||||
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_RECV_IF5, 1 );
|
||||
start_meas(&ru->rx_fhaul);
|
||||
|
||||
ru->ifdevice.trx_read_func2(&ru->ifdevice, &proc->timestamp_rx, NULL, fp->get_samples_per_slot(*tti, fp));
|
||||
ru->ifdevice.trx_read_func2(&ru->ifdevice, &proc->timestamp_rx, NULL, get_samples_per_slot(*tti, fp));
|
||||
if (proc->first_rx == 1)
|
||||
ru->ts_offset = proc->timestamp_rx;
|
||||
proc->frame_rx = ((proc->timestamp_rx - ru->ts_offset) / (fp->samples_per_subframe * 10)) & 1023;
|
||||
proc->tti_rx = fp->get_slot_from_timestamp(proc->timestamp_rx - ru->ts_offset, fp);
|
||||
proc->tti_rx = get_slot_from_timestamp(proc->timestamp_rx - ru->ts_offset, fp);
|
||||
|
||||
if (proc->first_rx == 0) {
|
||||
if (proc->tti_rx != *tti) {
|
||||
@@ -383,7 +377,7 @@ void fh_if4p5_south_in(RU_t *ru,
|
||||
//caculate timestamp_rx, timestamp_tx based on frame and subframe
|
||||
proc->tti_rx = sl;
|
||||
proc->frame_rx = f;
|
||||
proc->timestamp_rx = (proc->frame_rx * fp->samples_per_subframe * 10) + fp->get_samples_slot_timestamp(proc->tti_rx, fp, 0);
|
||||
proc->timestamp_rx = (proc->frame_rx * fp->samples_per_subframe * 10) + get_samples_slot_timestamp(fp, proc->tti_rx);
|
||||
// proc->timestamp_tx = proc->timestamp_rx + (4*fp->samples_per_subframe);
|
||||
proc->tti_tx = (sl+ru->sl_ahead)%fp->slots_per_frame;
|
||||
proc->frame_tx = (sl > (fp->slots_per_frame - 1 - (ru->sl_ahead))) ? (f + 1) & 1023 : f;
|
||||
@@ -528,7 +522,7 @@ void fh_if4p5_north_asynch_in(RU_t *ru,int *frame,int *slot) {
|
||||
proc->frame_tx_unwrap += 1024;
|
||||
|
||||
proc->timestamp_tx =
|
||||
((uint64_t)frame_tx + proc->frame_tx_unwrap) * fp->samples_per_subframe * 10 + fp->get_samples_slot_timestamp(slot_tx, fp, 0);
|
||||
((uint64_t)frame_tx + proc->frame_tx_unwrap) * fp->samples_per_subframe * 10 + get_samples_slot_timestamp(fp, slot_tx);
|
||||
LOG_D(PHY, "RU %d/%d TST %lu, frame %d, subframe %d\n", ru->idx, 0, proc->timestamp_tx, frame_tx, slot_tx);
|
||||
|
||||
// dump VCD output for first RU in list
|
||||
@@ -566,14 +560,14 @@ static void rx_rf(RU_t *ru, int *frame, int *slot)
|
||||
RU_proc_t *proc = &ru->proc;
|
||||
NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms;
|
||||
openair0_config_t *cfg = &ru->openair0_cfg;
|
||||
uint32_t samples_per_slot = fp->get_samples_per_slot(*slot, fp);
|
||||
uint32_t samples_per_slot = get_samples_per_slot(*slot, fp);
|
||||
AssertFatal(*slot < fp->slots_per_frame && *slot >= 0, "slot %d is illegal (%d)\n", *slot, fp->slots_per_frame);
|
||||
|
||||
start_meas(&ru->rx_fhaul);
|
||||
int nb = ru->nb_rx * ru->num_beams_period;
|
||||
void *rxp[nb];
|
||||
for (int i = 0; i < nb; i++)
|
||||
rxp[i] = (void *)&ru->common.rxdata[i][fp->get_samples_slot_timestamp(*slot, fp, 0)];
|
||||
rxp[i] = (void *)&ru->common.rxdata[i][get_samples_slot_timestamp(fp, *slot)];
|
||||
|
||||
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ, 1);
|
||||
openair0_timestamp old_ts = proc->timestamp_rx;
|
||||
@@ -590,7 +584,7 @@ static void rx_rf(RU_t *ru, int *frame, int *slot)
|
||||
LOG_E(PHY, "rx_rf: Asked for %d samples, got %d from USRP\n", samples_per_slot, rxs);
|
||||
|
||||
if (proc->first_rx != 1) {
|
||||
uint32_t samples_per_slot_prev = fp->get_samples_per_slot((*slot - 1) % fp->slots_per_frame, fp);
|
||||
uint32_t samples_per_slot_prev = get_samples_per_slot((*slot - 1) % fp->slots_per_frame, fp);
|
||||
|
||||
if (proc->timestamp_rx - old_ts != samples_per_slot_prev) {
|
||||
LOG_D(PHY,
|
||||
@@ -609,7 +603,7 @@ static void rx_rf(RU_t *ru, int *frame, int *slot)
|
||||
|
||||
// in fact the following line is the same as long as the timestamp_rx is synchronized to GPS.
|
||||
proc->frame_rx = (proc->timestamp_rx / (fp->samples_per_subframe*10))&1023;
|
||||
proc->tti_rx = fp->get_slot_from_timestamp(proc->timestamp_rx,fp);
|
||||
proc->tti_rx = get_slot_from_timestamp(proc->timestamp_rx, fp);
|
||||
// synchronize first reception to frame 0 subframe 0
|
||||
LOG_D(PHY,
|
||||
"RU %d/%d TS %ld, GPS %f, SR %f, frame %d, slot %d.%d / %d\n",
|
||||
@@ -725,9 +719,9 @@ void tx_rf(RU_t *ru, int frame,int slot, uint64_t timestamp)
|
||||
T_INT(frame),
|
||||
T_INT(slot),
|
||||
T_INT(0),
|
||||
T_BUFFER(&ru->common.txdata[0][fp->get_samples_slot_timestamp(slot, fp, 0)], fp->get_samples_per_slot(slot, fp) * 4));
|
||||
T_BUFFER(&ru->common.txdata[0][get_samples_slot_timestamp(fp, slot)], get_samples_per_slot(slot, fp) * 4));
|
||||
int sf_extension = 0;
|
||||
int siglen=fp->get_samples_per_slot(slot,fp);
|
||||
int siglen = get_samples_per_slot(slot, fp);
|
||||
radio_tx_burst_flag_t flags_burst = TX_BURST_INVALID;
|
||||
radio_tx_gpio_flag_t flags_gpio = 0;
|
||||
|
||||
@@ -786,7 +780,7 @@ void tx_rf(RU_t *ru, int frame,int slot, uint64_t timestamp)
|
||||
int nt = ru->nb_tx * ru->num_beams_period;
|
||||
void *txp[nt];
|
||||
for (int i = 0; i < nt; i++)
|
||||
txp[i] = (void *)&ru->common.txdata[i][fp->get_samples_slot_timestamp(slot, fp, 0)] - sf_extension * sizeof(int32_t);
|
||||
txp[i] = (void *)&ru->common.txdata[i][get_samples_slot_timestamp(fp, slot)] - sf_extension * sizeof(int32_t);
|
||||
|
||||
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_TRX_TST, (timestamp + ru->ts_offset) & 0xffffffff);
|
||||
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE, 1);
|
||||
@@ -1176,7 +1170,7 @@ void *ru_thread(void *param)
|
||||
}
|
||||
proc->timestamp_tx = proc->timestamp_rx;
|
||||
for (int i = proc->tti_rx; i < proc->tti_rx + ru->sl_ahead; i++)
|
||||
proc->timestamp_tx += fp->get_samples_per_slot(i % fp->slots_per_frame, fp);
|
||||
proc->timestamp_tx += get_samples_per_slot(i % fp->slots_per_frame, fp);
|
||||
proc->tti_tx = (proc->tti_rx + ru->sl_ahead) % fp->slots_per_frame;
|
||||
proc->frame_tx = proc->tti_rx > proc->tti_tx ? (proc->frame_rx + 1) & 1023 : proc->frame_rx;
|
||||
LOG_D(PHY,
|
||||
|
||||
+93
-57
@@ -19,6 +19,7 @@
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
#include "PHY/defs_nr_common.h"
|
||||
#define _GNU_SOURCE // For pthread_setname_np
|
||||
#include <pthread.h>
|
||||
#include <openair1/PHY/impl_defs_top.h>
|
||||
@@ -383,7 +384,7 @@ static void RU_write(nr_rxtx_thread_data_t *rxtxD, bool sl_tx_action, c16_t **tx
|
||||
openair0_timestamp writeTimestamp = proc->timestamp_tx;
|
||||
int writeBlockSize = rxtxD->writeBlockSize;
|
||||
// if writeBlockSize gets longer that slot size, fill with dummy
|
||||
const int maxWriteBlockSize = fp->get_samples_per_slot(proc->nr_slot_tx, fp);
|
||||
const int maxWriteBlockSize = get_samples_per_slot(proc->nr_slot_tx, fp);
|
||||
while (writeBlockSize > maxWriteBlockSize) {
|
||||
const int dummyBlockSize = min(writeBlockSize - maxWriteBlockSize, maxWriteBlockSize);
|
||||
int tmp = openair0_write_reorder(&UE->rfdevice, writeTimestamp, (void **)txp, dummyBlockSize, fp->nb_antennas_tx, flags);
|
||||
@@ -423,7 +424,7 @@ void processSlotTX(void *arg)
|
||||
NR_DL_FRAME_PARMS *fp = &UE->frame_parms;
|
||||
c16_t *txp[fp->nb_antennas_tx];
|
||||
for (int i = 0; i < fp->nb_antennas_tx; i++) {
|
||||
txp[i] = UE->common_vars.txData[i] + fp->get_samples_slot_timestamp(proc->nr_slot_tx, fp, 0);
|
||||
txp[i] = UE->common_vars.txData[i] + get_samples_slot_timestamp(fp, proc->nr_slot_tx);
|
||||
}
|
||||
|
||||
if (proc->tx_slot_type == NR_UPLINK_SLOT || proc->tx_slot_type == NR_MIXED_SLOT) {
|
||||
@@ -434,8 +435,10 @@ void processSlotTX(void *arg)
|
||||
nr_sidelink_indication_t sl_indication = {.module_id = UE->Mod_id,
|
||||
.gNB_index = proc->gNB_id,
|
||||
.cc_id = UE->CC_id,
|
||||
.hfn_tx = proc->hfn_tx,
|
||||
.frame_tx = proc->frame_tx,
|
||||
.slot_tx = proc->nr_slot_tx,
|
||||
.hfn_rx = proc->hfn_rx,
|
||||
.frame_rx = proc->frame_rx,
|
||||
.slot_rx = proc->nr_slot_rx,
|
||||
.slot_type = SIDELINK_SLOT_TYPE_TX,
|
||||
@@ -654,24 +657,25 @@ void readFrame(PHY_VARS_NR_UE *UE, openair0_timestamp *timestamp, int duration_r
|
||||
void *rxp[NB_ANTENNAS_RX];
|
||||
if (toTrash)
|
||||
for (int i = 0; i < fp->nb_antennas_rx; i++)
|
||||
rxp[i] = malloc16(fp->get_samples_per_slot(0, fp) * 4);
|
||||
rxp[i] = malloc16(get_samples_per_slot(0, fp) * 4);
|
||||
|
||||
for (int x = 0; x < num_frames * NR_NUMBER_OF_SUBFRAMES_PER_FRAME; x++) { // two frames for initial sync
|
||||
for (int slot = 0; slot < fp->slots_per_subframe; slot++) {
|
||||
if (!toTrash)
|
||||
for (int i = 0; i < fp->nb_antennas_rx; i++)
|
||||
rxp[i] = ((void *)&UE->common_vars.rxdata[i][0])
|
||||
+ 4 * ((x * fp->samples_per_subframe) + fp->get_samples_slot_timestamp(slot, fp, 0));
|
||||
rxp[i] =
|
||||
((void *)&UE->common_vars.rxdata[i][0]) + 4 * ((x * fp->samples_per_subframe) + get_samples_slot_timestamp(fp, slot));
|
||||
|
||||
int read_block_size = fp->get_samples_per_slot(slot, fp);
|
||||
int read_block_size = get_samples_per_slot(slot, fp);
|
||||
int tmp = UE->rfdevice.trx_read_func(&UE->rfdevice, timestamp, rxp, read_block_size, fp->nb_antennas_rx);
|
||||
UEscopeCopy(UE, ueTimeDomainSamplesBeforeSync, rxp[0], sizeof(c16_t), 1, read_block_size, 0);
|
||||
AssertFatal(read_block_size == tmp, "");
|
||||
|
||||
if (IS_SOFTMODEM_RFSIM) {
|
||||
int ta = UE->timing_advance + UE->timing_advance_ntn;
|
||||
const openair0_timestamp writeTimestamp =
|
||||
*timestamp + fp->get_samples_slot_timestamp(slot, fp, duration_rx_to_tx) - UE->N_TA_offset - UE->timing_advance;
|
||||
dummyWrite(UE, writeTimestamp, fp->get_samples_per_slot(slot, fp));
|
||||
*timestamp + get_samples_slot_duration(fp, slot, duration_rx_to_tx) - UE->N_TA_offset - ta;
|
||||
dummyWrite(UE, writeTimestamp, get_samples_per_slot(slot, fp));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -692,12 +696,13 @@ static void syncInFrame(PHY_VARS_NR_UE *UE, openair0_timestamp *timestamp, int d
|
||||
int slot = 0;
|
||||
int size = rx_offset;
|
||||
while (size > 0) {
|
||||
const int unitTransfer = min(fp->get_samples_per_slot(slot, fp), size);
|
||||
const int unitTransfer = min(get_samples_per_slot(slot, fp), size);
|
||||
const int res = UE->rfdevice.trx_read_func(&UE->rfdevice, timestamp, (void **)UE->common_vars.rxdata, unitTransfer, fp->nb_antennas_rx);
|
||||
DevAssert(unitTransfer == res);
|
||||
if (IS_SOFTMODEM_RFSIM) {
|
||||
int ta = UE->timing_advance + UE->timing_advance_ntn;
|
||||
const openair0_timestamp writeTimestamp =
|
||||
*timestamp + fp->get_samples_slot_timestamp(slot, fp, duration_rx_to_tx) - UE->N_TA_offset - UE->timing_advance;
|
||||
*timestamp + get_samples_slot_duration(fp, slot, duration_rx_to_tx) - UE->N_TA_offset - ta;
|
||||
dummyWrite(UE, writeTimestamp, unitTransfer);
|
||||
}
|
||||
slot = (slot + 1) % fp->slots_per_subframe;
|
||||
@@ -706,23 +711,72 @@ static void syncInFrame(PHY_VARS_NR_UE *UE, openair0_timestamp *timestamp, int d
|
||||
}
|
||||
|
||||
static inline int get_firstSymSamp(uint16_t slot, NR_DL_FRAME_PARMS *fp) {
|
||||
if (fp->numerology_index == 0)
|
||||
return fp->nb_prefix_samples0 + fp->ofdm_symbol_size;
|
||||
int num_samples = (slot%(fp->slots_per_subframe/2)) ? fp->nb_prefix_samples : fp->nb_prefix_samples0;
|
||||
num_samples += fp->ofdm_symbol_size;
|
||||
return num_samples;
|
||||
return get_samples_symbol_duration(fp, slot, 0, 1);
|
||||
}
|
||||
|
||||
static inline int get_readBlockSize(uint16_t slot, NR_DL_FRAME_PARMS *fp) {
|
||||
int rem_samples = fp->get_samples_per_slot(slot, fp) - get_firstSymSamp(slot, fp);
|
||||
int rem_samples = get_samples_per_slot(slot, fp) - get_firstSymSamp(slot, fp);
|
||||
int next_slot_first_symbol = 0;
|
||||
if (slot < (fp->slots_per_frame-1))
|
||||
next_slot_first_symbol = get_firstSymSamp(slot+1, fp);
|
||||
return rem_samples + next_slot_first_symbol;
|
||||
}
|
||||
|
||||
#define SPEED_OF_LIGHT 299792458
|
||||
static inline void apply_ntn_timing_advance(PHY_VARS_NR_UE *UE, const NR_DL_FRAME_PARMS *fp, int abs_subframe_tx)
|
||||
{
|
||||
const fapi_nr_dl_ntn_config_command_pdu *ntn_config_params = &UE->ntn_config_message->ntn_config_params;
|
||||
|
||||
const int abs_subframe_epoch = ntn_config_params->epoch_subframe
|
||||
+ ntn_config_params->epoch_sfn * 10
|
||||
+ ntn_config_params->epoch_hfn * 10240;
|
||||
const int ms_since_epoch = abs_subframe_tx - abs_subframe_epoch;
|
||||
|
||||
const double omega = ntn_config_params->omega;
|
||||
const double cos_wt = cos(omega * ms_since_epoch);
|
||||
const double sin_wt = sin(omega * ms_since_epoch);
|
||||
|
||||
const position_t pos_sat_0 = ntn_config_params->pos_sat_0;
|
||||
const position_t pos_sat_90 = ntn_config_params->pos_sat_90;
|
||||
const position_t pos_sat = {pos_sat_0.X * cos_wt + pos_sat_90.X * sin_wt,
|
||||
pos_sat_0.Y * cos_wt + pos_sat_90.Y * sin_wt,
|
||||
pos_sat_0.Z * cos_wt + pos_sat_90.Z * sin_wt};
|
||||
|
||||
position_t pos_ue = {0};
|
||||
get_position_coordinates(UE->Mod_id, &pos_ue);
|
||||
|
||||
// calculate directional vector from SAT to UE
|
||||
const position_t dir_sat_ue = {pos_ue.X - pos_sat.X, pos_ue.Y - pos_sat.Y, pos_ue.Z - pos_sat.Z};
|
||||
|
||||
// calculate distance between SAT and UE
|
||||
const double distance = sqrt(dir_sat_ue.X * dir_sat_ue.X + dir_sat_ue.Y * dir_sat_ue.Y + dir_sat_ue.Z * dir_sat_ue.Z);
|
||||
|
||||
// calculate round-trip-time (factor 2) between SAT and UE in ms (factor 1000)
|
||||
const double N_UE_TA_adj = 2000 * distance / SPEED_OF_LIGHT;
|
||||
|
||||
const double N_common_ta_adj = ntn_config_params->N_common_ta_adj;
|
||||
const double N_common_ta_drift = ntn_config_params->N_common_ta_drift;
|
||||
const double N_common_ta_drift_variant = ntn_config_params->N_common_ta_drift_variant;
|
||||
|
||||
UE->timing_advance_ntn = (N_UE_TA_adj + N_common_ta_adj
|
||||
+ N_common_ta_drift * ms_since_epoch / 1e6
|
||||
+ N_common_ta_drift_variant * ((int64_t)ms_since_epoch * ms_since_epoch) / 1e9)
|
||||
* fp->samples_per_subframe;
|
||||
|
||||
LOG_D(PHY,
|
||||
"N_UE_TA_adj = %f ms, N_common_ta_adj = %f ms, N_common_ta_drift = %f µs/s, N_common_ta_drift_variant = %f µs/s², ms_since_epoch = %d ms, "
|
||||
"computed timing_advance_ntn = %d samples\n",
|
||||
N_UE_TA_adj,
|
||||
N_common_ta_adj,
|
||||
N_common_ta_drift,
|
||||
N_common_ta_drift_variant,
|
||||
ms_since_epoch,
|
||||
UE->timing_advance_ntn);
|
||||
}
|
||||
|
||||
static inline void apply_ntn_config(PHY_VARS_NR_UE *UE,
|
||||
NR_DL_FRAME_PARMS *fp,
|
||||
int hfn_rx,
|
||||
int frame_rx,
|
||||
int slot_rx,
|
||||
int *duration_rx_to_tx,
|
||||
@@ -737,39 +791,13 @@ static inline void apply_ntn_config(PHY_VARS_NR_UE *UE,
|
||||
|
||||
*duration_rx_to_tx = NR_UE_CAPABILITY_SLOT_RX_TO_TX + (koffset << mu);
|
||||
if (koffset > *ntn_koffset)
|
||||
*timing_advance += fp->get_samples_slot_timestamp(slot_rx, fp, (koffset - *ntn_koffset) << mu);
|
||||
*timing_advance += get_samples_slot_duration(fp, slot_rx, (koffset - *ntn_koffset) << mu);
|
||||
else if (koffset < *ntn_koffset)
|
||||
*timing_advance -= fp->get_samples_slot_timestamp(slot_rx, fp, (*ntn_koffset - koffset) << mu);
|
||||
*timing_advance -= get_samples_slot_duration(fp, slot_rx, (*ntn_koffset - koffset) << mu);
|
||||
*ntn_koffset = koffset;
|
||||
|
||||
const int abs_subframe_tx = 10 * frame_rx + ((slot_rx + *duration_rx_to_tx) >> mu);
|
||||
const int abs_subframe_epoch =
|
||||
10 * UE->ntn_config_message->ntn_config_params.epoch_sfn + UE->ntn_config_message->ntn_config_params.epoch_subframe;
|
||||
int ms_since_epoch = abs_subframe_tx - abs_subframe_epoch;
|
||||
// cope with sfn wrap-around
|
||||
// this currently limits us to epoch times that are not more than 5.12 seconds in the future (allowed are up to 10.24 seconds)
|
||||
// and ntn-UlSyncValidityDuration < 5.12 seconds (allowed are up to 900 seconds)
|
||||
// TODO: fix this limitation by introducing the hyper frame number HFN
|
||||
if (ms_since_epoch < -5120)
|
||||
ms_since_epoch += 10240;
|
||||
else if (ms_since_epoch > 5120)
|
||||
ms_since_epoch -= 10240;
|
||||
|
||||
const double total_ta_ms = UE->ntn_config_message->ntn_config_params.ntn_total_time_advance_ms;
|
||||
const double total_ta_drift = UE->ntn_config_message->ntn_config_params.ntn_total_time_advance_drift; // µs/s
|
||||
const double total_ta_drift_variant = UE->ntn_config_message->ntn_config_params.ntn_total_time_advance_drift_variant; // µs/s²
|
||||
UE->timing_advance = fp->samples_per_subframe * (total_ta_ms + (total_ta_drift / 1000.0) * (ms_since_epoch / 1000.0) + (total_ta_drift_variant / 1000.0) * (ms_since_epoch / 1000.0) * (ms_since_epoch / 1000.0));
|
||||
|
||||
LOG_I(PHY,
|
||||
"k_offset = %d ms (%d slots), total_ta_ms = %f ms, total_ta_drift = %f µs/s, total_ta_drift_variant = %f µs/s², ms_since_epoch = %d ms, computed "
|
||||
"timing_advance = %d samples\n",
|
||||
*ntn_koffset,
|
||||
*ntn_koffset << mu,
|
||||
total_ta_ms,
|
||||
total_ta_drift,
|
||||
total_ta_drift_variant,
|
||||
ms_since_epoch,
|
||||
UE->timing_advance);
|
||||
const int abs_subframe_tx = 10240 * hfn_rx + 10 * frame_rx + ((slot_rx + *duration_rx_to_tx) >> mu);
|
||||
apply_ntn_timing_advance(UE, fp, abs_subframe_tx);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -809,7 +837,7 @@ void *UE_thread(void *arg)
|
||||
int ntn_koffset = 0;
|
||||
|
||||
int duration_rx_to_tx = NR_UE_CAPABILITY_SLOT_RX_TO_TX;
|
||||
int timing_advance = UE->timing_advance;
|
||||
int timing_advance = UE->timing_advance + UE->timing_advance_ntn;
|
||||
UE->N_TA_offset = determine_N_TA_offset(UE);
|
||||
NR_UE_MAC_INST_t *mac = get_mac_inst(UE->Mod_id);
|
||||
|
||||
@@ -968,6 +996,8 @@ void *UE_thread(void *arg)
|
||||
curMsg.proc.nr_slot_tx = (absolute_slot + duration_rx_to_tx) % nb_slot_frame;
|
||||
curMsg.proc.frame_rx = (absolute_slot / nb_slot_frame) % MAX_FRAME_NUMBER;
|
||||
curMsg.proc.frame_tx = ((absolute_slot + duration_rx_to_tx) / nb_slot_frame) % MAX_FRAME_NUMBER;
|
||||
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) {
|
||||
curMsg.proc.rx_slot_type = sl_nr_ue_slot_select(sl_cfg, curMsg.proc.nr_slot_rx, TDD);
|
||||
@@ -984,18 +1014,24 @@ void *UE_thread(void *arg)
|
||||
|
||||
int firstSymSamp = get_firstSymSamp(slot_nr, fp);
|
||||
for (int i = 0; i < fp->nb_antennas_rx; i++)
|
||||
rxp[i] = (void *)&UE->common_vars.rxdata[i][firstSymSamp + fp->get_samples_slot_timestamp(slot_nr, fp, 0)];
|
||||
rxp[i] = (void *)&UE->common_vars.rxdata[i][firstSymSamp + get_samples_slot_timestamp(fp, slot_nr)];
|
||||
|
||||
int iq_shift_to_apply = 0;
|
||||
if (slot_nr == nb_slot_frame - 1) {
|
||||
// we shift of half of measured drift, at each beginning of frame for both rx and tx
|
||||
iq_shift_to_apply = shiftForNextFrame;
|
||||
// TODO: remove this autonomous TA and use up-to-date values of ta-Common, ta-CommonDrift and ta-CommonDriftVariant from received SIB19 instead
|
||||
if (get_nrUE_params()->autonomous_ta)
|
||||
UE->timing_advance -= 2 * shiftForNextFrame;
|
||||
// autonomous timing advance calculation, which does not use SIB19 information
|
||||
if (ntn_koffset && get_nrUE_params()->autonomous_ta)
|
||||
UE->timing_advance_ntn -= 2 * shiftForNextFrame;
|
||||
shiftForNextFrame = -round(UE->max_pos_acc * get_nrUE_params()->time_sync_I);
|
||||
}
|
||||
|
||||
// Calculate new TA based on SIB19 information for each subframe in NTN mode, if "autonomous_ta" is not enabled
|
||||
if (ntn_koffset && !get_nrUE_params()->autonomous_ta && (absolute_slot + duration_rx_to_tx) % fp->slots_per_subframe == 0) {
|
||||
const int abs_subframe_tx = (absolute_slot + duration_rx_to_tx) / fp->slots_per_subframe;
|
||||
apply_ntn_timing_advance(UE, fp, abs_subframe_tx);
|
||||
}
|
||||
|
||||
const int readBlockSize = get_readBlockSize(slot_nr, fp) - iq_shift_to_apply;
|
||||
openair0_timestamp rx_timestamp;
|
||||
int tmp = UE->rfdevice.trx_read_func(&UE->rfdevice, &rx_timestamp, rxp, readBlockSize, fp->nb_antennas_rx);
|
||||
@@ -1025,8 +1061,8 @@ void *UE_thread(void *arg)
|
||||
}
|
||||
|
||||
// use previous timing_advance value to compute writeTimestamp
|
||||
const openair0_timestamp writeTimestamp = rx_timestamp + fp->get_samples_slot_timestamp(slot_nr, fp, duration_rx_to_tx)
|
||||
- firstSymSamp - UE->N_TA_offset - timing_advance;
|
||||
const openair0_timestamp writeTimestamp =
|
||||
rx_timestamp + get_samples_slot_duration(fp, slot_nr, duration_rx_to_tx) - firstSymSamp - UE->N_TA_offset - timing_advance;
|
||||
|
||||
// Calculate TX deadline, approximately 1 symbol before the first sample should be written
|
||||
const uint64_t samples_diff = writeTimestamp - rx_timestamp - fp->ofdm_symbol_size;
|
||||
@@ -1034,8 +1070,8 @@ void *UE_thread(void *arg)
|
||||
const uint64_t absolute_deadline_us = current_time.tv_sec * 1e6 + current_time.tv_nsec / 1e3 + deadline_us;
|
||||
|
||||
// but use current UE->timing_advance value to compute writeBlockSize
|
||||
int writeBlockSize = fp->get_samples_per_slot((slot_nr + duration_rx_to_tx) % nb_slot_frame, fp) - iq_shift_to_apply;
|
||||
int new_timing_advance = UE->timing_advance;
|
||||
int writeBlockSize = get_samples_per_slot((slot_nr + duration_rx_to_tx) % nb_slot_frame, fp) - iq_shift_to_apply;
|
||||
int new_timing_advance = UE->timing_advance + UE->timing_advance_ntn;
|
||||
if (new_timing_advance != timing_advance) {
|
||||
writeBlockSize -= new_timing_advance - timing_advance;
|
||||
timing_advance = new_timing_advance;
|
||||
@@ -1048,7 +1084,7 @@ void *UE_thread(void *arg)
|
||||
}
|
||||
|
||||
if (curMsg.proc.nr_slot_rx == 0)
|
||||
nr_ue_rrc_timer_trigger(UE->Mod_id, curMsg.proc.frame_rx, curMsg.proc.gNB_id);
|
||||
nr_ue_rrc_timer_trigger(UE->Mod_id, curMsg.proc.hfn_rx, curMsg.proc.frame_rx, curMsg.proc.gNB_id);
|
||||
|
||||
// RX slot processing. We launch and forget.
|
||||
notifiedFIFO_elt_t *newRx = newNotifiedFIFO_elt(sizeof(nr_rxtx_thread_data_t), curMsg.proc.nr_slot_tx, NULL, UE_dl_processing);
|
||||
@@ -1064,7 +1100,7 @@ void *UE_thread(void *arg)
|
||||
}
|
||||
|
||||
// apply new NTN timing information
|
||||
apply_ntn_config(UE, fp, curMsg.proc.frame_rx, curMsg.proc.nr_slot_rx, &duration_rx_to_tx, &timing_advance, &ntn_koffset);
|
||||
apply_ntn_config(UE, fp, curMsg.proc.hfn_rx, curMsg.proc.frame_rx, curMsg.proc.nr_slot_rx, &duration_rx_to_tx, &timing_advance, &ntn_koffset);
|
||||
|
||||
// Start TX slot processing here. It runs in parallel with RX slot processing
|
||||
// in current code, DURATION_RX_TO_TX constant is the limit to get UL data to encode from a RX slot
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
*/
|
||||
|
||||
#include "position_interface.h"
|
||||
#include "executables/nr-uesoftmodem.h"
|
||||
|
||||
static void read_position_coordinates(char *sectionName, position_t *position)
|
||||
{
|
||||
|
||||
@@ -22,11 +22,6 @@
|
||||
#ifndef __POSITION_INTERFACE__H__
|
||||
#define __POSITION_INTERFACE__H__
|
||||
|
||||
#include <executables/nr-softmodem-common.h>
|
||||
#include <executables/softmodem-common.h>
|
||||
#include "PHY/defs_nr_UE.h"
|
||||
#include "executables/nr-uesoftmodem.h"
|
||||
|
||||
/* position configuration parameters name */
|
||||
#define CONFIG_STRING_POSITION_X "x"
|
||||
#define CONFIG_STRING_POSITION_Y "y"
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "PHY/impl_defs_top.h"
|
||||
#include "PHY/impl_defs_nr.h"
|
||||
#include "common/utils/nr/nr_common.h"
|
||||
#include "executables/position_interface.h"
|
||||
|
||||
#define NFAPI_UE_MAX_NUM_CB 8
|
||||
#define NFAPI_MAX_NUM_UL_PDU 255
|
||||
@@ -562,18 +563,26 @@ typedef struct {
|
||||
} fapi_nr_ta_command_pdu;
|
||||
|
||||
typedef struct {
|
||||
int epoch_hfn;
|
||||
int epoch_sfn;
|
||||
int epoch_subframe;
|
||||
|
||||
// orbital angular velocity in rad/ms
|
||||
double omega;
|
||||
// satellite position at epoch time
|
||||
position_t pos_sat_0;
|
||||
// satellite position at 90° orbit
|
||||
position_t pos_sat_90;
|
||||
|
||||
// N_common_ta_adj represents common round-trip-time between gNB and SAT received in SIB19 (ms)
|
||||
double N_common_ta_adj;
|
||||
// drift rate of common ta in µs/s
|
||||
double N_common_ta_drift;
|
||||
// change rate of common ta drift in µs/s²
|
||||
double N_common_ta_drift_variant;
|
||||
|
||||
// cell scheduling offset expressed in terms of 15kHz SCS
|
||||
long cell_specific_k_offset;
|
||||
|
||||
// ntn_total_time_advance_ms represents the complete round-trip-time between gNB and UE via SAT
|
||||
double ntn_total_time_advance_ms;
|
||||
// drift rate of ntn_total_time_advance_ms in µs/s
|
||||
double ntn_total_time_advance_drift;
|
||||
// change rate of ntn_total_time_advance_ms drift in µs/s²
|
||||
double ntn_total_time_advance_drift_variant;
|
||||
} fapi_nr_dl_ntn_config_command_pdu;
|
||||
|
||||
typedef struct {
|
||||
@@ -697,7 +706,6 @@ typedef struct
|
||||
uint8_t restricted_set_config;//PRACH restricted set config Value: 0: unrestricted 1: restricted set type A 2: restricted set type B
|
||||
uint8_t num_prach_fd_occasions;//Corresponds to the parameter 𝑀 in [38.211, sec 6.3.3.2] which equals the higher layer parameter msg1FDM Value: 1,2,4,8
|
||||
fapi_nr_num_prach_fd_occasions_t* num_prach_fd_occasions_list;
|
||||
uint8_t ssb_per_rach;//SSB-per-RACH-occasion Value: 0: 1/8 1:1/4, 2:1/2 3:1 4:2 5:4, 6:8 7:16
|
||||
uint8_t prach_multiple_carriers_in_a_band;//0 = disabled 1 = enabled
|
||||
uint8_t root_seq_computed; // flag set and used only in PHY to indicate if table is computed with this config
|
||||
|
||||
|
||||
@@ -3,3 +3,6 @@ add_subdirectory(TOOLS)
|
||||
add_subdirectory(NR_TRANSPORT)
|
||||
add_subdirectory(CODING)
|
||||
add_subdirectory(MODULATION)
|
||||
if (ENABLE_TESTS)
|
||||
add_subdirectory(INIT/tests)
|
||||
endif()
|
||||
+122
-38
@@ -259,33 +259,116 @@ uint32_t get_samples_per_slot(int slot, const NR_DL_FRAME_PARMS *fp)
|
||||
return samp_count;
|
||||
}
|
||||
|
||||
uint32_t get_slot_from_timestamp(openair0_timestamp timestamp_rx, const NR_DL_FRAME_PARMS *fp)
|
||||
uint32_t get_samples_symbol_duration(const NR_DL_FRAME_PARMS *fp, int slot, int start_symbol, int num_symbols)
|
||||
{
|
||||
uint32_t slot_idx = 0;
|
||||
int samples_till_the_slot = fp->get_samples_per_slot(slot_idx,fp)-1;
|
||||
timestamp_rx = timestamp_rx%fp->samples_per_frame;
|
||||
int end_symbol = start_symbol + num_symbols - 1;
|
||||
AssertFatal(start_symbol <= end_symbol && start_symbol >= 0 && end_symbol < fp->symbols_per_slot,
|
||||
"Symbol range is invalid start_symbol %d, num_symbols %d symbols_per_slot %d\n",
|
||||
start_symbol,
|
||||
num_symbols,
|
||||
fp->symbols_per_slot);
|
||||
if (num_symbols == fp->symbols_per_slot) {
|
||||
return get_samples_per_slot(slot, fp);
|
||||
}
|
||||
uint32_t num_samples = 0;
|
||||
int num_symbols_added = 0;
|
||||
|
||||
while (timestamp_rx > samples_till_the_slot) {
|
||||
slot_idx++;
|
||||
samples_till_the_slot += fp->get_samples_per_slot(slot_idx,fp);
|
||||
}
|
||||
return slot_idx;
|
||||
// Handle symbols with different nb_prefix_samples0
|
||||
if (fp->numerology_index == 0) {
|
||||
// Add symbol 0
|
||||
if (start_symbol == 0) {
|
||||
num_samples += fp->nb_prefix_samples0 + fp->ofdm_symbol_size;
|
||||
num_symbols_added++;
|
||||
}
|
||||
// Add symbol 7
|
||||
if (start_symbol <= 7 && end_symbol >= 7) {
|
||||
num_samples += fp->nb_prefix_samples0 + fp->ofdm_symbol_size;
|
||||
num_symbols_added++;
|
||||
}
|
||||
} else {
|
||||
// Add first symbol
|
||||
if (start_symbol == 0) {
|
||||
num_samples += (slot % (fp->slots_per_subframe / 2)) ? fp->nb_prefix_samples : fp->nb_prefix_samples0;
|
||||
num_samples += fp->ofdm_symbol_size;
|
||||
num_symbols_added++;
|
||||
}
|
||||
}
|
||||
|
||||
int num_symbols_left = max(0, num_symbols - num_symbols_added);
|
||||
num_samples += num_symbols_left * (fp->nb_prefix_samples + fp->ofdm_symbol_size);
|
||||
return num_samples;
|
||||
}
|
||||
|
||||
uint32_t get_samples_slot_timestamp(int slot, const NR_DL_FRAME_PARMS *fp, unsigned int sl_ahead)
|
||||
uint32_t get_samples_symbol_timestamp(const NR_DL_FRAME_PARMS *fp, int slot, int symbol)
|
||||
{
|
||||
uint32_t samp_count = 0;
|
||||
|
||||
if(!sl_ahead) {
|
||||
for(unsigned int idx_slot = 0; idx_slot < slot; idx_slot++)
|
||||
samp_count += fp->get_samples_per_slot(idx_slot, fp);
|
||||
} else {
|
||||
for (unsigned int idx_slot = slot; idx_slot < slot + sl_ahead; idx_slot++)
|
||||
samp_count += fp->get_samples_per_slot(idx_slot, fp);
|
||||
if (symbol == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return get_samples_symbol_duration(fp, slot, 0, symbol);
|
||||
}
|
||||
|
||||
uint32_t get_slot_from_timestamp(openair0_timestamp timestamp_rx, const NR_DL_FRAME_PARMS *fp)
|
||||
{
|
||||
timestamp_rx = timestamp_rx % fp->samples_per_frame;
|
||||
if (timestamp_rx < fp->samples_per_slot0)
|
||||
return 0;
|
||||
|
||||
if (fp->numerology_index == 0)
|
||||
return timestamp_rx / fp->samples_per_subframe;
|
||||
|
||||
const unsigned int num_half_sf = timestamp_rx / (fp->samples_per_subframe / 2);
|
||||
const unsigned int slot_per_half_sf = fp->slots_per_subframe / 2;
|
||||
|
||||
uint32_t slot_count = num_half_sf * slot_per_half_sf;
|
||||
int samp_idx = num_half_sf * (fp->samples_per_subframe / 2) - 1;
|
||||
|
||||
// Remaining samples
|
||||
if (samp_idx < timestamp_rx) {
|
||||
slot_count++;
|
||||
samp_idx += fp->samples_per_slot0; // First slot of half subframe
|
||||
}
|
||||
if (samp_idx < timestamp_rx) {
|
||||
const unsigned int rem_samples = timestamp_rx - samp_idx;
|
||||
const unsigned int num_slots = ceil((double)rem_samples / fp->samples_per_slotN0);
|
||||
slot_count += num_slots;
|
||||
}
|
||||
|
||||
return slot_count - 1;
|
||||
}
|
||||
|
||||
uint32_t get_samples_slot_timestamp(const NR_DL_FRAME_PARMS *fp, unsigned int slot)
|
||||
{
|
||||
if (slot == 0)
|
||||
return 0;
|
||||
|
||||
if (fp->numerology_index == 0)
|
||||
return slot * fp->samples_per_subframe;
|
||||
|
||||
uint32_t samp_count = 0;
|
||||
// Number of half subframes
|
||||
const unsigned int num_half_sf = slot / (fp->slots_per_subframe / 2);
|
||||
samp_count += num_half_sf * fp->samples_per_subframe / 2;
|
||||
|
||||
// Remaining slots
|
||||
unsigned int rem_slots = slot % (fp->slots_per_subframe / 2);
|
||||
if (rem_slots > 0) {
|
||||
samp_count += fp->samples_per_slot0; // First slot of the last half subframe
|
||||
rem_slots--;
|
||||
}
|
||||
samp_count += rem_slots * fp->samples_per_slotN0; // Remaining slots of the last half subframe
|
||||
|
||||
return samp_count;
|
||||
}
|
||||
|
||||
uint32_t get_samples_slot_duration(const NR_DL_FRAME_PARMS *fp, unsigned int start_slot, unsigned int num_slots)
|
||||
{
|
||||
if (start_slot == 0 && num_slots == 0)
|
||||
return 0;
|
||||
|
||||
return (get_samples_slot_timestamp(fp, start_slot + num_slots) - get_samples_slot_timestamp(fp, start_slot));
|
||||
}
|
||||
|
||||
void nr_init_frame_parms(nfapi_nr_config_request_scf_t* cfg, NR_DL_FRAME_PARMS *fp)
|
||||
{
|
||||
|
||||
@@ -319,12 +402,11 @@ void nr_init_frame_parms(nfapi_nr_config_request_scf_t* cfg, NR_DL_FRAME_PARMS *
|
||||
fp->samples_per_frame_wCP = 10 * fp->samples_per_subframe_wCP;
|
||||
fp->samples_per_slot_wCP = fp->symbols_per_slot*fp->ofdm_symbol_size;
|
||||
fp->samples_per_slotN0 = (fp->nb_prefix_samples + fp->ofdm_symbol_size) * fp->symbols_per_slot;
|
||||
fp->samples_per_slot0 = fp->nb_prefix_samples0 + ((fp->symbols_per_slot-1)*fp->nb_prefix_samples) + (fp->symbols_per_slot*fp->ofdm_symbol_size);
|
||||
fp->samples_per_subframe = (fp->nb_prefix_samples0 + fp->ofdm_symbol_size) * 2 +
|
||||
(fp->nb_prefix_samples + fp->ofdm_symbol_size) * (fp->symbols_per_slot * fp->slots_per_subframe - 2);
|
||||
fp->get_samples_per_slot = &get_samples_per_slot;
|
||||
fp->get_samples_slot_timestamp = &get_samples_slot_timestamp;
|
||||
fp->get_slot_from_timestamp = &get_slot_from_timestamp;
|
||||
fp->samples_per_subframe = (fp->nb_prefix_samples0 + fp->ofdm_symbol_size) * 2
|
||||
+ (fp->nb_prefix_samples + fp->ofdm_symbol_size) * (fp->symbols_per_slot * fp->slots_per_subframe - 2);
|
||||
fp->samples_per_slot0 = fp->numerology_index == 0 ? fp->samples_per_subframe
|
||||
: fp->nb_prefix_samples0 + ((fp->symbols_per_slot - 1) * fp->nb_prefix_samples)
|
||||
+ (fp->symbols_per_slot * fp->ofdm_symbol_size);
|
||||
fp->samples_per_frame = 10 * fp->samples_per_subframe;
|
||||
fp->freq_range = get_freq_range_from_freq(fp->dl_CarrierFreq);
|
||||
|
||||
@@ -402,11 +484,11 @@ int nr_init_frame_parms_ue(NR_DL_FRAME_PARMS *fp,
|
||||
fp->samples_per_frame_wCP = 10 * fp->samples_per_subframe_wCP;
|
||||
fp->samples_per_slot_wCP = fp->symbols_per_slot*fp->ofdm_symbol_size;
|
||||
fp->samples_per_slotN0 = (fp->nb_prefix_samples + fp->ofdm_symbol_size) * fp->symbols_per_slot;
|
||||
fp->samples_per_slot0 = fp->nb_prefix_samples0 + ((fp->symbols_per_slot-1)*fp->nb_prefix_samples) + (fp->symbols_per_slot*fp->ofdm_symbol_size);
|
||||
fp->samples_per_subframe = (fp->nb_prefix_samples0 + fp->ofdm_symbol_size) * 2 +
|
||||
(fp->nb_prefix_samples + fp->ofdm_symbol_size) * (fp->symbols_per_slot * fp->slots_per_subframe - 2);
|
||||
fp->get_samples_per_slot = &get_samples_per_slot;
|
||||
fp->get_samples_slot_timestamp = &get_samples_slot_timestamp;
|
||||
fp->samples_per_subframe = (fp->nb_prefix_samples0 + fp->ofdm_symbol_size) * 2
|
||||
+ (fp->nb_prefix_samples + fp->ofdm_symbol_size) * (fp->symbols_per_slot * fp->slots_per_subframe - 2);
|
||||
fp->samples_per_slot0 = fp->numerology_index == 0 ? fp->samples_per_subframe
|
||||
: fp->nb_prefix_samples0 + ((fp->symbols_per_slot - 1) * fp->nb_prefix_samples)
|
||||
+ (fp->symbols_per_slot * fp->ofdm_symbol_size);
|
||||
fp->samples_per_frame = 10 * fp->samples_per_subframe;
|
||||
fp->freq_range = get_freq_range_from_freq(fp->dl_CarrierFreq);
|
||||
|
||||
@@ -460,11 +542,14 @@ void nr_init_frame_parms_ue_sa(NR_DL_FRAME_PARMS *frame_parms, uint64_t downlink
|
||||
frame_parms->samples_per_frame_wCP = 10 * frame_parms->samples_per_subframe_wCP;
|
||||
frame_parms->samples_per_slot_wCP = frame_parms->symbols_per_slot*frame_parms->ofdm_symbol_size;
|
||||
frame_parms->samples_per_slotN0 = (frame_parms->nb_prefix_samples + frame_parms->ofdm_symbol_size) * frame_parms->symbols_per_slot;
|
||||
frame_parms->samples_per_slot0 = frame_parms->nb_prefix_samples0 + ((frame_parms->symbols_per_slot-1)*frame_parms->nb_prefix_samples) + (frame_parms->symbols_per_slot*frame_parms->ofdm_symbol_size);
|
||||
frame_parms->samples_per_subframe = (frame_parms->nb_prefix_samples0 + frame_parms->ofdm_symbol_size) * 2 +
|
||||
(frame_parms->nb_prefix_samples + frame_parms->ofdm_symbol_size) * (frame_parms->symbols_per_slot * frame_parms->slots_per_subframe - 2);
|
||||
frame_parms->get_samples_per_slot = &get_samples_per_slot;
|
||||
frame_parms->get_samples_slot_timestamp = &get_samples_slot_timestamp;
|
||||
frame_parms->samples_per_subframe = (frame_parms->nb_prefix_samples0 + frame_parms->ofdm_symbol_size) * 2
|
||||
+ (frame_parms->nb_prefix_samples + frame_parms->ofdm_symbol_size)
|
||||
* (frame_parms->symbols_per_slot * frame_parms->slots_per_subframe - 2);
|
||||
frame_parms->samples_per_slot0 = frame_parms->numerology_index == 0
|
||||
? frame_parms->samples_per_subframe
|
||||
: frame_parms->nb_prefix_samples0
|
||||
+ ((frame_parms->symbols_per_slot - 1) * frame_parms->nb_prefix_samples)
|
||||
+ (frame_parms->symbols_per_slot * frame_parms->ofdm_symbol_size);
|
||||
frame_parms->samples_per_frame = 10 * frame_parms->samples_per_subframe;
|
||||
|
||||
LOG_W(PHY, "samples_per_subframe %d/per second %d, wCP %d\n", frame_parms->samples_per_subframe, 1000*frame_parms->samples_per_subframe, frame_parms->samples_per_subframe_wCP);
|
||||
@@ -560,12 +645,11 @@ int nr_init_frame_parms_ue_sl(NR_DL_FRAME_PARMS *fp,
|
||||
fp->samples_per_frame_wCP = 10 * fp->samples_per_subframe_wCP;
|
||||
fp->samples_per_slot_wCP = fp->symbols_per_slot * fp->ofdm_symbol_size;
|
||||
fp->samples_per_slotN0 = (fp->nb_prefix_samples + fp->ofdm_symbol_size) * fp->symbols_per_slot;
|
||||
fp->samples_per_slot0 =
|
||||
fp->nb_prefix_samples0 + ((fp->symbols_per_slot - 1) * fp->nb_prefix_samples) + (fp->symbols_per_slot * fp->ofdm_symbol_size);
|
||||
fp->samples_per_subframe = (fp->nb_prefix_samples0 + fp->ofdm_symbol_size) * 2
|
||||
+ (fp->nb_prefix_samples + fp->ofdm_symbol_size) * (fp->symbols_per_slot * fp->slots_per_subframe - 2);
|
||||
fp->get_samples_per_slot = &get_samples_per_slot;
|
||||
fp->get_samples_slot_timestamp = &get_samples_slot_timestamp;
|
||||
fp->samples_per_slot0 = fp->numerology_index == 0 ? fp->samples_per_subframe
|
||||
: fp->nb_prefix_samples0 + ((fp->symbols_per_slot - 1) * fp->nb_prefix_samples)
|
||||
+ (fp->symbols_per_slot * fp->ofdm_symbol_size);
|
||||
fp->samples_per_frame = 10 * fp->samples_per_subframe;
|
||||
fp->freq_range = get_freq_range_from_freq(fp->sl_CarrierFreq);
|
||||
|
||||
|
||||
@@ -55,10 +55,11 @@ void free_nr_ue_ul_harq(NR_UL_UE_HARQ_t harq_list[NR_MAX_ULSCH_HARQ_PROCESSES],
|
||||
|
||||
void phy_init_nr_top(PHY_VARS_NR_UE *ue);
|
||||
void phy_term_nr_top(void);
|
||||
#ifndef __cplusplus
|
||||
void init_delay_table(uint16_t ofdm_symbol_size,
|
||||
int max_delay_comp,
|
||||
int max_ofdm_symbol_size,
|
||||
c16_t delay_table[][max_ofdm_symbol_size]);
|
||||
|
||||
#endif
|
||||
void sl_ue_phy_init(PHY_VARS_NR_UE *UE);
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
add_executable(test_nr_frame_params test_nr_frame_params.cpp)
|
||||
target_link_libraries(test_nr_frame_params PRIVATE LOG minimal_lib PHY_NR -lm GTest::gtest)
|
||||
@@ -0,0 +1,177 @@
|
||||
/*
|
||||
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The OpenAirInterface Software Alliance licenses this file to You under
|
||||
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.openairinterface.org/?page_id=698
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*-------------------------------------------------------------------------------
|
||||
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
extern "C" {
|
||||
#include <stdlib.h>
|
||||
#include "openair1/PHY/defs_nr_common.h"
|
||||
#include "openair1/PHY/INIT/nr_phy_init.h"
|
||||
|
||||
static softmodem_params_t softmodem_params;
|
||||
softmodem_params_t *get_softmodem_params(void)
|
||||
{
|
||||
return &softmodem_params;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t ref_get_samples_slot_timestamp(NR_DL_FRAME_PARMS *fp, unsigned int slot)
|
||||
{
|
||||
uint32_t samp_count = 0;
|
||||
for (unsigned int i = 0; i < slot; i++) {
|
||||
samp_count += get_samples_per_slot(i, fp);
|
||||
}
|
||||
return samp_count;
|
||||
}
|
||||
|
||||
uint32_t ref_get_slot_from_timestamp(openair0_timestamp ts, NR_DL_FRAME_PARMS *fp)
|
||||
{
|
||||
uint32_t slot_idx = 0;
|
||||
int samples_till_the_slot = get_samples_per_slot(slot_idx, fp) - 1;
|
||||
ts = ts % fp->samples_per_frame;
|
||||
|
||||
while (ts > samples_till_the_slot) {
|
||||
slot_idx++;
|
||||
samples_till_the_slot += get_samples_per_slot(slot_idx, fp);
|
||||
}
|
||||
return slot_idx;
|
||||
}
|
||||
|
||||
void test_coherence_symbol_api(NR_DL_FRAME_PARMS *fp)
|
||||
{
|
||||
EXPECT_EQ(get_samples_symbol_timestamp(fp, 0, 0), get_samples_slot_timestamp(fp, 0));
|
||||
|
||||
for (int slot = 0; slot < 4; slot++) {
|
||||
EXPECT_EQ(get_samples_symbol_duration(fp, slot, 0, fp->symbols_per_slot) + get_samples_slot_timestamp(fp, slot),
|
||||
get_samples_slot_timestamp(fp, slot + 1));
|
||||
}
|
||||
|
||||
for (int symbol = 0; symbol < fp->symbols_per_slot - 1; symbol++) {
|
||||
EXPECT_EQ(get_samples_symbol_timestamp(fp, 0, symbol + 1) - get_samples_symbol_timestamp(fp, 0, symbol),
|
||||
get_samples_symbol_duration(fp, 0, symbol, 1));
|
||||
}
|
||||
}
|
||||
|
||||
void test_coherence_slot_api(NR_DL_FRAME_PARMS *fp)
|
||||
{
|
||||
for (unsigned int slot = 0; slot < fp->slots_per_frame; slot++) {
|
||||
EXPECT_EQ(get_samples_slot_timestamp(fp, slot), ref_get_samples_slot_timestamp(fp, slot));
|
||||
}
|
||||
|
||||
openair0_timestamp ts = get_samples_per_slot(0, fp);
|
||||
// When timestamp is the last sample of the slot
|
||||
EXPECT_EQ(get_slot_from_timestamp(ts - 1, fp), 0);
|
||||
for (unsigned int slot = 0; slot < fp->slots_per_frame; slot++) {
|
||||
// When timestamp is the first sample of the slot
|
||||
ts = ref_get_samples_slot_timestamp(fp, slot);
|
||||
EXPECT_EQ(get_slot_from_timestamp(ts, fp), slot);
|
||||
// When timestamp is anywhere in the slot
|
||||
ts += (rand() % fp->samples_per_slotN0);
|
||||
EXPECT_EQ(get_slot_from_timestamp(ts, fp), slot);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(nr_frame_params, test_mu_3)
|
||||
{
|
||||
NR_DL_FRAME_PARMS fp;
|
||||
int mu = NR_MU_3;
|
||||
memset(&fp, 0, sizeof(fp));
|
||||
nfapi_nr_config_request_scf_t cfg;
|
||||
cfg.carrier_config.num_rx_ant.value = 4;
|
||||
cfg.carrier_config.num_tx_ant.value = 4;
|
||||
cfg.carrier_config.dl_grid_size[mu].value = 66;
|
||||
cfg.carrier_config.ul_grid_size[mu].value = 66;
|
||||
cfg.cell_config.frame_duplex_type.value = TDD;
|
||||
cfg.ssb_config.scs_common.value = mu;
|
||||
fp.dl_CarrierFreq = 27524520000;
|
||||
fp.nr_band = 261;
|
||||
nr_init_frame_parms(&cfg, &fp);
|
||||
nr_dump_frame_parms(&fp);
|
||||
test_coherence_symbol_api(&fp);
|
||||
test_coherence_slot_api(&fp);
|
||||
}
|
||||
|
||||
TEST(nr_frame_params, test_mu_2)
|
||||
{
|
||||
NR_DL_FRAME_PARMS fp;
|
||||
int mu = NR_MU_2;
|
||||
memset(&fp, 0, sizeof(fp));
|
||||
nfapi_nr_config_request_scf_t cfg;
|
||||
cfg.carrier_config.num_rx_ant.value = 4;
|
||||
cfg.carrier_config.num_tx_ant.value = 4;
|
||||
cfg.carrier_config.dl_grid_size[mu].value = 51;
|
||||
cfg.carrier_config.ul_grid_size[mu].value = 51;
|
||||
cfg.cell_config.frame_duplex_type.value = TDD;
|
||||
cfg.ssb_config.scs_common.value = mu;
|
||||
fp.dl_CarrierFreq = 27524520000;
|
||||
fp.nr_band = 261;
|
||||
nr_init_frame_parms(&cfg, &fp);
|
||||
nr_dump_frame_parms(&fp);
|
||||
test_coherence_symbol_api(&fp);
|
||||
test_coherence_slot_api(&fp);
|
||||
}
|
||||
|
||||
TEST(nr_frame_params, test_mu_1)
|
||||
{
|
||||
NR_DL_FRAME_PARMS fp;
|
||||
int mu = NR_MU_1;
|
||||
memset(&fp, 0, sizeof(fp));
|
||||
nfapi_nr_config_request_scf_t cfg;
|
||||
cfg.carrier_config.num_rx_ant.value = 4;
|
||||
cfg.carrier_config.num_tx_ant.value = 4;
|
||||
cfg.carrier_config.dl_grid_size[mu].value = 106;
|
||||
cfg.carrier_config.ul_grid_size[mu].value = 106;
|
||||
cfg.cell_config.frame_duplex_type.value = TDD;
|
||||
cfg.ssb_config.scs_common.value = mu;
|
||||
fp.dl_CarrierFreq = 3600000000;
|
||||
fp.nr_band = 78;
|
||||
nr_init_frame_parms(&cfg, &fp);
|
||||
nr_dump_frame_parms(&fp);
|
||||
test_coherence_symbol_api(&fp);
|
||||
test_coherence_slot_api(&fp);
|
||||
}
|
||||
|
||||
TEST(nr_frame_params, test_mu_0)
|
||||
{
|
||||
int mu = NR_MU_0;
|
||||
NR_DL_FRAME_PARMS fp;
|
||||
memset(&fp, 0, sizeof(fp));
|
||||
nfapi_nr_config_request_scf_t cfg;
|
||||
cfg.carrier_config.num_rx_ant.value = 4;
|
||||
cfg.carrier_config.num_tx_ant.value = 4;
|
||||
cfg.carrier_config.dl_grid_size[mu].value = 216;
|
||||
cfg.carrier_config.ul_grid_size[mu].value = 216;
|
||||
cfg.cell_config.frame_duplex_type.value = TDD;
|
||||
cfg.ssb_config.scs_common.value = mu;
|
||||
fp.dl_CarrierFreq = 2600000000;
|
||||
fp.nr_band = 38;
|
||||
nr_init_frame_parms(&cfg, &fp);
|
||||
nr_dump_frame_parms(&fp);
|
||||
test_coherence_symbol_api(&fp);
|
||||
test_coherence_slot_api(&fp);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
uniqCfg = load_configmodule(argc, argv, CONFIG_ENABLECMDLINEONLY);
|
||||
logInit();
|
||||
testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
||||
@@ -80,7 +80,7 @@ int nr_slot_fep(PHY_VARS_NR_UE *ue,
|
||||
// For Sidelink 16 frames worth of samples is processed to find SSB, for 5G-NR 2.
|
||||
const unsigned int total_samples = (is_sl) ? 16 * frame_parms->samples_per_frame : 2 * frame_parms->samples_per_frame;
|
||||
|
||||
unsigned int rx_offset = frame_parms->get_samples_slot_timestamp(slot, frame_parms, 0);
|
||||
unsigned int rx_offset = get_samples_slot_timestamp(frame_parms, slot);
|
||||
const unsigned int abs_symbol = slot * frame_parms->symbols_per_slot + symbol;
|
||||
for (int idx_symb = slot * frame_parms->symbols_per_slot; idx_symb <= abs_symbol; idx_symb++)
|
||||
rx_offset += (idx_symb % (0x7 << frame_parms->numerology_index)) ? nb_prefix_samples : nb_prefix_samples0;
|
||||
@@ -150,7 +150,7 @@ int nr_slot_fep_ul(NR_DL_FRAME_PARMS *frame_parms,
|
||||
int32_t tmp_dft_in[8192] __attribute__ ((aligned (32)));
|
||||
|
||||
// offset of first OFDM symbol
|
||||
unsigned int rxdata_offset = frame_parms->get_samples_slot_timestamp(Ns,frame_parms,0);
|
||||
unsigned int rxdata_offset = get_samples_slot_timestamp(frame_parms, Ns);
|
||||
unsigned int abs_symbol = Ns * frame_parms->symbols_per_slot + symbol;
|
||||
for (int idx_symb = Ns*frame_parms->symbols_per_slot; idx_symb <= abs_symbol; idx_symb++)
|
||||
rxdata_offset += (idx_symb%(0x7<<frame_parms->numerology_index)) ? nb_prefix_samples : nb_prefix_samples0;
|
||||
|
||||
@@ -362,7 +362,7 @@ static void rx_nr_prach_ru_internal(prach_item_t *p,
|
||||
// Fixme: slot or slot makes no sense ???
|
||||
int slot2 = p->prach_sequence_length ? p->slot : p->slot;
|
||||
int idx = aa + beam_id * p->nb_rx;
|
||||
c16_t *prach = (c16_t *)&rxdata[idx][fp->get_samples_slot_timestamp(slot2, fp, 0) + sample_offset_slot - N_TA_offset];
|
||||
c16_t *prach = (c16_t *)&rxdata[idx][get_samples_slot_timestamp(fp, slot2) + sample_offset_slot - N_TA_offset];
|
||||
|
||||
// do DFT
|
||||
c16_t *prach2 = prach + Ncp;
|
||||
|
||||
@@ -324,7 +324,7 @@ nr_initial_sync_t sl_nr_slss_search(PHY_VARS_NR_UE *UE, UE_nr_rxtx_proc_t *proc,
|
||||
|
||||
int32_t sync_pos = -1; // sync_pos_frame = -1;
|
||||
int32_t metric_tdd_ncp = 0;
|
||||
uint8_t phase_tdd_ncp;
|
||||
uint8_t phase_tdd_ncp = 0;
|
||||
double im, re;
|
||||
int ret = -1;
|
||||
uint16_t rx_slss_id = 65535;
|
||||
|
||||
@@ -467,7 +467,8 @@ typedef struct PHY_VARS_NR_UE_s {
|
||||
|
||||
/// Timing Advance updates variables
|
||||
/// Timing advance update computed from the TA command signalled from gNB
|
||||
int timing_advance;
|
||||
int timing_advance; /// corresponds to N_TA
|
||||
int timing_advance_ntn; /// corresponds to N_common_TA_adj + N_UE_TA_adj
|
||||
int N_TA_offset; ///timing offset used in TDD
|
||||
int ta_frame;
|
||||
int ta_slot;
|
||||
@@ -538,11 +539,14 @@ typedef struct {
|
||||
/// NR slot index within frame_rx [0 .. slots_per_frame - 1] to act upon for transmission
|
||||
int nr_slot_rx;
|
||||
int tx_slot_type;
|
||||
//#endif
|
||||
/// frame to act upon for transmission
|
||||
int frame_tx;
|
||||
/// frame to act upon for reception
|
||||
int frame_rx;
|
||||
/// hyper frame number to act upon for transmission
|
||||
int hfn_tx;
|
||||
/// hyper frame number to act upon for reception
|
||||
int hfn_rx;
|
||||
} UE_nr_rxtx_proc_t;
|
||||
|
||||
typedef struct {
|
||||
|
||||
@@ -165,11 +165,6 @@ void init_prach_list(prach_list_t *);
|
||||
|
||||
typedef struct NR_DL_FRAME_PARMS NR_DL_FRAME_PARMS;
|
||||
|
||||
typedef uint32_t (*get_samples_per_slot_t)(int slot, const NR_DL_FRAME_PARMS *fp);
|
||||
typedef uint32_t (*get_slot_from_timestamp_t)(openair0_timestamp timestamp_rx, const NR_DL_FRAME_PARMS *fp);
|
||||
|
||||
typedef uint32_t (*get_samples_slot_timestamp_t)(int slot, const NR_DL_FRAME_PARMS *fp, unsigned int sl_ahead);
|
||||
|
||||
struct NR_DL_FRAME_PARMS {
|
||||
/// frequency range
|
||||
frequency_range_t freq_range;
|
||||
@@ -225,12 +220,6 @@ struct NR_DL_FRAME_PARMS {
|
||||
uint16_t slots_per_frame;
|
||||
/// Number of samples in a subframe
|
||||
uint32_t samples_per_subframe;
|
||||
/// Number of samples in current slot
|
||||
get_samples_per_slot_t get_samples_per_slot;
|
||||
/// slot calculation from timestamp
|
||||
get_slot_from_timestamp_t get_slot_from_timestamp;
|
||||
/// Number of samples before slot
|
||||
get_samples_slot_timestamp_t get_samples_slot_timestamp;
|
||||
/// Number of samples in 0th and center slot of a subframe
|
||||
uint32_t samples_per_slot0;
|
||||
/// Number of samples in other slots of the subframe
|
||||
@@ -336,4 +325,17 @@ typedef struct {
|
||||
#define KHz (1000UL)
|
||||
#define MHz (1000*KHz)
|
||||
|
||||
// Get symbol duration within slot in samples
|
||||
uint32_t get_samples_symbol_duration(const NR_DL_FRAME_PARMS *fp, int slot, int start_symbol, int num_symbols);
|
||||
// Get timestamp of symbol within slot in samples
|
||||
uint32_t get_samples_symbol_timestamp(const NR_DL_FRAME_PARMS *fp, int slot, int symbol);
|
||||
// Get slot duration between two slot
|
||||
uint32_t get_samples_slot_duration(const NR_DL_FRAME_PARMS *fp, unsigned int start_slot, unsigned int num_slots);
|
||||
// Get timestamp of slot from start of frame
|
||||
uint32_t get_samples_slot_timestamp(const NR_DL_FRAME_PARMS *fp, unsigned int slot);
|
||||
// Get slot from timestamp
|
||||
uint32_t get_slot_from_timestamp(openair0_timestamp timestamp_rx, const NR_DL_FRAME_PARMS *fp);
|
||||
// Get number of samples in the slot
|
||||
uint32_t get_samples_per_slot(int slot, const NR_DL_FRAME_PARMS *fp);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -58,7 +58,7 @@ void nr_feptx0(RU_t *ru, int tti_tx, int first_symbol, int num_symbols, int aa)
|
||||
|
||||
if (aa == 0 && first_symbol == 0)
|
||||
start_meas(&ru->ofdm_mod_stats);
|
||||
slot_offset = fp->get_samples_slot_timestamp(slot, fp, 0);
|
||||
slot_offset = get_samples_slot_timestamp(fp, slot);
|
||||
slot_offsetF = first_symbol * fp->ofdm_symbol_size;
|
||||
|
||||
int abs_first_symbol = slot * fp->symbols_per_slot;
|
||||
@@ -156,7 +156,7 @@ void nr_feptx_ofdm(RU_t *ru,int frame_tx,int tti_tx) {
|
||||
int slot_sizeF = (fp->ofdm_symbol_size)*
|
||||
((cyclic_prefix_type == 1) ? 12 : 14);
|
||||
int slot = tti_tx;
|
||||
int *txdata = &ru->common.txdata[aa][fp->get_samples_slot_timestamp(slot,fp,0)];
|
||||
int *txdata = &ru->common.txdata[aa][get_samples_slot_timestamp(fp, slot)];
|
||||
|
||||
if (nr_slot_select(cfg,frame_tx,slot) == NR_UPLINK_SLOT) return;
|
||||
|
||||
@@ -169,10 +169,13 @@ void nr_feptx_ofdm(RU_t *ru,int frame_tx,int tti_tx) {
|
||||
|
||||
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPTX_OFDM , 0 );
|
||||
|
||||
LOG_D(PHY,"feptx_ofdm (TXPATH): frame %d, slot %d: txp (time %p) %d dB, txp (freq) %d dB\n",
|
||||
frame_tx,slot,txdata,dB_fixed(signal_energy((int32_t*)txdata,fp->get_samples_per_slot(
|
||||
slot,fp))),dB_fixed(signal_energy_nodc((c16_t*)ru->common.txdataF_BF[aa],2*slot_sizeF)));
|
||||
|
||||
LOG_D(PHY,
|
||||
"feptx_ofdm (TXPATH): frame %d, slot %d: txp (time %p) %d dB, txp (freq) %d dB\n",
|
||||
frame_tx,
|
||||
slot,
|
||||
txdata,
|
||||
dB_fixed(signal_energy((int32_t *)txdata, get_samples_per_slot(slot, fp))),
|
||||
dB_fixed(signal_energy_nodc((c16_t *)ru->common.txdataF_BF[aa], 2 * slot_sizeF)));
|
||||
}
|
||||
|
||||
void nr_feptx_prec(RU_t *ru, int frame_tx, int slot_tx)
|
||||
|
||||
@@ -969,17 +969,14 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, N
|
||||
buf[7] = (int16_t)ulsch->harq_pid;
|
||||
memcpy(&gNB->common_vars.debugBuff[gNB->common_vars.debugBuff_sample_offset + 4],
|
||||
&ru->common.rxdata[0][slot_offset],
|
||||
frame_parms->get_samples_per_slot(slot_rx, frame_parms) * sizeof(int32_t));
|
||||
gNB->common_vars.debugBuff_sample_offset += (frame_parms->get_samples_per_slot(slot_rx, frame_parms) + 1000 + 4);
|
||||
if (gNB->common_vars.debugBuff_sample_offset > ((frame_parms->get_samples_per_slot(slot_rx, frame_parms) + 1000 + 2) * 20)) {
|
||||
get_samples_per_slot(slot_rx, frame_parms) * sizeof(int32_t));
|
||||
gNB->common_vars.debugBuff_sample_offset += (get_samples_per_slot(slot_rx, frame_parms) + 1000 + 4);
|
||||
if (gNB->common_vars.debugBuff_sample_offset > ((get_samples_per_slot(slot_rx, frame_parms) + 1000 + 2) * 20)) {
|
||||
FILE *f;
|
||||
f = fopen("rxdata_buff.raw", "w");
|
||||
if (f == NULL)
|
||||
exit(1);
|
||||
fwrite((int16_t *)gNB->common_vars.debugBuff,
|
||||
2,
|
||||
(frame_parms->get_samples_per_slot(slot_rx, frame_parms) + 1000 + 4) * 20 * 2,
|
||||
f);
|
||||
fwrite((int16_t *)gNB->common_vars.debugBuff, 2, (get_samples_per_slot(slot_rx, frame_parms) + 1000 + 4) * 20 * 2, f);
|
||||
fclose(f);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
@@ -95,12 +95,20 @@ static void configure_ntn_params(PHY_VARS_NR_UE *ue, fapi_nr_dl_ntn_config_comma
|
||||
ue->ntn_config_message = CALLOC(1, sizeof(*ue->ntn_config_message));
|
||||
}
|
||||
|
||||
ue->ntn_config_message->ntn_config_params.epoch_hfn = ntn_params_message->epoch_hfn;
|
||||
ue->ntn_config_message->ntn_config_params.epoch_sfn = ntn_params_message->epoch_sfn;
|
||||
ue->ntn_config_message->ntn_config_params.epoch_subframe = ntn_params_message->epoch_subframe;
|
||||
|
||||
ue->ntn_config_message->ntn_config_params.omega = ntn_params_message->omega;
|
||||
ue->ntn_config_message->ntn_config_params.pos_sat_0 = ntn_params_message->pos_sat_0;
|
||||
ue->ntn_config_message->ntn_config_params.pos_sat_90 = ntn_params_message->pos_sat_90;
|
||||
|
||||
ue->ntn_config_message->ntn_config_params.N_common_ta_adj = ntn_params_message->N_common_ta_adj;
|
||||
ue->ntn_config_message->ntn_config_params.N_common_ta_drift = ntn_params_message->N_common_ta_drift;
|
||||
ue->ntn_config_message->ntn_config_params.N_common_ta_drift_variant = ntn_params_message->N_common_ta_drift_variant;
|
||||
|
||||
ue->ntn_config_message->ntn_config_params.cell_specific_k_offset = ntn_params_message->cell_specific_k_offset;
|
||||
ue->ntn_config_message->ntn_config_params.ntn_total_time_advance_ms = ntn_params_message->ntn_total_time_advance_ms;
|
||||
ue->ntn_config_message->ntn_config_params.ntn_total_time_advance_drift = ntn_params_message->ntn_total_time_advance_drift;
|
||||
ue->ntn_config_message->ntn_config_params.ntn_total_time_advance_drift_variant = ntn_params_message->ntn_total_time_advance_drift_variant;
|
||||
|
||||
ue->ntn_config_message->update = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -95,6 +95,7 @@ void nr_fill_dl_indication(nr_downlink_indication_t *dl_ind,
|
||||
dl_ind->gNB_index = proc->gNB_id;
|
||||
dl_ind->module_id = ue->Mod_id;
|
||||
dl_ind->cc_id = ue->CC_id;
|
||||
dl_ind->hfn = proc->hfn_rx;
|
||||
dl_ind->frame = proc->frame_rx;
|
||||
dl_ind->slot = proc->nr_slot_rx;
|
||||
dl_ind->phy_data = phy_data;
|
||||
|
||||
@@ -44,8 +44,10 @@ void nr_fill_sl_indication(nr_sidelink_indication_t *sl_ind,
|
||||
sl_ind->gNB_index = proc->gNB_id;
|
||||
sl_ind->module_id = ue->Mod_id;
|
||||
sl_ind->cc_id = ue->CC_id;
|
||||
sl_ind->hfn_rx = proc->hfn_rx;
|
||||
sl_ind->frame_rx = proc->frame_rx;
|
||||
sl_ind->slot_rx = proc->nr_slot_rx;
|
||||
sl_ind->hfn_tx = proc->hfn_tx;
|
||||
sl_ind->frame_tx = proc->frame_tx;
|
||||
sl_ind->slot_tx = proc->nr_slot_tx;
|
||||
sl_ind->phy_data = phy_data;
|
||||
|
||||
@@ -887,8 +887,8 @@ int main(int argc, char **argv)
|
||||
|
||||
frame_length_complex_samples = frame_parms->samples_per_subframe*NR_NUMBER_OF_SUBFRAMES_PER_FRAME;
|
||||
//frame_length_complex_samples_no_prefix = frame_parms->samples_per_subframe_wCP*NR_NUMBER_OF_SUBFRAMES_PER_FRAME;
|
||||
int slot_offset = frame_parms->get_samples_slot_timestamp(slot,frame_parms,0);
|
||||
int slot_length = slot_offset - frame_parms->get_samples_slot_timestamp(slot-1,frame_parms,0);
|
||||
int slot_offset = get_samples_slot_timestamp(frame_parms, slot);
|
||||
int slot_length = slot_offset - get_samples_slot_timestamp(frame_parms, slot - 1);
|
||||
|
||||
s_re = malloc(n_tx*sizeof(double*));
|
||||
s_im = malloc(n_tx*sizeof(double*));
|
||||
@@ -964,8 +964,8 @@ int main(int argc, char **argv)
|
||||
|
||||
//Configure UE
|
||||
NR_BCCH_BCH_Message_t *mib = get_new_MIB_NR(scc);
|
||||
nr_rrc_mac_config_req_mib(0, 0, mib->message.choice.mib, false, false);
|
||||
nr_rrc_mac_config_req_cg(0, 0, UE_CellGroup, UE_Capability_nr);
|
||||
nr_rrc_mac_config_req_mib(0, 0, mib->message.choice.mib, false);
|
||||
nr_rrc_mac_config_req_cg(0, 0, 0, 0, UE_CellGroup, UE_Capability_nr);
|
||||
|
||||
asn1cFreeStruc(asn_DEF_NR_CellGroupConfig, UE_CellGroup);
|
||||
|
||||
|
||||
@@ -163,6 +163,7 @@ typedef uint32_t channel_t;
|
||||
int8_t nr_mac_rrc_data_ind_ue(const module_id_t module_id,
|
||||
const int CC_id,
|
||||
const uint8_t gNB_index,
|
||||
const int hfn,
|
||||
const frame_t frame,
|
||||
const int slot,
|
||||
const rnti_t rnti,
|
||||
|
||||
@@ -527,7 +527,7 @@ int main(int argc, char **argv)
|
||||
|
||||
nr_common_signal_procedures (gNB,frame,slot, &ssb_pdu[i]);
|
||||
|
||||
int samp = frame_parms->get_samples_slot_timestamp(slot, frame_parms, 0);
|
||||
int samp = get_samples_slot_timestamp(frame_parms, slot);
|
||||
for (aa=0; aa<gNB->frame_parms.nb_antennas_tx; aa++) {
|
||||
if (cyclic_prefix_type == 1) {
|
||||
apply_nr_rotation_TX(frame_parms,
|
||||
|
||||
@@ -665,7 +665,7 @@ int main(int argc, char **argv){
|
||||
UE->X_u);
|
||||
|
||||
int prach_start = subframe * frame_parms->samples_per_subframe;
|
||||
int slot_start = frame_parms->get_samples_slot_timestamp(slot, frame_parms, 0);
|
||||
int slot_start = get_samples_slot_timestamp(frame_parms, slot);
|
||||
c16_t *tx[frame_parms->nb_antennas_rx];
|
||||
for (int i = 0; i < frame_parms->nb_antennas_rx; i++)
|
||||
tx[i] = txdata[i] + slot_start;
|
||||
|
||||
@@ -574,7 +574,7 @@ int main(int argc, char **argv)
|
||||
proc.frame_rx,
|
||||
proc.nr_slot_rx,
|
||||
sl_uerx->sl_config.sl_sync_source.rx_slss_id);
|
||||
int slot_start = frame_parms->get_samples_slot_timestamp(slot, frame_parms, 0);
|
||||
int slot_start = get_samples_slot_timestamp(frame_parms, slot);
|
||||
c16_t *tx[frame_parms->nb_antennas_rx];
|
||||
for (int i = 0; i < frame_parms->nb_antennas_rx; i++)
|
||||
tx[i] = UE_TX->common_vars.txData[i] + slot_start;
|
||||
|
||||
@@ -1061,8 +1061,8 @@ int main(int argc, char *argv[])
|
||||
//for (int i=0;i<16;i++) printf("%f\n",gaussdouble(0.0,1.0));
|
||||
int read_errors=0;
|
||||
|
||||
int slot_offset = gNB->frame_parms.get_samples_slot_timestamp(slot, &gNB->frame_parms, 0);
|
||||
int slot_length = slot_offset - gNB->frame_parms.get_samples_slot_timestamp(slot - 1, &gNB->frame_parms, 0);
|
||||
int slot_offset = get_samples_slot_timestamp(&gNB->frame_parms, slot);
|
||||
int slot_length = slot_offset - get_samples_slot_timestamp(&gNB->frame_parms, slot - 1);
|
||||
|
||||
if (input_fd != NULL) {
|
||||
// 800 samples is N_TA_OFFSET for FR1 @ 30.72 Ms/s,
|
||||
@@ -1382,7 +1382,7 @@ int main(int argc, char *argv[])
|
||||
|
||||
/////////////////////////phy_procedures_nr_ue_TX///////////////////////
|
||||
///////////
|
||||
int slot_start = UE->frame_parms.get_samples_slot_timestamp(slot, &UE->frame_parms, 0);
|
||||
int slot_start = get_samples_slot_timestamp(&UE->frame_parms, slot);
|
||||
c16_t *tx[UE->frame_parms.nb_antennas_tx];
|
||||
for (int i = 0; i < UE->frame_parms.nb_antennas_tx; i++)
|
||||
tx[i] = UE->common_vars.txData[i] + slot_start;
|
||||
@@ -1400,7 +1400,7 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
///////////
|
||||
////////////////////////////////////////////////////
|
||||
tx_offset = gNB->frame_parms.get_samples_slot_timestamp(slot, &gNB->frame_parms, 0);
|
||||
tx_offset = get_samples_slot_timestamp(&gNB->frame_parms, slot);
|
||||
txlev_sum = 0;
|
||||
for (int aa = 0; aa < UE->frame_parms.nb_antennas_tx; aa++) {
|
||||
atxlev[aa] =
|
||||
|
||||
@@ -78,6 +78,7 @@
|
||||
|
||||
typedef struct NRRrcMacRaInd_s {
|
||||
bool RA_succeeded;
|
||||
int gnb_index;
|
||||
} NRRrcMacRaInd;
|
||||
|
||||
typedef struct NRRrcMacMsg3Ind_s {
|
||||
@@ -121,6 +122,7 @@ typedef struct RrcMacBcchDataInd_s {
|
||||
} RrcMacBcchDataInd;
|
||||
|
||||
typedef struct NRRrcMacBcchDataInd_s {
|
||||
uint32_t hfn;
|
||||
uint32_t frame;
|
||||
uint8_t slot;
|
||||
uint32_t sdu_size;
|
||||
@@ -134,6 +136,7 @@ typedef struct NRRrcMacBcchDataInd_s {
|
||||
} NRRrcMacBcchDataInd;
|
||||
|
||||
typedef struct NRRrcMacSBcchDataInd_s {
|
||||
uint32_t hfn;
|
||||
uint32_t frame;
|
||||
uint8_t slot;
|
||||
uint32_t sdu_size;
|
||||
|
||||
@@ -438,6 +438,7 @@ typedef struct rrc_subframe_process_s {
|
||||
} RrcSubframeProcess;
|
||||
|
||||
typedef struct nrrrc_frame_process_s {
|
||||
int hfn;
|
||||
int frame;
|
||||
int gnb_id;
|
||||
} NRRrcFrameProcess;
|
||||
@@ -475,10 +476,11 @@ typedef struct {
|
||||
typedef struct {
|
||||
NR_CellGroupConfig_t *cellGroupConfig;
|
||||
NR_UE_NR_Capability_t *UE_NR_Capability;
|
||||
int hfn;
|
||||
int frame;
|
||||
} nr_mac_rrc_config_cg_t;
|
||||
typedef struct {
|
||||
NR_BCCH_BCH_Message_t *bcch;
|
||||
int get_sib;
|
||||
bool access_barred;
|
||||
} nr_mac_rrc_config_mib_t;
|
||||
typedef struct {
|
||||
@@ -487,8 +489,14 @@ typedef struct {
|
||||
} nr_mac_rrc_config_sib1_t;
|
||||
typedef struct {
|
||||
NR_SIB19_r17_t *sib19;
|
||||
int hfn;
|
||||
int frame;
|
||||
bool can_start_ra;
|
||||
} nr_mac_rrc_config_other_sib_t;
|
||||
typedef struct {
|
||||
int get_sib;
|
||||
} nr_mac_rrc_sched_sib_t;
|
||||
|
||||
|
||||
enum payload_type {
|
||||
NR_MAC_RRC_CONFIG_RESET,
|
||||
@@ -496,6 +504,7 @@ enum payload_type {
|
||||
NR_MAC_RRC_CONFIG_MIB,
|
||||
NR_MAC_RRC_CONFIG_SIB1,
|
||||
NR_MAC_RRC_CONFIG_OTHER_SIB,
|
||||
NR_MAC_RRC_SCHED_SIB,
|
||||
NR_MAC_RRC_RESUME_RB
|
||||
};
|
||||
|
||||
@@ -506,6 +515,7 @@ typedef struct {
|
||||
nr_mac_rrc_config_cg_t config_cg;
|
||||
nr_mac_rrc_config_mib_t config_mib;
|
||||
nr_mac_rrc_config_sib1_t config_sib1;
|
||||
nr_mac_rrc_sched_sib_t sched_sib;
|
||||
nr_mac_rrc_config_other_sib_t config_other_sib;
|
||||
nr_mac_rrc_resume_rb_t resume_rb;
|
||||
} payload;
|
||||
|
||||
@@ -31,7 +31,6 @@
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#define SPEED_OF_LIGHT 299792458
|
||||
|
||||
#include "mac_defs.h"
|
||||
#include "NR_MAC_UE/mac_proto.h"
|
||||
@@ -41,7 +40,6 @@
|
||||
#include "executables/softmodem-common.h"
|
||||
#include "SCHED_NR/phy_frame_config_nr.h"
|
||||
#include "oai_asn1.h"
|
||||
#include "executables/position_interface.h"
|
||||
|
||||
#define ASIGN_P_VAL(dst, src) \
|
||||
do { \
|
||||
@@ -262,60 +260,63 @@ static void config_common_ue_sa(NR_UE_MAC_INST_t *mac, NR_ServingCellConfigCommo
|
||||
mac->frequency_range);
|
||||
//prach_fd_occasion->num_unused_root_sequences = ???
|
||||
}
|
||||
cfg->prach_config.ssb_per_rach = rach_ConfigCommon->ssb_perRACH_OccasionAndCB_PreamblesPerSSB->present-1;
|
||||
|
||||
}
|
||||
|
||||
// computes round-trip-time between ue and sat based on SIB19 ephemeris data
|
||||
static void calculate_ue_sat_ta(const position_t *position_params,
|
||||
const NR_PositionVelocity_r17_t *sat_pos,
|
||||
ntn_timing_advance_componets_t *ntn_ta)
|
||||
// prepare data for orbit propagation based on SIB19 ephemeris data to be able to compute the round-trip-time between ue and sat
|
||||
static void prepare_ue_sat_ta(const NR_PositionVelocity_r17_t *sat_pos, ntn_timing_advance_componets_t *ntn_ta)
|
||||
{
|
||||
// get UE position coordinates
|
||||
const position_t pos_ue = *position_params;
|
||||
|
||||
// get sat position coordinates
|
||||
const position_t pos_sat = {sat_pos->positionX_r17 * 1.3, sat_pos->positionY_r17 * 1.3, sat_pos->positionZ_r17 * 1.3};
|
||||
|
||||
// calculate directional vector from SAT to UE
|
||||
const position_t dir_sat_ue = {pos_ue.X - pos_sat.X, pos_ue.Y - pos_sat.Y, pos_ue.Z - pos_sat.Z};
|
||||
|
||||
// calculate distance between SAT and UE
|
||||
double distance = sqrt(dir_sat_ue.X * dir_sat_ue.X + dir_sat_ue.Y * dir_sat_ue.Y + dir_sat_ue.Z * dir_sat_ue.Z);
|
||||
|
||||
// get sat velocity vector
|
||||
const position_t vel_sat = {sat_pos->velocityVX_r17 * 0.06, sat_pos->velocityVY_r17 * 0.06, sat_pos->velocityVZ_r17 * 0.06};
|
||||
|
||||
// calculate SAT velocity towards UE
|
||||
double velocity = (vel_sat.X * dir_sat_ue.X + vel_sat.Y * dir_sat_ue.Y + vel_sat.Z * dir_sat_ue.Z) / distance;
|
||||
|
||||
// calculate SAT acceleration towards UE
|
||||
// calculate orbital radius
|
||||
const double radius_2 = pos_sat.X * pos_sat.X + pos_sat.Y * pos_sat.Y + pos_sat.Z * pos_sat.Z;
|
||||
const double radius = sqrt(radius_2);
|
||||
|
||||
// calculate sat velocity magnitude
|
||||
const double vel_sat_2 = vel_sat.X * vel_sat.X + vel_sat.Y * vel_sat.Y + vel_sat.Z * vel_sat.Z;
|
||||
const double acceleration =
|
||||
-(pos_sat.X * dir_sat_ue.X + pos_sat.Y * dir_sat_ue.Y + pos_sat.Z * dir_sat_ue.Z) * vel_sat_2 / (radius_2 * distance);
|
||||
const double vel_mag = sqrt(vel_sat_2);
|
||||
|
||||
LOG_D(NR_MAC, "Satellite velocity towards UE: %f m/s, acceleration towards UE: %f m/s²\n", velocity, acceleration);
|
||||
// calculate angular velocity in rad/ms
|
||||
const double omega = vel_mag / (radius * 1000);
|
||||
|
||||
ntn_ta->N_UE_TA_adj = (2 * distance / SPEED_OF_LIGHT) * 1e3; // in ms
|
||||
ntn_ta->N_UE_TA_drift = (2 * -velocity / SPEED_OF_LIGHT) * 1e6; // in µs/s
|
||||
ntn_ta->N_UE_TA_drift_variant = (2 * acceleration / SPEED_OF_LIGHT) * 1e6; // in µs/s²
|
||||
// calculate sat position in 90° orbit
|
||||
position_t pos_sat_90 = pos_sat;
|
||||
if (vel_mag) {
|
||||
const double scaling = radius / vel_mag;
|
||||
pos_sat_90 = (position_t){vel_sat.X * scaling, vel_sat.Y * scaling, vel_sat.Z * scaling};
|
||||
}
|
||||
|
||||
LOG_I(NR_MAC,
|
||||
"Satellite angular velocity = %e rad/ms, sat_pos = {%f, %f, %f}, sat_pos_90 = {%f, %f, %f}\n",
|
||||
omega,
|
||||
pos_sat.X,
|
||||
pos_sat.Y,
|
||||
pos_sat.Z,
|
||||
pos_sat_90.X,
|
||||
pos_sat_90.Y,
|
||||
pos_sat_90.Z);
|
||||
|
||||
ntn_ta->omega = omega;
|
||||
ntn_ta->pos_sat_0 = pos_sat;
|
||||
ntn_ta->pos_sat_90 = pos_sat_90;
|
||||
}
|
||||
|
||||
// populate ntn_ta structure from mac
|
||||
static void configure_ntn_ta(module_id_t module_id,
|
||||
ntn_timing_advance_componets_t *ntn_ta,
|
||||
const NR_NTN_Config_r17_t *ntn_Config_r17)
|
||||
static void configure_ntn_ta(ntn_timing_advance_componets_t *ntn_ta, const NR_NTN_Config_r17_t *ntn_Config_r17, int hfn, int frame)
|
||||
{
|
||||
if (!ntn_Config_r17)
|
||||
return;
|
||||
|
||||
position_t position_params = {0};
|
||||
get_position_coordinates(module_id, &position_params);
|
||||
|
||||
// epochTime_r17 must be present (this is assured by function `eval_epoch_time()`)
|
||||
const NR_EpochTime_r17_t *epoch_time_r17 = ntn_Config_r17->epochTime_r17;
|
||||
AssertFatal(epoch_time_r17, "epoch_time_r17 should not be NULL here\n");
|
||||
if (epoch_time_r17->sfn_r17 >= frame)
|
||||
ntn_ta->epoch_hfn = hfn;
|
||||
else
|
||||
ntn_ta->epoch_hfn = hfn + 1;
|
||||
ntn_ta->epoch_sfn = epoch_time_r17->sfn_r17;
|
||||
ntn_ta->epoch_subframe = epoch_time_r17->subFrameNR_r17;
|
||||
|
||||
@@ -325,17 +326,17 @@ static void configure_ntn_ta(module_id_t module_id,
|
||||
if (ephemeris_info->present == NR_EphemerisInfo_r17_PR_positionVelocity_r17) {
|
||||
const NR_PositionVelocity_r17_t *position_velocity = ephemeris_info->choice.positionVelocity_r17;
|
||||
AssertFatal(position_velocity, "position_velocity should not be NULL here\n");
|
||||
calculate_ue_sat_ta(&position_params, position_velocity, ntn_ta);
|
||||
prepare_ue_sat_ta(position_velocity, ntn_ta);
|
||||
} else {
|
||||
LOG_W(NR_MAC, "NR UE currently supports only ephemerisInfo_r17 of type positionVelocity_r17\n");
|
||||
ntn_ta->N_UE_TA_adj = 0;
|
||||
ntn_ta->N_UE_TA_drift = 0;
|
||||
ntn_ta->N_UE_TA_drift_variant = 0;
|
||||
ntn_ta->omega = 0;
|
||||
ntn_ta->pos_sat_0 = (position_t){0, 0, 0};
|
||||
ntn_ta->pos_sat_90 = (position_t){0, 0, 0};
|
||||
}
|
||||
} else { // Need R - Release if not present
|
||||
ntn_ta->N_UE_TA_adj = 0;
|
||||
ntn_ta->N_UE_TA_drift = 0;
|
||||
ntn_ta->N_UE_TA_drift_variant = 0;
|
||||
ntn_ta->omega = 0;
|
||||
ntn_ta->pos_sat_0 = (position_t){0, 0, 0};
|
||||
ntn_ta->pos_sat_90 = (position_t){0, 0, 0};
|
||||
}
|
||||
|
||||
// handle cellSpecificKoffset_r17
|
||||
@@ -366,21 +367,19 @@ static void configure_ntn_ta(module_id_t module_id,
|
||||
|
||||
ntn_ta->ntn_params_changed = true;
|
||||
|
||||
LOG_D(NR_MAC,
|
||||
"SIB19 Rxd. Epoch SFN: %d, Epoch Subframe: %d, k_offset: %ldms, N_Common_Ta: %fms, drift: %fµs/s, variant %fµs/s², "
|
||||
"N_UE_TA: %fms, drift: %fµs/s, variant %fµs/s²\n",
|
||||
LOG_I(NR_MAC,
|
||||
"SIB19 Rxd. Epoch HFN: %d, Epoch SFN: %d, Epoch Subframe: %d, k_offset: %ldms, "
|
||||
"N_Common_Ta: %fms, drift: %fµs/s, variant %fµs/s²\n",
|
||||
ntn_ta->epoch_hfn,
|
||||
ntn_ta->epoch_sfn,
|
||||
ntn_ta->epoch_subframe,
|
||||
ntn_ta->cell_specific_k_offset,
|
||||
ntn_ta->N_common_ta_adj,
|
||||
ntn_ta->N_common_ta_drift,
|
||||
ntn_ta->N_common_ta_drift_variant,
|
||||
ntn_ta->N_UE_TA_adj,
|
||||
ntn_ta->N_UE_TA_drift,
|
||||
ntn_ta->N_UE_TA_drift_variant);
|
||||
ntn_ta->N_common_ta_drift_variant);
|
||||
}
|
||||
|
||||
static void config_common_ue(NR_UE_MAC_INST_t *mac, NR_ServingCellConfigCommon_t *scc, int cc_idP)
|
||||
static void config_common_ue(NR_UE_MAC_INST_t *mac, NR_ServingCellConfigCommon_t *scc, int cc_idP, int hfn, int frame)
|
||||
{
|
||||
fapi_nr_config_request_t *cfg = &mac->phy_config.config_req;
|
||||
|
||||
@@ -547,7 +546,6 @@ static void config_common_ue(NR_UE_MAC_INST_t *mac, NR_ServingCellConfigCommon_t
|
||||
prach_fd_occasion->num_root_sequences =
|
||||
compute_nr_root_seq(rach_ConfigCommon, nb_preambles, frame_type, mac->frequency_range);
|
||||
|
||||
cfg->prach_config.ssb_per_rach = rach_ConfigCommon->ssb_perRACH_OccasionAndCB_PreamblesPerSSB->present - 1;
|
||||
// prach_fd_occasion->num_unused_root_sequences = ???
|
||||
}
|
||||
}
|
||||
@@ -555,7 +553,7 @@ static void config_common_ue(NR_UE_MAC_INST_t *mac, NR_ServingCellConfigCommon_t
|
||||
// NTN Config
|
||||
if (scc->ext2) {
|
||||
UPDATE_IE(mac->sc_info.ntn_Config_r17, scc->ext2->ntn_Config_r17, NR_NTN_Config_r17_t);
|
||||
configure_ntn_ta(mac->ue_id, &mac->ntn_ta, mac->sc_info.ntn_Config_r17);
|
||||
configure_ntn_ta(&mac->ntn_ta, mac->sc_info.ntn_Config_r17, hfn, frame);
|
||||
} else {
|
||||
asn1cFreeStruc(asn_DEF_NR_NTN_Config_r17, mac->sc_info.ntn_Config_r17);
|
||||
}
|
||||
@@ -886,7 +884,8 @@ static void nr_configure_lc_config(NR_UE_MAC_INST_t *mac,
|
||||
nr_lcid_rb_t rb)
|
||||
{
|
||||
NR_LC_SCHEDULING_INFO *lc_sched_info = get_scheduling_info_from_lcid(mac, lc_info->lcid);
|
||||
lc_info->rb = rb;
|
||||
if (rb.type != NR_LCID_NONE)
|
||||
lc_info->rb = rb;
|
||||
lc_info->rb_suspended = false;
|
||||
if (rb.type == NR_LCID_SRB && !mac_lc_config->ul_SpecificParameters) {
|
||||
// release configuration and reset to default
|
||||
@@ -914,6 +913,12 @@ static void nr_configure_lc_config(NR_UE_MAC_INST_t *mac,
|
||||
static nr_lcid_rb_t configure_lcid_rb(NR_RLC_BearerConfig_t *rlc_bearer)
|
||||
{
|
||||
nr_lcid_rb_t rb;
|
||||
if (!rlc_bearer->servedRadioBearer) {
|
||||
LOG_W(NR_MAC, "RLC bearer config does not contain servedRadioBearer.\n");
|
||||
rb.type = NR_LCID_NONE;
|
||||
return rb;
|
||||
}
|
||||
|
||||
if (rlc_bearer->servedRadioBearer->present == NR_RLC_BearerConfig__servedRadioBearer_PR_srb_Identity) {
|
||||
rb.type = NR_LCID_SRB;
|
||||
rb.choice.srb_id = rlc_bearer->servedRadioBearer->choice.srb_Identity;
|
||||
@@ -953,8 +958,6 @@ static void configure_logicalChannelBearer(NR_UE_MAC_INST_t *mac,
|
||||
for (int i = 0; i < rlc_toadd_list->list.count; i++) {
|
||||
NR_RLC_BearerConfig_t *rlc_bearer = rlc_toadd_list->list.array[i];
|
||||
nr_lcid_rb_t rb = configure_lcid_rb(rlc_bearer);
|
||||
if (rb.type == NR_LCID_NONE)
|
||||
continue;
|
||||
int lc_identity = rlc_bearer->logicalChannelIdentity;
|
||||
NR_LogicalChannelConfig_t *mac_lc_config = rlc_bearer->mac_LogicalChannelConfig;
|
||||
int j;
|
||||
@@ -1022,7 +1025,21 @@ static bool is_cset0_present(frequency_range_t const fr, uint8_t const kssb)
|
||||
return (fr == FR1) ? (kssb < 24) : (kssb < 12);
|
||||
}
|
||||
|
||||
void nr_rrc_mac_config_req_mib(module_id_t module_id, int cc_idP, NR_MIB_t *mib, int sched_sib, bool barred)
|
||||
void nr_rrc_mac_sched_sib(module_id_t module_id, int sched_sib)
|
||||
{
|
||||
NR_UE_MAC_INST_t *mac = get_mac_inst(module_id);
|
||||
if (sched_sib == 1) {
|
||||
bool const is_c0 = is_cset0_present(mac->frequency_range, mac->ssb_subcarrier_offset);
|
||||
mac->get_sib1 = is_c0;
|
||||
AssertFatal(is_c0, "RRC scheduling SIB1 reception but MIB indicates no SIB1 present in current cell\n");
|
||||
} else if (sched_sib > 1)
|
||||
mac->get_otherSI[sched_sib - 2] = true;
|
||||
|
||||
if (mac->state == UE_NOT_SYNC && mac->get_sib1)
|
||||
mac->state = UE_RECEIVING_SIB;
|
||||
}
|
||||
|
||||
void nr_rrc_mac_config_req_mib(module_id_t module_id, int cc_idP, NR_MIB_t *mib, bool barred)
|
||||
{
|
||||
NR_UE_MAC_INST_t *mac = get_mac_inst(module_id);
|
||||
int ret = pthread_mutex_lock(&mac->if_mutex);
|
||||
@@ -1042,22 +1059,10 @@ void nr_rrc_mac_config_req_mib(module_id_t module_id, int cc_idP, NR_MIB_t *mib,
|
||||
mac->phy_config.CC_id = cc_idP;
|
||||
|
||||
nr_ue_decode_mib(mac, cc_idP);
|
||||
|
||||
if (sched_sib == 1) {
|
||||
bool const is_c0 = is_cset0_present(mac->frequency_range, mac->ssb_subcarrier_offset);
|
||||
mac->get_sib1 = is_c0;
|
||||
AssertFatal(is_c0, "RRC scheduling SIB1 reception but MIB indicates no SIB1 present in current cell\n");
|
||||
} else if (sched_sib > 1)
|
||||
mac->get_otherSI[sched_sib - 2] = true;
|
||||
|
||||
if (get_softmodem_params()->phy_test)
|
||||
mac->state = UE_CONNECTED;
|
||||
else if (mac->state == UE_NOT_SYNC) {
|
||||
if (IS_SA_MODE(get_softmodem_params()) && mac->get_sib1)
|
||||
mac->state = UE_RECEIVING_SIB;
|
||||
else
|
||||
mac->state = UE_PERFORMING_RA;
|
||||
}
|
||||
else if (mac->state == UE_NOT_SYNC_RECONF)
|
||||
mac->state = UE_PERFORMING_RA;
|
||||
|
||||
ret = pthread_mutex_unlock(&mac->if_mutex);
|
||||
AssertFatal(!ret, "mutex failed %d\n", ret);
|
||||
@@ -1713,10 +1718,13 @@ static void configure_common_BWP_ul(NR_UE_MAC_INST_t *mac, int bwp_id, NR_BWP_Up
|
||||
mac->sc_info.initial_ul_BWPStart = bwp->BWPStart;
|
||||
}
|
||||
if (ul_common->rach_ConfigCommon) {
|
||||
HANDLE_SETUPRELEASE_DIRECT(bwp->rach_ConfigCommon,
|
||||
ul_common->rach_ConfigCommon,
|
||||
NR_RACH_ConfigCommon_t,
|
||||
asn_DEF_NR_RACH_ConfigCommon);
|
||||
// ssb_perRACH_OccasionAndCB_PreamblesPerSSB is need M
|
||||
// if NULL we need to maintain the information
|
||||
NR_SetupRelease_RACH_ConfigCommon_t *rachcommon = ul_common->rach_ConfigCommon;
|
||||
if (rachcommon->present == NR_SetupRelease_RACH_ConfigCommon_PR_setup
|
||||
&& rachcommon->choice.setup->ssb_perRACH_OccasionAndCB_PreamblesPerSSB)
|
||||
mac->ssb_ro_preambles = get_ssb_ro_preambles_4step(rachcommon->choice.setup->ssb_perRACH_OccasionAndCB_PreamblesPerSSB);
|
||||
HANDLE_SETUPRELEASE_DIRECT(bwp->rach_ConfigCommon, rachcommon, NR_RACH_ConfigCommon_t, asn_DEF_NR_RACH_ConfigCommon);
|
||||
}
|
||||
if (ul_common->ext1 && ul_common->ext1->msgA_ConfigCommon_r16) {
|
||||
HANDLE_SETUPRELEASE_DIRECT(bwp->msgA_ConfigCommon_r16,
|
||||
@@ -1804,7 +1812,7 @@ void nr_rrc_mac_config_req_reset(module_id_t module_id, NR_UE_MAC_reset_cause_t
|
||||
LOG_A(NR_MAC, "Received detach indication\n");
|
||||
reset_ra(mac, true);
|
||||
reset_mac_inst(mac);
|
||||
nr_ue_reset_sync_state(mac);
|
||||
nr_ue_reset_sync_state(mac, false);
|
||||
release_mac_configuration(mac, cause);
|
||||
mac->state = UE_DETACHING;
|
||||
break;
|
||||
@@ -1821,7 +1829,7 @@ void nr_rrc_mac_config_req_reset(module_id_t module_id, NR_UE_MAC_reset_cause_t
|
||||
case RE_ESTABLISHMENT:
|
||||
reset_mac_inst(mac);
|
||||
nr_ue_mac_default_configs(mac);
|
||||
nr_ue_reset_sync_state(mac);
|
||||
nr_ue_reset_sync_state(mac, true);
|
||||
release_mac_configuration(mac, cause);
|
||||
// suspend all RBs except SRB0
|
||||
for (int j = 0; j < mac->lc_ordered_list.count; j++) {
|
||||
@@ -1947,7 +1955,7 @@ void nr_rrc_mac_config_req_sib1(module_id_t module_id, int cc_idP, NR_SIB1_t *si
|
||||
AssertFatal(!ret, "mutex failed %d\n", ret);
|
||||
}
|
||||
|
||||
void nr_rrc_mac_config_other_sib(module_id_t module_id, NR_SIB19_r17_t *sib19, bool can_start_ra)
|
||||
void nr_rrc_mac_config_other_sib(module_id_t module_id, NR_SIB19_r17_t *sib19, int hfn, int frame, bool can_start_ra)
|
||||
{
|
||||
NR_UE_MAC_INST_t *mac = get_mac_inst(module_id);
|
||||
int ret = pthread_mutex_lock(&mac->if_mutex);
|
||||
@@ -1956,7 +1964,7 @@ void nr_rrc_mac_config_other_sib(module_id_t module_id, NR_SIB19_r17_t *sib19, b
|
||||
if (sib19) {
|
||||
// update ntn_Config_r17 with received values
|
||||
UPDATE_IE(mac->sc_info.ntn_Config_r17, sib19->ntn_Config_r17, NR_NTN_Config_r17_t);
|
||||
configure_ntn_ta(mac->ue_id, &mac->ntn_ta, mac->sc_info.ntn_Config_r17);
|
||||
configure_ntn_ta(&mac->ntn_ta, mac->sc_info.ntn_Config_r17, hfn, frame);
|
||||
}
|
||||
if (mac->state == UE_RECEIVING_SIB && can_start_ra)
|
||||
mac->state = UE_PERFORMING_RA;
|
||||
@@ -1966,6 +1974,8 @@ void nr_rrc_mac_config_other_sib(module_id_t module_id, NR_SIB19_r17_t *sib19, b
|
||||
|
||||
static void handle_reconfiguration_with_sync(NR_UE_MAC_INST_t *mac,
|
||||
int cc_idP,
|
||||
int hfn,
|
||||
int frame,
|
||||
const NR_ReconfigurationWithSync_t *reconfWithSync)
|
||||
{
|
||||
reset_mac_inst(mac);
|
||||
@@ -1973,19 +1983,30 @@ static void handle_reconfiguration_with_sync(NR_UE_MAC_INST_t *mac,
|
||||
LOG_I(NR_MAC, "Configuring CRNTI %x\n", mac->crnti);
|
||||
|
||||
RA_config_t *ra = &mac->ra;
|
||||
bool is_cfra = false;
|
||||
if (reconfWithSync->rach_ConfigDedicated) {
|
||||
AssertFatal(reconfWithSync->rach_ConfigDedicated->present == NR_ReconfigurationWithSync__rach_ConfigDedicated_PR_uplink,
|
||||
"RACH on supplementaryUplink not supported\n");
|
||||
NR_RACH_ConfigDedicated_t *rach_ConfigDedicated = reconfWithSync->rach_ConfigDedicated->choice.uplink;
|
||||
if (rach_ConfigDedicated->cfra)
|
||||
is_cfra = true;
|
||||
if (rach_ConfigDedicated->ext1 && rach_ConfigDedicated->ext1->cfra_TwoStep_r16)
|
||||
is_cfra = true;
|
||||
UPDATE_IE(ra->rach_ConfigDedicated, reconfWithSync->rach_ConfigDedicated->choice.uplink, NR_RACH_ConfigDedicated_t);
|
||||
}
|
||||
|
||||
// in case of CBRA and reconfiguration with sync (handover)
|
||||
// the UE sends MSG3 with C-RNTI to identify itself
|
||||
if (!is_cfra)
|
||||
mac->msg3_C_RNTI = true;
|
||||
|
||||
if (reconfWithSync->spCellConfigCommon) {
|
||||
NR_ServingCellConfigCommon_t *scc = reconfWithSync->spCellConfigCommon;
|
||||
if (scc->physCellId)
|
||||
mac->physCellId = *scc->physCellId;
|
||||
mac->dmrs_TypeA_Position = scc->dmrs_TypeA_Position;
|
||||
UPDATE_IE(mac->tdd_UL_DL_ConfigurationCommon, scc->tdd_UL_DL_ConfigurationCommon, NR_TDD_UL_DL_ConfigCommon_t);
|
||||
config_common_ue(mac, scc, cc_idP);
|
||||
config_common_ue(mac, scc, cc_idP, hfn, frame);
|
||||
// Build the list of all the valid/transmitted SSBs according to the config
|
||||
LOG_D(NR_MAC,"Build SSB list\n");
|
||||
build_ssb_list(mac);
|
||||
@@ -1997,7 +2018,7 @@ static void handle_reconfiguration_with_sync(NR_UE_MAC_INST_t *mac,
|
||||
configure_common_BWP_ul(mac, bwp_id, scc->uplinkConfigCommon->initialUplinkBWP);
|
||||
}
|
||||
|
||||
mac->state = UE_NOT_SYNC;
|
||||
mac->state = UE_NOT_SYNC_RECONF;
|
||||
ra->ra_state = nrRA_UE_IDLE;
|
||||
nr_ue_mac_default_configs(mac);
|
||||
|
||||
@@ -2754,6 +2775,8 @@ static void handle_mac_uecap_info(NR_UE_MAC_INST_t *mac, NR_UE_NR_Capability_t *
|
||||
|
||||
void nr_rrc_mac_config_req_cg(module_id_t module_id,
|
||||
int cc_idP,
|
||||
int hfn,
|
||||
int frame,
|
||||
NR_CellGroupConfig_t *cell_group_config,
|
||||
NR_UE_NR_Capability_t *ue_Capability)
|
||||
{
|
||||
@@ -2772,7 +2795,7 @@ void nr_rrc_mac_config_req_cg(module_id_t module_id,
|
||||
mac->servCellIndex = spCellConfig->servCellIndex ? *spCellConfig->servCellIndex : 0;
|
||||
if (spCellConfig->reconfigurationWithSync) {
|
||||
LOG_A(NR_MAC, "Received reconfigurationWithSync\n");
|
||||
handle_reconfiguration_with_sync(mac, cc_idP, spCellConfig->reconfigurationWithSync);
|
||||
handle_reconfiguration_with_sync(mac, cc_idP, hfn, frame, spCellConfig->reconfigurationWithSync);
|
||||
}
|
||||
if (scd) {
|
||||
mac->tag_Id = scd->tag_Id;
|
||||
|
||||
@@ -62,6 +62,8 @@
|
||||
#include "NR_MeasConfig.h"
|
||||
#include "NR_ServingCellConfigCommonSIB.h"
|
||||
|
||||
/* position_t */
|
||||
#include "executables/position_interface.h"
|
||||
|
||||
// ==========
|
||||
// NR UE defs
|
||||
@@ -148,6 +150,7 @@
|
||||
// Define the UE L2 states with X-Macro
|
||||
#define NR_UE_L2_STATES \
|
||||
UE_STATE(UE_NOT_SYNC) \
|
||||
UE_STATE(UE_NOT_SYNC_RECONF) \
|
||||
UE_STATE(UE_BARRED) \
|
||||
UE_STATE(UE_RECEIVING_SIB) \
|
||||
UE_STATE(UE_PERFORMING_RA) \
|
||||
@@ -543,21 +546,24 @@ typedef struct {
|
||||
} si_schedInfo_t;
|
||||
|
||||
typedef struct ntn_timing_advance_components {
|
||||
int epoch_hfn;
|
||||
int epoch_sfn;
|
||||
int epoch_subframe;
|
||||
|
||||
// orbital angular velocity in rad/ms
|
||||
double omega;
|
||||
// satellite position at epoch time
|
||||
position_t pos_sat_0;
|
||||
// satellite position at 90° orbit
|
||||
position_t pos_sat_90;
|
||||
|
||||
// N_common_ta_adj represents common round-trip-time between gNB and SAT received in SIB19 (ms)
|
||||
double N_common_ta_adj;
|
||||
// drift rate of common ta in µs/s
|
||||
double N_common_ta_drift;
|
||||
// change rate of common ta drift in µs/s²
|
||||
double N_common_ta_drift_variant;
|
||||
// N_UE_TA_adj calculated round-trip-time between UE and SAT (ms)
|
||||
double N_UE_TA_adj;
|
||||
// drift rate of N_UE_TA in µs/s
|
||||
double N_UE_TA_drift;
|
||||
// change rate of N_UE_TA drift in µs/s²
|
||||
double N_UE_TA_drift_variant;
|
||||
|
||||
// cell scheduling offset expressed in terms of 15kHz SCS
|
||||
long cell_specific_k_offset;
|
||||
|
||||
@@ -639,6 +645,7 @@ typedef struct NR_UE_MAC_INST_s {
|
||||
|
||||
NR_SSB_meas_t ssb_measurements[MAX_NB_SSB];
|
||||
NR_CSIRS_meas_t csirs_measurements;
|
||||
ssb_ro_preambles_t ssb_ro_preambles;
|
||||
|
||||
dci_pdu_rel15_t def_dci_pdu_rel15[NR_MAX_SLOTS_PER_FRAME][8];
|
||||
|
||||
@@ -678,20 +685,5 @@ static inline long GET_DURATION_RX_TO_TX(const ntn_timing_advance_componets_t *n
|
||||
return NR_UE_CAPABILITY_SLOT_RX_TO_TX + (ntn_ta->cell_specific_k_offset << scs);
|
||||
}
|
||||
|
||||
static inline double get_total_TA_ms(const ntn_timing_advance_componets_t *ntn_ta)
|
||||
{
|
||||
return ntn_ta->N_common_ta_adj + ntn_ta->N_UE_TA_adj;
|
||||
}
|
||||
|
||||
static inline double get_total_TA_drift(const ntn_timing_advance_componets_t *ntn_ta)
|
||||
{
|
||||
return ntn_ta->N_common_ta_drift + ntn_ta->N_UE_TA_drift;
|
||||
}
|
||||
|
||||
static inline double get_total_TA_drift_variant(const ntn_timing_advance_componets_t *ntn_ta)
|
||||
{
|
||||
return ntn_ta->N_common_ta_drift_variant + ntn_ta->N_UE_TA_drift_variant;
|
||||
}
|
||||
|
||||
/*@}*/
|
||||
#endif /*__LAYER2_MAC_DEFS_H__ */
|
||||
|
||||
@@ -73,6 +73,7 @@ void nr_ue_decode_BCCH_DL_SCH(NR_UE_MAC_INST_t *mac,
|
||||
uint8_t ack_nack,
|
||||
uint8_t *pduP,
|
||||
uint32_t pdu_len,
|
||||
int hfn,
|
||||
int frame,
|
||||
int slot);
|
||||
|
||||
@@ -82,15 +83,17 @@ void nr_release_mac_config_logicalChannelBearer(NR_UE_MAC_INST_t *mac, long chan
|
||||
|
||||
void nr_rrc_mac_config_req_cg(module_id_t module_id,
|
||||
int cc_idP,
|
||||
int hfn,
|
||||
int frame,
|
||||
NR_CellGroupConfig_t *cell_group_config,
|
||||
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, int sched_sib1, bool barred);
|
||||
|
||||
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);
|
||||
|
||||
struct position; /* forward declaration */
|
||||
void nr_rrc_mac_config_other_sib(module_id_t module_id, NR_SIB19_r17_t *sib19_r17, bool can_start_ra);
|
||||
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);
|
||||
void nr_rrc_mac_resume_rb(module_id_t module_id, bool is_srb, int rb_id);
|
||||
void nr_rrc_mac_config_req_reset(module_id_t module_id, NR_UE_MAC_reset_cause_t cause);
|
||||
|
||||
@@ -252,7 +255,7 @@ void nr_get_RA_window(NR_UE_MAC_INST_t *mac);
|
||||
void prepare_msg4_msgb_feedback(NR_UE_MAC_INST_t *mac, int pid, int ack_nack);
|
||||
void configure_initial_pucch(PUCCH_sched_t *pucch, int res_ind);
|
||||
void release_PUCCH_SRS(NR_UE_MAC_INST_t *mac);
|
||||
void nr_ue_reset_sync_state(NR_UE_MAC_INST_t *mac);
|
||||
void nr_ue_reset_sync_state(NR_UE_MAC_INST_t *mac, bool reconf);
|
||||
void nr_ue_send_synch_request(NR_UE_MAC_INST_t *mac, module_id_t module_id, int cc_id, const fapi_nr_synch_request_t *sync_req);
|
||||
bool is_ss_monitor_occasion(const int frame, const int slot, const int slots_per_frame, const NR_SearchSpace_t *ss);
|
||||
|
||||
@@ -360,5 +363,5 @@ int sl_nr_ue_slot_select(const sl_nr_phy_config_request_t *cfg, int nr_slot, uin
|
||||
void nr_ue_sidelink_scheduler(nr_sidelink_indication_t *sl_ind, NR_UE_MAC_INST_t *mac);
|
||||
|
||||
NR_SearchSpace_t *get_common_search_space(const NR_UE_MAC_INST_t *mac, const NR_SearchSpaceId_t ss_id);
|
||||
|
||||
ssb_ro_preambles_t get_ssb_ro_preambles_4step(struct NR_RACH_ConfigCommon__ssb_perRACH_OccasionAndCB_PreamblesPerSSB *config);
|
||||
#endif
|
||||
|
||||
@@ -54,7 +54,7 @@ void send_srb0_rrc(int ue_id, const uint8_t *sdu, sdu_size_t sdu_len, void *data
|
||||
void nr_ue_init_mac(NR_UE_MAC_INST_t *mac)
|
||||
{
|
||||
LOG_I(NR_MAC, "[UE%d] Initializing MAC\n", mac->ue_id);
|
||||
nr_ue_reset_sync_state(mac);
|
||||
nr_ue_reset_sync_state(mac, false);
|
||||
mac->get_sib1 = false;
|
||||
for (int i = 0; i < MAX_SI_GROUPS; i++)
|
||||
mac->get_otherSI[i] = false;
|
||||
@@ -117,10 +117,10 @@ void nr_ue_send_synch_request(NR_UE_MAC_INST_t *mac, module_id_t module_id, int
|
||||
mac->if_module->synch_request(&mac->synch_request);
|
||||
}
|
||||
|
||||
void nr_ue_reset_sync_state(NR_UE_MAC_INST_t *mac)
|
||||
void nr_ue_reset_sync_state(NR_UE_MAC_INST_t *mac, bool reconf)
|
||||
{
|
||||
// reset synchornization status
|
||||
mac->state = UE_NOT_SYNC;
|
||||
mac->state = reconf ? UE_NOT_SYNC_RECONF : UE_NOT_SYNC;
|
||||
mac->ra.ra_state = nrRA_UE_IDLE;
|
||||
}
|
||||
|
||||
|
||||
@@ -190,7 +190,7 @@ static void select_preamble_group(NR_UE_MAC_INST_t *mac)
|
||||
// else if Msg3 is being retransmitted, we keep what used in first transmission of Msg3
|
||||
}
|
||||
|
||||
static ssb_ro_preambles_t get_ssb_ro_preambles_4step(struct NR_RACH_ConfigCommon__ssb_perRACH_OccasionAndCB_PreamblesPerSSB *config)
|
||||
ssb_ro_preambles_t get_ssb_ro_preambles_4step(struct NR_RACH_ConfigCommon__ssb_perRACH_OccasionAndCB_PreamblesPerSSB *config)
|
||||
{
|
||||
ssb_ro_preambles_t ret = {0};
|
||||
switch (config->present) {
|
||||
@@ -293,9 +293,7 @@ static void config_preamble_index(NR_UE_MAC_INST_t *mac)
|
||||
bool groupBconfigured = false;
|
||||
int preamb_ga = 0;
|
||||
if (ra->ra_type == RA_4_STEP) {
|
||||
AssertFatal(nr_rach_ConfigCommon->ssb_perRACH_OccasionAndCB_PreamblesPerSSB,
|
||||
"Not expeting ssb_perRACH_OccasionAndCB_PreamblesPerSSB to be NULL here\n");
|
||||
ra->ssb_ro_config = get_ssb_ro_preambles_4step(nr_rach_ConfigCommon->ssb_perRACH_OccasionAndCB_PreamblesPerSSB);
|
||||
ra->ssb_ro_config = mac->ssb_ro_preambles;
|
||||
if (nr_rach_ConfigCommon->totalNumberOfRA_Preambles)
|
||||
nb_of_preambles = *nr_rach_ConfigCommon->totalNumberOfRA_Preambles;
|
||||
// Amongst the contention-based Random Access Preambles associated with an SSB the first numberOfRA-PreamblesGroupA
|
||||
@@ -321,7 +319,7 @@ static void config_preamble_index(NR_UE_MAC_INST_t *mac)
|
||||
if (twostep->msgA_SSB_PerRACH_OccasionAndCB_PreamblesPerSSB_r16)
|
||||
ra->ssb_ro_config = get_ssb_ro_preambles_2step(twostep->msgA_SSB_PerRACH_OccasionAndCB_PreamblesPerSSB_r16);
|
||||
else
|
||||
ra->ssb_ro_config = get_ssb_ro_preambles_4step(nr_rach_ConfigCommon->ssb_perRACH_OccasionAndCB_PreamblesPerSSB);
|
||||
ra->ssb_ro_config = mac->ssb_ro_preambles;
|
||||
if (twostep->msgA_TotalNumberOfRA_Preambles_r16)
|
||||
nb_of_preambles = *twostep->msgA_TotalNumberOfRA_Preambles_r16;
|
||||
}
|
||||
@@ -777,13 +775,12 @@ static int nr_get_RA_window_4Step(long ra_ResponseWindow)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void setup_ra_response_window(RA_config_t *ra,
|
||||
int slots_per_frame,
|
||||
NR_NTN_Config_r17_t *ntn_Config_r17,
|
||||
static void setup_ra_response_window(NR_UE_MAC_INST_t *mac,
|
||||
RA_config_t *ra,
|
||||
NR_RACH_ConfigGeneric_t *configGeneric,
|
||||
NR_RACH_ConfigGenericTwoStepRA_r16_t *twostep,
|
||||
ntn_timing_advance_componets_t *ntn_ta)
|
||||
NR_RACH_ConfigGenericTwoStepRA_r16_t *twostep)
|
||||
{
|
||||
const int slots_per_frame = mac->frame_structure.numb_slots_frame;
|
||||
int respwind_value = 0;
|
||||
if (ra->ra_type == RA_2_STEP) {
|
||||
long *msgB_ResponseWindow = twostep->msgB_ResponseWindow_r16;
|
||||
@@ -816,13 +813,8 @@ static void setup_ra_response_window(RA_config_t *ra,
|
||||
LOG_E(NR_MAC, "RA-ResponseWindow need to be configured to a value lower than or equal to 10 ms\n");
|
||||
}
|
||||
|
||||
int ta_Common_slots = 0;
|
||||
if (ntn_Config_r17) {
|
||||
const double ta_Common_ms = get_total_TA_ms(ntn_ta);
|
||||
ta_Common_slots = (int)ceil(ta_Common_ms * slots_per_frame / 10);
|
||||
}
|
||||
|
||||
ra->response_window_setup_time = respwind_value + ta_Common_slots;
|
||||
const int ntn_ue_koffset = GET_NTN_UE_K_OFFSET(&mac->ntn_ta, mac->current_UL_BWP->scs);
|
||||
ra->response_window_setup_time = respwind_value + ntn_ue_koffset;
|
||||
}
|
||||
|
||||
// Random Access procedure initialization as per 5.1.1 and initialization of variables specific
|
||||
@@ -1026,12 +1018,8 @@ bool init_RA(NR_UE_MAC_INST_t *mac, int frame)
|
||||
else
|
||||
ra->num_fd_occasions = 1 << rach_ConfigGeneric->msg1_FDM;
|
||||
|
||||
setup_ra_response_window(ra,
|
||||
mac->frame_structure.numb_slots_frame,
|
||||
mac->sc_info.ntn_Config_r17,
|
||||
rach_ConfigGeneric,
|
||||
twostep_generic,
|
||||
&mac->ntn_ta);
|
||||
setup_ra_response_window(mac, ra, rach_ConfigGeneric, twostep_generic);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1039,16 +1027,15 @@ void nr_Msg3_transmitted(NR_UE_MAC_INST_t *mac, uint8_t CC_id, frame_t frameP, s
|
||||
{
|
||||
RA_config_t *ra = &mac->ra;
|
||||
NR_RACH_ConfigCommon_t *nr_rach_ConfigCommon = mac->current_UL_BWP->rach_ConfigCommon;
|
||||
const double ta_Common_ms = get_total_TA_ms(&mac->ntn_ta);
|
||||
const int ntn_ue_koffset = GET_NTN_UE_K_OFFSET(&mac->ntn_ta, mac->current_UL_BWP->scs);
|
||||
const int slots_per_ms = mac->frame_structure.numb_slots_frame / 10;
|
||||
|
||||
// start contention resolution timer
|
||||
const int RA_contention_resolution_timer_ms = (nr_rach_ConfigCommon->ra_ContentionResolutionTimer + 1) << 3;
|
||||
const int RA_contention_resolution_timer_slots = RA_contention_resolution_timer_ms * slots_per_ms;
|
||||
const int ta_Common_slots = (int)ceil(ta_Common_ms * slots_per_ms);
|
||||
|
||||
// timer step 1 slot and timer target given by ra_ContentionResolutionTimer + ta-Common-r17
|
||||
nr_timer_setup(&ra->contention_resolution_timer, RA_contention_resolution_timer_slots + ta_Common_slots, 1);
|
||||
nr_timer_setup(&ra->contention_resolution_timer, RA_contention_resolution_timer_slots + ntn_ue_koffset, 1);
|
||||
nr_timer_start(&ra->contention_resolution_timer);
|
||||
|
||||
ra->ra_state = nrRA_WAIT_CONTENTION_RESOLUTION;
|
||||
|
||||
@@ -480,6 +480,15 @@ void ue_dci_configuration(NR_UE_MAC_INST_t *mac, fapi_nr_dl_config_request_t *dl
|
||||
}
|
||||
config_dci_pdu(mac, dl_config, rnti_type, slot, ra_SS);
|
||||
}
|
||||
// If Msg3 has C-RNTI MAC CE, also monitor dedicated search spaces during contention resolution
|
||||
// according to TS 38.321 section 5.1.5
|
||||
if (ra->ra_state == nrRA_WAIT_CONTENTION_RESOLUTION && mac->msg3_C_RNTI) {
|
||||
for (int i = 0; i < pdcch_config->list_SS.count; i++) {
|
||||
NR_SearchSpace_t *ss = pdcch_config->list_SS.array[i];
|
||||
if (is_ss_monitor_occasion(frame, slot, slots_per_frame, ss))
|
||||
config_dci_pdu(mac, dl_config, TYPE_C_RNTI_, slot, ss);
|
||||
}
|
||||
}
|
||||
} else if (mac->state == UE_CONNECTED) {
|
||||
/*
|
||||
In RRC Connected state, the UE monitors for fallback DCI with C-RNTI in common and UE-specific SS.
|
||||
|
||||
@@ -361,12 +361,13 @@ void nr_ue_decode_BCCH_DL_SCH(NR_UE_MAC_INST_t *mac,
|
||||
uint8_t ack_nack,
|
||||
uint8_t *pduP,
|
||||
uint32_t pdu_len,
|
||||
int hfn,
|
||||
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, frame, slot, 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, hfn, 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++) {
|
||||
@@ -383,7 +384,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, frame, slot, 0, mac->physCellId, 0, NR_BCCH_DL_SCH, NULL, 0);
|
||||
nr_mac_rrc_data_ind_ue(mac->ue_id, cc_id, gNB_index, hfn, frame, slot, 0, mac->physCellId, 0, NR_BCCH_DL_SCH, NULL, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1145,7 +1145,7 @@ void nr_ue_dl_scheduler(NR_UE_MAC_INST_t *mac, nr_downlink_indication_t *dl_info
|
||||
dl_config->slot = rx_slot;
|
||||
dl_config->number_pdus = 0;
|
||||
|
||||
if (mac->state == UE_NOT_SYNC || mac->state == UE_DETACHING)
|
||||
if (mac->state == UE_NOT_SYNC || mac->state == UE_NOT_SYNC_RECONF || mac->state == UE_DETACHING)
|
||||
return;
|
||||
|
||||
if (mac->state == UE_CONNECTED) {
|
||||
@@ -2848,12 +2848,19 @@ static void schedule_ntn_config_command(fapi_nr_dl_config_request_t *dl_config,
|
||||
{
|
||||
fapi_nr_dl_ntn_config_command_pdu *ntn_config_command_pdu = &dl_config->dl_config_list[dl_config->number_pdus].ntn_config_command_pdu;
|
||||
|
||||
ntn_config_command_pdu->epoch_hfn = mac->ntn_ta.epoch_hfn;
|
||||
ntn_config_command_pdu->epoch_sfn = mac->ntn_ta.epoch_sfn;
|
||||
ntn_config_command_pdu->epoch_subframe = mac->ntn_ta.epoch_subframe;
|
||||
|
||||
ntn_config_command_pdu->omega = mac->ntn_ta.omega;
|
||||
ntn_config_command_pdu->pos_sat_0 = mac->ntn_ta.pos_sat_0;
|
||||
ntn_config_command_pdu->pos_sat_90 = mac->ntn_ta.pos_sat_90;
|
||||
|
||||
ntn_config_command_pdu->N_common_ta_adj = mac->ntn_ta.N_common_ta_adj;
|
||||
ntn_config_command_pdu->N_common_ta_drift = mac->ntn_ta.N_common_ta_drift;
|
||||
ntn_config_command_pdu->N_common_ta_drift_variant = mac->ntn_ta.N_common_ta_drift_variant;
|
||||
|
||||
ntn_config_command_pdu->cell_specific_k_offset = mac->ntn_ta.cell_specific_k_offset;
|
||||
ntn_config_command_pdu->ntn_total_time_advance_ms = get_total_TA_ms(&mac->ntn_ta);
|
||||
ntn_config_command_pdu->ntn_total_time_advance_drift = get_total_TA_drift(&mac->ntn_ta);
|
||||
ntn_config_command_pdu->ntn_total_time_advance_drift_variant = get_total_TA_drift_variant(&mac->ntn_ta);
|
||||
|
||||
dl_config->dl_config_list[dl_config->number_pdus].pdu_type = FAPI_NR_DL_NTN_CONFIG_PARAMS;
|
||||
dl_config->number_pdus += 1;
|
||||
|
||||
@@ -104,7 +104,7 @@ static int16_t ssb_index_from_prach(module_id_t module_idP,
|
||||
int config_period = cc->prach_info.x;
|
||||
// prach_occasion_id = subframe_index * N_t_slot * N_RA_slot * fdm + N_RA_slot_index * N_t_slot * fdm + freq_index + fdm * start_symbol_index;
|
||||
prach_occasion_id =
|
||||
(((frameP % (cc->max_association_period * config_period)) / config_period) * cc->total_prach_occasions_per_config_period)
|
||||
(((frameP % (cc->association_period * config_period)) / config_period) * cc->total_prach_occasions_per_config_period)
|
||||
+ (RA_sfn_index + slot_index) * cc->prach_info.N_t_slot * fdm + start_symbol_index * fdm + freq_index;
|
||||
|
||||
//one SSB have more than one continuous RO
|
||||
@@ -178,7 +178,7 @@ void find_SSB_and_RO_available(gNB_MAC_INST *nrmac)
|
||||
float num_ssb_per_RO = ssb_per_rach_occasion[cfg->prach_config.ssb_per_rach.value];
|
||||
uint8_t fdm = cfg->prach_config.num_prach_fd_occasions.value;
|
||||
uint64_t L_ssb = (((uint64_t) cfg->ssb_table.ssb_mask_list[0].ssb_mask.value) << 32) | cfg->ssb_table.ssb_mask_list[1].ssb_mask.value;
|
||||
uint32_t total_RA_occasions = prach_info.N_RA_sfn * prach_info.N_t_slot * prach_info.N_RA_slot * fdm;
|
||||
cc->total_prach_occasions_per_config_period = prach_info.N_RA_sfn * prach_info.N_t_slot * prach_info.N_RA_slot * fdm;
|
||||
|
||||
for(int i = 0; i < 64; i++) {
|
||||
if ((L_ssb >> (63 - i)) & 0x01) { // only if the bit of L_ssb at current ssb index is 1
|
||||
@@ -187,15 +187,22 @@ void find_SSB_and_RO_available(gNB_MAC_INST *nrmac)
|
||||
}
|
||||
}
|
||||
|
||||
cc->total_prach_occasions_per_config_period = total_RA_occasions;
|
||||
// An association period, starting from frame 0, for mapping SS/PBCH block indexes to PRACH occasions is the smallest
|
||||
// value in the set determined by the PRACH configuration period according Table 8.1-1 of 38.213
|
||||
// such that all tx SSB indexes are mapped at least once to the PRACH occasions within the association period
|
||||
// An association pattern period includes one or more association periods and is determined
|
||||
// so that a pattern between PRACH occasions and SS/PBCH block indexes repeats at most every 160 msec
|
||||
int total_RA_occasions = 0;
|
||||
for (int i = 1; (1 << (i - 1)) <= prach_info.max_association_period; i++) {
|
||||
cc->max_association_period = (1 << (i - 1));
|
||||
total_RA_occasions = total_RA_occasions * cc->max_association_period;
|
||||
if(total_RA_occasions >= (int) (num_active_ssb / num_ssb_per_RO)) {
|
||||
cc->association_period = (1 << (i - 1));
|
||||
int temp_RA_occasions = cc->total_prach_occasions_per_config_period * cc->association_period;
|
||||
if(temp_RA_occasions >= (int) (num_active_ssb / num_ssb_per_RO)) {
|
||||
total_RA_occasions = temp_RA_occasions;
|
||||
repetition = (uint16_t)((total_RA_occasions * num_ssb_per_RO) / num_active_ssb);
|
||||
break;
|
||||
}
|
||||
}
|
||||
AssertFatal(total_RA_occasions > 0, "Couldn't find a valid association period for PRACH occasions\n");
|
||||
|
||||
unused_RA_occasion = total_RA_occasions - (int)((num_active_ssb * repetition) / num_ssb_per_RO);
|
||||
cc->total_prach_occasions = total_RA_occasions - unused_RA_occasion;
|
||||
@@ -208,7 +215,7 @@ void find_SSB_and_RO_available(gNB_MAC_INST *nrmac)
|
||||
cc->total_prach_occasions,
|
||||
cc->num_active_ssb,
|
||||
unused_RA_occasion,
|
||||
cc->max_association_period,
|
||||
cc->association_period,
|
||||
prach_info.N_RA_sfn,
|
||||
cc->total_prach_occasions_per_config_period);
|
||||
}
|
||||
@@ -401,7 +408,7 @@ void schedule_nr_prach(module_id_t module_idP, frame_t frameP, slot_t slotP)
|
||||
nfapi_nr_prach_pdu_t *prach_pdu = &newpdu->prach_pdu;
|
||||
for (int td_index = 0; td_index < N_t_slot; td_index++) {
|
||||
uint32_t config_period = cc->prach_info.x;
|
||||
prach_occasion_id = (((frameP % (cc->max_association_period * config_period))/config_period) * cc->total_prach_occasions_per_config_period) +
|
||||
prach_occasion_id = (((frameP % (cc->association_period * config_period))/config_period) * cc->total_prach_occasions_per_config_period) +
|
||||
(RA_sfn_index + slot_index) * N_t_slot * fdm + td_index * fdm + fdm_index;
|
||||
|
||||
if (prach_occasion_id >= cc->total_prach_occasions) // to be confirmed: unused occasion?
|
||||
@@ -756,7 +763,7 @@ void nr_initiate_ra_proc(module_id_t module_idP,
|
||||
// return current SSB order in the list of tranmitted SSBs
|
||||
int n_ssb = ssb_index_from_prach(module_idP, frame, slot, preamble_index, freq_index, symbol);
|
||||
UE->UE_beam_index = get_fapi_beamforming_index(nr_mac, cc->ssb_index[n_ssb]);
|
||||
|
||||
LOG_I(NR_MAC, "UE %04x: Sync beam index %d\n", UE->rnti, UE->UE_beam_index);
|
||||
NR_SCHED_UNLOCK(&nr_mac->sched_lock);
|
||||
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_INITIATE_RA_PROC, 0);
|
||||
}
|
||||
|
||||
@@ -319,7 +319,7 @@ typedef struct {
|
||||
//Total available prach occasions
|
||||
int total_prach_occasions;
|
||||
//Max Association period
|
||||
int max_association_period;
|
||||
int association_period;
|
||||
//SSB index
|
||||
uint8_t ssb_index[MAX_NUM_OF_SSB];
|
||||
//CB preambles for each SSB
|
||||
|
||||
@@ -123,7 +123,7 @@ static int handle_bcch_bch(NR_UE_MAC_INST_t *mac,
|
||||
else
|
||||
mac->frequency_range = FR1;
|
||||
// fixed 3 bytes MIB PDU
|
||||
nr_mac_rrc_data_ind_ue(mac->ue_id, cc_id, gNB_index, 0, 0, 0, cell_id, ssb_arfcn, NR_BCCH_BCH, (uint8_t *) pduP, 3);
|
||||
nr_mac_rrc_data_ind_ue(mac->ue_id, cc_id, gNB_index, 0, 0, 0, 0, cell_id, ssb_arfcn, NR_BCCH_BCH, (uint8_t *) pduP, 3);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -134,10 +134,11 @@ static int handle_bcch_dlsch(NR_UE_MAC_INST_t *mac,
|
||||
uint8_t ack_nack,
|
||||
uint8_t *pduP,
|
||||
uint32_t pdu_len,
|
||||
int hfn,
|
||||
int frame,
|
||||
int slot)
|
||||
{
|
||||
nr_ue_decode_BCCH_DL_SCH(mac, cc_id, gNB_index, ack_nack, pduP, pdu_len, frame, slot);
|
||||
nr_ue_decode_BCCH_DL_SCH(mac, cc_id, gNB_index, ack_nack, pduP, pdu_len, hfn, frame, slot);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -301,6 +302,7 @@ static uint32_t nr_ue_dl_processing(NR_UE_MAC_INST_t *mac, nr_downlink_indicatio
|
||||
rx_indication_body.pdsch_pdu.ack_nack,
|
||||
rx_indication_body.pdsch_pdu.pdu,
|
||||
rx_indication_body.pdsch_pdu.pdu_length,
|
||||
dl_info->hfn,
|
||||
dl_info->frame,
|
||||
dl_info->slot)) << FAPI_NR_RX_PDU_TYPE_SIB;
|
||||
break;
|
||||
@@ -389,6 +391,7 @@ static void handle_sl_bch(int ue_id,
|
||||
sl_nr_ue_mac_params_t *sl_mac,
|
||||
uint8_t *const sl_mib,
|
||||
const uint8_t len,
|
||||
int hfn_rx,
|
||||
uint16_t frame_rx,
|
||||
uint16_t slot_rx,
|
||||
uint16_t rx_slss_id)
|
||||
@@ -421,7 +424,7 @@ static void handle_sl_bch(int ue_id,
|
||||
sl_mac->decoded_DFN = frame;
|
||||
sl_mac->decoded_slot = slot;
|
||||
|
||||
nr_mac_rrc_data_ind_ue(ue_id, 0, 0, frame_rx, slot_rx, 0, rx_slss_id, 0, NR_SBCCH_SL_BCH, (uint8_t *)sl_mib, len);
|
||||
nr_mac_rrc_data_ind_ue(ue_id, 0, 0, hfn_rx, frame_rx, slot_rx, 0, rx_slss_id, 0, NR_SBCCH_SL_BCH, (uint8_t *)sl_mib, len);
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -433,6 +436,7 @@ if PSBCH rx - handle_psbch()
|
||||
if PSSCH DATa rx - handle slsch()
|
||||
*/
|
||||
void sl_nr_process_rx_ind(int ue_id,
|
||||
int hfn,
|
||||
uint32_t frame,
|
||||
uint32_t slot,
|
||||
sl_nr_ue_mac_params_t *sl_mac,
|
||||
@@ -456,6 +460,7 @@ void sl_nr_process_rx_ind(int ue_id,
|
||||
sl_mac,
|
||||
rx_ind->rx_indication_body[num_pdus - 1].ssb_pdu.psbch_payload,
|
||||
4,
|
||||
hfn,
|
||||
frame,
|
||||
slot,
|
||||
rx_ind->rx_indication_body[num_pdus - 1].ssb_pdu.rx_slss_id);
|
||||
@@ -488,11 +493,12 @@ void nr_ue_sl_indication(nr_sidelink_indication_t *sl_indication)
|
||||
|
||||
uint16_t slot = sl_indication->slot_rx;
|
||||
uint16_t frame = sl_indication->frame_rx;
|
||||
int hfn = sl_indication->hfn_rx;
|
||||
|
||||
sl_nr_ue_mac_params_t *sl_mac = mac->SL_MAC_PARAMS;
|
||||
|
||||
if (sl_indication->rx_ind) {
|
||||
sl_nr_process_rx_ind(ue_id, frame, slot, sl_mac, sl_indication->rx_ind);
|
||||
sl_nr_process_rx_ind(ue_id, hfn, frame, slot, sl_mac, sl_indication->rx_ind);
|
||||
} else {
|
||||
nr_ue_sidelink_scheduler(sl_indication, mac);
|
||||
}
|
||||
|
||||
@@ -56,6 +56,8 @@ typedef struct {
|
||||
uint32_t gNB_index;
|
||||
/// component carrier id
|
||||
int cc_id;
|
||||
/// hyper frame number
|
||||
int hfn;
|
||||
/// frame
|
||||
frame_t frame;
|
||||
/// slot
|
||||
@@ -101,10 +103,14 @@ typedef struct {
|
||||
uint32_t gNB_index;
|
||||
/// component carrier id
|
||||
int cc_id;
|
||||
/// hyper frame number rx
|
||||
int hfn_rx;
|
||||
/// frame rx
|
||||
frame_t frame_rx;
|
||||
/// slot rx
|
||||
uint32_t slot_rx;
|
||||
/// hyper frame number tx
|
||||
int hfn_tx;
|
||||
/// frame tx
|
||||
frame_t frame_tx;
|
||||
/// slot tx
|
||||
|
||||
@@ -59,6 +59,7 @@ void nr_mac_rrc_sync_ind(const module_id_t module_id, const frame_t frame, const
|
||||
void nr_mac_rrc_data_ind_ue(const module_id_t module_id,
|
||||
const int CC_id,
|
||||
const uint8_t gNB_index,
|
||||
const int hfn,
|
||||
const frame_t frame,
|
||||
const int slot,
|
||||
const rnti_t rnti,
|
||||
@@ -97,6 +98,7 @@ void nr_mac_rrc_data_ind_ue(const module_id_t module_id,
|
||||
else {
|
||||
NR_RRC_MAC_BCCH_DATA_IND (message_p).sdu_size = 0;
|
||||
}
|
||||
NR_RRC_MAC_BCCH_DATA_IND (message_p).hfn = hfn;
|
||||
NR_RRC_MAC_BCCH_DATA_IND (message_p).frame = frame; //frameP
|
||||
NR_RRC_MAC_BCCH_DATA_IND (message_p).slot = slot;
|
||||
NR_RRC_MAC_BCCH_DATA_IND (message_p).gnb_index = gNB_index;
|
||||
@@ -120,6 +122,7 @@ void nr_mac_rrc_data_ind_ue(const module_id_t module_id,
|
||||
message_p = itti_alloc_new_message(TASK_MAC_UE, 0, NR_RRC_MAC_SBCCH_DATA_IND);
|
||||
memset(NR_RRC_MAC_SBCCH_DATA_IND (message_p).sdu, 0, BCCH_SDU_SIZE);
|
||||
memcpy(NR_RRC_MAC_SBCCH_DATA_IND (message_p).sdu, pduP, sdu_size);
|
||||
NR_RRC_MAC_SBCCH_DATA_IND (message_p).hfn = hfn;
|
||||
NR_RRC_MAC_SBCCH_DATA_IND (message_p).frame = frame; //frameP
|
||||
NR_RRC_MAC_SBCCH_DATA_IND (message_p).slot = slot;
|
||||
NR_RRC_MAC_SBCCH_DATA_IND (message_p).sdu_size = sdu_size;
|
||||
@@ -139,14 +142,18 @@ void process_msg_rcc_to_mac(nr_mac_rrc_message_t *msg, int instance_id)
|
||||
nr_rrc_mac_config_req_reset(instance_id, msg->payload.config_reset.cause);
|
||||
break;
|
||||
case NR_MAC_RRC_CONFIG_CG:
|
||||
nr_rrc_mac_config_req_cg(instance_id, 0, msg->payload.config_cg.cellGroupConfig, msg->payload.config_cg.UE_NR_Capability);
|
||||
nr_rrc_mac_config_req_cg(instance_id,
|
||||
0,
|
||||
msg->payload.config_cg.hfn,
|
||||
msg->payload.config_cg.frame,
|
||||
msg->payload.config_cg.cellGroupConfig,
|
||||
msg->payload.config_cg.UE_NR_Capability);
|
||||
ASN_STRUCT_FREE(asn_DEF_NR_CellGroupConfig, msg->payload.config_cg.cellGroupConfig);
|
||||
break;
|
||||
case NR_MAC_RRC_CONFIG_MIB:
|
||||
nr_rrc_mac_config_req_mib(instance_id,
|
||||
0,
|
||||
msg->payload.config_mib.bcch->message.choice.mib,
|
||||
msg->payload.config_mib.get_sib,
|
||||
msg->payload.config_mib.access_barred);
|
||||
ASN_STRUCT_FREE(asn_DEF_NR_BCCH_BCH_Message, msg->payload.config_mib.bcch);
|
||||
break;
|
||||
@@ -157,9 +164,15 @@ void process_msg_rcc_to_mac(nr_mac_rrc_message_t *msg, int instance_id)
|
||||
SEQUENCE_free(&asn_DEF_NR_SIB1, msg->payload.config_sib1.sib1, ASFM_FREE_EVERYTHING);
|
||||
} break;
|
||||
case NR_MAC_RRC_CONFIG_OTHER_SIB: {
|
||||
bool can_start_ra = msg->payload.config_other_sib.can_start_ra;
|
||||
nr_rrc_mac_config_other_sib(instance_id, msg->payload.config_other_sib.sib19, can_start_ra);
|
||||
nr_rrc_mac_config_other_sib(instance_id,
|
||||
msg->payload.config_other_sib.sib19,
|
||||
msg->payload.config_other_sib.hfn,
|
||||
msg->payload.config_other_sib.frame,
|
||||
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);
|
||||
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);
|
||||
break;
|
||||
@@ -183,10 +196,11 @@ void nr_mac_rrc_msg3_ind(const module_id_t mod_id, const int rnti, bool prepare_
|
||||
itti_send_msg_to_task(TASK_RRC_NRUE, GNB_MODULE_ID_TO_INSTANCE(mod_id), message_p);
|
||||
}
|
||||
|
||||
void nr_ue_rrc_timer_trigger(int instance, int frame, int gnb_id)
|
||||
void nr_ue_rrc_timer_trigger(int instance, int hfn, int frame, int gnb_id)
|
||||
{
|
||||
MessageDef *message_p;
|
||||
message_p = itti_alloc_new_message(TASK_RRC_NRUE, 0, NRRRC_FRAME_PROCESS);
|
||||
NRRRC_FRAME_PROCESS(message_p).hfn = hfn;
|
||||
NRRRC_FRAME_PROCESS(message_p).frame = frame;
|
||||
NRRRC_FRAME_PROCESS(message_p).gnb_id = gnb_id;
|
||||
LOG_D(NR_RRC, "RRC timer trigger: frame %d\n", frame);
|
||||
|
||||
@@ -29,6 +29,7 @@ void nr_mac_rrc_sync_ind(const module_id_t module_id, const frame_t frame, const
|
||||
void nr_mac_rrc_data_ind_ue(const module_id_t module_id,
|
||||
const int CC_id,
|
||||
const uint8_t gNB_index,
|
||||
const int hfn,
|
||||
const frame_t frame,
|
||||
const int slot,
|
||||
const rnti_t rnti,
|
||||
@@ -45,7 +46,7 @@ void nr_mac_rrc_meas_ind_ue(module_id_t module_id,
|
||||
int rsrp_dBm);
|
||||
void nr_mac_rrc_inactivity_timer_ind(const module_id_t mod_id);
|
||||
void nr_mac_rrc_msg3_ind(const module_id_t mod_id, const int rnti, bool prepare_payload);
|
||||
void nr_ue_rrc_timer_trigger(int instance, int frame, int gnb_id);
|
||||
void nr_ue_rrc_timer_trigger(int instance, int hfn, int frame, int gnb_id);
|
||||
void nr_mac_rrc_ra_ind(const module_id_t mod_id, bool success);
|
||||
void process_msg_rcc_to_mac(nr_mac_rrc_message_t *msg, int instance_id);
|
||||
#endif
|
||||
|
||||
+238
-163
@@ -292,7 +292,7 @@ static void nr_rrc_process_ntnconfig(NR_UE_RRC_INST_t *rrc, NR_UE_RRC_SI_INFO *S
|
||||
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)
|
||||
static void nr_decode_SI(NR_UE_RRC_SI_INFO *SI_info, NR_SystemInformation_t *si, NR_UE_RRC_INST_t *rrc, int hfn, int frame)
|
||||
{
|
||||
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RRC_UE_DECODE_SI, VCD_FUNCTION_IN);
|
||||
|
||||
@@ -381,6 +381,8 @@ static void nr_decode_SI(NR_UE_RRC_SI_INFO *SI_info, NR_SystemInformation_t *si,
|
||||
rrc_msg.payload_type = NR_MAC_RRC_CONFIG_OTHER_SIB;
|
||||
nr_mac_rrc_config_other_sib_t *sib19_msg = &rrc_msg.payload.config_other_sib;
|
||||
asn_copy(&asn_DEF_NR_SIB19_r17, (void **)&sib19_msg->sib19, sib19);
|
||||
sib19_msg->hfn = hfn;
|
||||
sib19_msg->frame = frame;
|
||||
sib19_msg->can_start_ra = rrc->is_NTN_UE;
|
||||
nr_rrc_send_msg_to_mac(rrc, &rrc_msg);
|
||||
}
|
||||
@@ -748,6 +750,189 @@ static void nr_rrc_ue_process_RadioBearerConfig(NR_UE_RRC_INST_t *ue_rrc, NR_Rad
|
||||
LOG_I(NR_RRC, "State = NR_RRC_CONNECTED\n");
|
||||
}
|
||||
|
||||
static void nr_rrc_signal_maxrtxindication(int ue_id)
|
||||
{
|
||||
MessageDef *msg = itti_alloc_new_message(TASK_RLC_UE, ue_id, NR_RRC_RLC_MAXRTX);
|
||||
NR_RRC_RLC_MAXRTX(msg).ue_id = ue_id;
|
||||
itti_send_msg_to_task(TASK_RRC_NRUE, ue_id, msg);
|
||||
}
|
||||
|
||||
/** @brief Release all active RLC entities for a UE and set to inactive.
|
||||
* This is typically used when tearing down all DRBs at UE side,
|
||||
* such as after a PDU session release or full reconfiguration.
|
||||
* @param rrc Pointer to NR_UE_RRC_INST_t structure
|
||||
* @param id Logical Channel ID (must be in range [0, NR_MAX_NUM_LCID-1]) */
|
||||
static void nr_rrc_release_rlc_entity(NR_UE_RRC_INST_t *rrc, int id)
|
||||
{
|
||||
DevAssert(rrc);
|
||||
DevAssert(id >= 0 && id < NR_MAX_NUM_LCID);
|
||||
if (rrc->active_RLC_entity[id]) {
|
||||
rrc->active_RLC_entity[id] = false;
|
||||
nr_rlc_release_entity(rrc->ue_id, id);
|
||||
LOG_I(RLC, "Released RLC entity: ue_id=%ld, lc_id=%d\n", rrc->ue_id, id);
|
||||
}
|
||||
}
|
||||
|
||||
static void nr_rrc_manage_rlc_bearers(NR_UE_RRC_INST_t *rrc, const NR_CellGroupConfig_t *cellGroupConfig)
|
||||
{
|
||||
if (cellGroupConfig->rlc_BearerToReleaseList != NULL) {
|
||||
for (int i = 0; i < cellGroupConfig->rlc_BearerToReleaseList->list.count; i++) {
|
||||
NR_LogicalChannelIdentity_t *lcid = cellGroupConfig->rlc_BearerToReleaseList->list.array[i];
|
||||
AssertFatal(lcid, "LogicalChannelIdentity shouldn't be null here\n");
|
||||
nr_rrc_release_rlc_entity(rrc, *lcid);
|
||||
}
|
||||
}
|
||||
|
||||
if (cellGroupConfig->rlc_BearerToAddModList != NULL) {
|
||||
for (int i = 0; i < cellGroupConfig->rlc_BearerToAddModList->list.count; i++) {
|
||||
NR_RLC_BearerConfig_t *rlc_bearer = cellGroupConfig->rlc_BearerToAddModList->list.array[i];
|
||||
NR_LogicalChannelIdentity_t lcid = rlc_bearer->logicalChannelIdentity;
|
||||
if (rrc->active_RLC_entity[lcid]) {
|
||||
if (rlc_bearer->reestablishRLC)
|
||||
nr_rlc_reestablish_entity(rrc->ue_id, lcid);
|
||||
if (rlc_bearer->rlc_Config)
|
||||
nr_rlc_reconfigure_entity(rrc->ue_id, lcid, rlc_bearer->rlc_Config);
|
||||
} else {
|
||||
rrc->active_RLC_entity[lcid] = true;
|
||||
AssertFatal(rlc_bearer->servedRadioBearer, "servedRadioBearer mandatory in case of setup\n");
|
||||
AssertFatal(rlc_bearer->servedRadioBearer->present != NR_RLC_BearerConfig__servedRadioBearer_PR_NOTHING,
|
||||
"Invalid RB for RLC configuration\n");
|
||||
if (rlc_bearer->servedRadioBearer->present == NR_RLC_BearerConfig__servedRadioBearer_PR_srb_Identity) {
|
||||
NR_SRB_Identity_t srb_id = rlc_bearer->servedRadioBearer->choice.srb_Identity;
|
||||
nr_rlc_add_srb(rrc->ue_id, srb_id, rlc_bearer);
|
||||
nr_rlc_set_rlf_handler(rrc->ue_id, nr_rrc_signal_maxrtxindication);
|
||||
} else { // DRB
|
||||
NR_DRB_Identity_t drb_id = rlc_bearer->servedRadioBearer->choice.drb_Identity;
|
||||
if (!rlc_bearer->rlc_Config) {
|
||||
LOG_E(RLC, "RLC-Config not present but is mandatory for setup\n");
|
||||
rrc->active_RLC_entity[lcid] = false;
|
||||
} else {
|
||||
nr_rlc_add_drb(rrc->ue_id, drb_id, rlc_bearer);
|
||||
nr_rlc_set_rlf_handler(rrc->ue_id, nr_rrc_signal_maxrtxindication);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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)) {
|
||||
// if the AS security is not activated, perform the actions upon going to RRC_IDLE as specified in 5.3.11
|
||||
// with the release cause 'other' upon which the procedure ends
|
||||
NR_Release_Cause_t release_cause = OTHER;
|
||||
nr_rrc_going_to_IDLE(rrc, release_cause, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
if (reconfigurationWithSync->spCellConfigCommon) {
|
||||
/* if the frequencyInfoDL is included, consider the target SpCell
|
||||
to be one on the SSB frequency indicated by the frequencyInfoDL */
|
||||
const NR_DownlinkConfigCommon_t *dcc = reconfigurationWithSync->spCellConfigCommon->downlinkConfigCommon;
|
||||
if (dcc && dcc->frequencyInfoDL && dcc->frequencyInfoDL->absoluteFrequencySSB)
|
||||
rrc->arfcn_ssb = *dcc->frequencyInfoDL->absoluteFrequencySSB;
|
||||
|
||||
// consider the target SpCell to be one with a physical cell identity indicated by the physCellId
|
||||
if (!reconfigurationWithSync->spCellConfigCommon->physCellId)
|
||||
LOG_E(NR_RRC, "physCellId absent but should be mandatory present upon cell change and cell addition\n");
|
||||
else
|
||||
rrc->phyCellID = *reconfigurationWithSync->spCellConfigCommon->physCellId;
|
||||
}
|
||||
|
||||
NR_UE_Timers_Constants_t *tac = &rrc->timers_and_constants;
|
||||
nr_timer_stop(&tac->T310);
|
||||
if (!get_softmodem_params()->phy_test) {
|
||||
// T304 is stopped upon completion of RA procedure which is not done in phy-test mode
|
||||
int t304_value = nr_rrc_get_T304(reconfigurationWithSync->t304);
|
||||
nr_timer_setup(&tac->T304, t304_value, 10); // 10ms step
|
||||
nr_timer_start(&tac->T304);
|
||||
}
|
||||
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 (rrc->target_ntncfg) {
|
||||
ASN_STRUCT_FREE(asn_DEF_NR_NTN_Config_r17, rrc->target_ntncfg);
|
||||
rrc->target_ntncfg = NULL;
|
||||
rrc->process_target_ntncfg = false;
|
||||
}
|
||||
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");
|
||||
const int copy_result = asn_copy(&asn_DEF_NR_NTN_Config_r17, (void **)&rrc->target_ntncfg, ntncfg);
|
||||
AssertFatal(copy_result == 0, "unable to copy NR_NTN_Config_r17_t\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void nr_rrc_cellgroup_configuration(NR_UE_RRC_INST_t *rrc, NR_CellGroupConfig_t *cgConfig, int gNB_index, bool dedicatedsib1)
|
||||
{
|
||||
NR_SpCellConfig_t *spCellConfig = cgConfig->spCellConfig;
|
||||
if(spCellConfig) {
|
||||
NR_ServingCellConfig_t *spCellConfigDedicated = spCellConfig->spCellConfigDedicated;
|
||||
if (spCellConfigDedicated) {
|
||||
if (spCellConfigDedicated->firstActiveDownlinkBWP_Id)
|
||||
rrc->dl_bwp_id = *spCellConfigDedicated->firstActiveDownlinkBWP_Id;
|
||||
if (spCellConfigDedicated->uplinkConfig && spCellConfigDedicated->uplinkConfig->firstActiveUplinkBWP_Id)
|
||||
rrc->ul_bwp_id = *spCellConfigDedicated->uplinkConfig->firstActiveUplinkBWP_Id;
|
||||
}
|
||||
NR_ReconfigurationWithSync_t *reconfigurationWithSync = spCellConfig->reconfigurationWithSync;
|
||||
if (reconfigurationWithSync) {
|
||||
LOG_I(NR_RRC, "Processing reconfigurationWithSync\n");
|
||||
nr_rrc_process_reconfigurationWithSync(rrc, reconfigurationWithSync, gNB_index);
|
||||
// if RRCReconfiguration does not include dedicatedSIB1-Delivery
|
||||
// if the active downlink BWP, which is indicated by the firstActiveDownlinkBWP-Id for the target SpCell of the MCG,
|
||||
// has a common search space configured by searchSpaceSIB1
|
||||
// acquire the SIB1, which is scheduled as specified in TS 38.213 [13], of the target SpCell of the MCG
|
||||
if (!dedicatedsib1 && IS_SA_MODE(get_softmodem_params())) {
|
||||
if (rrc->dl_bwp_id == 0) {
|
||||
// Check initial DL BWP for searchSpaceSIB1
|
||||
NR_ServingCellConfigCommon_t *spCellConfigCommon = reconfigurationWithSync->spCellConfigCommon;
|
||||
if (spCellConfigCommon) {
|
||||
NR_DownlinkConfigCommon_t *downlinkConfig = spCellConfigCommon->downlinkConfigCommon;
|
||||
if (downlinkConfig
|
||||
&& downlinkConfig->initialDownlinkBWP
|
||||
&& downlinkConfig->initialDownlinkBWP->pdcch_ConfigCommon
|
||||
&& downlinkConfig->initialDownlinkBWP->pdcch_ConfigCommon->present == NR_SetupRelease_PDCCH_ConfigCommon_PR_setup
|
||||
&& downlinkConfig->initialDownlinkBWP->pdcch_ConfigCommon->choice.setup->searchSpaceSIB1) {
|
||||
rrc->sched_reconfsync_sib1 = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Check dedicated DL BWP for searchSpaceSIB1
|
||||
if (spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList) {
|
||||
for (int i = 0; i < spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.count; i++) {
|
||||
NR_BWP_Downlink_t *bwp = spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.array[i];
|
||||
if (bwp->bwp_Id == rrc->dl_bwp_id && bwp->bwp_Common && bwp->bwp_Common->pdcch_ConfigCommon
|
||||
&& bwp->bwp_Common->pdcch_ConfigCommon->present == NR_SetupRelease_PDCCH_ConfigCommon_PR_setup
|
||||
&& bwp->bwp_Common->pdcch_ConfigCommon->choice.setup->searchSpaceSIB1) {
|
||||
rrc->sched_reconfsync_sib1 = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
nr_rrc_handle_SetupRelease_RLF_TimersAndConstants(rrc, spCellConfig->rlf_TimersAndConstants);
|
||||
}
|
||||
|
||||
nr_rrc_manage_rlc_bearers(rrc, cgConfig);
|
||||
|
||||
if (cgConfig->ext1)
|
||||
AssertFatal(cgConfig->ext1->reportUplinkTxDirectCurrent == NULL, "Reporting of UplinkTxDirectCurrent not implemented\n");
|
||||
AssertFatal(cgConfig->sCellToReleaseList == NULL, "Secondary serving cell release not implemented\n");
|
||||
AssertFatal(cgConfig->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,
|
||||
@@ -768,7 +953,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, gNB_index);
|
||||
nr_rrc_cellgroup_configuration(rrc, cellGroupConfig, gNB_index, false);
|
||||
|
||||
LOG_D(RRC, "Sending CellGroupConfig to MAC the pointer will be managed by mac\n");
|
||||
nr_mac_rrc_message_t rrc_msg = {0};
|
||||
@@ -776,10 +961,12 @@ static void nr_rrc_ue_process_masterCellGroup(NR_UE_RRC_INST_t *rrc,
|
||||
nr_mac_rrc_config_cg_t *mac_msg = &rrc_msg.payload.config_cg;
|
||||
mac_msg->cellGroupConfig = cellGroupConfig;
|
||||
mac_msg->UE_NR_Capability = rrc->UECap.UE_NR_Capability;
|
||||
mac_msg->hfn = rrc->current_hfn;
|
||||
mac_msg->frame = rrc->current_frame;
|
||||
nr_rrc_send_msg_to_mac(rrc, &rrc_msg);
|
||||
}
|
||||
|
||||
static void nr_rrc_process_reconfiguration_v1530(NR_UE_RRC_INST_t *rrc, NR_RRCReconfiguration_v1530_IEs_t *rec_1530, int gNB_index)
|
||||
static bool nr_rrc_process_reconfiguration_v1530(NR_UE_RRC_INST_t *rrc, NR_RRCReconfiguration_v1530_IEs_t *rec_1530, int gNB_index)
|
||||
{
|
||||
if (rec_1530->fullConfig) {
|
||||
// TODO perform the full configuration procedure as specified in 5.3.5.11 of 331
|
||||
@@ -793,7 +980,9 @@ static void nr_rrc_process_reconfiguration_v1530(NR_UE_RRC_INST_t *rrc, NR_RRCRe
|
||||
nr_pdcp_config_set_security(rrc->ue_id, 1, true, &sp);
|
||||
}
|
||||
NR_UE_RRC_SI_INFO *SI_info = &rrc->perNB[gNB_index].SInfo;
|
||||
bool dedicatedsib1 = false;
|
||||
if (rec_1530->dedicatedSIB1_Delivery) {
|
||||
dedicatedsib1 = true;
|
||||
NR_SIB1_t *sib1 = NULL;
|
||||
asn_dec_rval_t dec_rval = uper_decode(NULL,
|
||||
&asn_DEF_NR_SIB1,
|
||||
@@ -824,7 +1013,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, rrc->current_frame);
|
||||
nr_decode_SI(SI_info, si, rrc, rrc->current_hfn, rrc->current_frame);
|
||||
}
|
||||
}
|
||||
if (rec_1530->otherConfig) {
|
||||
@@ -860,6 +1049,7 @@ static void nr_rrc_process_reconfiguration_v1530(NR_UE_RRC_INST_t *rrc, NR_RRCRe
|
||||
}
|
||||
}
|
||||
}
|
||||
return dedicatedsib1;
|
||||
}
|
||||
|
||||
static void handle_meas_reporting_remove(rrcPerNB_t *rrc, int id, NR_UE_Timers_Constants_t *timers)
|
||||
@@ -1138,8 +1328,9 @@ static void nr_rrc_ue_process_rrcReconfiguration(NR_UE_RRC_INST_t *rrc, int gNB_
|
||||
case NR_RRCReconfiguration__criticalExtensions_PR_rrcReconfiguration: {
|
||||
NR_RRCReconfiguration_IEs_t *ie = reconfiguration->criticalExtensions.choice.rrcReconfiguration;
|
||||
|
||||
bool dedicatedsib1 = false;
|
||||
if (ie->nonCriticalExtension)
|
||||
nr_rrc_process_reconfiguration_v1530(rrc, ie->nonCriticalExtension, gNB_index);
|
||||
dedicatedsib1 = nr_rrc_process_reconfiguration_v1530(rrc, ie->nonCriticalExtension, gNB_index);
|
||||
|
||||
if (ie->radioBearerConfig) {
|
||||
LOG_I(NR_RRC, "RRCReconfiguration includes radio Bearer Configuration\n");
|
||||
@@ -1175,13 +1366,15 @@ 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, gNB_index);
|
||||
nr_rrc_cellgroup_configuration(rrc, cellGroupConfig, gNB_index, dedicatedsib1);
|
||||
AssertFatal(!IS_SA_MODE(get_softmodem_params()), "secondaryCellGroup only used in NSA for now\n");
|
||||
nr_mac_rrc_message_t rrc_msg = {0};
|
||||
rrc_msg.payload_type = NR_MAC_RRC_CONFIG_CG;
|
||||
nr_mac_rrc_config_cg_t *config_cg = &rrc_msg.payload.config_cg;
|
||||
config_cg->cellGroupConfig = cellGroupConfig;
|
||||
config_cg->UE_NR_Capability = rrc->UECap.UE_NR_Capability;
|
||||
config_cg->hfn = rrc->current_hfn;
|
||||
config_cg->frame = rrc->current_frame;
|
||||
nr_rrc_send_msg_to_mac(rrc, &rrc_msg);
|
||||
}
|
||||
}
|
||||
@@ -1278,6 +1471,7 @@ NR_UE_RRC_INST_t* nr_rrc_init_ue(char* uecap_file, int instance_id, int num_ant_
|
||||
rrc->dl_bwp_id = 0;
|
||||
rrc->ul_bwp_id = 0;
|
||||
rrc->as_security_activated = false;
|
||||
rrc->sched_reconfsync_sib1 = false;
|
||||
rrc->detach_after_release = false;
|
||||
rrc->reconfig_after_reestab = false;
|
||||
/* 5G-S-TMSI */
|
||||
@@ -1507,17 +1701,21 @@ static void nr_rrc_ue_decode_NR_BCCH_BCH_Message(NR_UE_RRC_INST_t *rrc,
|
||||
&& rrc->nrRrcState != RRC_STATE_DETACH_NR) {
|
||||
// to schedule MAC to get SI if required
|
||||
get_sib = check_si_status(SI_info);
|
||||
if (get_sib)
|
||||
SI_info->sib_pending = true;
|
||||
}
|
||||
if (bcch_message->message.present == NR_BCCH_BCH_MessageType_PR_mib) {
|
||||
nr_mac_rrc_message_t rrc_msg = {0};
|
||||
rrc_msg.payload_type = NR_MAC_RRC_CONFIG_MIB;
|
||||
nr_mac_rrc_config_mib_t *config_mib = &rrc_msg.payload.config_mib;
|
||||
config_mib->bcch = bcch_message;
|
||||
config_mib->get_sib = get_sib;
|
||||
config_mib->access_barred = barred;
|
||||
nr_rrc_send_msg_to_mac(rrc, &rrc_msg);
|
||||
if (get_sib) {
|
||||
SI_info->sib_pending = true;
|
||||
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;
|
||||
nr_rrc_send_msg_to_mac(rrc, &sib_msg);
|
||||
}
|
||||
} else {
|
||||
LOG_E(NR_RRC, "RRC-received BCCH message is not a MIB\n");
|
||||
ASN_STRUCT_FREE(asn_DEF_NR_BCCH_BCH_Message, bcch_message);
|
||||
@@ -1611,6 +1809,7 @@ static void nr_rrc_ue_decode_NR_BCCH_DL_SCH_Message(NR_UE_RRC_INST_t *rrc,
|
||||
const uint8_t Sdu_len,
|
||||
const uint8_t rsrq,
|
||||
const uint8_t rsrp,
|
||||
int hfn,
|
||||
int frame,
|
||||
int slot)
|
||||
{
|
||||
@@ -1650,7 +1849,7 @@ static void nr_rrc_ue_decode_NR_BCCH_DL_SCH_Message(NR_UE_RRC_INST_t *rrc,
|
||||
case NR_BCCH_DL_SCH_MessageType__c1_PR_systemInformation:
|
||||
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, frame);
|
||||
nr_decode_SI(SI_info, si, rrc, hfn, frame);
|
||||
break;
|
||||
case NR_BCCH_DL_SCH_MessageType__c1_PR_NOTHING:
|
||||
default:
|
||||
@@ -1661,155 +1860,6 @@ static void nr_rrc_ue_decode_NR_BCCH_DL_SCH_Message(NR_UE_RRC_INST_t *rrc,
|
||||
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_UE_DECODE_BCCH, VCD_FUNCTION_OUT );
|
||||
}
|
||||
|
||||
static void nr_rrc_signal_maxrtxindication(int ue_id)
|
||||
{
|
||||
MessageDef *msg = itti_alloc_new_message(TASK_RLC_UE, ue_id, NR_RRC_RLC_MAXRTX);
|
||||
NR_RRC_RLC_MAXRTX(msg).ue_id = ue_id;
|
||||
itti_send_msg_to_task(TASK_RRC_NRUE, ue_id, msg);
|
||||
}
|
||||
|
||||
/** @brief Release all active RLC entities for a UE and set to inactive.
|
||||
* This is typically used when tearing down all DRBs at UE side,
|
||||
* such as after a PDU session release or full reconfiguration.
|
||||
* @param rrc Pointer to NR_UE_RRC_INST_t structure
|
||||
* @param id Logical Channel ID (must be in range [0, NR_MAX_NUM_LCID-1]) */
|
||||
static void nr_rrc_release_rlc_entity(NR_UE_RRC_INST_t *rrc, int id)
|
||||
{
|
||||
DevAssert(rrc);
|
||||
DevAssert(id >= 0 && id < NR_MAX_NUM_LCID);
|
||||
if (rrc->active_RLC_entity[id]) {
|
||||
rrc->active_RLC_entity[id] = false;
|
||||
nr_rlc_release_entity(rrc->ue_id, id);
|
||||
LOG_I(RLC, "Released RLC entity: ue_id=%ld, lc_id=%d\n", rrc->ue_id, id);
|
||||
}
|
||||
}
|
||||
|
||||
static void nr_rrc_manage_rlc_bearers(NR_UE_RRC_INST_t *rrc, const NR_CellGroupConfig_t *cellGroupConfig)
|
||||
{
|
||||
if (cellGroupConfig->rlc_BearerToReleaseList != NULL) {
|
||||
for (int i = 0; i < cellGroupConfig->rlc_BearerToReleaseList->list.count; i++) {
|
||||
NR_LogicalChannelIdentity_t *lcid = cellGroupConfig->rlc_BearerToReleaseList->list.array[i];
|
||||
AssertFatal(lcid, "LogicalChannelIdentity shouldn't be null here\n");
|
||||
nr_rrc_release_rlc_entity(rrc, *lcid);
|
||||
}
|
||||
}
|
||||
|
||||
if (cellGroupConfig->rlc_BearerToAddModList != NULL) {
|
||||
for (int i = 0; i < cellGroupConfig->rlc_BearerToAddModList->list.count; i++) {
|
||||
NR_RLC_BearerConfig_t *rlc_bearer = cellGroupConfig->rlc_BearerToAddModList->list.array[i];
|
||||
NR_LogicalChannelIdentity_t lcid = rlc_bearer->logicalChannelIdentity;
|
||||
if (rrc->active_RLC_entity[lcid]) {
|
||||
if (rlc_bearer->reestablishRLC)
|
||||
nr_rlc_reestablish_entity(rrc->ue_id, lcid);
|
||||
if (rlc_bearer->rlc_Config)
|
||||
nr_rlc_reconfigure_entity(rrc->ue_id, lcid, rlc_bearer->rlc_Config);
|
||||
} else {
|
||||
rrc->active_RLC_entity[lcid] = true;
|
||||
AssertFatal(rlc_bearer->servedRadioBearer, "servedRadioBearer mandatory in case of setup\n");
|
||||
AssertFatal(rlc_bearer->servedRadioBearer->present != NR_RLC_BearerConfig__servedRadioBearer_PR_NOTHING,
|
||||
"Invalid RB for RLC configuration\n");
|
||||
if (rlc_bearer->servedRadioBearer->present == NR_RLC_BearerConfig__servedRadioBearer_PR_srb_Identity) {
|
||||
NR_SRB_Identity_t srb_id = rlc_bearer->servedRadioBearer->choice.srb_Identity;
|
||||
nr_rlc_add_srb(rrc->ue_id, srb_id, rlc_bearer);
|
||||
nr_rlc_set_rlf_handler(rrc->ue_id, nr_rrc_signal_maxrtxindication);
|
||||
} else { // DRB
|
||||
NR_DRB_Identity_t drb_id = rlc_bearer->servedRadioBearer->choice.drb_Identity;
|
||||
if (!rlc_bearer->rlc_Config) {
|
||||
LOG_E(RLC, "RLC-Config not present but is mandatory for setup\n");
|
||||
rrc->active_RLC_entity[lcid] = false;
|
||||
} else {
|
||||
nr_rlc_add_drb(rrc->ue_id, drb_id, rlc_bearer);
|
||||
nr_rlc_set_rlf_handler(rrc->ue_id, nr_rrc_signal_maxrtxindication);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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)) {
|
||||
// if the AS security is not activated, perform the actions upon going to RRC_IDLE as specified in 5.3.11
|
||||
// with the release cause 'other' upon which the procedure ends
|
||||
NR_Release_Cause_t release_cause = OTHER;
|
||||
nr_rrc_going_to_IDLE(rrc, release_cause, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
if (reconfigurationWithSync->spCellConfigCommon) {
|
||||
/* if the frequencyInfoDL is included, consider the target SpCell
|
||||
to be one on the SSB frequency indicated by the frequencyInfoDL */
|
||||
const NR_DownlinkConfigCommon_t *dcc = reconfigurationWithSync->spCellConfigCommon->downlinkConfigCommon;
|
||||
if (dcc && dcc->frequencyInfoDL && dcc->frequencyInfoDL->absoluteFrequencySSB)
|
||||
rrc->arfcn_ssb = *dcc->frequencyInfoDL->absoluteFrequencySSB;
|
||||
|
||||
// consider the target SpCell to be one with a physical cell identity indicated by the physCellId
|
||||
if (!reconfigurationWithSync->spCellConfigCommon->physCellId)
|
||||
LOG_E(NR_RRC, "physCellId absent but should be mandatory present upon cell change and cell addition\n");
|
||||
else
|
||||
rrc->phyCellID = *reconfigurationWithSync->spCellConfigCommon->physCellId;
|
||||
}
|
||||
|
||||
NR_UE_Timers_Constants_t *tac = &rrc->timers_and_constants;
|
||||
nr_timer_stop(&tac->T310);
|
||||
if (!get_softmodem_params()->phy_test) {
|
||||
// T304 is stopped upon completion of RA procedure which is not done in phy-test mode
|
||||
int t304_value = nr_rrc_get_T304(reconfigurationWithSync->t304);
|
||||
nr_timer_setup(&tac->T304, t304_value, 10); // 10ms step
|
||||
nr_timer_start(&tac->T304);
|
||||
}
|
||||
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 (rrc->target_ntncfg) {
|
||||
ASN_STRUCT_FREE(asn_DEF_NR_NTN_Config_r17, rrc->target_ntncfg);
|
||||
rrc->target_ntncfg = NULL;
|
||||
rrc->process_target_ntncfg = false;
|
||||
}
|
||||
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");
|
||||
const int copy_result = asn_copy(&asn_DEF_NR_NTN_Config_r17, (void **)&rrc->target_ntncfg, ntncfg);
|
||||
AssertFatal(copy_result == 0, "unable to copy NR_NTN_Config_r17_t\n");
|
||||
}
|
||||
}
|
||||
|
||||
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, gNB_index);
|
||||
}
|
||||
nr_rrc_handle_SetupRelease_RLF_TimersAndConstants(rrc, spCellConfig->rlf_TimersAndConstants);
|
||||
if (spCellConfig->spCellConfigDedicated) {
|
||||
if (spCellConfig->spCellConfigDedicated->firstActiveDownlinkBWP_Id)
|
||||
rrc->dl_bwp_id = *spCellConfig->spCellConfigDedicated->firstActiveDownlinkBWP_Id;
|
||||
if (spCellConfig->spCellConfigDedicated->uplinkConfig &&
|
||||
spCellConfig->spCellConfigDedicated->uplinkConfig->firstActiveUplinkBWP_Id)
|
||||
rrc->dl_bwp_id = *spCellConfig->spCellConfigDedicated->uplinkConfig->firstActiveUplinkBWP_Id;
|
||||
}
|
||||
}
|
||||
|
||||
nr_rrc_manage_rlc_bearers(rrc, cellGroupConfig);
|
||||
|
||||
if (cellGroupConfig->ext1)
|
||||
AssertFatal(cellGroupConfig->ext1->reportUplinkTxDirectCurrent == NULL, "Reporting of UplinkTxDirectCurrent not implemented\n");
|
||||
AssertFatal(cellGroupConfig->sCellToReleaseList == NULL, "Secondary serving cell release not implemented\n");
|
||||
AssertFatal(cellGroupConfig->sCellToAddModList == NULL, "Secondary serving cell addition not implemented\n");
|
||||
}
|
||||
|
||||
static void rrc_ue_generate_RRCSetupComplete(const NR_UE_RRC_INST_t *rrc, const uint8_t Transaction_id)
|
||||
{
|
||||
uint8_t buffer[100];
|
||||
@@ -2585,14 +2635,37 @@ static void nr_ue_check_meas_report(NR_UE_RRC_INST_t *rrc, const uint8_t gnb_ind
|
||||
}
|
||||
}
|
||||
|
||||
void nr_rrc_handle_ra_indication(NR_UE_RRC_INST_t *rrc, bool ra_succeeded)
|
||||
static void nr_rrc_handle_ra_indication(NR_UE_RRC_INST_t *rrc, bool ra_succeeded, int gNB_index)
|
||||
{
|
||||
NR_UE_Timers_Constants_t *timers = &rrc->timers_and_constants;
|
||||
if (ra_succeeded && nr_timer_is_active(&timers->T304)) {
|
||||
// successful Random Access procedure triggered by reconfigurationWithSync
|
||||
nr_timer_stop(&timers->T304);
|
||||
// TODO handle the rest of procedures as described in 5.3.5.3 for when
|
||||
// procedures described in 5.3.5.3 of 38.331 when
|
||||
// reconfigurationWithSync is included in spCellConfig
|
||||
nr_timer_stop(&timers->T304);
|
||||
|
||||
// TODO apply the parts of the CQI reporting configuration,
|
||||
// the scheduling request configuration and the sounding RS
|
||||
// configuration that do not require the UE to know the SFN of the respective target SpCell
|
||||
// TODO apply the parts of the measurement and the radio resource configuration
|
||||
// that require the UE to know the SFN of the respective target SpCell
|
||||
// (not sure what to do for these two points, probably not relevant for our implementation)
|
||||
|
||||
// if T390 is running stop timer T390 for all access categories
|
||||
if (nr_timer_is_active(&timers->T390)) {
|
||||
nr_timer_stop(&timers->T390);
|
||||
// TODO perform the actions as specified in 5.3.14.4.
|
||||
}
|
||||
|
||||
if (rrc->sched_reconfsync_sib1) {
|
||||
rrc->sched_reconfsync_sib1 = false;
|
||||
NR_UE_RRC_SI_INFO *SI_info = &rrc->perNB[gNB_index].SInfo;
|
||||
SI_info->sib_pending = true;
|
||||
nr_mac_rrc_message_t sib_msg = {0};
|
||||
sib_msg.payload_type = NR_MAC_RRC_SCHED_SIB;
|
||||
sib_msg.payload.sched_sib.get_sib = 1;
|
||||
nr_rrc_send_msg_to_mac(rrc, &sib_msg);
|
||||
}
|
||||
} else if (!ra_succeeded) {
|
||||
// upon random access problem indication from MCG MAC
|
||||
// while neither T300, T301, T304, T311 nor T319 are running
|
||||
@@ -2640,6 +2713,7 @@ void *rrc_nrue(void *notUsed)
|
||||
} break;
|
||||
|
||||
case NRRRC_FRAME_PROCESS:
|
||||
rrc->current_hfn = NRRRC_FRAME_PROCESS(msg_p).hfn;
|
||||
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)
|
||||
@@ -2683,7 +2757,7 @@ void *rrc_nrue(void *notUsed)
|
||||
rrc->ue_id,
|
||||
ITTI_MSG_NAME(msg_p),
|
||||
NR_RRC_MAC_RA_IND(msg_p).RA_succeeded ? "successful" : "failed");
|
||||
nr_rrc_handle_ra_indication(rrc, NR_RRC_MAC_RA_IND(msg_p).RA_succeeded);
|
||||
nr_rrc_handle_ra_indication(rrc, NR_RRC_MAC_RA_IND(msg_p).RA_succeeded, NR_RRC_MAC_RA_IND(msg_p).gnb_index);
|
||||
break;
|
||||
|
||||
case NR_RRC_MAC_BCCH_DATA_IND:
|
||||
@@ -2698,6 +2772,7 @@ void *rrc_nrue(void *notUsed)
|
||||
bcch->sdu_size,
|
||||
bcch->rsrq,
|
||||
bcch->rsrp,
|
||||
bcch->hfn,
|
||||
bcch->frame,
|
||||
bcch->slot);
|
||||
break;
|
||||
|
||||
@@ -262,8 +262,9 @@ typedef struct NR_UE_RRC_INST_s {
|
||||
// 5G-S-TMSI
|
||||
uint64_t fiveG_S_TMSI;
|
||||
// Frame timing received from MAC
|
||||
int current_hfn;
|
||||
int current_frame;
|
||||
|
||||
bool sched_reconfsync_sib1;
|
||||
//Sidelink params
|
||||
NR_SL_PreconfigurationNR_r16_t *sl_preconfig;
|
||||
// NTN params
|
||||
|
||||
@@ -46,9 +46,6 @@ NR_UE_RRC_INST_t* get_NR_UE_rrc_inst(int instance);
|
||||
void init_nsa_message (NR_UE_RRC_INST_t *rrc, char* reconfig_file, char* rbconfig_file);
|
||||
|
||||
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, int gNB_index);
|
||||
|
||||
void nr_rrc_going_to_IDLE(NR_UE_RRC_INST_t *rrc,
|
||||
NR_Release_Cause_t release_cause,
|
||||
NR_RRCRelease_t *RRCRelease);
|
||||
@@ -73,7 +70,7 @@ int get_from_lte_ue_fd();
|
||||
void nr_rrc_SI_timers(NR_UE_RRC_SI_INFO *SInfo);
|
||||
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 nr_ue_rrc_timer_trigger(int module_id, int hfn, 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);
|
||||
|
||||
|
||||
@@ -99,21 +99,54 @@ void rxAddInput(const c16_t *input_sig,
|
||||
double vel_sat_gnb = 0;
|
||||
double acc_sat_gnb = 0;
|
||||
if (channelDesc->modelid == SAT_LEO_TRANS) {
|
||||
const double acc_sat_x = 0;
|
||||
const double acc_sat_y = -w_sat * w_sat * radius_sat * sin(w_sat * t);
|
||||
const double acc_sat_z = -w_sat * w_sat * radius_sat * cos(w_sat * t);
|
||||
const double t5 = t + 5;
|
||||
const double t10 = t + 10;
|
||||
|
||||
const double pos_gnb_x = 0;
|
||||
const double pos_gnb_y = 0;
|
||||
const double pos_gnb_z = radius_earth;
|
||||
|
||||
const double pos_sat_x5 = 0;
|
||||
const double pos_sat_y5 = radius_sat * sin(w_sat * t5);
|
||||
const double pos_sat_z5 = radius_sat * cos(w_sat * t5);
|
||||
|
||||
const double pos_sat_x10 = 0;
|
||||
const double pos_sat_y10 = radius_sat * sin(w_sat * t10);
|
||||
const double pos_sat_z10 = radius_sat * cos(w_sat * t10);
|
||||
|
||||
const double dir_sat_gnb_x = pos_gnb_x - pos_sat_x;
|
||||
const double dir_sat_gnb_y = pos_gnb_y - pos_sat_y;
|
||||
const double dir_sat_gnb_z = pos_gnb_z - pos_sat_z;
|
||||
|
||||
const double dir_sat_gnb_x5 = pos_gnb_x - pos_sat_x5;
|
||||
const double dir_sat_gnb_y5 = pos_gnb_y - pos_sat_y5;
|
||||
const double dir_sat_gnb_z5 = pos_gnb_z - pos_sat_z5;
|
||||
|
||||
const double dir_sat_gnb_x10 = pos_gnb_x - pos_sat_x10;
|
||||
const double dir_sat_gnb_y10 = pos_gnb_y - pos_sat_y10;
|
||||
const double dir_sat_gnb_z10 = pos_gnb_z - pos_sat_z10;
|
||||
|
||||
dist_sat_gnb = sqrt(dir_sat_gnb_x * dir_sat_gnb_x + dir_sat_gnb_y * dir_sat_gnb_y + dir_sat_gnb_z * dir_sat_gnb_z);
|
||||
vel_sat_gnb = (vel_sat_x * dir_sat_gnb_x + vel_sat_y * dir_sat_gnb_y + vel_sat_z * dir_sat_gnb_z) / dist_sat_gnb;
|
||||
acc_sat_gnb = (acc_sat_x * dir_sat_gnb_x + acc_sat_y * dir_sat_gnb_y + acc_sat_z * dir_sat_gnb_z) / dist_sat_gnb;
|
||||
const double dist_sat_gnb5 = sqrt(dir_sat_gnb_x5 * dir_sat_gnb_x5 + dir_sat_gnb_y5 * dir_sat_gnb_y5 + dir_sat_gnb_z5 * dir_sat_gnb_z5);
|
||||
const double dist_sat_gnb10 = sqrt(dir_sat_gnb_x10 * dir_sat_gnb_x10 + dir_sat_gnb_y10 * dir_sat_gnb_y10 + dir_sat_gnb_z10 * dir_sat_gnb_z10);
|
||||
|
||||
// calculate vel_sat_gnb and acc_sat_gnb, so the delay is correct for epoch_time, epoch_time + 5 seconds and epoch_time + 10 seconds
|
||||
//
|
||||
// dist_sat_gnb = dist_sat_gnb + 0 * vel_sat_gnb + 0 * acc_sat_gnb;
|
||||
// dist_sat_gnb5 = dist_sat_gnb + 5 * vel_sat_gnb + 25 * acc_sat_gnb;
|
||||
// dist_sat_gnb10 = dist_sat_gnb + 10 * vel_sat_gnb + 100 * acc_sat_gnb;
|
||||
//
|
||||
// vel_sat_gnb = (dist_sat_gnb5 - dist_sat_gnb) / 5 - 5 * acc_sat_gnb;
|
||||
// acc_sat_gnb = (dist_sat_gnb10 - dist_sat_gnb) / 100 - vel_sat_gnb / 10;
|
||||
//
|
||||
// vel_sat_gnb = (dist_sat_gnb5 - dist_sat_gnb) / 5 - 5 * ((dist_sat_gnb10 - dist_sat_gnb) / 100 - vel_sat_gnb / 10);
|
||||
|
||||
vel_sat_gnb = 2 * (dist_sat_gnb5 - dist_sat_gnb) / 5 - (dist_sat_gnb10 - dist_sat_gnb) / 10;
|
||||
acc_sat_gnb = (dist_sat_gnb10 - dist_sat_gnb) / 50 - (dist_sat_gnb5 - dist_sat_gnb) / 25;
|
||||
|
||||
// in the moment when the satellite disappears behind the horizon acc_sat_gnb might become negative, what is invalid
|
||||
if (acc_sat_gnb < 0)
|
||||
acc_sat_gnb = 0;
|
||||
}
|
||||
|
||||
const double prop_delay = (dist_ue_sat + dist_sat_gnb) / c;
|
||||
@@ -128,7 +161,7 @@ void rxAddInput(const c16_t *input_sig,
|
||||
last_TS = TS;
|
||||
LOG_I(HW, "Satellite orbit: time %f s, Position = (%f, %f, %f), Velocity = (%f, %f, %f)\n", t, pos_sat_x, pos_sat_y, pos_sat_z, vel_sat_x, vel_sat_y, vel_sat_z);
|
||||
LOG_I(HW, "Uplink delay %f ms, Doppler shift UE->SAT %f kHz\n", prop_delay * 1000, f_Doppler_shift_ue_sat / 1000);
|
||||
LOG_I(HW, "Satellite velocity towards gNB: %f m/s, acceleration towards gNB: %f m/s²\n", vel_sat_gnb, acc_sat_gnb);
|
||||
LOG_I(HW, "Satellite velocity towards gNB: %f m/s, acceleration towards gNB: %f m/s²\n", -vel_sat_gnb, acc_sat_gnb);
|
||||
}
|
||||
|
||||
const int samples_per_subframe = channelDesc->sampling_rate / 1000;
|
||||
@@ -138,7 +171,7 @@ void rxAddInput(const c16_t *input_sig,
|
||||
.sfn = (abs_subframe / 10 + 1) % 1024,
|
||||
.subframe = 0,
|
||||
.delay = 2 * dist_sat_gnb / (c * 4.072e-9),
|
||||
.drift = 2 * -vel_sat_gnb / (c * 0.2e-9),
|
||||
.drift = 2 * vel_sat_gnb / (c * 0.2e-9),
|
||||
.accel = 2 * acc_sat_gnb / (c * 0.2e-10),
|
||||
.position.X = pos_sat_x / 1.3,
|
||||
.position.Y = pos_sat_y / 1.3,
|
||||
|
||||
Reference in New Issue
Block a user