mirror of
https://gitlab.eurecom.fr/oai/openairinterface5g.git
synced 2026-07-13 04:30:28 +00:00
- all RAN code, CI code, configuration files, dockerfiles, in CSSL v1.0
- all deployment code (openshift, charts, ancillary files like shell
scripts), in MIT
- documentation in CC-BY-4.0
- exceptions might apply and are listed in NOTICE
- there is a new LICENSES folder with all licenses
- CONTRIBUTIONS.md has been updated accordingly
For automated changes based on OAI PL v1.1:
perl -i~ -0pe 's/\/\*.*Licensed to the OpenAirInterface.*openairinterface.org\n#?/\/*\n * SPDX-License-Identifier: LicenseRef-CSSL-1.0\n/s' **/*.{c,h,cpp}
perl -i~ -0pe 's/\/\*.*Licensed to the OpenAirInterface.*openairinterface.org\n#?/\/*\n * SPDX-License-Identifier: LicenseRef-CSSL-1.0\n/s' **/*.ts
perl -i~ -0pe 's/<!--.*Licensed to the OpenAirInterface.*openairinterface.org\n.*-->/<!-- SPDX-License-Identifier: LicenseRef-CSSL-1.0 -->/s' **/*.xml
The rest (cmake, files with missing license, cmake) manually.
100 lines
4.0 KiB
Markdown
100 lines
4.0 KiB
Markdown
<!-- SPDX-License-Identifier: CC-BY-4.0 -->
|
|
|
|
This document is a high-level overview over the L1 threading mechanism.
|
|
|
|
```mermaid
|
|
flowchart TB
|
|
ru_thread --> RFin[block rx_rf] --> UL{is UL slot?}
|
|
UL -- yes --> wait_free_rx_tti --> fep_rx --> rx_nr_prach_ru --> msg:L1_tx_out
|
|
UL -- no --> msg:L1_tx_out
|
|
msg:L1_tx_out -- asnyc launch --> L1_tx_thread
|
|
msg:L1_tx_out --> RFin
|
|
```
|
|
|
|
The main thread is `ru_thread()`. It blocks on reception of radio samples
|
|
(either time domain or frequency domain). In the case of an UL slot, it waits
|
|
that no more than N UL jobs are scheduled (via `wait_free_rx_tti()`, which
|
|
waits on queue `L1_rx_out`, cf. the RX L1 processing further below). Then:
|
|
|
|
- if the radio is time domain-based, it performs RX front-end processing (RX
|
|
FEP -> `fep_rx()`, i.e. DFT) to reach a frequency domain representation of
|
|
the RX signal, as well as does DFT for PRACH.
|
|
- if the radio is frequency domain-based, nothing is done.
|
|
|
|
Afterwards, it triggers TX processing by pushing a message into the FIFO queue
|
|
`L1_tx_out`, which asynchronously starts a TX job in `L1_tx_thread()` (see
|
|
below). After that, it blocks again on reception on the radio.
|
|
|
|
|
|
```mermaid
|
|
flowchart TB
|
|
L1_tx_thread --> TX_in[block L1_tx_out] --> NR_slot_indication
|
|
|
|
subgraph tx_func
|
|
|
|
NR_slot_indication --> msg:resp_L1 --> phy_procedures_gNB_tx --> ru_tx_func
|
|
NR_slot_indication["run the scheduler:
|
|
- monolithic: run_scheduler_monolithic()
|
|
- nFAPI: send indication via pnf_send_slot_ind()"]
|
|
msg:resp_L1 -- async launch --> L1_RX_thread
|
|
end
|
|
ru_tx_func --> TX_in
|
|
```
|
|
|
|
The `L1_tx_thread()` processes individual TX jobs sequentially, by waiting for
|
|
new messages on queue `L1_tx_out`, signalling individual TX jobs. For each
|
|
message, it calls `tx_func()` which does in order:
|
|
|
|
- run the scheduler through `NR_slot_indication`, which corresponds to a
|
|
"Slot.indication" in FAPI parlance. This runs the scheduler, and schedules a
|
|
given slot (either downlink, uplink, or both).
|
|
- trigger RX processing by pushing a message into the FIFO queue `resp_L1`,
|
|
asynchronously starting an RX job in `L1_rx_thread()` (see below).
|
|
- process the current L1 TX job through `phy_procedures_gNB_tx()`
|
|
- write to the radio board via `ru_tx_func()`.
|
|
|
|
After these steps, `tx_func()` return to `L1_tx_thread()`, which will wait for
|
|
the next TX job.
|
|
|
|
```mermaid
|
|
flowchart TB
|
|
L1_rx_thread --> RX_in[block resp_L1] --> L1_nr_prach_proc
|
|
|
|
subgraph rx_func
|
|
|
|
L1_nr_prach_proc --> phase_comp{apply phase comp.?}
|
|
phase_comp -- yes --> apply_nr_rotation --> phy_procedures_gNB_uespec_RX
|
|
phase_comp -- no --> phy_procedures_gNB_uespec_RX
|
|
phy_procedures_gNB_uespec_RX --> NR_ul_indication --> msg:L1_rx_out
|
|
NR_ul_indication["run the scheduler: NR_UL_indication()"]
|
|
msg:L1_rx_out -- async signal free --> ru_thread
|
|
end
|
|
msg:L1_rx_out --> RX_in
|
|
```
|
|
|
|
The `L1_rx_thread()` processes individual RX jobs sequentially. It waits for a
|
|
new RX job through the queue `resp_L1`, and then calls `rx_func()`, which does
|
|
in order:
|
|
|
|
- run PRACH processing via `L1_nr_prach_proc()`
|
|
- optionally apply rotation to the RX signal if phase compensation is to be
|
|
applied
|
|
- run the current L1 RX job through (`phy_procedures_gNB_uespec_RX()`), which
|
|
notably includes PUCCH, PUSCH, SRS processing
|
|
- call the scheduler through `NR_ul_indication()`, which corresponds to FAPI
|
|
uplink messages (e.g., `RX_data.indication`, `CRC.indication`,
|
|
`UCI.indication` etc.)
|
|
- signal completion via FIFO queue `L1_rx_out()`, which tells `ru_thread()`
|
|
that RX processing finished.
|
|
|
|
The signalling of scheduler data is done through a variable `UL_INFO`, which is
|
|
filled by `L1_nr_prach_proc()` (for PRACH) and `phy_procedures_gNB_uespec_RX()`
|
|
(for PUCCH, PUSCH, SRS).
|
|
|
|
After these steps, `rx_func()` returns to `L1_rx_thread()`, which will wait the
|
|
next RX job.
|
|
|
|
Note that while individual TX (RX) jobs are run sequentially through
|
|
`L1_tx_thread()` (`L1_rx_thread()`), both TX and RX processing run in
|
|
parallel.
|