mirror of
https://gitlab.eurecom.fr/oai/openairinterface5g.git
synced 2026-07-15 05:30:29 +00:00
Compare commits
159 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
70508ebaf5 | ||
|
|
4a84b92d88 | ||
|
|
9c7b3d02e0 | ||
|
|
3acb40cb85 | ||
|
|
aff84037a7 | ||
|
|
0f45f471b2 | ||
|
|
016ab2cfb3 | ||
|
|
7729bab5af | ||
|
|
fef2154525 | ||
|
|
546fc0628b | ||
|
|
ddea885bc7 | ||
|
|
be4d64a576 | ||
|
|
afcd77108d | ||
|
|
dde7ecf994 | ||
|
|
4bff655952 | ||
|
|
14b5bcb600 | ||
|
|
6e1bfb2c19 | ||
|
|
3921017988 | ||
|
|
e6dd656e52 | ||
|
|
223fd132e0 | ||
|
|
7d029ed5b1 | ||
|
|
991ede5c59 | ||
|
|
f34ecdd021 | ||
|
|
96dc20010e | ||
|
|
1edb0a09bb | ||
|
|
ff9b39145e | ||
|
|
ebdedfffcf | ||
|
|
486f4423d9 | ||
|
|
bfeba0de48 | ||
|
|
80a8b81e96 | ||
|
|
8bed33d44e | ||
|
|
1ec719bd44 | ||
|
|
9e94084e9d | ||
|
|
5fad2465f0 | ||
|
|
75545fa2c1 | ||
|
|
dc35ce95b9 | ||
|
|
48b329d115 | ||
|
|
6bdf1dde3d | ||
|
|
3a3fd87633 | ||
|
|
c8e36d3968 | ||
|
|
bf89f7997c | ||
|
|
d86bad7915 | ||
|
|
fcf078b18c | ||
|
|
fcea45b215 | ||
|
|
fe56b68514 | ||
|
|
ad304b62d6 | ||
|
|
0dab3bb6a1 | ||
|
|
ecb98e575f | ||
|
|
f63c444bb7 | ||
|
|
1cbfef20f4 | ||
|
|
2828e63dd8 | ||
|
|
384186b0a6 | ||
|
|
aa6f141498 | ||
|
|
32847ee143 | ||
|
|
b1c7bdf99b | ||
|
|
69a017f57b | ||
|
|
602d729d43 | ||
|
|
29c20ac232 | ||
|
|
0a885dcf5a | ||
|
|
447ff67aba | ||
|
|
465b57d8c5 | ||
|
|
35cf1c91bb | ||
|
|
b58631ce79 | ||
|
|
860232782a | ||
|
|
e179a6df8f | ||
|
|
1c659403b7 | ||
|
|
1a1502ac5a | ||
|
|
cb9dab74e3 | ||
|
|
f79f5087e5 | ||
|
|
f5aaacd9e8 | ||
|
|
cde7d98a61 | ||
|
|
d568920466 | ||
|
|
2716a5a3dc | ||
|
|
ede596cfc7 | ||
|
|
33ff225739 | ||
|
|
11cf337b6a | ||
|
|
c5d1895540 | ||
|
|
58eebfe1d8 | ||
|
|
3dbb22cad8 | ||
|
|
3226e5bb34 | ||
|
|
b61d41a440 | ||
|
|
7b5baa5104 | ||
|
|
cea29f9c3f | ||
|
|
a65ddf5cd3 | ||
|
|
e47e28301f | ||
|
|
8c4e48a670 | ||
|
|
6d75ca8e9c | ||
|
|
0d4a4a6d78 | ||
|
|
0abc46b708 | ||
|
|
05af0556af | ||
|
|
14ec3a930f | ||
|
|
cd376c904b | ||
|
|
2a3f0ffc02 | ||
|
|
e59473f8fe | ||
|
|
ea3e1dbaf2 | ||
|
|
326f2a0cfb | ||
|
|
fd794a85c1 | ||
|
|
9c0577ad1e | ||
|
|
102792c373 | ||
|
|
61a1e8c0d8 | ||
|
|
c2dbfd79d5 | ||
|
|
bc32bf8875 | ||
|
|
9f5ac5ac8e | ||
|
|
ac738ae714 | ||
|
|
6f7a26d681 | ||
|
|
6d437cffcf | ||
|
|
52c53c868f | ||
|
|
274d999526 | ||
|
|
c4125d1c74 | ||
|
|
919b61f147 | ||
|
|
5b2a75f518 | ||
|
|
0b7c6bbb95 | ||
|
|
d81d30af28 | ||
|
|
7b2252d52d | ||
|
|
fe211685ec | ||
|
|
29e75444e6 | ||
|
|
eba9f272ce | ||
|
|
09c9bb998f | ||
|
|
6d4573905a | ||
|
|
dc01a3540a | ||
|
|
c3f6af1008 | ||
|
|
633b6de92a | ||
|
|
ad5e941bc9 | ||
|
|
75d7fa275d | ||
|
|
328968cecf | ||
|
|
a5f60811c5 | ||
|
|
840abd0048 | ||
|
|
829d6fe7cf | ||
|
|
db7dbda8e2 | ||
|
|
f448088c8d | ||
|
|
a3268a9c2f | ||
|
|
716c29fe1f | ||
|
|
3cbf777835 | ||
|
|
813a90bd21 | ||
|
|
0548191fac | ||
|
|
145ab730c0 | ||
|
|
5f2108edb0 | ||
|
|
b7ab31854e | ||
|
|
f7d0ec0960 | ||
|
|
7032477784 | ||
|
|
7e0c0fe18b | ||
|
|
5a478deac4 | ||
|
|
40024d4caa | ||
|
|
dcae0070a6 | ||
|
|
3fb74dc66e | ||
|
|
82c3c04018 | ||
|
|
df5a9facbe | ||
|
|
71c692d727 | ||
|
|
159c219bdd | ||
|
|
ecfe769205 | ||
|
|
21329e1b70 | ||
|
|
0aa3f89c52 | ||
|
|
cd79eec3ec | ||
|
|
a1049e8dd1 | ||
|
|
28786af8bf | ||
|
|
eb1ae91051 | ||
|
|
0f50702483 | ||
|
|
7a0489842b | ||
|
|
910f8cef33 |
@@ -5,3 +5,4 @@ common/utils/T/T_IDs.h
|
||||
common/utils/T/T_messages.txt.h
|
||||
common/utils/T/genids
|
||||
common/utils/T/genids.o
|
||||
build/
|
||||
|
||||
90
.github/workflows/jenkins-dispatch.yml
vendored
90
.github/workflows/jenkins-dispatch.yml
vendored
@@ -17,12 +17,72 @@ permissions:
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
verify-signed-commits:
|
||||
runs-on: ubuntu-24.04
|
||||
|
||||
if: github.event_name == 'pull_request_target'
|
||||
|
||||
steps:
|
||||
- name: Check all commits are signed
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
UNSIGNED=$(gh api repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }}/commits \
|
||||
--paginate --jq '[.[] | select(.commit.verification.verified == false) | .sha[:7]] | join(", ")')
|
||||
|
||||
if [ -n "$UNSIGNED" ]; then
|
||||
echo -e "$UNSIGNED commits are missing signature"
|
||||
gh pr comment ${{ github.event.pull_request.number }} --repo ${{ github.repository }} --body "$(cat <<EOF
|
||||
**Validation:**
|
||||
The following commit(s) are missing signature:
|
||||
|
||||
$UNSIGNED
|
||||
|
||||
Please use 'git commit -S' to sign your commits.
|
||||
For detailed instructions, refer to the [CONTRIBUTING.md](https://github.com/duranta-project/openairinterface5g/blob/develop/CONTRIBUTING.md) file at the root of this repository or [GitHub Docs](https://docs.github.com/en/authentication/managing-commit-signature-verification/about-commit-signature-verification)
|
||||
EOF
|
||||
)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
check-labels:
|
||||
needs: verify-signed-commits
|
||||
runs-on: ubuntu-24.04
|
||||
|
||||
if: github.event_name == 'pull_request_target'
|
||||
|
||||
steps:
|
||||
- name: Check for mandatory CI label
|
||||
run: |
|
||||
PR_LABELS=$(echo '${{ toJson(github.event.pull_request.labels) }}' | jq -r '.[].name')
|
||||
|
||||
for label in \
|
||||
"${{ vars.BUILD_ONLY_LABEL }}" \
|
||||
"${{ vars.DOC_LABEL }}" \
|
||||
"${{ vars.NR_LABEL }}" \
|
||||
"${{ vars.NRUE_LABEL }}" \
|
||||
"${{ vars.LTE_LABEL }}" \
|
||||
"${{ vars.CI_LABEL }}" \
|
||||
"${{ vars.RETRIGGER_CI_LABEL }}"; do
|
||||
if echo "$PR_LABELS" | grep -qxF "$label"; then
|
||||
exit 0
|
||||
fi
|
||||
done
|
||||
|
||||
exit 1
|
||||
|
||||
detect-changes:
|
||||
needs: check-labels
|
||||
runs-on: ubuntu-24.04
|
||||
|
||||
if: |
|
||||
github.event.action != 'labeled' ||
|
||||
github.event.label.name == vars.RETRIGGER_CI_LABEL
|
||||
always() && (
|
||||
github.event_name == 'push' ||
|
||||
needs.check-labels.result == 'success'
|
||||
) && (
|
||||
github.event.action != 'labeled' ||
|
||||
github.event.label.name == vars.RETRIGGER_CI_LABEL
|
||||
)
|
||||
|
||||
outputs:
|
||||
protected_files_changed: ${{ steps.filter.outputs.protected }}
|
||||
@@ -49,8 +109,9 @@ jobs:
|
||||
require-maintainer-approval:
|
||||
needs: detect-changes
|
||||
|
||||
if: needs.detect-changes.outputs.protected_files_changed == 'true'
|
||||
|
||||
if: |
|
||||
always() &&
|
||||
needs.detect-changes.outputs.protected_files_changed == 'true'
|
||||
runs-on: ubuntu-24.04
|
||||
|
||||
environment:
|
||||
@@ -61,6 +122,7 @@ jobs:
|
||||
|
||||
trigger-jenkins:
|
||||
needs:
|
||||
- check-labels
|
||||
- detect-changes
|
||||
- require-maintainer-approval
|
||||
|
||||
@@ -105,8 +167,24 @@ jobs:
|
||||
-H "X-Github-Hook-Installation-Target-Type: repository" \
|
||||
--data @/tmp/filtered_payload.json
|
||||
|
||||
cleanup:
|
||||
needs:
|
||||
- verify-signed-commits
|
||||
- check-labels
|
||||
- detect-changes
|
||||
- require-maintainer-approval
|
||||
- trigger-jenkins
|
||||
|
||||
if: always() && github.event_name == 'pull_request_target'
|
||||
|
||||
runs-on: ubuntu-24.04
|
||||
|
||||
steps:
|
||||
- name: Remove retrigger-ci label
|
||||
if: always() && github.event.action == 'labeled' && github.event.label.name == vars.RETRIGGER_CI_LABEL
|
||||
run: gh pr edit ${{ github.event.pull_request.number }} --remove-label "${{ vars.RETRIGGER_CI_LABEL }}"
|
||||
run: |
|
||||
PR_LABELS=$(echo '${{ toJson(github.event.pull_request.labels) }}' | jq -r '.[].name')
|
||||
if echo "$PR_LABELS" | grep -qxF "${{ vars.RETRIGGER_CI_LABEL }}"; then
|
||||
gh pr edit ${{ github.event.pull_request.number }} --remove-label "${{ vars.RETRIGGER_CI_LABEL }}" --repo ${{ github.repository }}
|
||||
fi
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
@@ -383,6 +383,12 @@ endif()
|
||||
add_boolean_option(ENABLE_IMSCOPE OFF "Enable phy scope based on imgui" OFF)
|
||||
add_boolean_option(ENABLE_IMSCOPE_RECORD OFF "Enable recording IQ data for imscope" OFF)
|
||||
|
||||
#########################
|
||||
##### E3 AGENT
|
||||
#########################
|
||||
set(E3_AGENT "OFF" CACHE STRING "O-RAN nGRG E3 Agent for dApps")
|
||||
set_property(CACHE E3_AGENT PROPERTY STRINGS "ON" "OFF")
|
||||
|
||||
##################################################
|
||||
# ASN.1 grammar C code generation & dependencies #
|
||||
##################################################
|
||||
@@ -855,7 +861,6 @@ set(NR_PHY_SRC_RU
|
||||
${OPENAIR1_DIR}/PHY/MODULATION/nr_beamforming.c
|
||||
${OPENAIR1_DIR}/PHY/MODULATION/slot_fep_nr.c
|
||||
${OPENAIR1_DIR}/PHY/INIT/nr_init_ru.c
|
||||
${OPENAIR1_DIR}/PHY/if4_tools.c
|
||||
)
|
||||
|
||||
set(PHY_SRC_UE
|
||||
@@ -1769,23 +1774,25 @@ target_link_libraries(lte-uesoftmodem PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs
|
||||
# force the generation of ASN.1 so that we don't need to wait during the build
|
||||
target_link_libraries(lte-uesoftmodem PRIVATE
|
||||
asn1_lte_rrc asn1_s1ap asn1_m2ap asn1_m3ap asn1_x2ap)
|
||||
# nr RRU
|
||||
add_executable(nr-oru
|
||||
${OPENAIR_DIR}/executables/nr-ru.c
|
||||
${OPENAIR_DIR}/openair1/PHY/INIT/nr_parms.c
|
||||
${OPENAIR_DIR}/openair1/SCHED_NR/phy_frame_config_nr.c
|
||||
${OPENAIR_DIR}/openair1/SCHED_NR/nr_prach_procedures.c
|
||||
${OPENAIR_DIR}/openair1/SCHED_NR/nr_ru_procedures.c
|
||||
${OPENAIR_DIR}/openair1/SCHED/phy_procedures_lte_common.c
|
||||
${OPENAIR_DIR}/executables/main_nr_ru.c
|
||||
)
|
||||
target_link_libraries(nr-oru PRIVATE
|
||||
UTIL NR_PHY_RU PHY_NR shlib_loader dl
|
||||
radio_common softmodem_common nfapi_pnf_lib)
|
||||
target_link_libraries(nr-oru PRIVATE pthread m CONFIG_LIB rt ${T_LIB} utils
|
||||
barrier actor nfapi_user_lib)
|
||||
target_link_libraries(nr-oru PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs nr_phy_common time_management)
|
||||
|
||||
if (OAI_RU_FRONTHAUL)
|
||||
add_executable(nr-oru
|
||||
${OPENAIR_DIR}/executables/nr-ru.c
|
||||
${OPENAIR_DIR}/openair1/PHY/INIT/nr_parms.c
|
||||
${OPENAIR_DIR}/openair1/SCHED_NR/phy_frame_config_nr.c
|
||||
${OPENAIR_DIR}/openair1/SCHED_NR/nr_prach_procedures.c
|
||||
${OPENAIR_DIR}/openair1/SCHED_NR/nr_ru_procedures.c
|
||||
${OPENAIR_DIR}/openair1/SCHED/phy_procedures_lte_common.c
|
||||
${OPENAIR_DIR}/executables/main_nr_ru.c
|
||||
${OPENAIR_DIR}/executables/nr-oru.c
|
||||
)
|
||||
target_link_libraries(nr-oru PRIVATE
|
||||
UTIL NR_PHY_RU PHY_NR shlib_loader dl oru_fh MAC_NR_COMMON
|
||||
radio_common softmodem_common nfapi_pnf_lib)
|
||||
target_link_libraries(nr-oru PRIVATE pthread m CONFIG_LIB rt ${T_LIB} utils
|
||||
barrier actor nfapi_user_lib)
|
||||
target_link_libraries(nr-oru PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs nr_phy_common time_management)
|
||||
endif()
|
||||
# nr-softmodem
|
||||
###################################################
|
||||
|
||||
@@ -1830,6 +1837,11 @@ if(E2_AGENT)
|
||||
target_compile_definitions(nr-softmodem PRIVATE ${E2AP_VERSION} ${KPM_VERSION} E2_AGENT)
|
||||
endif()
|
||||
|
||||
if (E3_AGENT)
|
||||
target_link_libraries(nr-softmodem PRIVATE e3ap)
|
||||
target_compile_definitions(nr-softmodem PRIVATE E3_AGENT)
|
||||
endif()
|
||||
|
||||
|
||||
# force the generation of ASN.1 so that we don't need to wait during the build
|
||||
target_link_libraries(nr-softmodem PRIVATE
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<!-- SPDX-License-Identifier: CC-BY-4.0 -->
|
||||
|
||||
# Contributing to OpenAirInterface
|
||||
# Contributing to Duranta
|
||||
|
||||
We want to make contributing to this project as easy and transparent as possible.
|
||||
|
||||
@@ -18,41 +18,30 @@ We want to make contributing to this project as easy and transparent as possible
|
||||
|
||||
## Commit Guidelines
|
||||
|
||||
Every pull request must pass two CI checks before it can be merged:
|
||||
|
||||
1. **[Developer Certificate of Origin (DCO)](https://en.wikipedia.org/wiki/Developer_Certificate_of_Origin)**:
|
||||
Each commit must include a `Signed-off-by:` trailer in the commit message.
|
||||
Use `git commit -s` (or `--signoff`).
|
||||
|
||||
2. **[Verified commits](https://docs.github.com/en/authentication/managing-commit-signature-verification/about-commit-signature-verification)**:
|
||||
Each commit must be cryptographically signed using SSH or GPG keys to confirm
|
||||
its origin.
|
||||
|
||||
### Signing Commits
|
||||
|
||||
To sign commits:
|
||||
|
||||
You can also get the verified label on your commits via using [SSH keys or GPG
|
||||
keys](https://docs.github.com/en/authentication/managing-commit-signature-verification/signing-commits)
|
||||
|
||||
```
|
||||
# Edit .git/config in the git repository you are working on
|
||||
# Add the user section
|
||||
[user]
|
||||
name = YOUR NAME
|
||||
email = YOUR EMAIL ADDRESS
|
||||
|
||||
# If you use a signing key, use the below configuration instead
|
||||
[user]
|
||||
name = YOUR NAME
|
||||
email = YOUR EMAIL ADDRESS
|
||||
signingkey = LOCATION OF SSH KEYS or GPG KEY
|
||||
|
||||
[gpg]
|
||||
format = ssh
|
||||
|
||||
[commit]
|
||||
gpgsign = true
|
||||
```
|
||||
|
||||
> **NOTE:** If your commits are not signed the CI framework will not accept the PR.
|
||||
GitHub supports commit signing using either SSH keys or GPG keys. For the
|
||||
step-by-step setup (key generation, Git configuration, registering the key on
|
||||
GitHub, and verifying signatures locally), see the
|
||||
[commit signing section of the Git guide](doc/git-guide.md#setting-up-commit-signing).
|
||||
|
||||
> **NOTE:** If your commits are not signed, the CI framework will not accept the PR.
|
||||
For more information regarding contribution guidelines
|
||||
please check [this document](doc/code-style-contrib.md)
|
||||
|
||||
## License
|
||||
|
||||
By contributing to OpenAirInterface, you agree that your contributions will be
|
||||
By contributing to Duranta, you agree that your contributions will be
|
||||
licensed under
|
||||
|
||||
1. [CSSL v1.0 license](LICENSES/preferred/CSSL-v1.0.txt): for RAN and UE
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<!-- SPDX-License-Identifier: CC-BY-4.0 -->
|
||||
|
||||
<h1 align="center">
|
||||
<a href="https://lfnetworking.org/projects/duranta/"><img src="https://raw.githubusercontent.com/duranta-project/governance/main/logos/Duranta-OAI-Combined.png" alt="Duranta OAI" width="550"></a>
|
||||
<a href="https://lfnetworking.org/projects/duranta/"><img src="https://raw.githubusercontent.com/duranta-project/governance/main/logos/Duranta-Logo-Color.png" alt="Duranta OAI" width="550"></a>
|
||||
</h1>
|
||||
|
||||
<p align="center">
|
||||
|
||||
@@ -14,7 +14,7 @@ description: A Helm chart for physical simulators network function
|
||||
# pipeline. Library charts do not define any templates and therefore cannot be deployed.
|
||||
type: application
|
||||
|
||||
icon: http://www.openairinterface.org/wp-content/uploads/2015/06/cropped-oai_final_logo.png
|
||||
icon: https://raw.githubusercontent.com/duranta-project/governance/main/logos/Duranta-Logo-Color.png
|
||||
|
||||
# This is the chart version. This version number should be incremented each time you make changes
|
||||
# to the chart and its templates, including the app version.
|
||||
|
||||
@@ -14,7 +14,7 @@ description: A Helm subchart for 4G physims network function
|
||||
# pipeline. Library charts do not define any templates and therefore cannot be deployed.
|
||||
type: application
|
||||
|
||||
icon: http://www.openairinterface.org/wp-content/uploads/2015/06/cropped-oai_final_logo.png
|
||||
icon: https://raw.githubusercontent.com/duranta-project/governance/main/logos/Duranta-Logo-Color.png
|
||||
|
||||
# This is the chart version. This version number should be incremented each time you make changes
|
||||
# to the chart and its templates, including the app version.
|
||||
|
||||
@@ -14,7 +14,7 @@ description: A Helm chart for physical simulators network function
|
||||
# pipeline. Library charts do not define any templates and therefore cannot be deployed.
|
||||
type: application
|
||||
|
||||
icon: http://www.openairinterface.org/wp-content/uploads/2015/06/cropped-oai_final_logo.png
|
||||
icon: https://raw.githubusercontent.com/duranta-project/governance/main/logos/Duranta-Logo-Color.png
|
||||
|
||||
# This is the chart version. This version number should be incremented each time you make changes
|
||||
# to the chart and its templates, including the app version.
|
||||
|
||||
@@ -14,7 +14,7 @@ description: A Helm subchart for 5G physims network function
|
||||
# pipeline. Library charts do not define any templates and therefore cannot be deployed.
|
||||
type: application
|
||||
|
||||
icon: http://www.openairinterface.org/wp-content/uploads/2015/06/cropped-oai_final_logo.png
|
||||
icon: https://raw.githubusercontent.com/duranta-project/governance/main/logos/Duranta-Logo-Color.png
|
||||
|
||||
# This is the chart version. This version number should be incremented each time you make changes
|
||||
# to the chart and its templates, including the app version.
|
||||
|
||||
@@ -48,7 +48,6 @@ def nsaTDDB200Status = ''
|
||||
def saTDDB200Status = ''
|
||||
def phytestLDPCoffloadStatus = ''
|
||||
def saAW2SStatus = ''
|
||||
def cn5gCOTSUESanityCheck = ''
|
||||
def saAERIALStatus = ''
|
||||
def saMultiAntennaStatus = ''
|
||||
def saFHI72Status = ''
|
||||
@@ -712,29 +711,6 @@ pipeline {
|
||||
}
|
||||
}
|
||||
}
|
||||
stage ("Sanity-Check OAI-CN5G") {
|
||||
when { expression {do5Gtest} }
|
||||
steps {
|
||||
script {
|
||||
triggerCN5GDownstreamJob ('OAI-CN5G-COTS-UE-Test')
|
||||
}
|
||||
}
|
||||
post {
|
||||
always {
|
||||
script {
|
||||
// Using a unique variable name for each test stage to avoid overwriting on a global variable
|
||||
// due to parallel-time concurrency
|
||||
cn5gCOTSUESanityCheck = finalizeDownstreamJob('OAI-CN5G-COTS-UE-Test')
|
||||
}
|
||||
}
|
||||
failure {
|
||||
script {
|
||||
currentBuild.result = 'FAILURE'
|
||||
failingStages += cn5gCOTSUESanityCheck
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
stage ("SA-AERIAL-CN5G") {
|
||||
when { expression {do5Gtest} }
|
||||
steps {
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#define N_ANTENNA_UL 1
|
||||
#define TDD 1
|
||||
|
||||
log_options: "all.level=debug,all.max_size=0,nas.level=debug,nas.max_size=1,rrc.level=debug,rrc.max_size=1",
|
||||
log_options: "all.level=info,all.max_size=0,nas.level=debug,nas.max_size=1,rrc.level=debug,rrc.max_size=1",
|
||||
log_filename: "/tmp/ue.log",
|
||||
|
||||
/* Enable remote API and Web interface */
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#define N_ANTENNA_UL 1
|
||||
#define TDD 1
|
||||
|
||||
log_options: "all.level=debug,all.max_size=0,nas.level=debug,nas.max_size=1,rrc.level=debug,rrc.max_size=1",
|
||||
log_options: "all.level=info,all.max_size=0,nas.level=debug,nas.max_size=1,rrc.level=debug,rrc.max_size=1",
|
||||
log_filename: "/tmp/ue.log",
|
||||
|
||||
/* Enable remote API and Web interface */
|
||||
|
||||
@@ -217,11 +217,19 @@ amarisoft_00105_40MHz:
|
||||
InitScript: /root/lteue-linux-2025-03-15/lteue /root/oaicicd/ran_sa_fhi72_mplane_40MHz/multi-00105-40.cfg &
|
||||
TermScript: /root/lteue-linux-2025-03-15/ws.js -t 10 127.0.0.1:9002 '{"message":"quit"}' || killall -KILL lteue-avx2
|
||||
NetworkScript: ip netns exec ue1 ip a show dev pdn0
|
||||
Tracing:
|
||||
Start: '' # nothing to be done
|
||||
Stop: '' # nothing to be done
|
||||
Collect: 'cp /tmp/ue.log %%log_dir%%'
|
||||
amarisoft_00105_100MHz:
|
||||
Host: amariue
|
||||
InitScript: /root/lteue-linux-2025-03-15/lteue /root/oaicicd/ran_sa_fhi72_mplane_100MHz/multi-00105-100.cfg &
|
||||
TermScript: /root/lteue-linux-2025-03-15/ws.js -t 10 127.0.0.1:9002 '{"message":"quit"}' || killall -KILL lteue-avx2
|
||||
NetworkScript: ip netns exec ue1 ip a show dev pdn0
|
||||
Tracing:
|
||||
Start: '' # nothing to be done
|
||||
Stop: '' # nothing to be done
|
||||
Collect: 'cp /tmp/ue.log %%log_dir%%'
|
||||
amarisoft_ue_1:
|
||||
Host: amariue
|
||||
AttachScript: /root/lteue-linux-2025-03-15/ws.js 127.0.0.1:9002 '{"message":"power_on","ue_id":1}'
|
||||
|
||||
@@ -75,12 +75,12 @@ class HTMLManagement():
|
||||
self.htmlFile.write(' <tr style="border-collapse: collapse; border: none;">\n')
|
||||
self.htmlFile.write(' <td style="border-collapse: collapse; border: none;">\n')
|
||||
self.htmlFile.write(' <a href="http://www.openairinterface.org/">\n')
|
||||
self.htmlFile.write(' <img src="http://www.openairinterface.org/wp-content/uploads/2016/03/cropped-oai_final_logo2.png" alt="" border="none" height=50 width=150>\n')
|
||||
self.htmlFile.write(' <img src="https://raw.githubusercontent.com/duranta-project/governance/main/logos/Duranta-Logo-Color.png" alt="" border="none" style="margin-right: 2rem;" width=150>\n')
|
||||
self.htmlFile.write(' </img>\n')
|
||||
self.htmlFile.write(' </a>\n')
|
||||
self.htmlFile.write(' </td>\n')
|
||||
self.htmlFile.write(' <td style="border-collapse: collapse; border: none; vertical-align: center;">\n')
|
||||
self.htmlFile.write(' <b><font size = "6">Job Summary -- Job: TEMPLATE_JOB_NAME -- Build-ID: TEMPLATE_BUILD_ID</font></b>\n')
|
||||
self.htmlFile.write(' <b><font size = "6">TEMPLATE_JOB_NAME -- Build-ID: TEMPLATE_BUILD_ID</font></b>\n')
|
||||
self.htmlFile.write(' </td>\n')
|
||||
self.htmlFile.write(' </tr>\n')
|
||||
self.htmlFile.write(' </table>\n')
|
||||
|
||||
@@ -184,7 +184,8 @@ L1s = (
|
||||
{
|
||||
num_cc = 1;
|
||||
tr_n_preference = "local_mac";
|
||||
}
|
||||
prach_dtx_threshold = 200;
|
||||
}
|
||||
);
|
||||
|
||||
RUs = (
|
||||
|
||||
@@ -184,7 +184,8 @@ L1s = (
|
||||
{
|
||||
num_cc = 1;
|
||||
tr_n_preference = "local_mac";
|
||||
}
|
||||
prach_dtx_threshold = 200;
|
||||
}
|
||||
);
|
||||
|
||||
RUs = (
|
||||
|
||||
@@ -216,6 +216,7 @@ L1s =
|
||||
{
|
||||
num_cc = 1;
|
||||
tr_n_preference = "local_mac";
|
||||
prach_dtx_threshold = 200;
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
@@ -216,6 +216,7 @@ L1s =
|
||||
{
|
||||
num_cc = 1;
|
||||
tr_n_preference = "local_mac";
|
||||
prach_dtx_threshold = 200;
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
@@ -216,6 +216,7 @@ L1s =
|
||||
{
|
||||
num_cc = 1;
|
||||
tr_n_preference = "local_mac";
|
||||
prach_dtx_threshold = 200;
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
@@ -216,6 +216,7 @@ L1s =
|
||||
{
|
||||
num_cc = 1;
|
||||
tr_n_preference = "local_mac";
|
||||
prach_dtx_threshold = 200;
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
@@ -10,8 +10,7 @@
|
||||
FROM ran-base:develop AS ran-tests
|
||||
|
||||
RUN apt-get update && \
|
||||
DEBIAN_FRONTEND=noninteractive apt-get upgrade --yes && \
|
||||
DEBIAN_FRONTEND=noninteractive apt-get install --yes \
|
||||
DEBIAN_FRONTEND=noninteractive apt-get install --yes --no-install-recommends \
|
||||
libgtest-dev \
|
||||
libyaml-cpp-dev \
|
||||
libzmq3-dev \
|
||||
@@ -26,7 +25,9 @@ WORKDIR /oai-ran
|
||||
COPY . .
|
||||
|
||||
WORKDIR /oai-ran/build
|
||||
RUN cmake .. -GNinja \
|
||||
RUN --mount=type=cache,target=/root/.cache/ccache/ \
|
||||
--mount=type=cache,target=/root/.cache/cpm/ \
|
||||
cmake .. -GNinja \
|
||||
-DENABLE_TESTS=ON -DOAI_ZMQ=ON -DCMAKE_BUILD_TYPE=Debug \
|
||||
-DSANITIZE_ADDRESS=True -DOAI_VRTSIM_TAPS_CLIENT=ON -DOAI_RU_FRONTHAUL=ON \
|
||||
&& \
|
||||
|
||||
@@ -1,20 +1,6 @@
|
||||
<!-- SPDX-License-Identifier: CC-BY-4.0 -->
|
||||
|
||||
<table style="border-collapse: collapse; border: none;">
|
||||
<tr style="border-collapse: collapse; border: none;">
|
||||
<td style="border-collapse: collapse; border: none;">
|
||||
<a href="http://www.openairinterface.org/">
|
||||
<img src="../../../doc/images/oai_final_logo.png" alt="" border=3 height=50 width=150>
|
||||
</img>
|
||||
</a>
|
||||
</td>
|
||||
<td style="border-collapse: collapse; border: none; vertical-align: center;">
|
||||
<b><font size = "5">OAI Full Stack 4G-LTE RF simulation with containers</font></b>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
This page is only valid for an `Ubuntu 22` host.
|
||||
OAI Full Stack 4G-LTE RF simulation with containers
|
||||
|
||||
**Table of Contents**
|
||||
|
||||
|
||||
@@ -1,22 +1,6 @@
|
||||
<!-- SPDX-License-Identifier: CC-BY-4.0 -->
|
||||
|
||||
<table style="border-collapse: collapse; border: none;">
|
||||
<tr style="border-collapse: collapse; border: none;">
|
||||
<td style="border-collapse: collapse; border: none;">
|
||||
<a href="http://www.openairinterface.org/">
|
||||
<img src="../../../doc/images/oai_final_logo.png" alt="" border=3 height=50 width=150>
|
||||
</img>
|
||||
</a>
|
||||
</td>
|
||||
<td style="border-collapse: collapse; border: none; vertical-align: center;">
|
||||
<b><font size = "5">OAI Full Stack 5G-NR RF simulation with containers</font></b>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
This page is only valid for an `Ubuntu 22` host.
|
||||
|
||||
**NOTE: this version (2023-01-27) has been updated for the `v1.5.0` version of the `OAI 5G CN`.**
|
||||
OAI Full Stack 5G-NR RF simulation with containers
|
||||
|
||||
**Table of Contents**
|
||||
|
||||
|
||||
@@ -1,18 +1,6 @@
|
||||
<!-- SPDX-License-Identifier: CC-BY-4.0 -->
|
||||
|
||||
<table style="border-collapse: collapse; border: none;">
|
||||
<tr style="border-collapse: collapse; border: none;">
|
||||
<td style="border-collapse: collapse; border: none;">
|
||||
<a href="http://www.openairinterface.org/">
|
||||
<img src="../../../doc/images/oai_final_logo.png" alt="" border=3 height=50 width=150>
|
||||
</img>
|
||||
</a>
|
||||
</td>
|
||||
<td style="border-collapse: collapse; border: none; vertical-align: center;">
|
||||
<b><font size = "5">OAI O-RAN 7.2 Front-haul Docker Compose</font></b>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
OAI O-RAN 7.2 Front-haul Docker Compose
|
||||
|
||||

|
||||
|
||||
|
||||
@@ -43,6 +43,8 @@ Options:
|
||||
Sets build directory (will be <oai-root>/cmake_targets/<build-dir>/build)
|
||||
--build-e2
|
||||
Enable the the E2 Agent
|
||||
--build-e3
|
||||
Enable the the E3 Agent
|
||||
-I | --install-external-packages
|
||||
Installs required packages such as LibXML, asn1.1 compiler, ...
|
||||
This option will require root password
|
||||
@@ -143,6 +145,10 @@ function main() {
|
||||
CMAKE_CMD="$CMAKE_CMD -DE2_AGENT=ON"
|
||||
shift
|
||||
;;
|
||||
--build-e3 )
|
||||
CMAKE_CMD="$CMAKE_CMD -DE3_AGENT=ON"
|
||||
shift
|
||||
;;
|
||||
-I | --install-external-packages)
|
||||
INSTALL_EXTERNAL=1
|
||||
echo_info "Will install external packages"
|
||||
@@ -201,6 +207,7 @@ function main() {
|
||||
shift;;
|
||||
--nrRU)
|
||||
NRRU=1
|
||||
CMAKE_CMD="$CMAKE_CMD -DOAI_RU_FRONTHAUL=ON"
|
||||
TARGET_LIST="$TARGET_LIST nr-oru"
|
||||
echo_info "Will compile NR O-RU"
|
||||
shift;;
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
# Finds the xran library. Note that the library number is as follows:
|
||||
# - oran_e_maintenance_release_v1.5 -> 5.1.6
|
||||
# - oran_f_release_v1.3 -> 6.1.4
|
||||
# - oran_k_release_v1.1 -> 11.1.1
|
||||
# - oran_k_release_v1.3 -> 11.1.3
|
||||
#
|
||||
# Required options
|
||||
# ^^^^^^^^^^^^^^^^
|
||||
|
||||
@@ -494,8 +494,8 @@ install_simde_from_source(){
|
||||
if [[ -v SIMDE_VERSION ]]; then
|
||||
git checkout -f $SIMDE_VERSION
|
||||
else
|
||||
# At time of writing, last working commit for OAI: c7f26b7
|
||||
git checkout c7f26b73ba8e874b95c2cec2b497826ad2188f68
|
||||
# At time of writing, last working commit for OAI: 1c68d9a
|
||||
git checkout 1c68d9ad60bf63f3fb527c4ee3b2319d828ffcc6
|
||||
fi
|
||||
# Showing which version is used
|
||||
git log -n1
|
||||
|
||||
@@ -39,8 +39,9 @@ typedef enum { NON_DYNAMIC, DYNAMIC } fiveQI_t;
|
||||
/* 5QI (5G QoS Identifier) - 3GPP TS 23.501 §5.7.2.1
|
||||
* Range: 0..255
|
||||
* - Standardized 5QI values: have one-to-one mapping to standardized 5G QoS characteristics (Table 5.7.4-1)
|
||||
* - Pre-configured 5QI values: pre-configured in the AN
|
||||
* - Dynamically assigned 5QI values: require signaling of QoS characteristics as part of QoS profile */
|
||||
* - Pre-configured 5QI values: pre-configured in the AN (not in Table 5.7.4-1)
|
||||
* - Dynamically assigned 5QI values: require signaling of QoS characteristics as part of QoS profile
|
||||
* OAI implements standardized non-dynamic 5QI only. */
|
||||
#define MIN_FIVEQI 0
|
||||
#define MAX_STANDARDIZED_FIVEQI 90
|
||||
#define MAX_FIVEQI 255
|
||||
|
||||
@@ -45,6 +45,8 @@
|
||||
|
||||
#define NR_MAX_NB_PDU_SESSIONS (256)
|
||||
|
||||
#define NR_MAX_NB_ALLOWED_SNSSAI (8) /* Maximum number of allowed S-NSSAI in TS 38.413 */
|
||||
|
||||
#define MAX_DRBS_PER_UE (32) /* Maximum number of Data Radio Bearers per UE
|
||||
* defined for NGAP in TS 38.413 - maxnoofDRBs */
|
||||
#define MAX_PDUS_PER_UE (8) /* Maximum number of PDU Sessions per UE */
|
||||
@@ -55,6 +57,8 @@
|
||||
/** Maximum number of Paging Occasions per Paging Frame (TS 38.331 PCCH-Config) */
|
||||
#define NR_PCCH_MAX_PO 4
|
||||
|
||||
#define NR_PHYS_CELL_ID_MAX 1007 /* Maximum Physical Cell ID (0..1007) */
|
||||
|
||||
#define NB_RB_MBMS_MAX (29 * 16) /* 29 = LTE_maxSessionPerPMCH + 16 = LTE_maxServiceCount from LTE_asn_constant.h */
|
||||
|
||||
#define NB_RAB_MAX 11 /* from LTE_maxDRB in LTE_asn_constant.h */
|
||||
|
||||
@@ -11,7 +11,7 @@ LOG_D(<component>,<format>,<argument>,...)
|
||||
LOG_T(<component>,<format>,<argument>,...)
|
||||
)
|
||||
```
|
||||
these macros are used in place of the printf C function. The additionnal ***component*** parameter identifies the functionnal module which generates the message. At run time, the message will only be printed if the configured log level for the component is greater or equal than the macro level used in the code.
|
||||
these macros are used in place of the printf C function. The additional ***component*** parameter identifies the functional module which generates the message. At run time, the message will only be printed if the configured log level for the component is greater or equal than the macro level used in the code.
|
||||
|
||||
| macro | level letter | level value | level name |
|
||||
|:---------|:---------------|:---------------|----------------:|
|
||||
|
||||
@@ -155,6 +155,7 @@ static const char *const flag_name[] = {FOREACH_FLAG(FLAG_TEXT) ""};
|
||||
COMP_DEF(NFAPI_PNF, log) \
|
||||
COMP_DEF(ITTI, log) \
|
||||
COMP_DEF(UTIL, log) \
|
||||
COMP_DEF(E3AP, log) \
|
||||
COMP_DEF(MAX_LOG_PREDEF_COMPONENTS, )
|
||||
|
||||
#define COMP_ENUM(comp, file_extension) comp,
|
||||
|
||||
@@ -434,6 +434,27 @@ ID = LEGACY_MAC_TRACE
|
||||
GROUP = ALL:LEGACY_MAC:LEGACY_GROUP_TRACE:LEGACY
|
||||
FORMAT = string,log
|
||||
|
||||
ID = LEGACY_E3AP_INFO
|
||||
DESC = E3AP legacy logs - info level
|
||||
GROUP = ALL:LEGACY_E3AP:LEGACY_GROUP_INFO:LEGACY
|
||||
FORMAT = string,log
|
||||
ID = LEGACY_E3AP_ERROR
|
||||
DESC = E3AP legacy logs - error level
|
||||
GROUP = ALL:LEGACY_E3AP:LEGACY_GROUP_ERROR:LEGACY
|
||||
FORMAT = string,log
|
||||
ID = LEGACY_E3AP_WARNING
|
||||
DESC = E3AP legacy logs - warning level
|
||||
GROUP = ALL:LEGACY_E3AP:LEGACY_GROUP_WARNING:LEGACY
|
||||
FORMAT = string,log
|
||||
ID = LEGACY_E3AP_DEBUG
|
||||
DESC = E3AP legacy logs - debug level
|
||||
GROUP = ALL:LEGACY_E3AP:LEGACY_GROUP_DEBUG:LEGACY
|
||||
FORMAT = string,log
|
||||
ID = LEGACY_E3AP_TRACE
|
||||
DESC = E3AP legacy logs - trace level
|
||||
GROUP = ALL:LEGACY_E3AP:LEGACY_GROUP_TRACE:LEGACY
|
||||
FORMAT = string,log
|
||||
|
||||
ID = LEGACY_NR_MAC_INFO
|
||||
DESC = NR_MAC legacy logs - info level
|
||||
GROUP = ALL:LEGACY_NR_MAC:LEGACY_GROUP_INFO:LEGACY
|
||||
|
||||
@@ -31,7 +31,6 @@
|
||||
#include <arpa/inet.h>
|
||||
#include <common/utils/assertions.h>
|
||||
#include <common/utils/LOG/log.h>
|
||||
#include "common_lib.h"
|
||||
|
||||
#ifdef T
|
||||
#undef T
|
||||
|
||||
25
doc/5Gnas.md
25
doc/5Gnas.md
@@ -17,13 +17,19 @@ Key 5GS NAS messages:
|
||||
|
||||
## OAI Implementation Status
|
||||
|
||||
The following table lists implemented NAS messages and whether there is an encoder or decoder function, and if a corresponding unit test exists.
|
||||
The following table lists NAS messages with dedicated `encode_*` / `decode_*` codecs under
|
||||
`openair3/NAS/NR_UE/5GS/` (`5GMM/MSG`, `5GSM/MSG`). Unit test entries refer to
|
||||
[`nas_lib_test.c`](../openair3/NAS/NR_UE/5GS/tests/nas_lib_test.c), most are encode/decode round-trips.
|
||||
|
||||
| Type | Message | Encoding | Decoding | Unit test |
|
||||
|-------|-------------------------------------------|----------|----------|------------|
|
||||
| 5GMM | Service Request | yes | yes | yes |
|
||||
| 5GMM | Service Accept | yes | yes | yes |
|
||||
| 5GMM | Service Reject | yes | yes | yes |
|
||||
| 5GMM | Authentication Failure | yes | yes | yes |
|
||||
| 5GMM | Authentication Reject | yes | yes | yes |
|
||||
| 5GMM | Security Mode Reject | yes | yes | yes |
|
||||
| 5GMM | Identity Request | no | yes | no |
|
||||
| 5GMM | Authentication Response | yes | no | no |
|
||||
| 5GMM | Identity Response | yes | no | no |
|
||||
| 5GMM | Security Mode Complete | yes | no | no |
|
||||
@@ -38,6 +44,23 @@ The following table lists implemented NAS messages and whether there is an encod
|
||||
| 5GSM | PDU Session Establishment Request | yes | no | no |
|
||||
| 5GSM | PDU Session Establishment Accept | no | yes | no |
|
||||
|
||||
### Runtime-handled messages
|
||||
|
||||
These network-originated messages are handled in [`nr_nas_msg.c`](../openair3/NAS/NR_UE/nr_nas_msg.c):
|
||||
|
||||
* Authentication Request
|
||||
* Security Mode Command
|
||||
* Downlink NAS Transport
|
||||
* Deregistration Accept (UE originating)
|
||||
* Registration Reject
|
||||
* PDU Session Establishment Reject
|
||||
|
||||
## Integration testing
|
||||
|
||||
End-to-end attach can be tested with the [NR UE NAS simulator](../tests/nr-ue-nas-simulator/README.md),
|
||||
which runs the OAI UE NAS stack and gNB NGAP against the AMF, forwarding NAS PDUs without PHY/MAC/RLC.
|
||||
Use `nas_lib_test` for isolated codec round-trips.
|
||||
|
||||
### Code Structure
|
||||
|
||||
[openair3/NAS/NR_UE/nr_nas_msg.c](../openair3/NAS/NR_UE/nr_nas_msg.c):
|
||||
|
||||
@@ -51,7 +51,7 @@ PROJECT_BRIEF = "Full experimental OpenSource LTE and NR implementation
|
||||
# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy
|
||||
# the logo to the output directory.
|
||||
|
||||
PROJECT_LOGO = @CMAKE_SOURCE_DIR@/doc/images/oai_logo.png
|
||||
PROJECT_LOGO =
|
||||
|
||||
# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
|
||||
# into which the generated documentation will be written. If a relative path is
|
||||
|
||||
@@ -421,15 +421,14 @@ git apply ~/openairinterface5g/cmake_targets/tools/oran_fhi_integration_patches/
|
||||
```bash
|
||||
git clone https://github.com/openairinterface/o-du-phy.git ~/phy
|
||||
cd ~/phy
|
||||
git checkout 11.1.1 # the tag points to the `main` branch which has all patches applied that are relevant for OAI integration; the tag matches the value of cmake variable `K_VERSION`
|
||||
git checkout 11.1.3 # the tag points to the `main` branch which has all patches applied that are relevant for OAI integration; the tag matches the value of cmake variable `K_VERSION`
|
||||
```
|
||||
or use `xran_DOWNLOAD` option when compiling OAI gNB.
|
||||
|
||||
Compile the fronthaul interface library by calling `make` and the option
|
||||
`XRAN_LIB_SO=1` to have it build a shared object. Note that we provide two
|
||||
environment variables `RTE_SDK` for the path to the source tree of DPDK, and
|
||||
`XRAN_DIR` to set the path to the fronthaul library. For building for a Arm
|
||||
target, set as well the environment variable `TARGET=armv8`.
|
||||
`XRAN_DIR` to set the path to the fronthaul library.
|
||||
|
||||
**Note**: you need at least gcc-11 and g++-11.
|
||||
|
||||
@@ -1259,7 +1258,7 @@ The OAI configuration file [`gnb.sa.band78.106prb.fhi72.1x1-proto-ru.conf`](../t
|
||||
First, compile the RU as outlined in the [building ProtO-RU tutorial](https://github.com/NUS-CIR/ProtO-RU/tree/proto-ru?tab=readme-ov-file#building-proto-ru).
|
||||
Then, ensure that both your DU and ProtO-RU host are PTP synchronized.
|
||||
|
||||
Next, use the RU config, [protoru-OAI-B210-TDD-n78-40MHz-1x1-30kHz.yml](https://github.com/NUS-CIR/ProtO-RU/blob/proto-ru/proto-ru/conf-files/protoru-OAI-B210-TDD-n78-40MHz-1x1-30kHz.yml), which corresponds to the above mentioned DU config file.
|
||||
Next, use the RU config, [protoru-OAI-B210-TDD-n78-40MHz-1x1-30kHz.yml](https://github.com/NUS-CIR/ProtO-RU/blob/proto-ru/proto-ru/conf-files/protoru-OAI-B210-TDD-n78-40MHz-1x1-30kHz.yml), which corresponds to the above mentioned DU config file. Please note that the RU delay profile might need to be adjusted according to the setup. The E2E test with xran K release required `T2a_max_cp_ul: 2985`.
|
||||
In addition, please adapt the DU MAC address and VLAN tag to your needs.
|
||||
|
||||
ProtO-RU was successfully tested with USRP B210.
|
||||
@@ -1557,7 +1556,10 @@ Edit the sample OAI gNB configuration file and check following parameters:
|
||||
|
||||
* `RUs` section
|
||||
* Set an isolated core for RU thread `ru_thread_core`, in our environment we are using CPU 6
|
||||
|
||||
* If testing with a numerology different than 1 (e.g., FDD with numerology 0),
|
||||
set `nr_scs_for_raster` to the used numerology, and adapt `sl_ahead`: it must be
|
||||
strictly less than the number of slots in a frame (e.g., 5 for numerology 0).
|
||||
|
||||
* `fhi_72` (FrontHaul Interface) section: this config follows the structure
|
||||
that is employed by the xRAN library (`xran_fh_init` and `xran_fh_config`
|
||||
structs in the code):
|
||||
|
||||
@@ -133,6 +133,9 @@ The other SDRs (AW2S, LimeSDR, ...) have no READMEs.
|
||||
## Developer tools
|
||||
|
||||
- [code-style-contrib.md](./code-style-contrib.md): overall working practices, code style, and review process
|
||||
- [git-guide.md](./git-guide.md): Git how-tos — commit signing setup, branch
|
||||
management, submodules, recovering from mistakes, reusing conflict
|
||||
resolutions (rerere)
|
||||
- [cross-compile.md](./cross-compile.md): how to cross-compile OAI for ARM
|
||||
- [clang-format.md](./clang-format.md): how to format the code. See also the
|
||||
next entry for an error detection tool.
|
||||
|
||||
@@ -90,9 +90,9 @@ the [MAC configuration](../MAC/mac-usage.md) as well for SIB configuration.
|
||||
`0xffffff` is a reserved value and means "no SD"
|
||||
Note that: SST=1, no SD is "eMBB"; SST=2, no SD is "URLLC"; SST=3, no SD
|
||||
is "mMTC"
|
||||
- `enable_sdap` (default: true): enable the use of the SDAP layer. If
|
||||
deactivated, a transparent SDAP header is prepended to packets, but no
|
||||
further processing is being done.
|
||||
- `enable_sdap` (default: true): set `sdap-HeaderUL` and `sdap-HeaderDL` to
|
||||
present in the RRC `SDAP-Config` IE for SA PDU sessions. If false, both
|
||||
headers are absent (per DRB). SDAP entities are still created, SDAP layer always enabled.
|
||||
- `cu_sibs` (default: `[]`) list of SIBs to give to the DU for transmission.
|
||||
Currently supported:
|
||||
- SIB2: serving-cell reselection parameters (configured in `sib2_config`)
|
||||
|
||||
@@ -118,43 +118,12 @@ e.g., `v3.0`. We target to make releases bi-yearly.
|
||||
|
||||
### How to manage your own branch
|
||||
|
||||
Before starting to work, please make sure to branch off the latest `develop`
|
||||
branch. Make commits as appropriate.
|
||||
```bash
|
||||
$ git fetch origin
|
||||
$ git checkout develop
|
||||
$ git checkout -b my-new-feature # name as appropriate
|
||||
$ git add -p # add changes for change set 1, use `-p` to review what to include
|
||||
$ git commit # in the editor, describe your changes
|
||||
$ git add -p # add changes for change set 2
|
||||
$ git commit # in the editor, describe your changes
|
||||
```
|
||||
|
||||
Again, commit message should take multiple lines; after the initial title, a
|
||||
blank line should follow. Read the `DISCUSSION` section in `man git commit` for
|
||||
more information.
|
||||
|
||||
If your development takes longer, make sure to synchronize regularly with
|
||||
`origin/develop` using `git rebase`:
|
||||
```bash
|
||||
$ git fetch origin
|
||||
$ git rebase -i origin/develop
|
||||
```
|
||||
|
||||
If you do logical changes, you should not have to resolve the same conflicts
|
||||
over and over again. Note that if you jumped over multiple develop tags, you
|
||||
can also rebase in intermediate steps, in case you fear the differences might
|
||||
be too big.
|
||||
```
|
||||
$ git rebase -i 2023.w38
|
||||
$ git rebase -i 2023.w41
|
||||
$ git rebase -i develop
|
||||
```
|
||||
|
||||
Once you rebased, push the changes to the remote
|
||||
```
|
||||
$ git push origin my-new-feature --force-with-lease # force with lease let's you only overwrite what you also have locally in origin/my-new-feature
|
||||
```
|
||||
Branch off the latest `develop` branch before starting to work, keep your
|
||||
branch synchronized with `origin/develop` through regular rebases, and push
|
||||
with `--force-with-lease` after rebasing. The step-by-step commands — including
|
||||
how to rebase over multiple develop tags in intermediate steps and how to avoid
|
||||
resolving the same conflicts repeatedly with `git rerere` — are in the
|
||||
[branch management section of the Git guide](./git-guide.md#managing-your-own-branch).
|
||||
|
||||
### Use of git commit trailers
|
||||
|
||||
|
||||
@@ -61,7 +61,7 @@ Correct (Markdown):
|
||||
**Bold text**
|
||||
*Italic text*
|
||||
|
||||
 instead of <img src="./images/oai_final_logo.png" alt="OAI Logo">
|
||||

|
||||
|
||||
| Feature | Description |
|
||||
|---------------|---------------------------------|
|
||||
@@ -75,7 +75,7 @@ Incorrect (HTML):
|
||||
<b>Bold text</b>
|
||||
<i>Italic text</i>
|
||||
|
||||
<img src="./images/oai_final_logo.png" alt="OAI Logo">
|
||||
<img src="./path/to/image.png" alt="some image">
|
||||
|
||||
<table style="border-collapse: collapse; border: none;">
|
||||
<tr>
|
||||
@@ -114,7 +114,7 @@ Incorrect (HTML):
|
||||
is](https://www.kernel.org/doc/html/latest/process/submitting-patches.html#separate-your-changes).
|
||||
- See [OAI CN5G configuration files](#22-oai-cn5g-configuration-files) for
|
||||
details.
|
||||
- 
|
||||
- 
|
||||
```
|
||||
|
||||
## Inline code for technical elements
|
||||
|
||||
390
doc/git-guide.md
Normal file
390
doc/git-guide.md
Normal file
@@ -0,0 +1,390 @@
|
||||
<!-- SPDX-License-Identifier: CC-BY-4.0 -->
|
||||
|
||||
# Git guide
|
||||
|
||||
This guide collects the practical Git knowledge needed to contribute to OAI in
|
||||
one place: how to set up commit signing, how to manage and synchronize a
|
||||
feature branch, how to handle submodules, how to recover from common mistakes,
|
||||
and how to avoid resolving the same merge conflicts over and over. It is a
|
||||
how-to companion to the contribution *requirements*, which are
|
||||
defined in [CONTRIBUTING.md](../CONTRIBUTING.md) (CLA, DCO, verified commits)
|
||||
and [code-style-contrib.md](./code-style-contrib.md) (workflow, commit, and
|
||||
review policy).
|
||||
|
||||
[[_TOC_]]
|
||||
|
||||
## Setting up commit signing
|
||||
|
||||
Every commit in a pull request must pass two independent CI checks, described
|
||||
in [CONTRIBUTING.md](../CONTRIBUTING.md#commit-guidelines):
|
||||
|
||||
1. **[Developer Certificate of Origin (DCO)](https://en.wikipedia.org/wiki/Developer_Certificate_of_Origin)**:
|
||||
the commit message carries a `Signed-off-by:` trailer.
|
||||
2. **[Verified commits](https://docs.github.com/en/authentication/managing-commit-signature-verification/about-commit-signature-verification)**:
|
||||
the commit is cryptographically signed with an SSH or GPG key.
|
||||
|
||||
These are two different mechanisms: the sign-off is a line of text you add with
|
||||
`git commit -s`, the signature is created automatically by Git once signing is
|
||||
configured. You need both.
|
||||
|
||||
### Quick setup (SSH signing)
|
||||
|
||||
```bash
|
||||
# 1. Generate a key pair (skip if you already have one)
|
||||
ssh-keygen -t ed25519 -C "<your email>"
|
||||
|
||||
# 2. Configure Git to sign every commit with it
|
||||
git config --global user.name "<Your Name>"
|
||||
git config --global user.email "<your email>"
|
||||
git config --global gpg.format ssh
|
||||
git config --global user.signingkey ~/.ssh/id_ed25519.pub
|
||||
git config --global commit.gpgsign true
|
||||
```
|
||||
|
||||
> **NOTE:**
|
||||
> `--global` writes to `~/.gitconfig` and applies to every repository on the
|
||||
> machine. When working on a shared server (or with different identities in
|
||||
> different clones), drop `--global` to store the same settings in the current
|
||||
> repository's `.git/config` only.
|
||||
|
||||
Then print the public key with `cat ~/.ssh/id_ed25519.pub` and paste it into
|
||||
your GitHub account under *Settings → SSH and GPG keys → New SSH key*, choosing
|
||||
the key type **Signing Key**.
|
||||
|
||||
> **NOTE:**
|
||||
> Adding an SSH key for repository access does not automatically enable commit
|
||||
> signing. The key must also be added under GitHub's Signing Keys settings.
|
||||
|
||||
For commits to show as *Verified* on GitHub:
|
||||
|
||||
- your `git config user.email` must match an email of your GitHub account,
|
||||
- that email must be [verified in your GitHub account](https://docs.github.com/en/account-and-profile/how-tos/email-preferences/verifying-your-email-address),
|
||||
- and it must be the email address used for the CLA (see
|
||||
[CONTRIBUTING.md](../CONTRIBUTING.md)).
|
||||
|
||||
If you prefer GPG over SSH, set `gpg.format` to `openpgp` and `user.signingkey`
|
||||
to your GPG key ID instead; see the [GitHub documentation on signing
|
||||
commits](https://docs.github.com/en/authentication/managing-commit-signature-verification/signing-commits)
|
||||
for the full walkthrough of both methods.
|
||||
|
||||
### Signing off your commits (DCO)
|
||||
|
||||
The `Signed-off-by:` trailer is added with the `-s`/`--signoff` flag:
|
||||
|
||||
```bash
|
||||
git commit -s # new commit
|
||||
git commit --amend -s --no-edit # add the trailer to the last commit
|
||||
```
|
||||
|
||||
It must read `Signed-off-by: Full Name <email-for-cla>`. See the
|
||||
[commit trailers section](./code-style-contrib.md#use-of-git-commit-trailers)
|
||||
of the contribution guidelines for this and other trailers.
|
||||
|
||||
### Verifying signed commits
|
||||
|
||||
You can verify that commits are properly signed locally using:
|
||||
|
||||
```bash
|
||||
git log --show-signature
|
||||
```
|
||||
|
||||
GitHub should also display a *Verified* badge next to signed commits once the
|
||||
signing key has been correctly configured in your account.
|
||||
|
||||
For SSH commit signing, local Git verification may require an
|
||||
`allowed_signers` file. This is only used for local verification in Git and is
|
||||
not required by GitHub. If you see errors such as:
|
||||
|
||||
```text
|
||||
No principal matched
|
||||
Can't check signature
|
||||
error: gpg.ssh.allowedSignersFile needs to be configured
|
||||
```
|
||||
|
||||
create the file, add your signing identity, and enable it in your Git config:
|
||||
|
||||
```bash
|
||||
mkdir -p ~/.config/git
|
||||
echo "user@example.com ssh-ed25519 AAAACexamplekeystringhere" > ~/.config/git/allowed_signers
|
||||
git config gpg.ssh.allowedSignersFile ~/.config/git/allowed_signers
|
||||
```
|
||||
|
||||
> **NOTE:**
|
||||
> This is only for local Git signature verification and does not affect GitHub,
|
||||
> or remote repository behavior.
|
||||
|
||||
## Managing your own branch
|
||||
|
||||
The general development branch, and the target of every contribution, is
|
||||
`develop`; see [GET_SOURCES.md](./GET_SOURCES.md) for the branch and tag model
|
||||
(weekly `YYYY.wXX` tags, `vX.Y` releases). The rules for what a branch should
|
||||
look like — linear history, small self-contained logical commits, commit
|
||||
messages that explain *why* — are policy and live in
|
||||
[code-style-contrib.md](./code-style-contrib.md#workflow).
|
||||
|
||||
Before starting to work, please make sure to branch off the latest `develop`
|
||||
branch. Make commits as appropriate.
|
||||
|
||||
```bash
|
||||
git fetch origin
|
||||
git checkout develop
|
||||
git checkout -b my-new-feature # name as appropriate
|
||||
git add -p # add changes for change set 1, use `-p` to review what to include
|
||||
git commit -s # in the editor, describe your changes
|
||||
git add -p # add changes for change set 2
|
||||
git commit -s # in the editor, describe your changes
|
||||
```
|
||||
|
||||
Recent Git versions also offer `git switch` as a clearer alternative to
|
||||
`git checkout` for branch operations: `git switch develop` changes branch,
|
||||
`git switch -c my-new-feature` creates one.
|
||||
|
||||
Commit messages should take multiple lines; after the initial title, a blank
|
||||
line should follow. Read the `DISCUSSION` section in `man git commit` for more
|
||||
information. For documentation-only commits, prefix the title with `docs:`
|
||||
(see [doc_best_practices.md](./doc_best_practices.md)).
|
||||
|
||||
Code must be formatted with clang-format; an optional pre-commit hook can
|
||||
check this automatically at every commit — see
|
||||
[clang-format.md](./clang-format.md) for its installation and how to combine
|
||||
it with `git add -p`/`git stash -p`.
|
||||
|
||||
If your development takes longer, make sure to synchronize regularly with
|
||||
`origin/develop` using `git rebase`:
|
||||
|
||||
```bash
|
||||
git fetch origin
|
||||
git rebase -i origin/develop
|
||||
```
|
||||
|
||||
If you do logical changes, you should not have to resolve the same conflicts
|
||||
over and over again. If the same conflicts do keep reappearing, e.g., when
|
||||
maintaining a long-lived fork, consider enabling
|
||||
[`git rerere`](#reusing-conflict-resolutions-with-git-rerere). Note that if
|
||||
you jumped over multiple develop tags, you can also rebase in intermediate
|
||||
steps, in case you fear the differences might be too big.
|
||||
|
||||
```bash
|
||||
git rebase -i 2023.w38
|
||||
git rebase -i 2023.w41
|
||||
git rebase -i develop
|
||||
```
|
||||
|
||||
Once you rebased, push the changes to the remote:
|
||||
|
||||
```bash
|
||||
git push origin my-new-feature --force-with-lease # force with lease lets you only overwrite what you also have locally in origin/my-new-feature
|
||||
```
|
||||
|
||||
### Fixing up earlier commits
|
||||
|
||||
The [workflow policy](./code-style-contrib.md#workflow) asks for a history
|
||||
without "clean up" commits: when review or testing reveals a problem in an
|
||||
earlier commit of your branch, fold the fix into that commit instead of
|
||||
appending a `Fix bug` commit on top. Git automates this with fixup commits and
|
||||
`--autosquash`:
|
||||
|
||||
```bash
|
||||
git add -p # stage the fix
|
||||
git commit --fixup=<commit> # creates a commit titled "fixup! <original title>"
|
||||
git rebase -i --autosquash origin/develop # moves it after <commit> and squashes the two
|
||||
```
|
||||
|
||||
During the `--autosquash` rebase, Git pre-arranges the todo list so each
|
||||
`fixup!` commit is squashed into the commit it references; you normally just
|
||||
accept it. The result is the same clean history as if the fix had been part of
|
||||
the original commit.
|
||||
|
||||
A handy variant is `git commit --fixup=amend:<commit>`, which folds in the fix
|
||||
and also rewrites the commit message: during the `--autosquash` rebase the
|
||||
editor opens pre-filled with the original message, ready to be edited into the
|
||||
new one.
|
||||
|
||||
## Working with submodules
|
||||
|
||||
Parts of the tree are Git submodules. After cloning, and after every branch
|
||||
switch or pull, make sure they match the superproject:
|
||||
|
||||
```bash
|
||||
git submodule update --init --recursive
|
||||
```
|
||||
|
||||
A recurring review problem is the *unintended submodule pointer update*: a
|
||||
submodule whose checked-out commit differs from what the superproject records
|
||||
shows up in `git status` as `modified: <path> (new commits)`, and a broad
|
||||
`git add .`, `git add -A`, or `git commit -a` silently records the new pointer
|
||||
in your commit. To avoid it:
|
||||
|
||||
- review `git status` before committing and stage files explicitly (e.g. with
|
||||
`git add -p`) rather than adding everything;
|
||||
- if a pointer change was staged by accident, unstage it with
|
||||
`git restore --staged <path>` and realign the submodule with
|
||||
`git submodule update --init <path>`.
|
||||
|
||||
Only commit a submodule pointer change when updating that submodule is the
|
||||
purpose of the commit, and say so in the commit message.
|
||||
|
||||
## Recovering from mistakes
|
||||
|
||||
To unstage a file that was added by accident (the changes stay in your working
|
||||
tree), or to throw away local changes to a file:
|
||||
|
||||
```bash
|
||||
git restore --staged <file> # unstage; keeps the modifications
|
||||
git restore <file> # discard unstaged modifications - cannot be undone
|
||||
```
|
||||
|
||||
`git reset` moves the current branch to another commit and differs in what it
|
||||
does to your files:
|
||||
|
||||
```bash
|
||||
git reset --soft HEAD~1 # undo the last commit, keep its changes staged (e.g. to re-split it)
|
||||
git reset --hard <commit> # make branch, index and working tree identical to <commit>
|
||||
```
|
||||
|
||||
> **Warning:** `git reset --hard` discards all uncommitted changes; there is no
|
||||
> way to recover them.
|
||||
|
||||
Committed work is much harder to lose than it seems: `git reflog` records every
|
||||
position of `HEAD` (commits, rebases, resets, checkouts) for a retention period
|
||||
of at least 30 days, even for commits no branch points to anymore. If a rebase
|
||||
or reset went wrong, find the last good state and reset back to it:
|
||||
|
||||
```bash
|
||||
git reflog # e.g.: e75076172 HEAD@{5}: commit: doc: add git rerere guide
|
||||
git reset --hard 'HEAD@{5}' # return the branch to that state
|
||||
```
|
||||
|
||||
## Reusing conflict resolutions with git rerere
|
||||
|
||||
The `develop` branch is updated roughly once a week. Feature branches that live
|
||||
for more than a few days therefore have to be re-synced with `develop`
|
||||
repeatedly, and the same merge conflicts tend to reappear at every sync - often
|
||||
in the same scheduler, PHY, or RRC files that several contributors touch at
|
||||
once. Resolving the identical conflict by hand every week is error-prone and
|
||||
wastes time.
|
||||
|
||||
Git ships a built-in feature for exactly this situation: `rerere`, short for
|
||||
**reuse recorded resolution**. Once enabled, Git remembers how you resolved a
|
||||
given conflict and replays that resolution automatically the next time the same
|
||||
conflict appears.
|
||||
|
||||
This section explains how to enable and use it. It is a local developer
|
||||
convenience: nothing about it changes the repository, the history you push, or
|
||||
the contribution workflow.
|
||||
|
||||
### What it does
|
||||
|
||||
When a conflict occurs, `rerere` records the conflicted hunk (the *preimage*).
|
||||
After you resolve it, `rerere` records your resolution (the *postimage*), keyed
|
||||
by a hash of the preimage. The next time a conflict with the same preimage shows
|
||||
up - in a later rebase, a later merge, or even another branch - Git reapplies
|
||||
your recorded resolution instead of presenting the conflict again.
|
||||
|
||||
The data lives in `.git/rr-cache/` inside your local clone. It is never part of
|
||||
any commit and is never pushed.
|
||||
|
||||
### Enabling it
|
||||
|
||||
Enable it once, globally, so it applies to every repository on your machine:
|
||||
|
||||
```bash
|
||||
git config --global rerere.enabled true
|
||||
git config --global rerere.autoupdate true
|
||||
```
|
||||
|
||||
`rerere.autoupdate` stages a replayed resolution automatically. Without it, the
|
||||
resolution is still written into your working tree, but you have to `git add`
|
||||
the file yourself.
|
||||
|
||||
### Typical flow
|
||||
|
||||
The first time you hit a conflict after enabling `rerere`, resolve it exactly as
|
||||
you always have:
|
||||
|
||||
```bash
|
||||
# during a rebase or a merge that conflicts
|
||||
git status # rerere reports which paths it is recording
|
||||
# edit the conflicted files, remove the markers
|
||||
git add <resolved-files>
|
||||
git rebase --continue # or: git commit, for a merge
|
||||
```
|
||||
|
||||
That resolution is now recorded. The next time the same conflict appears, Git
|
||||
resolves it for you. With `autoupdate` on, the file is already staged and you can
|
||||
go straight to:
|
||||
|
||||
```bash
|
||||
git rebase --continue # or git commit
|
||||
```
|
||||
|
||||
Always review the replayed result before continuing - see *Caveats* below.
|
||||
|
||||
### Inspecting and undoing recorded resolutions
|
||||
|
||||
```bash
|
||||
git rerere status # paths with a recorded preimage in the current operation
|
||||
git rerere diff # the resolution rerere is applying
|
||||
git rerere forget <path> # discard a recorded resolution (e.g. a wrong one)
|
||||
```
|
||||
|
||||
`git rerere forget` is the escape hatch when you recorded a bad resolution: it
|
||||
drops the cached entry for that path so the next conflict is presented fresh.
|
||||
|
||||
### Seeding from existing history
|
||||
|
||||
If your branch already contains **merge commits** whose conflicts you resolved
|
||||
before enabling `rerere`, you can backfill the cache so those resolutions are
|
||||
available immediately. Git ships a helper for this in `contrib/`:
|
||||
|
||||
```bash
|
||||
sh /path/to/git/contrib/rerere-train.sh origin/develop..HEAD
|
||||
```
|
||||
|
||||
It replays the merge commits in the given range, reconstructs each conflict, and
|
||||
records the resolution found in the merge commit.
|
||||
|
||||
> **Note:** this only works for resolutions captured in merge commits. A purely
|
||||
> linear (rebased) history has no merge commits to learn from, so there is
|
||||
> nothing to backfill - `rerere` will simply start recording from your next
|
||||
> conflict onward.
|
||||
|
||||
### Sharing the cache (optional)
|
||||
|
||||
The cache is local. If you work across several machines, or want a team to share
|
||||
resolutions for the same recurring conflicts, copy the directory:
|
||||
|
||||
```bash
|
||||
rsync -a ~/work/oai-A/.git/rr-cache/ ~/work/oai-B/.git/rr-cache/
|
||||
```
|
||||
|
||||
There is no built-in push/pull for the cache; treat it as an ordinary directory
|
||||
to sync.
|
||||
|
||||
### Caveats and good practice
|
||||
|
||||
- `rerere` matches on the **exact** conflicting text. If `develop` changed the
|
||||
lines surrounding your change, the preimage differs and the conflict is
|
||||
presented as new. This is expected - the resolution is still recorded for the
|
||||
next identical occurrence.
|
||||
- A replayed resolution is only as correct as the original. When the code around
|
||||
a conflict has evolved, an old resolution can apply cleanly yet be wrong.
|
||||
**Review every replayed resolution and build/test before continuing.**
|
||||
- `rerere` reduces repeated manual work; it does not change which branch
|
||||
strategy you use. It helps both when rebasing onto `develop` and when merging
|
||||
`develop` into a feature branch. Remember that branches intended for
|
||||
contribution must have a linear history without merge commits (see the
|
||||
[workflow policy](./code-style-contrib.md#workflow)); a fork can of course
|
||||
carry merge commits if that is convenient for its development.
|
||||
|
||||
## See also
|
||||
|
||||
- [CONTRIBUTING.md](../CONTRIBUTING.md) - CLA, DCO, and licensing requirements.
|
||||
- [code-style-contrib.md](./code-style-contrib.md) - workflow, commit, and
|
||||
review policy, including commit trailers.
|
||||
- [GET_SOURCES.md](./GET_SOURCES.md) - branches, tags, and how to obtain the
|
||||
sources.
|
||||
- [clang-format.md](./clang-format.md) - code formatting and its Git
|
||||
integration (pre-commit hook).
|
||||
- The [Git Book](https://git-scm.com/book/en/v2) and the
|
||||
[`git rerere` manual](https://git-scm.com/docs/git-rerere)
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 271 KiB After Width: | Height: | Size: 161 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 361 KiB After Width: | Height: | Size: 209 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 24 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 9.4 KiB |
@@ -9,7 +9,7 @@
|
||||
|
||||
FROM ran-base:latest AS ran-base
|
||||
|
||||
ARG xran_VERSION=11.1.1
|
||||
ARG xran_VERSION=11.1.3
|
||||
ARG E2AP_VERSION=E2AP_V3
|
||||
ARG KPM_VERSION=KPM_V3_00
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
@@ -27,7 +27,6 @@ RUN apt-get update && \
|
||||
|
||||
RUN rm -Rf /oai-ran
|
||||
WORKDIR /oai-ran
|
||||
COPY . .
|
||||
|
||||
## Download and build DPDK
|
||||
RUN wget --no-verbose http://fast.dpdk.org/rel/dpdk-24.11.4.tar.xz && \
|
||||
@@ -42,7 +41,7 @@ RUN git clone https://github.com/openairinterface/o-du-phy.git /opt/phy && \
|
||||
cd /opt/phy && \
|
||||
git checkout $xran_VERSION &&\
|
||||
cd /opt/phy/fhi_lib/lib && \
|
||||
TARGET=armv8 WIRELESS_SDK_TOOLCHAIN=gcc RTE_SDK=/oai-ran/dpdk-stable-24.11.4/ XRAN_DIR=/opt/phy/fhi_lib make XRAN_LIB_SO=1
|
||||
WIRELESS_SDK_TOOLCHAIN=gcc RTE_SDK=/oai-ran/dpdk-stable-24.11.4/ XRAN_DIR=/opt/phy/fhi_lib make XRAN_LIB_SO=1
|
||||
|
||||
## Build Arm RAN Acceleration Library
|
||||
RUN git clone https://git.gitlab.arm.com/networking/ral.git /opt/ral && \
|
||||
@@ -54,6 +53,8 @@ RUN git clone https://git.gitlab.arm.com/networking/ral.git /opt/ral && \
|
||||
ninja && \
|
||||
ninja install
|
||||
|
||||
COPY . .
|
||||
|
||||
FROM ran-base AS ran-build-fhi72
|
||||
## Build and install OAI
|
||||
#run build_oai to build the target image
|
||||
|
||||
@@ -12,9 +12,8 @@ ENV TZ=Europe
|
||||
|
||||
RUN rm -Rf /oai-ran
|
||||
WORKDIR /oai-ran
|
||||
COPY . .
|
||||
|
||||
ARG xran_VERSION=11.1.1
|
||||
ARG xran_VERSION=11.1.3
|
||||
|
||||
## Download and build DPDK
|
||||
RUN wget --no-verbose http://fast.dpdk.org/rel/dpdk-24.11.4.tar.xz && \
|
||||
@@ -31,6 +30,8 @@ RUN git clone https://github.com/openairinterface/o-du-phy.git /opt/phy && \
|
||||
cd /opt/phy/fhi_lib/lib && \
|
||||
WIRELESS_SDK_TOOLCHAIN=gcc RTE_SDK=/oai-ran/dpdk-stable-24.11.4/ XRAN_DIR=/opt/phy/fhi_lib make XRAN_LIB_SO=1
|
||||
|
||||
COPY . .
|
||||
|
||||
FROM ran-base AS ran-build-fhi72
|
||||
ARG E2AP_VERSION=E2AP_V3
|
||||
ARG KPM_VERSION=KPM_V3_00
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
FROM ran-base:latest AS ran-base
|
||||
|
||||
ARG xran_VERSION=11.1.1
|
||||
ARG xran_VERSION=11.1.3
|
||||
ARG DPDK_VERSION=22.11
|
||||
ARG T2_PATCH=AMD-T2-SDFEC_25-03-1.patch
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
@@ -27,7 +27,7 @@ RUN apt-get update && \
|
||||
|
||||
RUN rm -Rf /oai-ran
|
||||
WORKDIR /oai-ran
|
||||
COPY . .
|
||||
|
||||
## Copy T2 patch
|
||||
COPY ./$T2_PATCH /opt/.
|
||||
## Download and build DPDK
|
||||
@@ -46,6 +46,8 @@ RUN git clone https://github.com/openairinterface/o-du-phy.git /opt/phy && \
|
||||
cd /opt/phy/fhi_lib/lib && \
|
||||
WIRELESS_SDK_TOOLCHAIN=gcc RTE_SDK=/oai-ran/dpdk-$DPDK_VERSION/ XRAN_DIR=/opt/phy/fhi_lib make XRAN_LIB_SO=1
|
||||
|
||||
COPY . .
|
||||
|
||||
FROM ran-base AS ran-build-fhi72-t2
|
||||
## Build and install OAI
|
||||
## Run build_oai to build the target image, if T2 patch present, build with T2 support
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
FROM ran-base:latest AS ran-base
|
||||
|
||||
ARG xran_VERSION=11.1.1
|
||||
ARG xran_VERSION=11.1.3
|
||||
ARG E2AP_VERSION=E2AP_V3
|
||||
ARG KPM_VERSION=KPM_V3_00
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
@@ -32,7 +32,6 @@ RUN apt-get update && \
|
||||
|
||||
RUN rm -Rf /oai-ran
|
||||
WORKDIR /oai-ran
|
||||
COPY . .
|
||||
|
||||
RUN git clone https://github.com/CESNET/libyang.git && \
|
||||
cd libyang && \
|
||||
@@ -81,6 +80,8 @@ RUN git clone https://github.com/openairinterface/o-du-phy.git /opt/phy && \
|
||||
cd /opt/phy/fhi_lib/lib && \
|
||||
WIRELESS_SDK_TOOLCHAIN=gcc RTE_SDK=/oai-ran/dpdk-stable-24.11.4/ XRAN_DIR=/opt/phy/fhi_lib make XRAN_LIB_SO=1
|
||||
|
||||
COPY . .
|
||||
|
||||
FROM ran-base AS ran-build-fhi72
|
||||
## Build and install OAI
|
||||
#run build_oai to build the target image
|
||||
|
||||
@@ -1,20 +1,6 @@
|
||||
<!-- SPDX-License-Identifier: CC-BY-4.0 -->
|
||||
|
||||
<table style="border-collapse: collapse; border: none;">
|
||||
<tr style="border-collapse: collapse; border: none;">
|
||||
<td style="border-collapse: collapse; border: none;">
|
||||
<a href="http://www.openairinterface.org/">
|
||||
<img src="../doc/images/oai_final_logo.png" alt="" border=3 height=50 width=150>
|
||||
</img>
|
||||
</a>
|
||||
</td>
|
||||
<td style="border-collapse: collapse; border: none; vertical-align: center;">
|
||||
<b><font size = "5">OAI Docker/Podman Build and Usage Procedures</font></b>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
---
|
||||
OAI Docker/Podman Build and Usage Procedures
|
||||
|
||||
**Table of Contents**
|
||||
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
#include "SCHED/sched_eNB.h"
|
||||
#include "PHY/LTE_TRANSPORT/transport_proto.h"
|
||||
#include "nfapi/oai_integration/vendor_ext.h"
|
||||
#include "radio/COMMON/common_lib.h"
|
||||
|
||||
#include "PHY/if4_tools.h"
|
||||
#include "PHY/LTE_ESTIMATION/lte_estimation.h"
|
||||
|
||||
@@ -33,7 +33,6 @@
|
||||
#include "SCHED/sched_common.h"
|
||||
#include "common/utils/LOG/log.h"
|
||||
#include "common/utils/LOG/vcd_signal_dumper.h"
|
||||
#include "radio/COMMON/common_lib.h"
|
||||
#include "radio/ETHERNET/ethernet_lib.h"
|
||||
|
||||
/* these variables have to be defined before including ENB_APP/enb_paramdef.h */
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
#include "common/ran_context.h"
|
||||
#include "common/config/config_userapi.h"
|
||||
#include "common/utils/load_module_shlib.h"
|
||||
#include "radio/COMMON/common_lib.h"
|
||||
#include "radio/ETHERNET/if_defs.h"
|
||||
|
||||
#include <openair1/PHY/phy_extern_ue.h>
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
#include <sys/sysinfo.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include "radio/COMMON/common_lib.h"
|
||||
#include "assertions.h"
|
||||
#include "PHY/types.h"
|
||||
#include "PHY/defs_eNB.h"
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
#include "common/ran_context.h"
|
||||
#include "common/config/config_userapi.h"
|
||||
#include "common/utils/load_module_shlib.h"
|
||||
#include "radio/COMMON/common_lib.h"
|
||||
#include "radio/ETHERNET/if_defs.h"
|
||||
|
||||
#include "PHY/phy_vars_ue.h"
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
#include "common/config/config_userapi.h"
|
||||
#include "common/utils/load_module_shlib.h"
|
||||
#include "common/ran_context.h"
|
||||
#include "radio/COMMON/common_lib.h"
|
||||
#include "radio/ETHERNET/if_defs.h"
|
||||
#include "PHY/phy_vars.h"
|
||||
#include "PHY/phy_extern.h"
|
||||
@@ -22,6 +21,9 @@
|
||||
#include <executables/softmodem-common.h>
|
||||
#include <executables/thread-common.h>
|
||||
#include "executables/nr-softmodem.h"
|
||||
#include "nr-oru.h"
|
||||
#include "openair1/PHY/INIT/nr_phy_init.h"
|
||||
#include "openair1/SCHED_NR/sched_nr.h"
|
||||
|
||||
pthread_cond_t sync_cond;
|
||||
pthread_mutex_t sync_mutex;
|
||||
@@ -33,6 +35,9 @@ int sf_ahead = 4;
|
||||
int emulate_rf = 0;
|
||||
|
||||
RAN_CONTEXT_t RC;
|
||||
|
||||
|
||||
|
||||
int64_t uplink_frequency_offset[MAX_NUM_CCs][4];
|
||||
|
||||
void nfapi_setmode(nfapi_mode_t nfapi_mode)
|
||||
@@ -106,26 +111,15 @@ struct timespec timespec_sub(struct timespec, struct timespec)
|
||||
struct timespec t = {0};
|
||||
return t;
|
||||
};
|
||||
|
||||
void perform_symbol_rotation(const int nsymb, const int numerology_index, double f0, c16_t *symbol_rotation)
|
||||
void beam_index_allocation(uint16_t fapi_beam_index,
|
||||
int ant,
|
||||
int num_ports,
|
||||
int symbols_per_slot,
|
||||
int slot,
|
||||
uint16_t bitmap_symbols,
|
||||
int num_ant_max,
|
||||
uint16_t **ant_beam_id_list)
|
||||
{
|
||||
return;
|
||||
}
|
||||
void init_timeshift_rotation(const int ofdm_symbol_size,
|
||||
const int nb_prefix_samples,
|
||||
const uint ofdm_offset_divisor,
|
||||
c16_t *timeshift_symbol_rotation)
|
||||
{
|
||||
return;
|
||||
};
|
||||
int beam_index_allocation(bool das,
|
||||
int fapi_beam_index,
|
||||
NR_gNB_COMMON *common_vars,
|
||||
int slot,
|
||||
int symbols_per_slot,
|
||||
int bitmap_symbols)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
uint16_t get_first_ant_idx(bool das, uint16_t num_ports_beams, uint16_t beam_id, uint16_t fapi_start_port)
|
||||
{
|
||||
@@ -135,6 +129,12 @@ void nr_fill_du(uint16_t N_ZC, const uint16_t *prach_root_sequence_map, uint16_t
|
||||
{
|
||||
return;
|
||||
};
|
||||
|
||||
static void sig_handler(int sig_num)
|
||||
{
|
||||
oai_exit = 1;
|
||||
}
|
||||
|
||||
uint16_t nr_du[838];
|
||||
|
||||
uint64_t downlink_frequency[MAX_NUM_CCs][4];
|
||||
@@ -171,6 +171,7 @@ int main(int argc, char **argv)
|
||||
printf("About to Init RU threads\n");
|
||||
|
||||
lock_memory_to_ram();
|
||||
load_dftslib();
|
||||
|
||||
RC.nb_RU = 1;
|
||||
RC.ru = malloc(sizeof(RC.ru));
|
||||
@@ -178,24 +179,77 @@ int main(int argc, char **argv)
|
||||
init_NR_RU(config_get_if(), NULL);
|
||||
|
||||
RU_t *ru = RC.ru[0];
|
||||
ORU_t oru = {0};
|
||||
oru.ru = ru;
|
||||
int ret = get_oru_options(&oru);
|
||||
AssertFatal(ret == 0, "Cannot configure oru, check your config file/cmdline");
|
||||
ru->numerology = oru.numerology;
|
||||
oru_init_frame_parms(&oru);
|
||||
NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms;
|
||||
nr_dump_frame_parms(fp);
|
||||
init_symbol_rotation(fp);
|
||||
init_timeshift_rotation(fp->ofdm_symbol_size, fp->nb_prefix_samples, fp->ofdm_offset_divisor, fp->timeshift_symbol_rotation);
|
||||
ru->if_south = LOCAL_RF;
|
||||
nr_phy_init_RU(oru.ru);
|
||||
fill_rf_config(ru, ru->rf_config_file);
|
||||
ru->N_TA_offset = set_default_nta_offset(fp->freq_range, fp->samples_per_subframe);
|
||||
|
||||
while (oai_exit == 0)
|
||||
/* set PRACH configuration */
|
||||
nfapi_nr_prach_config_t *prach_config = &ru->config.prach_config;
|
||||
prach_config->prach_ConfigurationIndex.value = oru.prach_config_index;
|
||||
prach_config->num_prach_fd_occasions_list[0].k1.value = oru.prach_msg1_freq;
|
||||
prach_config->prach_sequence_length.value = 1;
|
||||
prach_config->prach_sub_c_spacing.value = 1;
|
||||
prach_config->num_prach_fd_occasions.value = 1;
|
||||
|
||||
reset_meas(&oru.rx_prach);
|
||||
oru.prach_info = get_nr_prach_occasion_info_from_index(oru.prach_config_index, FR1, fp->frame_type);
|
||||
LOG_A(PHY, "PRACH configuration index %d\n", oru.prach_config_index);
|
||||
LOG_A(PHY,
|
||||
"PRACH format %d start_symbol %d duration %d\n",
|
||||
oru.prach_info.format,
|
||||
oru.prach_info.start_symbol,
|
||||
oru.prach_info.N_dur);
|
||||
prepare_prach_item(&oru);
|
||||
|
||||
oru.fronthaul = oru_fh_init(&oru.fh_config);
|
||||
AssertFatal(oru.fronthaul != NULL, "Cannot configure oru fronthaul, check your config file/cmdline");
|
||||
|
||||
LOG_I(PHY, "starting rfdevice\n");
|
||||
ret = openair0_device_load(&ru->rfdevice, &ru->openair0_cfg);
|
||||
AssertFatal(ret == 0, "RU %u: openair0_device_load() ret %d: cannot initialize rfdevice\n", ru->idx, ret);
|
||||
ret = ru->rfdevice.trx_start_func(&ru->rfdevice);
|
||||
AssertFatal(ret == 0, "RU %u: trx_start_func() ret %d: cannot start rfdevice\n", ru->idx, ret);
|
||||
|
||||
threadCreate(&oru.north_read_thread, oru_north_read_thread, (void *)&oru, "north_read_thread", -1, OAI_PRIORITY_RT_MAX);
|
||||
threadCreate(&oru.south_read_thread, oru_south_read_thread, (void *)&oru, "south_read_thread", -1, OAI_PRIORITY_RT_MAX);
|
||||
usleep(1000);
|
||||
oru_fh_start(oru.fronthaul);
|
||||
|
||||
// Signal handler
|
||||
signal(SIGINT, sig_handler);
|
||||
|
||||
while (oai_exit == 0) {
|
||||
oru_fh_print_stats(oru.fronthaul);
|
||||
sleep(1);
|
||||
// stop threads
|
||||
}
|
||||
|
||||
kill_NR_RU_proc(0);
|
||||
pthread_join(oru.north_read_thread, NULL);
|
||||
pthread_join(oru.south_read_thread, NULL);
|
||||
|
||||
end_configmodule(uniqCfg);
|
||||
oru_fh_stop(oru.fronthaul);
|
||||
|
||||
if (ru->rfdevice.trx_stop_func) {
|
||||
ru->rfdevice.trx_stop_func(&ru->rfdevice);
|
||||
ru->rfdevice.trx_stop_func = NULL;
|
||||
}
|
||||
|
||||
if (ru->rfdevice.trx_end_func) {
|
||||
ru->rfdevice.trx_end_func(&ru->rfdevice);
|
||||
ru->rfdevice.trx_end_func = NULL;
|
||||
}
|
||||
|
||||
if (ru->ifdevice.trx_end_func) {
|
||||
ru->ifdevice.trx_end_func(&ru->ifdevice);
|
||||
ru->ifdevice.trx_end_func = NULL;
|
||||
}
|
||||
end_configmodule(uniqCfg);
|
||||
|
||||
logClean();
|
||||
printf("Bye.\n");
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
#include "common/utils/load_module_shlib.h"
|
||||
|
||||
|
||||
#include "radio/COMMON/common_lib.h"
|
||||
#include "radio/ETHERNET/if_defs.h"
|
||||
|
||||
#include "PHY/phy_vars.h"
|
||||
|
||||
760
executables/nr-oru.c
Normal file
760
executables/nr-oru.c
Normal file
@@ -0,0 +1,760 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: LicenseRef-CSSL-1.0
|
||||
*/
|
||||
|
||||
#include "common/config/config_userapi.h"
|
||||
#include "common/utils/system.h"
|
||||
#include "nr-oru.h"
|
||||
#include "openair1/PHY/defs_nr_common.h"
|
||||
#include "PHY/NR_TRANSPORT/nr_transport_proto.h"
|
||||
#include "oru_packet_processor.h"
|
||||
#include <time.h>
|
||||
#include "openair1/PHY/MODULATION/nr_modulation.h"
|
||||
#include "openair1/SCHED_NR/sched_nr.h"
|
||||
#include "openair1/PHY/MODULATION/modulation_common.h"
|
||||
#include "openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h"
|
||||
|
||||
#define CONFIG_SECTION_ORU "ORUs.[0]"
|
||||
|
||||
#define CONFIG_STRING_ORU_TX_BW_LIST "tx_bw"
|
||||
#define CONFIG_STRING_ORU_RX_BW_LIST "rx_bw"
|
||||
#define CONFIG_STRING_ORU_CARRIER_TX_LIST "carrier_tx"
|
||||
#define CONFIG_STRING_ORU_CARRIER_RX_LIST "carrier_rx"
|
||||
#define CONFIG_STRING_ORU_FRAME_TYPE "frame_type"
|
||||
#define CONFIG_STRING_ORU_PRACH_CONFIGID "prach_config_index"
|
||||
#define CONFIG_STRING_ORU_PRACH_MSG1FREQ "prach_msg1_start"
|
||||
#define CONFIG_STRING_ORU_NUMEROLOGY "mu"
|
||||
#define CONFIG_STRING_ORU_TDD_PERIOD "tdd_period"
|
||||
#define CONFIG_STRING_ORU_NUM_DL_SLOTS "num_dl_slots"
|
||||
#define CONFIG_STRING_ORU_NUM_UL_SLOTS "num_ul_slots"
|
||||
#define CONFIG_STRING_ORU_NUM_DL_SYMBOLS "num_dl_symbols"
|
||||
#define CONFIG_STRING_ORU_NUM_UL_SYMBOLS "num_ul_symbols"
|
||||
|
||||
#define HLP_ORU_TX_BW "set the TX bandwidth list per component carrier"
|
||||
#define HLP_ORU_RX_BW "set the RX bandwidth list per component carrier"
|
||||
#define HLP_ORU_CARRIER_TX "set the TX carrier frequencies per component carrier"
|
||||
#define HLP_ORU_CARRIER_RX "set the RX carrier frequencies per component carrier"
|
||||
#define HLP_ORU_FRAMETYPE "set the Frame type TDD/FDD of all component carriers"
|
||||
#define HLP_ORU_PRACH_CONFIGID "set the PRACH configuration id of all component carriers"
|
||||
#define HLP_ORU_PRACH_MSG1FREQ "set the PRACH MSG1 frequency of all component carriers"
|
||||
#define HLP_ORU_NUMEROLOGY "set the numerology of the RU"
|
||||
#define HLP_ORU_TDD_PERIOD "set the 3GPP TDD periodificty 0-9"
|
||||
#define HLP_ORU_NUM_DL_SLOTS "set the number of DL Slots in TDD"
|
||||
#define HLP_ORU_NUM_UL_SLOTS "set the number of UL Slots in TDD"
|
||||
#define HLP_ORU_NUM_DL_SYMBOLS "set the number of DL symbols in the mixed slot"
|
||||
#define HLP_ORU_NUM_UL_SYMBOLS "set the number of UL symbols in the mixed slot"
|
||||
|
||||
// clang-format off
|
||||
#define CMDLINE_PARAMS_DESC_ORU \
|
||||
{ \
|
||||
{CONFIG_STRING_ORU_TX_BW_LIST, HLP_ORU_TX_BW, 0, .iptr=NULL, .defintarrayval=DEFBW, TYPE_INTARRAY, 0}, \
|
||||
{CONFIG_STRING_ORU_RX_BW_LIST, HLP_ORU_RX_BW, 0, .iptr=NULL, .defintarrayval=DEFBW, TYPE_INTARRAY, 0}, \
|
||||
{CONFIG_STRING_ORU_CARRIER_TX_LIST, HLP_ORU_CARRIER_TX, 0, .iptr=NULL, .defintarrayval=DEFCARRIER, TYPE_INTARRAY, 0}, \
|
||||
{CONFIG_STRING_ORU_CARRIER_RX_LIST, HLP_ORU_CARRIER_RX, 0, .iptr=NULL, .defintarrayval=DEFCARRIER, TYPE_INTARRAY, 0}, \
|
||||
{CONFIG_STRING_ORU_FRAME_TYPE, HLP_ORU_FRAMETYPE, 0, .uptr=NULL, .defintval=1, TYPE_UINT, 0}, \
|
||||
{CONFIG_STRING_ORU_PRACH_CONFIGID, HLP_ORU_PRACH_CONFIGID, 0, .uptr=NULL, .defintval=152, TYPE_UINT, 0}, \
|
||||
{CONFIG_STRING_ORU_PRACH_MSG1FREQ, HLP_ORU_PRACH_MSG1FREQ, 0, .uptr=NULL, .defintval=0, TYPE_UINT, 0}, \
|
||||
{CONFIG_STRING_ORU_NUMEROLOGY, HLP_ORU_NUMEROLOGY, 0, .uptr=NULL, .defintval=1, TYPE_UINT, 0}, \
|
||||
{CONFIG_STRING_ORU_TDD_PERIOD, HLP_ORU_TDD_PERIOD, 0, .uptr=NULL, .defintval=5, TYPE_UINT, 0}, \
|
||||
{CONFIG_STRING_ORU_NUM_DL_SLOTS, HLP_ORU_NUM_DL_SLOTS, 0, .uptr=NULL, .defintval=3, TYPE_UINT, 0}, \
|
||||
{CONFIG_STRING_ORU_NUM_UL_SLOTS, HLP_ORU_NUM_UL_SLOTS, 0, .uptr=NULL, .defintval=1, TYPE_UINT, 0}, \
|
||||
{CONFIG_STRING_ORU_NUM_DL_SYMBOLS, HLP_ORU_NUM_DL_SYMBOLS, 0, .uptr=NULL, .defintval=7, TYPE_UINT, 0}, \
|
||||
{CONFIG_STRING_ORU_NUM_UL_SYMBOLS, HLP_ORU_NUM_UL_SYMBOLS, 0, .uptr=NULL, .defintval=3, TYPE_UINT, 0}, \
|
||||
}
|
||||
// clang-format on
|
||||
|
||||
#define CONFIG_SECTION_ORU_FH "ORUs.[0].fronthaul"
|
||||
|
||||
#define CONFIG_STRING_ORU_DPDK_DEVICES "dpdk_devices"
|
||||
#define CONFIG_STRING_RX_CORE "rx_core"
|
||||
#define CONFIG_STRING_EXTRA_EAL_ARGS "extra_eal_args"
|
||||
#define CONFIG_STRING_DU_MAC_ADDRESSES "du_mac_addr"
|
||||
#define CONFIG_STRING_MTU "mtu"
|
||||
#define CONFIG_STRING_T2A_UP "T2a_up"
|
||||
#define CONFIG_STRING_T2A_CP "T2a_cp"
|
||||
#define CONFIG_STRING_PRACH_EAXC_OFFSET "prach_eaxc_offset"
|
||||
|
||||
#define HLP_DPDK_DEVICES "DPDK devices to use for the O-RU."
|
||||
#define HLP_RX_CORE "The CPU core to be used to deploy dpdk RX worker for O-RU."
|
||||
#define HLP_EXTRA_EAL_ARGS "Extra arguments passed to RTE_EAL_INIT."
|
||||
#define HLP_DU_MAC_ADDRESSES "DU MAC addreses, used to prepare Ethernet headers."
|
||||
#define HLP_MTU "MTU for RX and TX."
|
||||
#define HLP_PRACH_EAXC_OFFSET "PRACH eAxC offset."
|
||||
|
||||
// clang-format off
|
||||
#define CMDLINE_PARAMS_DESC_ORU_FH \
|
||||
{ \
|
||||
{CONFIG_STRING_ORU_DPDK_DEVICES, HLP_DPDK_DEVICES, PARAMFLAG_MANDATORY, .strptr=NULL, .defstrval=NULL, TYPE_STRINGLIST, 0}, \
|
||||
{CONFIG_STRING_RX_CORE, HLP_RX_CORE, PARAMFLAG_MANDATORY, .iptr=NULL, .defintval=-1, TYPE_INT, 0}, \
|
||||
{CONFIG_STRING_EXTRA_EAL_ARGS, HLP_EXTRA_EAL_ARGS, 0, .strptr=NULL, .defstrval=NULL, TYPE_STRINGLIST, 0}, \
|
||||
{CONFIG_STRING_DU_MAC_ADDRESSES, HLP_DU_MAC_ADDRESSES, PARAMFLAG_MANDATORY, .strptr=NULL, .defstrval=NULL, TYPE_STRINGLIST, 0}, \
|
||||
{CONFIG_STRING_MTU, HLP_MTU, 0, .iptr=NULL, .defintval=9600, TYPE_INT, 0}, \
|
||||
{CONFIG_STRING_T2A_UP, "", 0, .iptr=NULL, .defintarrayval=NULL, TYPE_INTARRAY, 0}, \
|
||||
{CONFIG_STRING_T2A_CP, "", 0, .iptr=NULL, .defintarrayval=NULL, TYPE_INTARRAY, 0}, \
|
||||
{CONFIG_STRING_PRACH_EAXC_OFFSET, HLP_PRACH_EAXC_OFFSET, 0, .iptr=NULL, .defintval=0, TYPE_INT, 0} \
|
||||
}
|
||||
// clang-format on
|
||||
|
||||
extern void set_scs_parameters(NR_DL_FRAME_PARMS *fp, int mu, int N_RB_DL, int ssb_case);
|
||||
void tx_rf_symbols(RU_t *ru, int frame, int slot, uint64_t timestamp, int start_symbol, int num_symbols);
|
||||
|
||||
void prepare_prach_item(ORU_t *oru)
|
||||
{
|
||||
AssertFatal(oru->ru != NULL, "ORU not configured\n");
|
||||
AssertFatal(oru->ru->nr_frame_parms != NULL, "ORU not configured\n");
|
||||
NR_DL_FRAME_PARMS *fp = oru->ru->nr_frame_parms;
|
||||
RU_t *ru = oru->ru;
|
||||
prach_item_t *prach_item = &oru->prach_item;
|
||||
prach_item->num_slots = oru->prach_info.format < 4 ? get_long_prach_dur(oru->prach_info.format, fp->numerology_index) : 1;
|
||||
prach_item->msg1_frequencystart = oru->prach_msg1_freq;
|
||||
prach_item->mu = fp->numerology_index;
|
||||
nfapi_nr_config_request_scf_t *cfg = &ru->config;
|
||||
prach_item->prach_sequence_length = cfg->prach_config.prach_sequence_length.value;
|
||||
prach_item->restricted_set = 0;
|
||||
prach_item->numerology_index = fp->numerology_index;
|
||||
prach_item->nb_rx = ru->nb_rx;
|
||||
prach_item->rx_prach = &oru->rx_prach;
|
||||
|
||||
// Fill PRACH PDU
|
||||
nfapi_nr_prach_pdu_t *prach_pdu = &prach_item->pdu;
|
||||
prach_pdu->prach_start_symbol = oru->prach_info.start_symbol;
|
||||
prach_pdu->num_prach_ocas = 1; // TODO: Hardcoded.
|
||||
|
||||
uint16_t format0 = oru->prach_info.format & 0xff;
|
||||
uint16_t format1 = (oru->prach_info.format >> 8) & 0xff;
|
||||
if (format1 != 0xff) {
|
||||
switch (format0) {
|
||||
case 0xa1:
|
||||
prach_pdu->prach_format = 11;
|
||||
break;
|
||||
case 0xa2:
|
||||
prach_pdu->prach_format = 12;
|
||||
break;
|
||||
case 0xa3:
|
||||
prach_pdu->prach_format = 13;
|
||||
break;
|
||||
default:
|
||||
AssertFatal(1 == 0, "Only formats A1/B1 A2/B2 A3/B3 are valid for dual format");
|
||||
}
|
||||
} else {
|
||||
switch (format0) {
|
||||
case 0:
|
||||
prach_pdu->prach_format = 0;
|
||||
break;
|
||||
case 1:
|
||||
prach_pdu->prach_format = 1;
|
||||
break;
|
||||
case 2:
|
||||
prach_pdu->prach_format = 2;
|
||||
break;
|
||||
case 3:
|
||||
prach_pdu->prach_format = 3;
|
||||
break;
|
||||
case 0xa1:
|
||||
prach_pdu->prach_format = 4;
|
||||
break;
|
||||
case 0xa2:
|
||||
prach_pdu->prach_format = 5;
|
||||
break;
|
||||
case 0xa3:
|
||||
prach_pdu->prach_format = 6;
|
||||
break;
|
||||
case 0xb1:
|
||||
prach_pdu->prach_format = 7;
|
||||
break;
|
||||
case 0xb4:
|
||||
prach_pdu->prach_format = 8;
|
||||
break;
|
||||
case 0xc0:
|
||||
prach_pdu->prach_format = 9;
|
||||
break;
|
||||
case 0xc2:
|
||||
prach_pdu->prach_format = 10;
|
||||
break;
|
||||
default:
|
||||
AssertFatal(1 == 0, "Invalid PRACH format");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int get_oru_options(ORU_t *oru)
|
||||
{
|
||||
int DEFBW[] = {273};
|
||||
int DEFCARRIER[] = {3430560};
|
||||
paramdef_t param[] = CMDLINE_PARAMS_DESC_ORU;
|
||||
int nump = sizeofArray(param);
|
||||
|
||||
int ret = config_get(config_get_if(), param, nump, CONFIG_SECTION_ORU);
|
||||
if (ret <= 0) {
|
||||
LOG_E(NR_PHY, "problem reading section \"%s\"\n", CONFIG_SECTION_ORU);
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (int i = 0; i < oru->ru->num_bands; i++) {
|
||||
oru->bw_tx[i] = gpd(param, nump, CONFIG_STRING_ORU_TX_BW_LIST)->iptr[i];
|
||||
oru->bw_rx[i] = gpd(param, nump, CONFIG_STRING_ORU_RX_BW_LIST)->iptr[i];
|
||||
oru->carrier_freq_tx[i] = gpd(param, nump, CONFIG_STRING_ORU_CARRIER_TX_LIST)->iptr[i];
|
||||
oru->carrier_freq_rx[i] = gpd(param, nump, CONFIG_STRING_ORU_CARRIER_RX_LIST)->iptr[i];
|
||||
}
|
||||
oru->frame_type = *gpd(param, nump, CONFIG_STRING_ORU_FRAME_TYPE)->iptr;
|
||||
oru->prach_config_index = *gpd(param, nump, CONFIG_STRING_ORU_PRACH_CONFIGID)->iptr;
|
||||
oru->prach_msg1_freq = *gpd(param, nump, CONFIG_STRING_ORU_PRACH_MSG1FREQ)->iptr;
|
||||
oru->numerology = *gpd(param, nump, CONFIG_STRING_ORU_NUMEROLOGY)->iptr;
|
||||
oru->tdd_period = *gpd(param, nump, CONFIG_STRING_ORU_TDD_PERIOD)->iptr;
|
||||
oru->num_DL_slots = *gpd(param, nump, CONFIG_STRING_ORU_NUM_DL_SLOTS)->iptr;
|
||||
oru->num_UL_slots = *gpd(param, nump, CONFIG_STRING_ORU_NUM_UL_SLOTS)->iptr;
|
||||
oru->num_DL_symbols = *gpd(param, nump, CONFIG_STRING_ORU_NUM_DL_SYMBOLS)->iptr;
|
||||
oru->num_UL_symbols = *gpd(param, nump, CONFIG_STRING_ORU_NUM_UL_SYMBOLS)->iptr;
|
||||
|
||||
paramdef_t fh_param[] = CMDLINE_PARAMS_DESC_ORU_FH;
|
||||
nump = sizeofArray(fh_param);
|
||||
oru_fh_config_t *fh_cfg = &oru->fh_config;
|
||||
ret = config_get(config_get_if(), fh_param, nump, CONFIG_SECTION_ORU_FH);
|
||||
if (ret <= 0) {
|
||||
printf("problem reading section \"%s\"\n", CONFIG_SECTION_ORU_FH);
|
||||
return -1;
|
||||
}
|
||||
|
||||
oru_fh_dpdk_config_t *dpdk_conf = &fh_cfg->dpdk_conf;
|
||||
int num_dpdk_devices = gpd(fh_param, nump, CONFIG_STRING_ORU_DPDK_DEVICES)->numelt;
|
||||
dpdk_conf->num_dpdk_devices = num_dpdk_devices;
|
||||
AssertFatal(num_dpdk_devices > 0 && num_dpdk_devices <= 2,
|
||||
"Invalid number of DPDK devices (%d). Configure 1 or 2 devices\n",
|
||||
num_dpdk_devices);
|
||||
for (int i = 0; i < num_dpdk_devices; i++) {
|
||||
dpdk_conf->dpdk_devices[i] = gpd(fh_param, nump, CONFIG_STRING_ORU_DPDK_DEVICES)->strlistptr[i];
|
||||
}
|
||||
dpdk_conf->extra_eal_args = gpd(fh_param, nump, CONFIG_STRING_EXTRA_EAL_ARGS)->strlistptr;
|
||||
dpdk_conf->num_extra_eal_args = gpd(fh_param, nump, CONFIG_STRING_EXTRA_EAL_ARGS)->numelt;
|
||||
|
||||
fh_cfg->num_du_mac_addrs = gpd(fh_param, nump, CONFIG_STRING_DU_MAC_ADDRESSES)->numelt;
|
||||
for (int i = 0; i < fh_cfg->num_du_mac_addrs; i++) {
|
||||
fh_cfg->du_mac_addrs[i] = gpd(fh_param, nump, CONFIG_STRING_DU_MAC_ADDRESSES)->strlistptr[i];
|
||||
AssertFatal(strlen(fh_cfg->du_mac_addrs[i]) == 17, "Invalid MAC address\n");
|
||||
}
|
||||
fh_cfg->enable_compression = false;
|
||||
fh_cfg->rx_core = *gpd(fh_param, nump, CONFIG_STRING_RX_CORE)->iptr;
|
||||
fh_cfg->mtu = *gpd(fh_param, nump, CONFIG_STRING_MTU)->iptr;
|
||||
fh_cfg->num_prbs = oru->bw_tx[0];
|
||||
fh_cfg->numerology = oru->numerology;
|
||||
fh_cfg->prach_eaxc_offset = *gpd(fh_param, nump, CONFIG_STRING_PRACH_EAXC_OFFSET)->iptr;
|
||||
|
||||
AssertFatal(gpd(fh_param, nump, CONFIG_STRING_T2A_UP)->numelt == 2, "Two parameters required for %s\n", CONFIG_STRING_T2A_UP);
|
||||
fh_cfg->T2a_up_min_uS = gpd(fh_param, nump, CONFIG_STRING_T2A_UP)->iptr[0];
|
||||
fh_cfg->T2a_up_max_uS = gpd(fh_param, nump, CONFIG_STRING_T2A_UP)->iptr[1];
|
||||
AssertFatal(fh_cfg->T2a_up_min_uS <= fh_cfg->T2a_up_max_uS,
|
||||
"T2a max (%d) has to be greater than T2a min (%d)\n",
|
||||
fh_cfg->T2a_up_max_uS,
|
||||
fh_cfg->T2a_up_min_uS);
|
||||
|
||||
AssertFatal(gpd(fh_param, nump, CONFIG_STRING_T2A_CP)->numelt == 2, "Two parameters required for %s\n", CONFIG_STRING_T2A_CP);
|
||||
fh_cfg->T2a_cp_min_uS = gpd(fh_param, nump, CONFIG_STRING_T2A_CP)->iptr[0];
|
||||
fh_cfg->T2a_cp_max_uS = gpd(fh_param, nump, CONFIG_STRING_T2A_CP)->iptr[1];
|
||||
AssertFatal(fh_cfg->T2a_cp_min_uS <= fh_cfg->T2a_cp_max_uS,
|
||||
"T2a max (%d) has to be greater than T2a min (%d)\n",
|
||||
fh_cfg->T2a_cp_max_uS,
|
||||
fh_cfg->T2a_cp_min_uS);
|
||||
|
||||
oru_fh_tdd_pattern_t *tdd_pattern = &fh_cfg->tdd_pattern;
|
||||
tdd_pattern->num_dl_slots = oru->num_DL_slots;
|
||||
tdd_pattern->num_ul_slots = oru->num_UL_slots;
|
||||
tdd_pattern->num_dl_symbols = oru->num_DL_symbols;
|
||||
tdd_pattern->num_ul_symbols = oru->num_UL_symbols;
|
||||
int num_slots_frame = (1 << oru->numerology) * NR_NUMBER_OF_SUBFRAMES_PER_FRAME;
|
||||
int num_period_frame = get_nb_periods_per_frame(oru->tdd_period);
|
||||
int num_slots_period = num_slots_frame / num_period_frame;
|
||||
tdd_pattern->tdd_pattern_length_slots = num_slots_period;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void oru_init_frame_parms(ORU_t *oru)
|
||||
{
|
||||
RU_t *ru = oru->ru;
|
||||
NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms;
|
||||
|
||||
fp->frame_type = oru->frame_type;
|
||||
ru->config.cell_config.frame_duplex_type.value = oru->frame_type;
|
||||
ru->config.cell_config.frame_duplex_type.tl.tag = 0x100D;
|
||||
fp->N_RB_DL = oru->bw_tx[0];
|
||||
ru->config.ssb_config.scs_common.value = ru->numerology;
|
||||
ru->config.carrier_config.dl_grid_size[ru->config.ssb_config.scs_common.value].value = oru->bw_tx[0];
|
||||
fp->N_RB_UL = oru->bw_rx[0];
|
||||
ru->config.carrier_config.ul_grid_size[ru->config.ssb_config.scs_common.value].value = oru->bw_rx[0];
|
||||
fp->numerology_index = ru->numerology;
|
||||
LOG_I(NR_PHY,
|
||||
"Set RU frame type to %s, N_RB_DL %d, N_RB_UL %d, mu %d\n",
|
||||
oru->frame_type == TDD ? "TDD" : "FDD",
|
||||
oru->bw_tx[0],
|
||||
oru->bw_rx[0],
|
||||
ru->numerology);
|
||||
set_scs_parameters(fp, fp->numerology_index, oru->bw_tx[0], 0);
|
||||
fp->slots_per_frame = 10 * fp->slots_per_subframe;
|
||||
fp->nb_antennas_rx = ru->nb_rx;
|
||||
fp->nb_antennas_tx = ru->nb_tx;
|
||||
fp->symbols_per_slot = 14;
|
||||
fp->samples_per_subframe_wCP = fp->ofdm_symbol_size * fp->symbols_per_slot * fp->slots_per_subframe;
|
||||
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->samples_per_frame = 10 * fp->samples_per_subframe;
|
||||
fp->freq_range = (oru->carrier_freq_tx[0] < 6e6) ? FR1 : FR2;
|
||||
|
||||
fp->dl_CarrierFreq = (double)oru->carrier_freq_tx[0] * 1000;
|
||||
fp->ul_CarrierFreq = (double)oru->carrier_freq_rx[0] * 1000;
|
||||
fp->Ncp = NORMAL;
|
||||
fp->ofdm_offset_divisor = 8;
|
||||
|
||||
// Split 7.2 parameters
|
||||
ru->config.prach_config.num_prach_fd_occasions.value = 1;
|
||||
ru->config.prach_config.prach_ConfigurationIndex.value = oru->prach_config_index;
|
||||
ru->config.prach_config.prach_ConfigurationIndex.tl.tag = 0x1029;
|
||||
ru->config.prach_config.num_prach_fd_occasions_list = malloc(sizeof(*ru->config.prach_config.num_prach_fd_occasions_list));
|
||||
ru->config.prach_config.num_prach_fd_occasions_list[0].k1.value = oru->prach_msg1_freq;
|
||||
if (ru->config.cell_config.frame_duplex_type.value == 1 /* TDD */) {
|
||||
ru->config.tdd_table.tdd_period.value = oru->tdd_period;
|
||||
ru->config.tdd_table.tdd_period.tl.tag = 0x1026;
|
||||
int numb_slots_frame = (1 << ru->numerology) * NR_NUMBER_OF_SUBFRAMES_PER_FRAME;
|
||||
int numb_period_frame = get_nb_periods_per_frame(oru->tdd_period);
|
||||
int numb_slots_period = numb_slots_frame / numb_period_frame;
|
||||
ru->config.tdd_table.max_tdd_periodicity_list =
|
||||
malloc(sizeof(*ru->config.tdd_table.max_tdd_periodicity_list) * (numb_slots_frame));
|
||||
for (int n = 0; n < numb_slots_frame; n++) {
|
||||
int s = 0;
|
||||
int p = n % numb_slots_period;
|
||||
nfapi_nr_max_tdd_periodicity_t *periodicity = &ru->config.tdd_table.max_tdd_periodicity_list[n];
|
||||
periodicity->max_num_of_symbol_per_slot_list =
|
||||
malloc(sizeof(*periodicity->max_num_of_symbol_per_slot_list) * NR_SYMBOLS_PER_SLOT);
|
||||
nfapi_nr_max_num_of_symbol_per_slot_t *symbol_list = periodicity->max_num_of_symbol_per_slot_list;
|
||||
if (p < oru->num_DL_slots) {
|
||||
for (s = 0; s < 14; s++)
|
||||
symbol_list[s].slot_config.value = 0;
|
||||
} else if (p == oru->num_DL_slots) {
|
||||
for (s = 0; s < oru->num_DL_symbols; s++)
|
||||
symbol_list[s].slot_config.value = 0;
|
||||
for (; s < NR_SYMBOLS_PER_SLOT - oru->num_UL_symbols; s++)
|
||||
symbol_list[s].slot_config.value = 2;
|
||||
for (; s < NR_SYMBOLS_PER_SLOT; s++)
|
||||
symbol_list[s].slot_config.value = 1;
|
||||
} else {
|
||||
for (s = 0; s < NR_SYMBOLS_PER_SLOT; s++)
|
||||
symbol_list[s].slot_config.value = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void fft_and_cp_insertion(NR_DL_FRAME_PARMS *fp, c16_t *txdataF, c16_t *txdata, int slot, int symbol)
|
||||
{
|
||||
int nb_prefix_samples = fp->nb_prefix_samples;
|
||||
if (fp->Ncp != 1) {
|
||||
if (fp->numerology_index != 0) {
|
||||
if (!(slot % (fp->slots_per_subframe / 2)) && (symbol == 0)) {
|
||||
nb_prefix_samples = fp->nb_prefix_samples0;
|
||||
}
|
||||
} else {
|
||||
if (symbol % 0x7 == 0) {
|
||||
nb_prefix_samples = fp->nb_prefix_samples0;
|
||||
}
|
||||
}
|
||||
}
|
||||
PHY_ofdm_mod((int *)txdataF, (int *)txdata, fp->ofdm_symbol_size, 1, nb_prefix_samples, CYCLIC_PREFIX);
|
||||
}
|
||||
|
||||
static void dl_symbol_process(RU_t *ru, int frame, int slot, int symbol, c16_t **txDataF, int64_t timestamp)
|
||||
{
|
||||
NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms;
|
||||
uint32_t slot_offset = get_samples_slot_timestamp(fp, slot);
|
||||
uint32_t symbol_offset = get_samples_symbol_timestamp(fp, slot, symbol);
|
||||
|
||||
__attribute__((aligned(64))) c16_t txdataF_shifted[fp->ofdm_symbol_size];
|
||||
memset(txdataF_shifted, 0, sizeof(txdataF_shifted));
|
||||
c16_t *rotation = fp->symbol_rotation[0] + (slot % fp->slots_per_subframe) * fp->symbols_per_slot + symbol;
|
||||
for (int aatx = 0; aatx < ru->nb_tx; aatx++) {
|
||||
// Phase compensation
|
||||
rotate_cpx_vector(txDataF[aatx], *rotation, txDataF[aatx], fp->N_RB_DL * NR_NB_SC_PER_RB, 15);
|
||||
// FFT Shift
|
||||
const int num_samp_half = fp->N_RB_DL * NR_NB_SC_PER_RB / 2;
|
||||
const int first_carrier_offset = fp->ofdm_symbol_size - num_samp_half;
|
||||
memcpy(txdataF_shifted + first_carrier_offset, txDataF[aatx], num_samp_half * sizeof(c16_t));
|
||||
memcpy(txdataF_shifted, txDataF[aatx] + num_samp_half, num_samp_half * sizeof(c16_t));
|
||||
fft_and_cp_insertion(ru->nr_frame_parms,
|
||||
txdataF_shifted,
|
||||
(c16_t *)&ru->common.txdata[aatx][slot_offset + symbol_offset],
|
||||
slot,
|
||||
symbol);
|
||||
}
|
||||
tx_rf_symbols(ru, frame, slot, timestamp, symbol, 1);
|
||||
}
|
||||
|
||||
void *oru_north_read_thread(void *arg)
|
||||
{
|
||||
ORU_t *oru = (ORU_t *)arg;
|
||||
|
||||
RU_t *ru = (RU_t *)oru->ru;
|
||||
NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms;
|
||||
|
||||
__attribute__((aligned(64))) c16_t txDataF[ru->nb_tx][fp->N_RB_DL * NR_NB_SC_PER_RB];
|
||||
memset(txDataF, 0, sizeof(txDataF));
|
||||
c16_t *txDataF_ptr[ru->nb_tx];
|
||||
for (int aatx = 0; aatx < ru->nb_tx; aatx++) {
|
||||
txDataF_ptr[aatx] = txDataF[aatx];
|
||||
}
|
||||
uint32_t start_frame, start_slot;
|
||||
uint64_t start_hyper_frame;
|
||||
struct timespec utc_anchor_point;
|
||||
oru_fh_get_utc_anchor_point(oru->fronthaul, &start_hyper_frame, &start_frame, &start_slot, &utc_anchor_point);
|
||||
AssertFatal(ru->rfdevice.get_timestamp != NULL, "rfdevice has no capability to translate UTC timestamp to sample index\n");
|
||||
int64_t start_timestamp = ru->rfdevice.get_timestamp(&ru->rfdevice, &utc_anchor_point);
|
||||
// subtract the start_frame and start_slot from the timestamp simplify calculation below.
|
||||
start_timestamp -= (start_frame * fp->samples_per_frame + get_samples_slot_timestamp(fp, start_slot));
|
||||
// Now start_timestamp points to the start sample of the frame 0 slot 0 symbol 0 of hyperframe 0
|
||||
LOG_A(PHY, "DL thread started: start_timestamp %ld, start_frame %d, start_slot %d\n", start_timestamp, start_frame, start_slot);
|
||||
|
||||
while (!oai_exit) {
|
||||
int frame = -1, slot = -1, symbol = -1;
|
||||
uint64_t hyper_frame;
|
||||
int ret = oru_fh_tx_read_symbol(oru->fronthaul, (uint32_t **)txDataF_ptr, ru->nb_tx, &hyper_frame, &frame, &slot, &symbol);
|
||||
if (ret != 0) {
|
||||
LOG_E(PHY, "[RU_thread] read data error: frame %d, slot %d, symbol %d\n", frame, slot, symbol);
|
||||
continue;
|
||||
}
|
||||
if (start_hyper_frame > hyper_frame) {
|
||||
continue;
|
||||
}
|
||||
uint64_t num_frames = (hyper_frame - start_hyper_frame) * 1024 + frame;
|
||||
int64_t timestamp = start_timestamp + num_frames * fp->samples_per_frame + get_samples_slot_timestamp(fp, slot)
|
||||
+ get_samples_symbol_timestamp(fp, slot, symbol);
|
||||
if (timestamp < 0) {
|
||||
continue;
|
||||
}
|
||||
dl_symbol_process(ru, frame, slot, symbol, txDataF_ptr, timestamp);
|
||||
if (frame % 256 == 0 && slot == 0 && symbol == 0) {
|
||||
LOG_I(PHY, "[RU_thread] read data: frame %d, slot %d, symbol %d\n", frame, slot, symbol);
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Returns PRACH symbol that was received in current frame, slot and symbol.
|
||||
// If no PRACH symbol was received, returns -1
|
||||
int get_prach_symbol(ORU_t *oru, int frame, int slot, int symbol, int numerology)
|
||||
{
|
||||
uint16_t RA_sfn_index;
|
||||
AssertFatal(oru->ru->nr_frame_parms->frame_type == TDD, "Only supports TDD\n");
|
||||
if (get_nr_prach_sched_from_info(oru->prach_info, oru->prach_config_index, frame, slot, numerology, FR1, &RA_sfn_index, true)) {
|
||||
int format = oru->prach_item.pdu.prach_format;
|
||||
int start_symbol = oru->prach_item.pdu.prach_start_symbol;
|
||||
symbol -= start_symbol;
|
||||
// TODO: Support more PRACH formats
|
||||
AssertFatal(format == 8, "only support format B4\n");
|
||||
// TODO: This is not exactly the case but it is correct
|
||||
if (symbol >= 0 && symbol < 12) {
|
||||
return symbol;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void receive_prach(ORU_t *oru, int frame, int slot, int symbol, int prach_symbol)
|
||||
{
|
||||
RU_t *ru = oru->ru;
|
||||
NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms;
|
||||
oru->prach_item.frame = frame;
|
||||
oru->prach_item.slot = slot;
|
||||
|
||||
c16_t rxdataF[ru->nb_rx][NR_PRACH_SEQ_LEN_L];
|
||||
memset(rxdataF, 0, sizeof(rxdataF));
|
||||
|
||||
rx_nr_prach_ru_rep(&oru->prach_item,
|
||||
ru->common.rxdata,
|
||||
fp,
|
||||
ru->N_TA_offset,
|
||||
prach_symbol,
|
||||
0, // prachOccasion
|
||||
rxdataF);
|
||||
|
||||
c16_t *rxdataF_ptr[ru->nb_rx];
|
||||
for (int aarx = 0; aarx < ru->nb_rx; aarx++) {
|
||||
rxdataF_ptr[aarx] = rxdataF[aarx];
|
||||
}
|
||||
oru_fh_rx_send_prach(oru->fronthaul, (uint32_t **)rxdataF_ptr, ru->nb_rx, frame, slot, symbol);
|
||||
}
|
||||
|
||||
#define MAX_PENDING_UL_JOBS 64
|
||||
|
||||
typedef struct {
|
||||
ul_job_t job;
|
||||
bool active;
|
||||
int symbols_sent;
|
||||
} ul_pending_t;
|
||||
|
||||
static void receive_pusch(ORU_t *oru, int frame, int slot, int symbol, ul_job_t *job)
|
||||
{
|
||||
RU_t *ru = oru->ru;
|
||||
NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms;
|
||||
int aarx = job->antenna_id;
|
||||
|
||||
if (aarx < 0 || aarx >= fp->nb_antennas_rx) {
|
||||
LOG_W(PHY, "[ORU south] receive_pusch: invalid antenna_id %d\n", aarx);
|
||||
return;
|
||||
}
|
||||
|
||||
// CP removal + FFT → full ofdm_symbol_size frequency-domain output
|
||||
c16_t rxdataF_fft[fp->ofdm_symbol_size] __attribute__((aligned(32)));
|
||||
nr_symbol_fep_ul(fp, (c16_t *)ru->common.rxdata[aarx], rxdataF_fft, symbol, slot, ru->N_TA_offset);
|
||||
|
||||
// Phase decompensation (conjugate rotation for UL)
|
||||
apply_nr_rotation_symbol_RX(fp->symbols_per_slot,
|
||||
fp->slots_per_subframe,
|
||||
fp->timeshift_symbol_rotation,
|
||||
fp->first_carrier_offset,
|
||||
rxdataF_fft,
|
||||
fp->symbol_rotation[link_type_ul],
|
||||
fp->N_RB_UL,
|
||||
slot,
|
||||
symbol);
|
||||
|
||||
// Inverse FFT shift: split format → contiguous PRB format sent to DU.
|
||||
// DL TX shift: contiguous[0..N/2-1] → FFT_input[first_carrier_offset..] (negative freqs)
|
||||
// contiguous[N/2..N-1] → FFT_input[0..N/2-1] (positive freqs)
|
||||
// UL RX inverse: FFT_out[first_carrier_offset..] → contiguous[0..N/2-1]
|
||||
// FFT_out[0..N/2-1] → contiguous[N/2..N-1]
|
||||
const int num_samp_half = fp->N_RB_UL * NR_NB_SC_PER_RB / 2;
|
||||
const int first_carrier_offset = fp->ofdm_symbol_size - num_samp_half;
|
||||
c16_t rxdataF[fp->N_RB_UL * NR_NB_SC_PER_RB];
|
||||
memcpy(rxdataF, rxdataF_fft + first_carrier_offset, num_samp_half * sizeof(c16_t));
|
||||
memcpy(rxdataF + num_samp_half, rxdataF_fft, num_samp_half * sizeof(c16_t));
|
||||
|
||||
oru_fh_rx_send_pusch(oru->fronthaul, (uint32_t *)rxdataF, symbol, job);
|
||||
}
|
||||
|
||||
#define UL_WORK_QUEUE_DEPTH 128
|
||||
|
||||
typedef struct {
|
||||
ORU_t *oru;
|
||||
int frame;
|
||||
int slot;
|
||||
int symbol;
|
||||
ul_job_t job;
|
||||
} ul_work_item_t;
|
||||
|
||||
typedef struct {
|
||||
ul_work_item_t ring[UL_WORK_QUEUE_DEPTH];
|
||||
int head;
|
||||
int tail;
|
||||
int count;
|
||||
pthread_mutex_t lock;
|
||||
pthread_cond_t work_available;
|
||||
pthread_cond_t space_available;
|
||||
bool running;
|
||||
} ul_work_queue_t;
|
||||
|
||||
static void *ul_worker_thread(void *arg)
|
||||
{
|
||||
ul_work_queue_t *q = arg;
|
||||
while (1) {
|
||||
pthread_mutex_lock(&q->lock);
|
||||
while (q->count == 0 && q->running)
|
||||
pthread_cond_wait(&q->work_available, &q->lock);
|
||||
if (!q->running && q->count == 0) {
|
||||
pthread_mutex_unlock(&q->lock);
|
||||
break;
|
||||
}
|
||||
ul_work_item_t item = q->ring[q->head];
|
||||
q->head = (q->head + 1) % UL_WORK_QUEUE_DEPTH;
|
||||
q->count--;
|
||||
pthread_cond_signal(&q->space_available);
|
||||
pthread_mutex_unlock(&q->lock);
|
||||
|
||||
receive_pusch(item.oru, item.frame, item.slot, item.symbol, &item.job);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void dispatch_ul_work(ul_work_queue_t *q, ORU_t *oru, int frame, int slot, int symbol, const ul_job_t *job)
|
||||
{
|
||||
pthread_mutex_lock(&q->lock);
|
||||
while (q->count == UL_WORK_QUEUE_DEPTH)
|
||||
pthread_cond_wait(&q->space_available, &q->lock);
|
||||
q->ring[q->tail] = (ul_work_item_t){.oru = oru, .frame = frame, .slot = slot, .symbol = symbol, .job = *job};
|
||||
q->tail = (q->tail + 1) % UL_WORK_QUEUE_DEPTH;
|
||||
q->count++;
|
||||
pthread_cond_signal(&q->work_available);
|
||||
pthread_mutex_unlock(&q->lock);
|
||||
}
|
||||
|
||||
void *oru_south_read_thread(void *arg)
|
||||
{
|
||||
ORU_t *oru = arg;
|
||||
RU_t *ru = oru->ru;
|
||||
NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms;
|
||||
struct timespec utc_anchor_point;
|
||||
AssertFatal(ru->rfdevice.get_timestamp != NULL, "rfdevice has no capability to translate UTC timestamp to sample index\n");
|
||||
uint32_t start_frame, start_slot;
|
||||
uint64_t hyper_frame;
|
||||
oru_fh_get_utc_anchor_point(oru->fronthaul, &hyper_frame, &start_frame, &start_slot, &utc_anchor_point);
|
||||
int64_t start_timestamp = ru->rfdevice.get_timestamp(&ru->rfdevice, &utc_anchor_point);
|
||||
|
||||
const int num_samples = 3000;
|
||||
c16_t throwaway_samples[ru->nb_rx][num_samples];
|
||||
void *rxp[ru->nb_rx];
|
||||
for (int i = 0; i < ru->nb_rx; i++)
|
||||
rxp[i] = throwaway_samples[i];
|
||||
|
||||
openair0_timestamp_t timestamp;
|
||||
int num_samples_read = ru->rfdevice.trx_read_func(&ru->rfdevice, ×tamp, rxp, num_samples, ru->nb_rx);
|
||||
AssertFatal(num_samples_read == num_samples, "Unexpected number of samples received\n");
|
||||
openair0_timestamp_t next_timestamp = timestamp + num_samples_read;
|
||||
while (next_timestamp > start_timestamp) {
|
||||
start_timestamp += get_samples_slot_duration(fp, start_slot, 1);
|
||||
start_slot++;
|
||||
if (start_slot == fp->slots_per_frame) {
|
||||
start_slot = 0;
|
||||
start_frame++;
|
||||
if (start_frame == 1024) {
|
||||
start_frame = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
while (next_timestamp < start_timestamp) {
|
||||
int num_samples_to_read = min(num_samples, (int)(start_timestamp - next_timestamp));
|
||||
int num_samples_read = ru->rfdevice.trx_read_func(&ru->rfdevice, ×tamp, rxp, num_samples_to_read, ru->nb_rx);
|
||||
AssertFatal(num_samples_read == num_samples_to_read, "Unexpected number of samples received\n");
|
||||
next_timestamp += num_samples_read;
|
||||
}
|
||||
|
||||
AssertFatal(next_timestamp == start_timestamp, "O-RU South thread could not sync to UTC anchor point\n");
|
||||
|
||||
int slot = start_slot;
|
||||
int frame = start_frame;
|
||||
|
||||
// Worker pool: one thread per RX antenna so all antennas in a symbol process in parallel.
|
||||
const int num_workers = ru->nb_rx;
|
||||
pthread_t workers[num_workers];
|
||||
ul_work_queue_t work_queue = {
|
||||
.lock = PTHREAD_MUTEX_INITIALIZER,
|
||||
.work_available = PTHREAD_COND_INITIALIZER,
|
||||
.space_available = PTHREAD_COND_INITIALIZER,
|
||||
.running = true,
|
||||
};
|
||||
for (int i = 0; i < num_workers; i++) {
|
||||
char name[32];
|
||||
snprintf(name, sizeof(name), "ul_worker_%d", i);
|
||||
threadCreate(&workers[i], ul_worker_thread, &work_queue, name, -1, OAI_PRIORITY_RT_MAX);
|
||||
}
|
||||
|
||||
ul_pending_t pending_ul[MAX_PENDING_UL_JOBS] = {0};
|
||||
|
||||
while (!oai_exit) {
|
||||
int rx_slot_type = nr_slot_select(&ru->config, frame, slot);
|
||||
for (int symbol = 0; symbol < 14; symbol++) {
|
||||
int samples_to_read = get_samples_symbol_duration(fp, slot, symbol, 1);
|
||||
size_t offset = get_samples_slot_timestamp(fp, slot) + get_samples_symbol_timestamp(fp, slot, symbol);
|
||||
c16_t *rxp[fp->nb_antennas_rx];
|
||||
for (int aarx = 0; aarx < fp->nb_antennas_rx; aarx++) {
|
||||
rxp[aarx] = (c16_t *)&ru->common.rxdata[aarx][offset];
|
||||
}
|
||||
|
||||
openair0_timestamp_t timestamp;
|
||||
int num_samples_read = ru->rfdevice.trx_read_func(&ru->rfdevice, ×tamp, (void **)rxp, samples_to_read, ru->nb_rx);
|
||||
AssertFatal(num_samples_read == samples_to_read, "Unexpected number of samples received\n");
|
||||
LOG_D(PHY,
|
||||
"[ORU south] read data: frame %d, slot %d, symbol %d, timestamp %ld num_symbols %d, samples %d\n",
|
||||
frame,
|
||||
slot,
|
||||
symbol,
|
||||
timestamp,
|
||||
1,
|
||||
num_samples_read);
|
||||
|
||||
// Drain the UL job ring
|
||||
ul_job_t new_job;
|
||||
while (oru_fh_poll_ul_job(oru->fronthaul, &new_job) == 0) {
|
||||
bool added = false;
|
||||
for (int i = 0; i < MAX_PENDING_UL_JOBS; i++) {
|
||||
if (!pending_ul[i].active) {
|
||||
pending_ul[i] = (ul_pending_t){.job = new_job, .active = true, .symbols_sent = 0};
|
||||
added = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!added)
|
||||
LOG_W(PHY, "[ORU south] UL pending queue full, dropping job frame=%d slot=%d sym=%d\n",
|
||||
new_job.frame, new_job.slot_in_frame, new_job.symbol);
|
||||
}
|
||||
|
||||
if (rx_slot_type == NR_UPLINK_SLOT || rx_slot_type == NR_MIXED_SLOT) {
|
||||
|
||||
// Process pending jobs whose next symbol matches the current one
|
||||
for (int i = 0; i < MAX_PENDING_UL_JOBS; i++) {
|
||||
if (!pending_ul[i].active)
|
||||
continue;
|
||||
ul_job_t *j = &pending_ul[i].job;
|
||||
|
||||
// Skip jobs scheduled for a future slot or frame, and drop jobs in the past
|
||||
int slots_per_frame = fp->slots_per_frame;
|
||||
int total_slots = 1024 * slots_per_frame;
|
||||
int diff_slots = (j->frame * slots_per_frame + j->slot_in_frame) - (frame * slots_per_frame + slot);
|
||||
if (diff_slots < -total_slots / 2) {
|
||||
diff_slots += total_slots;
|
||||
} else if (diff_slots > total_slots / 2) {
|
||||
diff_slots -= total_slots;
|
||||
}
|
||||
|
||||
if (diff_slots > 0) {
|
||||
// Future slot: skip
|
||||
continue;
|
||||
}
|
||||
if (diff_slots < 0) {
|
||||
// Past slot: drop
|
||||
LOG_W(PHY, "[ORU south] missed UL slot %d.%d (now %d.%d), dropping job ant=%d\n",
|
||||
j->frame, j->slot_in_frame, frame, slot, j->antenna_id);
|
||||
pending_ul[i].active = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Same slot: check symbol
|
||||
int expected_symbol = j->symbol + pending_ul[i].symbols_sent;
|
||||
if (expected_symbol < symbol) {
|
||||
LOG_W(PHY, "[ORU south] missed UL symbol %d (now %d), dropping job ant=%d\n",
|
||||
expected_symbol, symbol, j->antenna_id);
|
||||
pending_ul[i].active = false;
|
||||
} else if (expected_symbol == symbol) {
|
||||
dispatch_ul_work(&work_queue, oru, frame, slot, symbol, j);
|
||||
if (++pending_ul[i].symbols_sent == j->num_symbols)
|
||||
pending_ul[i].active = false;
|
||||
}
|
||||
// expected_symbol > symbol: job spans multiple symbols, revisit next iteration
|
||||
}
|
||||
}
|
||||
int prach_symbol = get_prach_symbol(oru, frame, slot, symbol, ru->numerology);
|
||||
if (prach_symbol != -1)
|
||||
receive_prach(oru, frame, slot, symbol, prach_symbol);
|
||||
}
|
||||
slot++;
|
||||
if (slot == fp->slots_per_frame) {
|
||||
slot = 0;
|
||||
frame++;
|
||||
if (frame == 1024) {
|
||||
frame = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&work_queue.lock);
|
||||
work_queue.running = false;
|
||||
pthread_cond_broadcast(&work_queue.work_available);
|
||||
pthread_mutex_unlock(&work_queue.lock);
|
||||
for (int i = 0; i < num_workers; i++)
|
||||
pthread_join(workers[i], NULL);
|
||||
pthread_cond_destroy(&work_queue.work_available);
|
||||
pthread_cond_destroy(&work_queue.space_available);
|
||||
pthread_mutex_destroy(&work_queue.lock);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
59
executables/nr-oru.h
Normal file
59
executables/nr-oru.h
Normal file
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: LicenseRef-CSSL-1.0
|
||||
*/
|
||||
|
||||
#ifndef __NR_ORU_H__
|
||||
#define __NR_ORU_H__
|
||||
#include "openair1/PHY/defs_RU.h"
|
||||
#include <pthread.h>
|
||||
#include "oru_fh.h"
|
||||
#include "openair2/LAYER2/NR_MAC_COMMON/nr_prach_config.h"
|
||||
#include "openair1/PHY/defs_gNB.h"
|
||||
|
||||
typedef struct {
|
||||
RU_t *ru;
|
||||
/// tx carrier
|
||||
uint64_t carrier_freq_tx[MAX_BANDS_PER_RRU];
|
||||
/// rx carrier
|
||||
uint64_t carrier_freq_rx[MAX_BANDS_PER_RRU];
|
||||
/// tx BW in PRBs
|
||||
int bw_tx[MAX_BANDS_PER_RRU];
|
||||
/// rx BW in PRBs
|
||||
int bw_rx[MAX_BANDS_PER_RRU];
|
||||
/// 3GPP FRAME Type FDD/TDD
|
||||
int frame_type;
|
||||
/// 3GPP PRACH configuration index
|
||||
int prach_config_index;
|
||||
/// 3GPP MSG1 Start frequency
|
||||
int prach_msg1_freq;
|
||||
/// 3GPP TDD periodicity (0.5 ms, 1 0.625ms, 2 1ms, 3 1.25ms, 4 2ms,5 2.5ms, 6 5ms, 7 10ms, 8 3ms, 9 4ms
|
||||
int tdd_period;
|
||||
/// number of DL slots
|
||||
int num_DL_slots;
|
||||
/// number of UL slots
|
||||
int num_UL_slots;
|
||||
/// number of DL symbols
|
||||
int num_DL_symbols;
|
||||
/// number of UL symbols
|
||||
int num_UL_symbols;
|
||||
int numerology;
|
||||
|
||||
pthread_t north_read_thread;
|
||||
pthread_t south_read_thread;
|
||||
oru_fh_config_t fh_config;
|
||||
void *fronthaul;
|
||||
|
||||
// PRACH related
|
||||
nr_prach_info_t prach_info;
|
||||
time_stats_t rx_prach;
|
||||
time_stats_t rx;
|
||||
prach_item_t prach_item;
|
||||
} ORU_t;
|
||||
|
||||
int get_oru_options(ORU_t *oru);
|
||||
void oru_init_frame_parms(ORU_t *oru);
|
||||
void *oru_north_read_thread(void *arg);
|
||||
void *oru_south_read_thread(void *arg);
|
||||
void prepare_prach_item(ORU_t *oru);
|
||||
|
||||
#endif
|
||||
@@ -18,11 +18,8 @@
|
||||
#include "common/utils/fsn.h"
|
||||
#include "common/ran_context.h"
|
||||
|
||||
#include "radio/COMMON/common_lib.h"
|
||||
#include "radio/ETHERNET/ethernet_lib.h"
|
||||
|
||||
#include "PHY/if4_tools.h"
|
||||
|
||||
#include "PHY/defs_nr_common.h"
|
||||
#include "PHY/phy_extern.h"
|
||||
#include "PHY/NR_TRANSPORT/nr_transport_proto.h"
|
||||
@@ -76,15 +73,6 @@ void fh_if5_south_out(RU_t *ru, int frame, int slot, uint64_t timestamp)
|
||||
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
|
||||
void fh_if4p5_south_out(RU_t *ru, int frame, int slot, uint64_t timestamp)
|
||||
{
|
||||
LOG_D(PHY,"Sending IF4p5 for frame %d subframe %d\n",ru->proc.frame_tx,ru->proc.tti_tx);
|
||||
|
||||
if ((nr_slot_select(&ru->config, ru->proc.frame_tx, ru->proc.tti_tx) & NR_DOWNLINK_SLOT) > 0)
|
||||
send_IF4p5(ru,frame, slot, IF4p5_PDLFFT);
|
||||
}
|
||||
|
||||
/*************************************************************/
|
||||
/* Input Fronthaul from south RCC/RAU */
|
||||
|
||||
@@ -148,196 +136,6 @@ void fh_if5_south_in(RU_t *ru, int *frame, int *tti)
|
||||
rxmeas.tv_nsec);
|
||||
}
|
||||
|
||||
// Synchronous if4p5 from south
|
||||
void fh_if4p5_south_in(RU_t *ru,
|
||||
int *frame,
|
||||
int *slot) {
|
||||
NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms;
|
||||
RU_proc_t *proc = &ru->proc;
|
||||
int f,sl;
|
||||
uint16_t packet_type;
|
||||
uint32_t symbol_number=0;
|
||||
uint32_t symbol_mask_full=0;
|
||||
|
||||
do { // Blocking, we need a timeout on this !!!!!!!!!!!!!!!!!!!!!!!
|
||||
recv_IF4p5(ru, &f, &sl, &packet_type, &symbol_number);
|
||||
|
||||
if (packet_type == IF4p5_PULFFT) proc->symbol_mask[sl] = proc->symbol_mask[sl] | (1<<symbol_number);
|
||||
else if (packet_type == IF4p5_PULTICK) {
|
||||
if ((proc->first_rx == 0) && (f != *frame))
|
||||
LOG_E(PHY, "rx_fh_if4p5: PULTICK received frame %d != expected %d\n", f, *frame);
|
||||
|
||||
if ((proc->first_rx == 0) && (sl != *slot))
|
||||
LOG_E(PHY, "rx_fh_if4p5: PULTICK received subframe %d != expected %d (first_rx %d)\n", sl, *slot, proc->first_rx);
|
||||
|
||||
break;
|
||||
} else if (packet_type == IF4p5_PRACH) {
|
||||
// nothing in RU for RAU
|
||||
}
|
||||
|
||||
LOG_D(PHY,"rx_fh_if4p5: subframe %d symbol mask %x\n",*slot,proc->symbol_mask[sl]);
|
||||
} while(proc->symbol_mask[sl] != symbol_mask_full);
|
||||
|
||||
//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) + 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;
|
||||
|
||||
if (proc->first_rx == 0) {
|
||||
if (proc->tti_rx != *slot) {
|
||||
LOG_E(PHY,"Received Timestamp (IF4p5) doesn't correspond to the time we think it is (proc->tti_rx %d, subframe %d)\n",proc->tti_rx,*slot);
|
||||
exit_fun("Exiting");
|
||||
}
|
||||
|
||||
if (proc->frame_rx != *frame) {
|
||||
LOG_E(PHY,"Received Timestamp (IF4p5) doesn't correspond to the time we think it is (proc->frame_rx %d frame %d)\n",proc->frame_rx,*frame);
|
||||
exit_fun("Exiting");
|
||||
}
|
||||
} else {
|
||||
proc->first_rx = 0;
|
||||
*frame = proc->frame_rx;
|
||||
*slot = proc->tti_rx;
|
||||
}
|
||||
|
||||
proc->symbol_mask[proc->tti_rx] = 0;
|
||||
LOG_D(PHY,"RU %d: fh_if4p5_south_in sleeping ...\n",ru->idx);
|
||||
}
|
||||
|
||||
// asynchronous inbound if4p5 fronthaul from south
|
||||
void fh_if4p5_south_asynch_in(RU_t *ru,int *frame,int *slot) {
|
||||
NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms;
|
||||
RU_proc_t *proc = &ru->proc;
|
||||
uint16_t packet_type;
|
||||
uint32_t symbol_number = 0;
|
||||
uint32_t symbol_mask = (1 << fp->symbols_per_slot) - 1;
|
||||
uint32_t prach_rx = 0;
|
||||
|
||||
do { // Blocking, we need a timeout on this !!!!!!!!!!!!!!!!!!!!!!!
|
||||
recv_IF4p5(ru, &proc->frame_rx, &proc->tti_rx, &packet_type, &symbol_number);
|
||||
if (proc->first_rx != 0) {
|
||||
*frame = proc->frame_rx;
|
||||
*slot = proc->tti_rx;
|
||||
proc->first_rx = 0;
|
||||
} else {
|
||||
if (proc->frame_rx != *frame) {
|
||||
LOG_E(PHY,"frame_rx %d is not what we expect %d\n",proc->frame_rx,*frame);
|
||||
exit_fun("Exiting");
|
||||
}
|
||||
if (proc->tti_rx != *slot) {
|
||||
LOG_E(PHY,"tti_rx %d is not what we expect %d\n",proc->tti_rx,*slot);
|
||||
exit_fun("Exiting");
|
||||
}
|
||||
}
|
||||
|
||||
if (packet_type == IF4p5_PULFFT)
|
||||
symbol_mask &= ~(1 << symbol_number);
|
||||
else if (packet_type == IF4p5_PRACH)
|
||||
prach_rx &= ~0x1;
|
||||
} while (symbol_mask > 0 || prach_rx > 0); // haven't received all PUSCH symbols and PRACH information
|
||||
}
|
||||
|
||||
/*************************************************************/
|
||||
/* Input Fronthaul from North RRU */
|
||||
|
||||
// RRU IF4p5 TX fronthaul receiver. Assumes an if_device on input and if or rf device on output
|
||||
// receives one subframe's worth of IF4p5 OFDM symbols and OFDM modulates
|
||||
void fh_if4p5_north_in(RU_t *ru,int *frame,int *slot)
|
||||
{
|
||||
uint32_t symbol_number=0;
|
||||
uint32_t symbol_mask, symbol_mask_full;
|
||||
uint16_t packet_type;
|
||||
/// **** incoming IF4p5 from remote RCC/RAU **** ///
|
||||
symbol_number = 0;
|
||||
symbol_mask = 0;
|
||||
symbol_mask_full = (1<<(ru->nr_frame_parms->symbols_per_slot))-1;
|
||||
|
||||
do {
|
||||
recv_IF4p5(ru, frame, slot, &packet_type, &symbol_number);
|
||||
symbol_mask = symbol_mask | (1<<symbol_number);
|
||||
} while (symbol_mask != symbol_mask_full);
|
||||
}
|
||||
|
||||
void fh_if5_north_asynch_in(RU_t *ru, int *frame, int *slot)
|
||||
{
|
||||
AssertFatal(1 == 0, "Shouldn't get here\n");
|
||||
}
|
||||
|
||||
void fh_if4p5_north_asynch_in(RU_t *ru,int *frame,int *slot) {
|
||||
NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms;
|
||||
nfapi_nr_config_request_scf_t *cfg = &ru->config;
|
||||
RU_proc_t *proc = &ru->proc;
|
||||
uint16_t packet_type;
|
||||
uint32_t symbol_mask_full = 0;
|
||||
int slot_tx,frame_tx;
|
||||
LOG_D(PHY, "%s(ru:%p frame, subframe)\n", __FUNCTION__, ru);
|
||||
uint32_t symbol_number = 0;
|
||||
uint32_t symbol_mask = 0;
|
||||
|
||||
// symbol_mask_full = ((subframe_select(fp,*slot) == SF_S) ? (1<<fp->dl_symbols_in_S_subframe) : (1<<fp->symbols_per_slot))-1;
|
||||
do {
|
||||
recv_IF4p5(ru, &frame_tx, &slot_tx, &packet_type, &symbol_number);
|
||||
|
||||
if (((nr_slot_select(cfg, frame_tx, slot_tx) & NR_DOWNLINK_SLOT) > 0) && (symbol_number == 0))
|
||||
start_meas(&ru->rx_fhaul);
|
||||
|
||||
LOG_D(PHY,"slot %d (%d): frame %d, slot %d, symbol %d\n",
|
||||
*slot,nr_slot_select(cfg,frame_tx,*slot),frame_tx,slot_tx,symbol_number);
|
||||
|
||||
if (proc->first_tx != 0) {
|
||||
*frame = frame_tx;
|
||||
*slot = slot_tx;
|
||||
proc->first_tx = 0;
|
||||
} else {
|
||||
AssertFatal(frame_tx == *frame,
|
||||
"frame_tx %d is not what we expect %d\n",frame_tx,*frame);
|
||||
AssertFatal(slot_tx == *slot,
|
||||
"slot_tx %d is not what we expect %d\n",slot_tx,*slot);
|
||||
}
|
||||
|
||||
if (packet_type == IF4p5_PDLFFT) {
|
||||
symbol_mask = symbol_mask | (1<<symbol_number);
|
||||
} else
|
||||
AssertFatal(false, "Illegal IF4p5 packet type (should only be IF4p5_PDLFFT%d\n", packet_type);
|
||||
} while (symbol_mask != symbol_mask_full);
|
||||
|
||||
if ((nr_slot_select(cfg, frame_tx, slot_tx) & NR_DOWNLINK_SLOT) > 0)
|
||||
stop_meas(&ru->rx_fhaul);
|
||||
|
||||
proc->tti_tx = slot_tx;
|
||||
proc->frame_tx = frame_tx;
|
||||
|
||||
if (frame_tx == 0 && slot_tx == 0)
|
||||
proc->frame_tx_unwrap += 1024;
|
||||
|
||||
proc->timestamp_tx =
|
||||
((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);
|
||||
|
||||
if (ru->feptx_ofdm)
|
||||
ru->feptx_ofdm(ru, frame_tx, slot_tx);
|
||||
|
||||
if (ru->fh_south_out)
|
||||
ru->fh_south_out(ru, frame_tx, slot_tx, proc->timestamp_tx);
|
||||
}
|
||||
|
||||
void fh_if5_north_out(RU_t *ru)
|
||||
{
|
||||
/// **** send_IF5 of rxdata to BBU **** ///
|
||||
AssertFatal(1 == 0, "Shouldn't get here\n");
|
||||
}
|
||||
|
||||
// RRU IF4p5 northbound interface (RX)
|
||||
void fh_if4p5_north_out(RU_t *ru)
|
||||
{
|
||||
RU_proc_t *proc=&ru->proc;
|
||||
start_meas(&ru->tx_fhaul);
|
||||
send_IF4p5(ru, proc->frame_rx, proc->tti_rx, IF4p5_PULFFT);
|
||||
stop_meas(&ru->tx_fhaul);
|
||||
}
|
||||
|
||||
static void rx_rf(RU_t *ru, int *frame, int *slot)
|
||||
{
|
||||
RU_proc_t *proc = &ru->proc;
|
||||
@@ -494,7 +292,7 @@ static radio_tx_gpio_flag_t get_gpio_flags(RU_t *ru, int slot)
|
||||
return flags_gpio;
|
||||
}
|
||||
|
||||
void tx_rf(RU_t *ru, int frame,int slot, uint64_t timestamp)
|
||||
void tx_rf_symbols(RU_t *ru, int frame, int slot, uint64_t timestamp, int start_symbol, int num_symbols)
|
||||
{
|
||||
RU_proc_t *proc = &ru->proc;
|
||||
NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms;
|
||||
@@ -521,22 +319,23 @@ void tx_rf(RU_t *ru, int frame,int slot, uint64_t timestamp)
|
||||
txsymb++;
|
||||
}
|
||||
|
||||
AssertFatal(txsymb>0,"illegal txsymb %d\n",txsymb);
|
||||
AssertFatal(txsymb > 0, "illegal txsymb %d\n", txsymb);
|
||||
|
||||
if (fp->slots_per_subframe == 1) {
|
||||
if (txsymb <= 7)
|
||||
siglen = (fp->ofdm_symbol_size + fp->nb_prefix_samples0) + (txsymb - 1) * (fp->ofdm_symbol_size + fp->nb_prefix_samples);
|
||||
else
|
||||
siglen = 2 * (fp->ofdm_symbol_size + fp->nb_prefix_samples0) + (txsymb - 2) * (fp->ofdm_symbol_size + fp->nb_prefix_samples);
|
||||
} else {
|
||||
if(slot%(fp->slots_per_subframe/2))
|
||||
siglen = txsymb * (fp->ofdm_symbol_size + fp->nb_prefix_samples);
|
||||
else
|
||||
siglen = (fp->ofdm_symbol_size + fp->nb_prefix_samples0) + (txsymb - 1) * (fp->ofdm_symbol_size + fp->nb_prefix_samples);
|
||||
if (txsymb < start_symbol) {
|
||||
// No DL symbols in this transmission
|
||||
return;
|
||||
}
|
||||
|
||||
//+ ru->end_of_burst_delay;
|
||||
flags_burst = TX_BURST_END;
|
||||
int end_symbol = start_symbol + num_symbols - 1;
|
||||
if (end_symbol >= txsymb) {
|
||||
flags_burst = TX_BURST_END;
|
||||
} else {
|
||||
flags_burst = TX_BURST_MIDDLE;
|
||||
}
|
||||
|
||||
int num_symbols_this_transmission = min(txsymb, end_symbol) - start_symbol + 1;
|
||||
|
||||
siglen = get_samples_symbol_duration(fp, slot, start_symbol, num_symbols_this_transmission);
|
||||
} else if (slot_type == NR_DOWNLINK_SLOT) {
|
||||
int prevslot_type = nr_slot_select(cfg,frame,(slot+(fp->slots_per_frame-1))%fp->slots_per_frame);
|
||||
int nextslot_type = nr_slot_select(cfg,frame,(slot+1)%fp->slots_per_frame);
|
||||
@@ -548,9 +347,11 @@ void tx_rf(RU_t *ru, int frame,int slot, uint64_t timestamp)
|
||||
} else {
|
||||
flags_burst = proc->first_tx == 1 ? TX_BURST_START : TX_BURST_MIDDLE;
|
||||
}
|
||||
siglen = get_samples_symbol_duration(fp, slot, start_symbol, num_symbols);
|
||||
}
|
||||
} else { // FDD
|
||||
flags_burst = proc->first_tx == 1 ? TX_BURST_START : TX_BURST_MIDDLE;
|
||||
siglen = get_samples_symbol_duration(fp, slot, start_symbol, num_symbols);
|
||||
}
|
||||
|
||||
if (ru->openair0_cfg.gpio_controller != RU_GPIO_CONTROL_NONE)
|
||||
@@ -561,8 +362,9 @@ void tx_rf(RU_t *ru, int frame,int slot, uint64_t timestamp)
|
||||
|
||||
int nt = ru->nb_tx;
|
||||
void *txp[nt];
|
||||
uint32_t time_offset = get_samples_slot_timestamp(fp, slot) + get_samples_symbol_timestamp(fp, slot, start_symbol);
|
||||
for (int i = 0; i < nt; i++)
|
||||
txp[i] = (void *)&ru->common.txdata[i][get_samples_slot_timestamp(fp, slot)] - sf_extension * sizeof(int32_t);
|
||||
txp[i] = (void *)&ru->common.txdata[i][time_offset] - sf_extension * sizeof(int32_t);
|
||||
|
||||
// prepare tx buffer pointers
|
||||
uint32_t txs = ru->rfdevice.trx_write_func(&ru->rfdevice,
|
||||
@@ -586,7 +388,12 @@ void tx_rf(RU_t *ru, int frame,int slot, uint64_t timestamp)
|
||||
10 * log10((double)signal_energy(txp[0], siglen + sf_extension)));
|
||||
}
|
||||
|
||||
static void fill_rf_config(RU_t *ru, char *rf_config_file)
|
||||
void tx_rf(RU_t *ru, int frame, int slot, uint64_t timestamp)
|
||||
{
|
||||
tx_rf_symbols(ru, frame, slot, timestamp, 0, 14);
|
||||
}
|
||||
|
||||
void fill_rf_config(RU_t *ru, char *rf_config_file)
|
||||
{
|
||||
NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms;
|
||||
nfapi_nr_config_request_scf_t *config = &ru->config; //tmp index
|
||||
@@ -649,7 +456,7 @@ static void fill_rf_config(RU_t *ru, char *rf_config_file)
|
||||
}
|
||||
}
|
||||
|
||||
static void fill_split7_2_config(split7_config_t *split7, const nfapi_nr_config_request_scf_t *config, const NR_DL_FRAME_PARMS *fp)
|
||||
void fill_split7_2_config(split7_config_t *split7, const nfapi_nr_config_request_scf_t *config, const NR_DL_FRAME_PARMS *fp)
|
||||
{
|
||||
const nfapi_nr_prach_config_t *prach_config = &config->prach_config;
|
||||
const nfapi_nr_tdd_table_t *tdd_table = &config->tdd_table;
|
||||
@@ -833,7 +640,7 @@ void *ru_thread(void *param)
|
||||
ret = openair0_transport_load(&ru->ifdevice, &ru->openair0_cfg, &ru->eth_params);
|
||||
AssertFatal(ret == 0, "RU %u: openair0_transport_init() ret %d: cannot initialize transport protocol\n", ru->idx, ret);
|
||||
|
||||
if (ru->ifdevice.get_internal_parameter != NULL) {
|
||||
if (ru->ifdevice.get_internal_parameter) {
|
||||
/* it seems the device can "overwrite" (request?) to set the callbacks
|
||||
* for fh_south_in()/fh_south_out() differently */
|
||||
void *t = ru->ifdevice.get_internal_parameter("fh_if4p5_south_in");
|
||||
@@ -842,8 +649,6 @@ void *ru_thread(void *param)
|
||||
t = ru->ifdevice.get_internal_parameter("fh_if4p5_south_out");
|
||||
if (t != NULL)
|
||||
ru->fh_south_out = t;
|
||||
} else {
|
||||
malloc_IF4p5_buffer(ru);
|
||||
}
|
||||
|
||||
int cpu = sched_getcpu();
|
||||
@@ -1088,94 +893,59 @@ void set_function_spec_param(RU_t *ru)
|
||||
switch (ru->if_south) {
|
||||
case LOCAL_RF: // this is an RU with integrated RF (RRU, gNB)
|
||||
reset_meas(&ru->rx_fhaul);
|
||||
if (ru->function == NGFI_RRU_IF5) { // IF5 RRU
|
||||
ru->do_prach = 0; // no prach processing in RU
|
||||
ru->fh_north_in = NULL; // no shynchronous incoming fronthaul from north
|
||||
ru->fh_north_out = fh_if5_north_out; // need only to do send_IF5 reception
|
||||
ru->fh_south_out = tx_rf; // send output to RF
|
||||
ru->fh_north_asynch_in = fh_if5_north_asynch_in; // TX packets come asynchronously
|
||||
ru->feprx = NULL; // nothing (this is a time-domain signal)
|
||||
ru->feptx_ofdm = NULL; // nothing (this is a time-domain signal)
|
||||
ru->feptx_prec = NULL; // nothing (this is a time-domain signal)
|
||||
ru->nr_start_if = nr_start_if; // need to start the if interface for if5
|
||||
ru->ifdevice.host_type = RRU_HOST;
|
||||
ru->rfdevice.host_type = RRU_HOST;
|
||||
ru->ifdevice.eth_params = &ru->eth_params;
|
||||
reset_meas(&ru->rx_fhaul);
|
||||
reset_meas(&ru->tx_fhaul);
|
||||
reset_meas(&ru->compression);
|
||||
reset_meas(&ru->transport);
|
||||
} else if (ru->function == NGFI_RRU_IF4p5) {
|
||||
ru->do_prach = 1; // do part of prach processing in RU
|
||||
ru->fh_north_in = NULL; // no synchronous incoming fronthaul from north
|
||||
ru->fh_north_out = fh_if4p5_north_out; // send_IF4p5 on reception
|
||||
ru->fh_south_out = tx_rf; // send output to RF
|
||||
ru->fh_north_asynch_in = fh_if4p5_north_asynch_in; // TX packets come asynchronously
|
||||
ru->feprx = nr_fep_tp; // this is frequency-shift + DFTs
|
||||
ru->feptx_ofdm = nr_feptx_tp; // this is fep with idft only (no precoding in RRU)
|
||||
ru->feptx_prec = NULL;
|
||||
ru->nr_start_if = nr_start_if; // need to start the if interface for if4p5
|
||||
ru->ifdevice.host_type = RRU_HOST;
|
||||
ru->rfdevice.host_type = RRU_HOST;
|
||||
ru->ifdevice.eth_params = &ru->eth_params;
|
||||
reset_meas(&ru->tx_fhaul);
|
||||
reset_meas(&ru->compression);
|
||||
reset_meas(&ru->transport);
|
||||
} else if (ru->function == gNodeB_3GPP) {
|
||||
ru->do_prach = 0; // no prach processing in RU
|
||||
ru->feprx = nr_fep_tp; // this is frequency-shift + DFTs
|
||||
ru->feptx_ofdm = nr_feptx_tp; // this is fep with idft and precoding
|
||||
ru->feptx_prec = NULL;
|
||||
ru->fh_north_in = NULL; // no incoming fronthaul from north
|
||||
ru->fh_north_out = NULL; // no outgoing fronthaul to north
|
||||
ru->nr_start_if = NULL; // no if interface
|
||||
ru->rfdevice.host_type = RAU_HOST;
|
||||
ru->fh_south_in = rx_rf; // local synchronous RF RX
|
||||
ru->fh_south_out = tx_rf; // local synchronous RF TX
|
||||
ru->start_rf = start_rf; // need to start the local RF interface
|
||||
ru->stop_rf = stop_rf;
|
||||
ru->start_write_thread = start_write_thread; // starting RF TX in different thread
|
||||
}
|
||||
AssertFatal(ru->function == gNodeB_3GPP, "ru->function %d not supported for LOCAL_RF\n", ru->function);
|
||||
ru->do_prach = 0; // no prach processing in RU
|
||||
ru->feprx = nr_fep_tp; // this is frequency-shift + DFTs
|
||||
ru->feptx_ofdm = nr_feptx_tp; // this is fep with idft and precoding
|
||||
ru->feptx_prec = NULL;
|
||||
ru->fh_north_in = NULL; // no incoming fronthaul from north
|
||||
ru->fh_north_out = NULL; // no outgoing fronthaul to north
|
||||
ru->nr_start_if = NULL; // no if interface
|
||||
ru->rfdevice.host_type = RAU_HOST;
|
||||
ru->fh_south_in = rx_rf; // local synchronous RF RX
|
||||
ru->fh_south_out = tx_rf; // local synchronous RF TX
|
||||
ru->start_rf = start_rf; // need to start the local RF interface
|
||||
ru->stop_rf = stop_rf;
|
||||
ru->start_write_thread = start_write_thread; // starting RF TX in different thread
|
||||
break;
|
||||
|
||||
case REMOTE_IF5: // the remote unit is IF5 RRU
|
||||
ru->do_prach = 0;
|
||||
ru->txfh_in_fep = 0;
|
||||
ru->feprx = nr_fep_tp; // this is frequency-shift + DFTs
|
||||
ru->feptx_prec = NULL; // need to do transmit Precoding + IDFTs
|
||||
ru->feptx_ofdm = nr_feptx_tp; // need to do transmit Precoding + IDFTs
|
||||
ru->fh_south_in = fh_if5_south_in; // synchronous IF5 reception
|
||||
ru->fh_south_out = (ru->txfh_in_fep>0) ? NULL : fh_if5_south_out; // synchronous IF5 transmission
|
||||
ru->fh_south_asynch_in = NULL; // no asynchronous UL
|
||||
ru->start_rf = ru->eth_params.transp_preference == ETH_UDP_IF5_ECPRI_MODE ? start_streaming : NULL;
|
||||
ru->stop_rf = NULL;
|
||||
ru->start_write_thread = NULL;
|
||||
ru->nr_start_if = nr_start_if; // need to start if interface for IF5
|
||||
ru->ifdevice.host_type = RAU_HOST;
|
||||
ru->ifdevice.eth_params = &ru->eth_params;
|
||||
|
||||
ru->do_prach = 0;
|
||||
ru->txfh_in_fep = 0;
|
||||
ru->feprx = nr_fep_tp; // this is frequency-shift + DFTs
|
||||
ru->feptx_prec = NULL; // need to do transmit Precoding + IDFTs
|
||||
ru->feptx_ofdm = nr_feptx_tp; // need to do transmit Precoding + IDFTs
|
||||
ru->fh_south_in = fh_if5_south_in; // synchronous IF5 reception
|
||||
ru->fh_south_out = (ru->txfh_in_fep > 0) ? NULL : fh_if5_south_out; // synchronous IF5 transmission
|
||||
ru->fh_south_asynch_in = NULL; // no asynchronous UL
|
||||
ru->start_rf = ru->eth_params.transp_preference == ETH_UDP_IF5_ECPRI_MODE ? start_streaming : NULL;
|
||||
ru->stop_rf = NULL;
|
||||
ru->start_write_thread = NULL;
|
||||
ru->nr_start_if = nr_start_if; // need to start if interface for IF5
|
||||
ru->ifdevice.host_type = RAU_HOST;
|
||||
ru->ifdevice.eth_params = &ru->eth_params;
|
||||
break;
|
||||
|
||||
case REMOTE_IF4p5:
|
||||
ru->do_prach = 0;
|
||||
ru->feprx = NULL; // DFTs
|
||||
ru->feptx_prec = nr_feptx_prec; // Precoding operation
|
||||
ru->feptx_ofdm = NULL; // no OFDM mod
|
||||
ru->fh_south_in = fh_if4p5_south_in; // synchronous IF4p5 reception
|
||||
ru->fh_south_out = fh_if4p5_south_out; // synchronous IF4p5 transmission
|
||||
ru->fh_south_asynch_in = (ru->if_timing == synch_to_other) ? fh_if4p5_south_in : NULL; // asynchronous UL if synch_to_other
|
||||
ru->fh_north_out = NULL;
|
||||
ru->fh_north_asynch_in = NULL;
|
||||
ru->start_rf = NULL; // no local RF
|
||||
ru->stop_rf = NULL;
|
||||
ru->start_write_thread = NULL;
|
||||
ru->nr_start_if = nr_start_if; // need to start if interface for IF4p5
|
||||
ru->ifdevice.host_type = RAU_HOST;
|
||||
ru->ifdevice.eth_params = &ru->eth_params;
|
||||
ru->do_prach = 0;
|
||||
ru->feprx = NULL; // DFTs
|
||||
ru->feptx_prec = nr_feptx_prec; // Precoding operation
|
||||
ru->feptx_ofdm = NULL; // no OFDM mod
|
||||
ru->fh_south_in = NULL;
|
||||
ru->fh_south_out = NULL;
|
||||
ru->fh_south_asynch_in = NULL;
|
||||
ru->fh_north_out = NULL;
|
||||
ru->fh_north_asynch_in = NULL;
|
||||
ru->start_rf = NULL; // no local RF
|
||||
ru->stop_rf = NULL;
|
||||
ru->start_write_thread = NULL;
|
||||
ru->nr_start_if = nr_start_if; // need to start if interface for IF4p5
|
||||
ru->ifdevice.host_type = RAU_HOST;
|
||||
ru->ifdevice.eth_params = &ru->eth_params;
|
||||
break;
|
||||
|
||||
default:
|
||||
LOG_E(PHY,"RU with invalid or unknown southbound interface type %d\n",ru->if_south);
|
||||
LOG_E(PHY, "RU with invalid or unknown southbound interface type %d\n", ru->if_south);
|
||||
break;
|
||||
} // switch on interface type
|
||||
}
|
||||
@@ -1369,47 +1139,14 @@ static void NRRCconfig_RU(configmodule_interface_t *cfg)
|
||||
ru->openair0_cfg.tune_offset = get_softmodem_params()->tune_offset;
|
||||
|
||||
if (strcmp(*param[RU_LOCAL_RF_IDX].strptr, "yes") == 0) {
|
||||
if (!config_isparamset(param, RU_LOCAL_IF_NAME_IDX)) {
|
||||
ru->if_south = LOCAL_RF;
|
||||
ru->function = gNodeB_3GPP;
|
||||
LOG_D(PHY, "Setting function for RU %d to gNodeB_3GPP\n", j);
|
||||
} else {
|
||||
ru->eth_params.local_if_name = strdup(*param[RU_LOCAL_IF_NAME_IDX].strptr);
|
||||
ru->eth_params.my_addr = strdup(*param[RU_LOCAL_ADDRESS_IDX].strptr);
|
||||
ru->eth_params.remote_addr = strdup(*param[RU_REMOTE_ADDRESS_IDX].strptr);
|
||||
ru->eth_params.my_portc = *param[RU_LOCAL_PORTC_IDX].uptr;
|
||||
ru->eth_params.remote_portc = *param[RU_REMOTE_PORTC_IDX].uptr;
|
||||
ru->eth_params.my_portd = *param[RU_LOCAL_PORTD_IDX].uptr;
|
||||
ru->eth_params.remote_portd = *param[RU_REMOTE_PORTD_IDX].uptr;
|
||||
char *str = *param[RU_TRANSPORT_PREFERENCE_IDX].strptr;
|
||||
if (strcmp(str, "udp") == 0) {
|
||||
ru->if_south = LOCAL_RF;
|
||||
ru->function = NGFI_RRU_IF5;
|
||||
ru->eth_params.transp_preference = ETH_UDP_MODE;
|
||||
LOG_D(PHY, "Setting function for RU %d to NGFI_RRU_IF5 (udp)\n", j);
|
||||
} else if (strcmp(str, "raw") == 0) {
|
||||
ru->if_south = LOCAL_RF;
|
||||
ru->function = NGFI_RRU_IF5;
|
||||
ru->eth_params.transp_preference = ETH_RAW_MODE;
|
||||
LOG_D(PHY, "Setting function for RU %d to NGFI_RRU_IF5 (raw)\n", j);
|
||||
} else if (strcmp(str, "udp_if4p5") == 0) {
|
||||
ru->if_south = LOCAL_RF;
|
||||
ru->function = NGFI_RRU_IF4p5;
|
||||
ru->eth_params.transp_preference = ETH_UDP_IF4p5_MODE;
|
||||
LOG_D(PHY, "Setting function for RU %d to NGFI_RRU_IF4p5 (udp)\n", j);
|
||||
} else if (strcmp(str, "raw_if4p5") == 0) {
|
||||
ru->if_south = LOCAL_RF;
|
||||
ru->function = NGFI_RRU_IF4p5;
|
||||
ru->eth_params.transp_preference = ETH_RAW_IF4p5_MODE;
|
||||
LOG_D(PHY, "Setting function for RU %d to NGFI_RRU_IF4p5 (raw)\n", j);
|
||||
}
|
||||
}
|
||||
|
||||
AssertFatal(!config_isparamset(param, RU_LOCAL_IF_NAME_IDX), "RU_TRANSPORT_PREFERENCE not supported for local RF\n");
|
||||
ru->if_south = LOCAL_RF;
|
||||
ru->function = gNodeB_3GPP;
|
||||
LOG_D(PHY, "Setting function for RU %d to gNodeB_3GPP\n", j);
|
||||
ru->max_pdschReferenceSignalPower = *param[RU_MAX_RS_EPRE_IDX].uptr;
|
||||
ru->max_rxgain = *param[RU_MAX_RXGAIN_IDX].uptr;
|
||||
ru->sf_extension = *param[RU_SF_EXTENSION_IDX].uptr;
|
||||
} // strcmp(local_rf, "yes") == 0
|
||||
else {
|
||||
} else { // strcmp(local_rf, "yes") == 0
|
||||
char *str = *param[RU_TRANSPORT_PREFERENCE_IDX].strptr;
|
||||
LOG_D(PHY, "RU %d: Transport %s\n", j, str);
|
||||
ru->eth_params.local_if_name = strdup(*param[RU_LOCAL_IF_NAME_IDX].strptr);
|
||||
@@ -1432,10 +1169,6 @@ static void NRRCconfig_RU(configmodule_interface_t *cfg)
|
||||
ru->if_south = REMOTE_IF5;
|
||||
ru->function = NGFI_RAU_IF5;
|
||||
ru->eth_params.transp_preference = ETH_RAW_MODE;
|
||||
} else if (strcmp(str, "udp_if4p5") == 0) {
|
||||
ru->if_south = REMOTE_IF4p5;
|
||||
ru->function = NGFI_RAU_IF4p5;
|
||||
ru->eth_params.transp_preference = ETH_UDP_IF4p5_MODE;
|
||||
} else if (strcmp(str, "raw_if4p5") == 0) {
|
||||
ru->if_south = REMOTE_IF4p5;
|
||||
ru->function = NGFI_RAU_IF4p5;
|
||||
|
||||
@@ -28,7 +28,6 @@
|
||||
#include <unistd.h>
|
||||
|
||||
#include <sys/sysinfo.h>
|
||||
#include "radio/COMMON/common_lib.h"
|
||||
#include "assertions.h"
|
||||
|
||||
/* help strings definition for command line options, used in CMDLINE_XXX_DESC macros and printed when -h option is used */
|
||||
|
||||
@@ -19,6 +19,11 @@ unsigned short config_frames[4] = {2,9,11,13};
|
||||
#include "openair2/E2AP/flexric/src/agent/e2_agent_api.h"
|
||||
#include "openair2/E2AP/RAN_FUNCTION/init_ran_func.h"
|
||||
#endif
|
||||
|
||||
#ifdef E3_AGENT
|
||||
#include "openair2/E3AP/e3_agent.h"
|
||||
#endif
|
||||
|
||||
#include "nr-softmodem.h"
|
||||
#include <common/utils/assertions.h>
|
||||
#include <openair2/GNB_APP/gnb_app.h>
|
||||
@@ -60,7 +65,6 @@ unsigned short config_frames[4] = {2,9,11,13};
|
||||
#include "nr-softmodem-common.h"
|
||||
#include "openair2/E1AP/e1ap_common.h"
|
||||
#include "pdcp.h"
|
||||
#include "radio/COMMON/common_lib.h"
|
||||
#include "s1ap_eNB.h"
|
||||
#include "sctp_eNB_task.h"
|
||||
#include "system.h"
|
||||
@@ -521,6 +525,13 @@ int main( int argc, char **argv ) {
|
||||
|
||||
softmodem_verify_mode(get_softmodem_params());
|
||||
|
||||
//////////////////////////////////
|
||||
//// Init the E3 Agent
|
||||
#ifdef E3_AGENT
|
||||
printf("Init E3 Agent\n");
|
||||
e3_init();
|
||||
#endif // E3_AGENT
|
||||
|
||||
#if T_TRACER
|
||||
T_Config_Init();
|
||||
#endif
|
||||
@@ -727,6 +738,11 @@ int main( int argc, char **argv ) {
|
||||
|
||||
time_manager_finish();
|
||||
|
||||
#ifdef E3_AGENT
|
||||
printf("Destroy E3 Agent\n");
|
||||
e3_destroy();
|
||||
#endif // E3_AGENT
|
||||
|
||||
free(pckg);
|
||||
logClean();
|
||||
printf("Bye.\n");
|
||||
|
||||
@@ -64,4 +64,6 @@ void init_eNB_afterRU(void);
|
||||
|
||||
void init_pdcp(void);
|
||||
|
||||
void fill_rf_config(RU_t *ru, char *rf_config_file);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -215,9 +215,8 @@ static void UE_synch(void *arg) {
|
||||
((ret.rx_offset << 1) / fp->samples_per_subframe * fp->slots_per_subframe)
|
||||
+ round((float)((ret.rx_offset << 1) % fp->samples_per_subframe) / fp->samples_per_slot0);
|
||||
|
||||
if (get_nrUE_params()->cont_fo_comp) {
|
||||
UE->freq_offset = freq_offset - UE->dl_Doppler_shift;
|
||||
} else {
|
||||
UE->freq_offset = freq_offset - UE->dl_Doppler_shift;
|
||||
if (!get_nrUE_params()->cont_fo_comp) {
|
||||
// rerun with new cell parameters and frequency-offset
|
||||
nrue_ru_set_freq(UE, ul_carrier, dl_carrier, freq_offset);
|
||||
}
|
||||
@@ -711,6 +710,18 @@ static inline int get_readBlockSize(uint16_t slot, const NR_DL_FRAME_PARMS *fp)
|
||||
return rem_samples + next_slot_first_symbol;
|
||||
}
|
||||
|
||||
void trs_freq_correction(PHY_VARS_NR_UE *ue, int cfo)
|
||||
{
|
||||
if (abs(cfo) > TRS_CFO_THRESH) {
|
||||
LOG_A(PHY, "CFO estimated (%d) from TRS exceeded threshold (%d). Adjusting radio CF\n", cfo, TRS_CFO_THRESH);
|
||||
ue->freq_offset += cfo;
|
||||
uint64_t dl_carrier;
|
||||
uint64_t ul_carrier;
|
||||
nr_get_carrier_frequencies(ue, &dl_carrier, &ul_carrier);
|
||||
nrue_ru_set_freq(ue, ul_carrier, dl_carrier, ue->freq_offset);
|
||||
}
|
||||
}
|
||||
|
||||
void *UE_thread(void *arg)
|
||||
{
|
||||
//this thread should be over the processing thread to keep in real time
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
#include "common/config/config_userapi.h"
|
||||
#include "common/utils/load_module_shlib.h"
|
||||
#include "common/utils/nr/nr_common.h"
|
||||
#include "radio/COMMON/common_lib.h"
|
||||
#include "radio/ETHERNET/if_defs.h"
|
||||
#include "openair1/PHY/MODULATION/nr_modulation.h"
|
||||
#include "PHY/CODING/nrLDPC_coding/nrLDPC_coding_interface.h"
|
||||
|
||||
@@ -24,7 +24,6 @@
|
||||
#include "PHY/types.h"
|
||||
|
||||
#include "PHY/defs_common.h"
|
||||
#include "radio/COMMON/common_lib.h"
|
||||
#include "radio/ETHERNET/ethernet_lib.h"
|
||||
|
||||
#include "PHY/if4_tools.h"
|
||||
@@ -562,7 +561,8 @@ void* ru_thread_control( void* param )
|
||||
|
||||
//if (ru->is_slave == 1) lte_sync_time_init(&ru->frame_parms);
|
||||
|
||||
if (ru->rfdevice.is_init != 1) openair0_device_load(&ru->rfdevice,&ru->openair0_cfg);
|
||||
int ret = openair0_device_load(&ru->rfdevice, &ru->openair0_cfg);
|
||||
AssertFatal(ret == 0, "could not load device library\n");
|
||||
|
||||
if (ru->rfdevice.trx_config_func) AssertFatal((ru->rfdevice.trx_config_func(&ru->rfdevice,&ru->openair0_cfg)==0),
|
||||
"Failed to configure RF device for RU %d\n",ru->idx);
|
||||
|
||||
@@ -223,12 +223,12 @@ void oru_fh_cleanup(void *handle)
|
||||
free(fh);
|
||||
}
|
||||
|
||||
int oru_fh_tx_read_symbol(void *handle, uint32_t **txdataF, int nb_tx, int *frame, int *slot, int *symbol)
|
||||
int oru_fh_tx_read_symbol(void *handle, uint32_t **txdataF, int nb_tx, uint64_t *hyper_frame, int *frame, int *slot, int *symbol)
|
||||
{
|
||||
if (!handle)
|
||||
return -1;
|
||||
oru_fh_t *fh = (oru_fh_t *)handle;
|
||||
read_dl_iq(fh->packet_processor, txdataF, nb_tx, frame, slot, symbol);
|
||||
read_dl_iq(fh->packet_processor, txdataF, nb_tx, hyper_frame, frame, slot, symbol);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -240,7 +240,7 @@ int oru_fh_get_ready_jobs(void *handle)
|
||||
return get_ready_job_count(fh->packet_processor);
|
||||
}
|
||||
|
||||
int oru_fh_get_utc_anchor_point(void *handle, uint32_t *frame, uint32_t *slot, struct timespec *ts)
|
||||
int oru_fh_get_utc_anchor_point(void *handle, uint64_t *hyper_frame, uint32_t *frame, uint32_t *slot, struct timespec *ts)
|
||||
{
|
||||
if (!handle || !frame || !slot || !ts)
|
||||
return -1;
|
||||
@@ -249,6 +249,7 @@ int oru_fh_get_utc_anchor_point(void *handle, uint32_t *frame, uint32_t *slot, s
|
||||
absolute_gps_symbol -= absolute_gps_symbol % NR_SYMBOLS_PER_SLOT; // Round down to start of current slot
|
||||
uint64_t absolute_slot = absolute_gps_symbol / NR_SYMBOLS_PER_SLOT;
|
||||
uint32_t slots_per_frame = 10 << fh->cfg.numerology;
|
||||
*hyper_frame = (absolute_slot / slots_per_frame) / 1024;
|
||||
*frame = (absolute_slot / slots_per_frame) % 1024;
|
||||
*slot = absolute_slot % slots_per_frame;
|
||||
|
||||
@@ -267,11 +268,17 @@ void oru_fh_rx_send_prach(void *handle, uint32_t **prachF, int nb_rx, int frame,
|
||||
write_prach_iq(fh->packet_processor, prachF, nb_rx, frame, slot, symbol);
|
||||
}
|
||||
|
||||
void oru_fh_rx_send_pusch(void *handle, uint32_t **puschF, int nb_rx, int frame, int slot, int symbol)
|
||||
int oru_fh_poll_ul_job(void *handle, ul_job_t *job) {
|
||||
oru_fh_t *fh = (oru_fh_t *)handle;
|
||||
AssertFatal(fh, "Invalid handle\n");
|
||||
return poll_ul_job(fh->packet_processor, job);
|
||||
}
|
||||
|
||||
void oru_fh_rx_send_pusch(void *handle, uint32_t *puschF, int symbol_index, const ul_job_t *job)
|
||||
{
|
||||
oru_fh_t *fh = (oru_fh_t *)handle;
|
||||
AssertFatal(fh, "Invalid handle\n");
|
||||
write_ul_iq(fh->packet_processor, puschF, nb_rx, frame, slot, symbol);
|
||||
write_ul_iq(fh->packet_processor, puschF, symbol_index, job);
|
||||
}
|
||||
|
||||
int oru_fh_start(void *handle)
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
#include "oru_io.h"
|
||||
#include <stdint.h>
|
||||
#include "oru_packet_processor.h"
|
||||
|
||||
typedef struct {
|
||||
char *dpdk_devices[MAX_RU_PORTS];
|
||||
@@ -74,23 +75,25 @@ int oru_fh_get_ready_jobs(void *handle);
|
||||
* @param handle Pointer to the fronthaul handle.
|
||||
* @param txdataF Array of pointers to buffers to store the received frequency-domain IQ samples (per TX antenna).
|
||||
* @param nb_tx Number of TX antennas.
|
||||
* @param hyper_frame Absolute GPS hyper-frame number
|
||||
* @param frame Pointer to store the frame number of the read symbol.
|
||||
* @param slot Pointer to store the slot number of the read symbol.
|
||||
* @param symbol Pointer to store the symbol number.
|
||||
* @return 0 on success or -1 on failure
|
||||
*/
|
||||
int oru_fh_tx_read_symbol(void *handle, uint32_t **txdataF, int nb_tx, int *frame, int *slot, int *symbol);
|
||||
int oru_fh_tx_read_symbol(void *handle, uint32_t **txdataF, int nb_tx, uint64_t *hyper_frame, int *frame, int *slot, int *symbol);
|
||||
|
||||
/**
|
||||
* @brief Get the UTC anchor point mapping between 5G time and system time.
|
||||
*
|
||||
* @param handle Pointer to the fronthaul handle.
|
||||
* @param frame Pointer to store the reference frame number.
|
||||
* @param hyper_frame Pointer to store the reference hyperframe number (1024 frames each)
|
||||
* @param slot Pointer to store the reference slot number.
|
||||
* @param ts Pointer to a timespec structure to store the corresponding system time.
|
||||
* @return 0 on success, negative on error.
|
||||
*/
|
||||
int oru_fh_get_utc_anchor_point(void *handle, uint32_t* frame, uint32_t* slot, struct timespec *ts);
|
||||
int oru_fh_get_utc_anchor_point(void *handle, uint64_t *hyper_frame, uint32_t* frame, uint32_t* slot, struct timespec *ts);
|
||||
|
||||
/**
|
||||
* @brief Send PRACH symbol data (U-Plane) over the Fronthaul interface.
|
||||
@@ -104,17 +107,25 @@ int oru_fh_get_utc_anchor_point(void *handle, uint32_t* frame, uint32_t* slot, s
|
||||
*/
|
||||
void oru_fh_rx_send_prach(void *handle, uint32_t **prachF, int nb_rx, int frame, int slot, int symbol);
|
||||
|
||||
/**
|
||||
* @brief Poll for pending UL jobs
|
||||
*
|
||||
* @param handle Pointer to the fronthaul handle.
|
||||
* @param job Job descriptor
|
||||
*
|
||||
* @returns 0 if successful, -1 otherwise
|
||||
*/
|
||||
int oru_fh_poll_ul_job(void *handle, ul_job_t *job);
|
||||
|
||||
/**
|
||||
* @brief Send PUSCH symbol data (U-Plane) over the Fronthaul interface.
|
||||
*
|
||||
* @param handle Pointer to the fronthaul handle.
|
||||
* @param puschF Array of pointers to buffers containing the frequency-domain PUSCH IQ samples.
|
||||
* @param nb_rx Number of RX antennas.
|
||||
* @param frame Target frame number.
|
||||
* @param slot Target slot number.
|
||||
* @param symbol Target symbol number.
|
||||
* @param symbol Absolute symbol index within slot (0–13); must be within the job's symbol range
|
||||
* @param job Job descriptor
|
||||
*/
|
||||
void oru_fh_rx_send_pusch(void *handle, uint32_t **puschF, int nb_rx, int frame, int slot, int symbol);
|
||||
void oru_fh_rx_send_pusch(void *handle, uint32_t *puschF, int symbol, const ul_job_t *job);
|
||||
|
||||
/**
|
||||
* @brief Start the O-RU Fronthaul processing threads and loops.
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <time.h>
|
||||
#include "assertions.h"
|
||||
#include "log.h"
|
||||
#include <rte_ring.h>
|
||||
@@ -16,8 +17,21 @@
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdatomic.h>
|
||||
|
||||
#define PRACH_ERR_LOG_RATELIMIT 10000
|
||||
|
||||
#define RATELIMIT(n, block) \
|
||||
do { \
|
||||
static _Atomic unsigned long counter = 0; \
|
||||
unsigned long current = atomic_fetch_add_explicit(&counter, 1, memory_order_relaxed); \
|
||||
if (current % (n) == 0) { \
|
||||
block \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define DL_JOB_RING_SIZE 128
|
||||
#define UL_JOB_RING_SIZE 128
|
||||
#define MAX_CONCURRENT_DL_JOBS (DL_JOB_RING_SIZE - 1)
|
||||
#define NUM_CONCURRENT_DL_SYMBOL_WINDOWS MAX_CONCURRENT_DL_JOBS
|
||||
#define NUM_CONCURRENT_UL_SYMBOL_WINDOWS 128
|
||||
@@ -28,13 +42,7 @@
|
||||
#define SYMBOL_BITMASK_SIZE ((NR_SYMBOLS_PER_SLOT * MAX_TDD_PATTERN_LENGTH_MS * MAX_SLOTS_PER_MS + 7) / 8)
|
||||
#define MAX_RX_FRAGMENTS 4
|
||||
#define MAX_MBUFS_PER_SYMBOL 64
|
||||
|
||||
typedef enum {
|
||||
SYM_UL_IDLE,
|
||||
SYM_UL_ACTIVE,
|
||||
SYM_UL_READY,
|
||||
SYM_UL_EMPTY,
|
||||
} ul_symbol_job_state_t;
|
||||
#define MAX_SLOTS_PER_FRAME 160
|
||||
|
||||
typedef struct {
|
||||
struct {
|
||||
@@ -54,43 +62,43 @@ typedef struct {
|
||||
} dl_symbol_job_t;
|
||||
|
||||
typedef struct {
|
||||
struct {
|
||||
bool cplane_received;
|
||||
int section_id;
|
||||
int num_prb;
|
||||
int start_prb;
|
||||
} per_antenna[MAX_ANTENNAS];
|
||||
uint64_t absolute_symbol;
|
||||
ul_symbol_job_state_t state;
|
||||
} ul_symbol_job_t;
|
||||
typedef struct {
|
||||
struct {
|
||||
bool cplane_received;
|
||||
int section_id;
|
||||
int num_prb;
|
||||
int start_prb;
|
||||
int filter_id;
|
||||
} per_antenna[MAX_ANTENNAS];
|
||||
uint64_t absolute_symbol;
|
||||
} prach_symbol_job_t;
|
||||
bool active;
|
||||
uint64_t start_absolute_symbol;
|
||||
uint32_t num_symbols;
|
||||
int section_id;
|
||||
int num_prb;
|
||||
int start_prb;
|
||||
int filter_id;
|
||||
} prach_job_t;
|
||||
typedef struct {
|
||||
_Atomic(uint64_t) dl_tdd_mismatch;
|
||||
_Atomic(uint64_t) ul_tdd_mismatch;
|
||||
_Atomic(uint64_t) ul_cplane_missing;
|
||||
_Atomic(uint64_t) prach_cplane_missing;
|
||||
_Atomic(uint64_t) prach_cplane_missing_ant;
|
||||
_Atomic(uint64_t) prach_cplane_missing_inactive;
|
||||
_Atomic(uint64_t) prach_cplane_missing_stale;
|
||||
_Atomic(uint64_t) prach_cplane_missing_early;
|
||||
_Atomic(uint64_t) prach_out_of_mbufs;
|
||||
_Atomic(uint64_t) prach_jobs_pool_exhausted;
|
||||
_Atomic(uint64_t) out_of_mbufs;
|
||||
_Atomic(uint64_t) total_uplane_sent;
|
||||
_Atomic(int64_t) ul_uplane_ota_delay_sum;
|
||||
_Atomic(uint64_t) ul_uplane_ota_delay_count;
|
||||
} thread_safe_stats_t;
|
||||
|
||||
typedef struct {
|
||||
dl_symbol_job_t dl_symbol_jobs[MAX_CONCURRENT_DL_JOBS];
|
||||
dl_symbol_job_t *dl_symbol_rx_window[NUM_CONCURRENT_DL_SYMBOL_WINDOWS];
|
||||
bool was_dl_symbol_completed[NUM_CONCURRENT_DL_SYMBOL_WINDOWS];
|
||||
ul_symbol_job_t ul_symbol_jobs[NUM_CONCURRENT_UL_SYMBOL_WINDOWS];
|
||||
prach_symbol_job_t prach_jobs[NUM_CONCURRENT_UL_SYMBOL_WINDOWS];
|
||||
prach_job_t prach_jobs[MAX_SLOTS_PER_FRAME][MAX_ANTENNAS];
|
||||
uint64_t current_absolute_symbol;
|
||||
uint64_t last_pushed_symbol;
|
||||
struct rte_ring *dl_free_jobs;
|
||||
struct rte_ring *dl_ready_jobs;
|
||||
struct rte_ring *ul_free_jobs;
|
||||
struct rte_ring *ul_ready_jobs;
|
||||
ul_job_t ul_jobs_pool[UL_JOB_RING_SIZE];
|
||||
uint32_t T2a_min_cp_sym_diff;
|
||||
uint32_t T2a_max_cp_sym_diff;
|
||||
uint32_t T2a_min_up_dl_sym_diff;
|
||||
@@ -169,6 +177,13 @@ void *init_packet_processor(int numerology,
|
||||
for (int i = 0; i < MAX_CONCURRENT_DL_JOBS; i++) {
|
||||
rte_ring_enqueue(ctx->dl_free_jobs, (void *)&ctx->dl_symbol_jobs[i]);
|
||||
}
|
||||
ctx->ul_ready_jobs = rte_ring_create("ul_ready_jobs", UL_JOB_RING_SIZE, rte_socket_id(), 0);
|
||||
AssertFatal(ctx->ul_ready_jobs != NULL, "Failed to create ring ul_ready_jobs\n");
|
||||
ctx->ul_free_jobs = rte_ring_create("ul_free_jobs", UL_JOB_RING_SIZE, rte_socket_id(), 0);
|
||||
AssertFatal(ctx->ul_free_jobs != NULL, "Failed to create ring ul_free_jobs\n");
|
||||
for (int i = 0; i < UL_JOB_RING_SIZE - 1; i++) {
|
||||
rte_ring_enqueue(ctx->ul_free_jobs, (void *)&ctx->ul_jobs_pool[i]);
|
||||
}
|
||||
|
||||
ctx->eaxcid_config = (struct xran_eaxcid_config){.mask_cuPortId = 0xF000,
|
||||
.mask_bandSectorId = 0x0F00,
|
||||
@@ -201,6 +216,12 @@ void cleanup_packet_processor(void *context)
|
||||
if (ctx->dl_free_jobs) {
|
||||
rte_ring_free(ctx->dl_free_jobs);
|
||||
}
|
||||
if (ctx->ul_ready_jobs) {
|
||||
rte_ring_free(ctx->ul_ready_jobs);
|
||||
}
|
||||
if (ctx->ul_free_jobs) {
|
||||
rte_ring_free(ctx->ul_free_jobs);
|
||||
}
|
||||
free(ctx);
|
||||
}
|
||||
}
|
||||
@@ -465,6 +486,7 @@ static void handle_dl_cplane_packet(oru_packet_processor_context_t *ctx,
|
||||
}
|
||||
if (job->per_antenna[ant_id].cplane_received) {
|
||||
ctx->stats.cplane_err_dup++;
|
||||
ctx->stats.cplane_err_dup_dl++;
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -507,30 +529,25 @@ static void handle_ul_cplane_packet(oru_packet_processor_context_t *ctx,
|
||||
ctx->stats.ul_tdd_mismatch++;
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < num_symbols; i++) {
|
||||
uint32_t job_index = (target_absolute_symbol + i) % NUM_CONCURRENT_UL_SYMBOL_WINDOWS;
|
||||
ul_symbol_job_t *job = &ctx->ul_symbol_jobs[job_index];
|
||||
if (job->state == SYM_UL_IDLE) {
|
||||
job->absolute_symbol = target_absolute_symbol + i;
|
||||
job->state = SYM_UL_ACTIVE;
|
||||
for (int j = 0; j < MAX_ANTENNAS; j++) {
|
||||
job->per_antenna[j].cplane_received = false;
|
||||
}
|
||||
} else if (job->state == SYM_UL_READY) {
|
||||
ctx->stats.application_too_slow++;
|
||||
return;
|
||||
}
|
||||
if (job->per_antenna[ant_id].cplane_received) {
|
||||
ctx->stats.cplane_err_dup++;
|
||||
return;
|
||||
}
|
||||
job->absolute_symbol = target_absolute_symbol + i;
|
||||
if (!job->per_antenna[ant_id].cplane_received) {
|
||||
job->per_antenna[ant_id].cplane_received = true;
|
||||
job->per_antenna[ant_id].section_id = section->hdr.u1.common.sectionId;
|
||||
job->per_antenna[ant_id].num_prb = section->hdr.u1.common.numPrbc == 0 ? ctx->num_prb : section->hdr.u1.common.numPrbc;
|
||||
job->per_antenna[ant_id].start_prb = section->hdr.u1.common.startPrbc;
|
||||
}
|
||||
ul_job_t *ul_job = NULL;
|
||||
if (rte_ring_dequeue(ctx->ul_free_jobs, (void **)&ul_job) == 0) {
|
||||
memset(ul_job, 0, sizeof(*ul_job));
|
||||
ul_job->response_payload.section_id = section->hdr.u1.common.sectionId;
|
||||
ul_job->response_payload.comp_method = hdr->udComp.udCompMeth;
|
||||
ul_job->response_payload.iq_width = hdr->udComp.udIqWidth == 0 ? 16 : hdr->udComp.udIqWidth;
|
||||
uint64_t absolute_gps_symbol = target_absolute_symbol;
|
||||
ul_job->hyper_frame = absolute_gps_symbol / (1024 * (10 * (1 << ctx->numerology) * 14));
|
||||
ul_job->frame = (absolute_gps_symbol / (10 * (1 << ctx->numerology) * 14)) % 1024;
|
||||
ul_job->slot_in_frame = (absolute_gps_symbol % (10 * (1 << ctx->numerology) * 14)) / 14;
|
||||
ul_job->symbol = absolute_gps_symbol % 14;
|
||||
ul_job->num_symbols = num_symbols;
|
||||
ul_job->antenna_id = ant_id;
|
||||
ul_job->num_prb = section->hdr.u1.common.numPrbc == 0 ? ctx->num_prb : section->hdr.u1.common.numPrbc;
|
||||
ul_job->start_prb = section->hdr.u1.common.startPrbc;
|
||||
int ret = rte_ring_enqueue(ctx->ul_ready_jobs, (void *)ul_job);
|
||||
AssertFatal(ret == 0, "Failed to enqueue ul_job to ul_ready_jobs ring\n");
|
||||
} else {
|
||||
ctx->stats.application_too_slow++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -541,6 +558,8 @@ void handle_prach_cplane_packet(oru_packet_processor_context_t *ctx,
|
||||
{
|
||||
if (hdr->cmnhdr.numOfSections != 1) {
|
||||
ctx->stats.cplane_err_hdr++;
|
||||
RATELIMIT(PRACH_ERR_LOG_RATELIMIT,
|
||||
{ LOG_W(HW, "PRACH CP: Invalid numOfSections %d (expected 1)\n", hdr->cmnhdr.numOfSections); });
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -550,11 +569,14 @@ void handle_prach_cplane_packet(oru_packet_processor_context_t *ctx,
|
||||
struct xran_cp_radioapp_section3 *section = (void *)rte_pktmbuf_adj(pkt, sizeof(struct xran_cp_radioapp_section3_header));
|
||||
if (section == NULL) {
|
||||
ctx->stats.cplane_err_hdr++;
|
||||
RATELIMIT(PRACH_ERR_LOG_RATELIMIT, { LOG_W(HW, "PRACH CP: Failed to adjust mbuf for section3 header\n"); });
|
||||
return;
|
||||
}
|
||||
*((uint64_t *)section) = rte_be_to_cpu_64(*((uint64_t *)section));
|
||||
int aarx = ant_id - ctx->prach_eaxc_offset;
|
||||
if (aarx < 0 || aarx >= MAX_ANTENNAS) {
|
||||
RATELIMIT(PRACH_ERR_LOG_RATELIMIT,
|
||||
{ LOG_W(HW, "PRACH CP: Invalid aarx %d (ant_id %d, eaxc_offset %d)\n", aarx, ant_id, ctx->prach_eaxc_offset); });
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -574,26 +596,34 @@ void handle_prach_cplane_packet(oru_packet_processor_context_t *ctx,
|
||||
txrx_window_histogram_count(&ctx->stats.prach_cplane_hist, diff);
|
||||
uint64_t target_absolute_symbol = ctx->current_absolute_symbol + diff;
|
||||
|
||||
for (int i = 0; i < num_symbols; i++) {
|
||||
uint32_t job_index = (target_absolute_symbol + i) % NUM_CONCURRENT_UL_SYMBOL_WINDOWS;
|
||||
prach_symbol_job_t *job = &ctx->prach_jobs[job_index];
|
||||
|
||||
if (job->absolute_symbol != target_absolute_symbol + i) {
|
||||
job->absolute_symbol = target_absolute_symbol + i;
|
||||
for (int j = 0; j < MAX_ANTENNAS; j++) {
|
||||
job->per_antenna[j].cplane_received = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (job->per_antenna[aarx].cplane_received) {
|
||||
continue;
|
||||
}
|
||||
job->per_antenna[aarx].cplane_received = true;
|
||||
job->per_antenna[aarx].section_id = section->hdr.u1.common.sectionId;
|
||||
job->per_antenna[aarx].num_prb = section->hdr.u1.common.numPrbc == 0 ? ctx->num_prb : section->hdr.u1.common.numPrbc;
|
||||
job->per_antenna[aarx].start_prb = section->hdr.u1.common.startPrbc;
|
||||
job->per_antenna[aarx].filter_id = hdr->cmnhdr.field.filterIndex;
|
||||
if (slot_in_frame < 0 || slot_in_frame >= MAX_SLOTS_PER_FRAME) {
|
||||
RATELIMIT(PRACH_ERR_LOG_RATELIMIT, { LOG_W(HW, "PRACH CP: Invalid slot_in_frame %d\n", slot_in_frame); });
|
||||
return;
|
||||
}
|
||||
|
||||
prach_job_t *job = &ctx->prach_jobs[slot_in_frame][aarx];
|
||||
if (job->active && job->start_absolute_symbol == target_absolute_symbol) {
|
||||
ctx->stats.cplane_err_dup++;
|
||||
ctx->stats.cplane_err_dup_prach++;
|
||||
RATELIMIT(PRACH_ERR_LOG_RATELIMIT, {
|
||||
LOG_W(HW, "PRACH CP: Duplicate packet for slot %d, aarx %d, start_symbol %lu\n", slot_in_frame, aarx, target_absolute_symbol);
|
||||
});
|
||||
return;
|
||||
}
|
||||
job->active = true;
|
||||
job->start_absolute_symbol = target_absolute_symbol;
|
||||
job->num_symbols = num_symbols;
|
||||
job->section_id = section->hdr.u1.common.sectionId;
|
||||
job->num_prb = section->hdr.u1.common.numPrbc == 0 ? ctx->num_prb : section->hdr.u1.common.numPrbc;
|
||||
job->start_prb = section->hdr.u1.common.startPrbc;
|
||||
job->filter_id = hdr->cmnhdr.field.filterIndex;
|
||||
RATELIMIT(PRACH_ERR_LOG_RATELIMIT, {
|
||||
LOG_A(HW,
|
||||
"PRACH JOB added slot_in_frame %d, aarx %d target_absolute_symbol %lu\n",
|
||||
slot_in_frame,
|
||||
aarx,
|
||||
target_absolute_symbol);
|
||||
});
|
||||
}
|
||||
|
||||
void handle_cplane_packet(void *context, void *pkt)
|
||||
@@ -633,20 +663,24 @@ void handle_cplane_packet(void *context, void *pkt)
|
||||
}
|
||||
*((uint64_t *)section) = rte_be_to_cpu_64(*((uint64_t *)section));
|
||||
if (hdr->cmnhdr.field.dataDirection == XRAN_DIR_DL) {
|
||||
ctx->stats.cplane_received_dl++;
|
||||
handle_dl_cplane_packet(ctx, pkt, hdr, section, ant_id);
|
||||
} else {
|
||||
ctx->stats.cplane_received_ul++;
|
||||
handle_ul_cplane_packet(ctx, pkt, hdr, section, ant_id);
|
||||
}
|
||||
rte_pktmbuf_free(pkt);
|
||||
return;
|
||||
}
|
||||
case XRAN_CP_SECTIONTYPE_3: {
|
||||
ctx->stats.cplane_received_prach++;
|
||||
struct xran_cp_radioapp_section3_header *hdr = (struct xran_cp_radioapp_section3_header *)apphdr;
|
||||
handle_prach_cplane_packet(ctx, pkt, hdr, ant_id);
|
||||
rte_pktmbuf_free(pkt);
|
||||
return;
|
||||
}
|
||||
default:
|
||||
ctx->stats.cplane_received_other++;
|
||||
rte_pktmbuf_free(pkt);
|
||||
return;
|
||||
}
|
||||
@@ -656,19 +690,38 @@ static void print_histogram(const char *name, txrx_histogram_t *hist, uint32_t w
|
||||
{
|
||||
if (hist->count == 0)
|
||||
return;
|
||||
printf(" %s (mean: %.2f symbols) window start: %u, end %u:\n", name, (double)hist->sum / hist->count, window_start, window_end);
|
||||
char buf[4096];
|
||||
int len = snprintf(buf,
|
||||
sizeof(buf),
|
||||
" %s (mean: %.2f symbols) window [%u, %u]:",
|
||||
name,
|
||||
(double)hist->sum / hist->count,
|
||||
window_start,
|
||||
window_end);
|
||||
bool first = true;
|
||||
for (int i = 0; i < HIST_SIZE; i++) {
|
||||
if (hist->hist[i] > 0) {
|
||||
int bucket = i - HIST_SIZE / 2;
|
||||
char bin_str[64];
|
||||
int bin_len = 0;
|
||||
if (i == 0) {
|
||||
printf(" <= %+d : %lu\n", bucket, hist->hist[i]);
|
||||
bin_len = snprintf(bin_str, sizeof(bin_str), "%s<=%+d:%lu", first ? " " : ", ", bucket, hist->hist[i]);
|
||||
} else if (i == HIST_SIZE - 1) {
|
||||
printf(" >= %+d : %lu\n", bucket, hist->hist[i]);
|
||||
bin_len = snprintf(bin_str, sizeof(bin_str), "%s>=%+d:%lu", first ? " " : ", ", bucket, hist->hist[i]);
|
||||
} else {
|
||||
printf(" %+d : %lu\n", bucket, hist->hist[i]);
|
||||
bin_len = snprintf(bin_str, sizeof(bin_str), "%s%+d:%lu", first ? " " : ", ", bucket, hist->hist[i]);
|
||||
}
|
||||
first = false;
|
||||
if (len + bin_len < sizeof(buf)) {
|
||||
strcpy(buf + len, bin_str);
|
||||
len += bin_len;
|
||||
} else {
|
||||
break; // buffer full
|
||||
}
|
||||
}
|
||||
}
|
||||
LOG_I(HW, "%s\n", buf);
|
||||
memset(hist, 0, sizeof(*hist));
|
||||
}
|
||||
|
||||
void print_packet_processor_stats(void *context)
|
||||
@@ -677,39 +730,73 @@ void print_packet_processor_stats(void *context)
|
||||
if (ctx == NULL)
|
||||
return;
|
||||
|
||||
printf("ORU Packet Processor Stats:\n");
|
||||
printf(" Total C-Plane Packets received: %lu\n", ctx->stats.total_cplane);
|
||||
printf(" Total U-Plane Packets received: %lu\n", ctx->stats.total_uplane_received);
|
||||
printf(" Total U-Plane Packets sent: %lu\n", ctx->thread_safe_stats.total_uplane_sent);
|
||||
LOG_I(HW, "ORU Packet Processor Stats:\n");
|
||||
LOG_I(HW,
|
||||
" Total C-Plane Packets received: %lu (DL: %lu, UL: %lu, PRACH: %lu, Other: %lu)\n",
|
||||
ctx->stats.total_cplane,
|
||||
ctx->stats.cplane_received_dl,
|
||||
ctx->stats.cplane_received_ul,
|
||||
ctx->stats.cplane_received_prach,
|
||||
ctx->stats.cplane_received_other);
|
||||
LOG_I(HW, " Total U-Plane Packets received: %lu\n", ctx->stats.total_uplane_received);
|
||||
LOG_I(HW, " Total U-Plane Packets sent: %lu\n", ctx->thread_safe_stats.total_uplane_sent);
|
||||
if (ctx->thread_safe_stats.ul_uplane_ota_delay_count > 0)
|
||||
LOG_I(HW,
|
||||
" UL U-Plane OTA delay (mean symbols): %.2f (%lu packets)\n",
|
||||
(double)(int64_t)ctx->thread_safe_stats.ul_uplane_ota_delay_sum
|
||||
/ (double)ctx->thread_safe_stats.ul_uplane_ota_delay_count,
|
||||
(uint64_t)ctx->thread_safe_stats.ul_uplane_ota_delay_count);
|
||||
|
||||
if (ctx->stats.cplane_err_hdr > 0)
|
||||
printf(" C-Plane Header Errors: %lu\n", ctx->stats.cplane_err_hdr);
|
||||
LOG_I(HW, " C-Plane Header Errors: %lu\n", ctx->stats.cplane_err_hdr);
|
||||
if (ctx->stats.cplane_err_ver > 0)
|
||||
printf(" C-Plane Protocol Version Errors: %lu\n", ctx->stats.cplane_err_ver);
|
||||
LOG_I(HW, " C-Plane Protocol Version Errors: %lu\n", ctx->stats.cplane_err_ver);
|
||||
if (ctx->stats.cplane_err_early > 0)
|
||||
printf(" C-Plane Timing Early Errors: %lu\n", ctx->stats.cplane_err_early);
|
||||
LOG_I(HW, " C-Plane Timing Early Errors: %lu\n", ctx->stats.cplane_err_early);
|
||||
if (ctx->stats.cplane_err_late > 0)
|
||||
printf(" C-Plane Timing Late Errors: %lu\n", ctx->stats.cplane_err_late);
|
||||
LOG_I(HW, " C-Plane Timing Late Errors: %lu\n", ctx->stats.cplane_err_late);
|
||||
if (ctx->stats.cplane_err_dup > 0)
|
||||
printf(" C-Plane Duplicate Packet Errors: %lu\n", ctx->stats.cplane_err_dup);
|
||||
LOG_I(HW,
|
||||
" C-Plane Duplicate Packet Errors: %lu (DL: %lu, UL: %lu, PRACH: %lu)\n",
|
||||
ctx->stats.cplane_err_dup,
|
||||
ctx->stats.cplane_err_dup_dl,
|
||||
ctx->stats.cplane_err_dup_ul,
|
||||
ctx->stats.cplane_err_dup_prach);
|
||||
if (ctx->stats.uplane_err_early > 0)
|
||||
printf(" U-Plane Timing Early Errors: %lu\n", ctx->stats.uplane_err_early);
|
||||
LOG_I(HW, " U-Plane Timing Early Errors: %lu\n", ctx->stats.uplane_err_early);
|
||||
if (ctx->stats.uplane_err_late > 0)
|
||||
printf(" U-Plane Timing Late Errors: %lu\n", ctx->stats.uplane_err_late);
|
||||
LOG_I(HW, " U-Plane Timing Late Errors: %lu\n", ctx->stats.uplane_err_late);
|
||||
if (ctx->stats.uplane_err_dup > 0)
|
||||
printf(" U-Plane Duplicate Packet Errors: %lu\n", ctx->stats.uplane_err_dup);
|
||||
LOG_I(HW, " U-Plane Duplicate Packet Errors: %lu\n", ctx->stats.uplane_err_dup);
|
||||
if (ctx->stats.uplane_missing_cplane > 0)
|
||||
printf(" U-Plane Missing C-Plane Errors: %lu\n", ctx->stats.uplane_missing_cplane);
|
||||
LOG_I(HW, " U-Plane Missing C-Plane Errors: %lu\n", ctx->stats.uplane_missing_cplane);
|
||||
if (ctx->stats.dl_tdd_mismatch + ctx->thread_safe_stats.dl_tdd_mismatch > 0)
|
||||
printf(" DL TDD Mismatch Errors: %lu\n", ctx->stats.dl_tdd_mismatch + ctx->thread_safe_stats.dl_tdd_mismatch);
|
||||
LOG_I(HW, " DL TDD Mismatch Errors: %lu\n", ctx->stats.dl_tdd_mismatch + ctx->thread_safe_stats.dl_tdd_mismatch);
|
||||
if (ctx->stats.ul_tdd_mismatch + ctx->thread_safe_stats.ul_tdd_mismatch > 0)
|
||||
printf(" UL TDD Mismatch Errors: %lu\n", ctx->stats.ul_tdd_mismatch + ctx->thread_safe_stats.ul_tdd_mismatch);
|
||||
LOG_I(HW, " UL TDD Mismatch Errors: %lu\n", ctx->stats.ul_tdd_mismatch + ctx->thread_safe_stats.ul_tdd_mismatch);
|
||||
if (ctx->stats.ul_cplane_missing + ctx->thread_safe_stats.ul_cplane_missing > 0)
|
||||
printf(" UL C-Plane Missing Errors: %lu\n", ctx->stats.ul_cplane_missing + ctx->thread_safe_stats.ul_cplane_missing);
|
||||
LOG_I(HW, " UL C-Plane Missing Errors: %lu\n", ctx->stats.ul_cplane_missing + ctx->thread_safe_stats.ul_cplane_missing);
|
||||
if (ctx->stats.prach_cplane_missing + ctx->thread_safe_stats.prach_cplane_missing > 0)
|
||||
LOG_I(HW,
|
||||
" PRACH C-Plane Missing Errors: %lu (Never Received: %lu, Stale: %lu, Early: %lu)\n",
|
||||
ctx->stats.prach_cplane_missing + ctx->thread_safe_stats.prach_cplane_missing,
|
||||
ctx->stats.prach_cplane_missing_inactive + ctx->thread_safe_stats.prach_cplane_missing_inactive,
|
||||
ctx->stats.prach_cplane_missing_stale + ctx->thread_safe_stats.prach_cplane_missing_stale,
|
||||
ctx->stats.prach_cplane_missing_early + ctx->thread_safe_stats.prach_cplane_missing_early);
|
||||
if (ctx->stats.prach_cplane_missing_ant + ctx->thread_safe_stats.prach_cplane_missing_ant > 0)
|
||||
LOG_I(HW,
|
||||
" PRACH Ant C-Plane Missing Errors: %lu\n",
|
||||
ctx->stats.prach_cplane_missing_ant + ctx->thread_safe_stats.prach_cplane_missing_ant);
|
||||
if (ctx->stats.prach_out_of_mbufs + ctx->thread_safe_stats.prach_out_of_mbufs > 0)
|
||||
LOG_I(HW, " PRACH Out Of Mbufs Errors: %lu\n", ctx->stats.prach_out_of_mbufs + ctx->thread_safe_stats.prach_out_of_mbufs);
|
||||
if (ctx->stats.prach_jobs_pool_exhausted + ctx->thread_safe_stats.prach_jobs_pool_exhausted > 0)
|
||||
LOG_I(HW,
|
||||
" PRACH Jobs Pool Exhausted Errors: %lu\n",
|
||||
ctx->stats.prach_jobs_pool_exhausted + ctx->thread_safe_stats.prach_jobs_pool_exhausted);
|
||||
if (ctx->stats.out_of_mbufs + ctx->thread_safe_stats.out_of_mbufs > 0)
|
||||
printf(" Out Of Mbufs Errors: %lu\n", ctx->stats.out_of_mbufs + ctx->thread_safe_stats.out_of_mbufs);
|
||||
LOG_I(HW, " Out Of Mbufs Errors: %lu\n", ctx->stats.out_of_mbufs + ctx->thread_safe_stats.out_of_mbufs);
|
||||
if (ctx->stats.application_too_slow > 0)
|
||||
printf(" Application Too Slow Errors: %lu\n", ctx->stats.application_too_slow);
|
||||
LOG_I(HW, " Application Too Slow Errors: %lu\n", ctx->stats.application_too_slow);
|
||||
|
||||
print_histogram("DL C-Plane", &ctx->stats.dl_cplane_hist, ctx->T2a_max_cp_sym_diff, ctx->T2a_min_cp_sym_diff);
|
||||
print_histogram("DL U-Plane", &ctx->stats.dl_uplane_hist, ctx->T2a_max_up_dl_sym_diff, ctx->T2a_min_up_dl_sym_diff);
|
||||
@@ -725,8 +812,17 @@ void get_packet_processor_stats(void *context, oru_packet_processor_stats_t *out
|
||||
out_stats->dl_tdd_mismatch += ctx->thread_safe_stats.dl_tdd_mismatch;
|
||||
out_stats->ul_tdd_mismatch += ctx->thread_safe_stats.ul_tdd_mismatch;
|
||||
out_stats->ul_cplane_missing += ctx->thread_safe_stats.ul_cplane_missing;
|
||||
out_stats->prach_cplane_missing += ctx->thread_safe_stats.prach_cplane_missing;
|
||||
out_stats->prach_cplane_missing_ant += ctx->thread_safe_stats.prach_cplane_missing_ant;
|
||||
out_stats->prach_cplane_missing_inactive += ctx->thread_safe_stats.prach_cplane_missing_inactive;
|
||||
out_stats->prach_cplane_missing_stale += ctx->thread_safe_stats.prach_cplane_missing_stale;
|
||||
out_stats->prach_cplane_missing_early += ctx->thread_safe_stats.prach_cplane_missing_early;
|
||||
out_stats->prach_out_of_mbufs += ctx->thread_safe_stats.prach_out_of_mbufs;
|
||||
out_stats->prach_jobs_pool_exhausted += ctx->thread_safe_stats.prach_jobs_pool_exhausted;
|
||||
out_stats->out_of_mbufs += ctx->thread_safe_stats.out_of_mbufs;
|
||||
out_stats->total_uplane_sent = ctx->thread_safe_stats.total_uplane_sent;
|
||||
out_stats->ul_uplane_ota_delay_sum += ctx->thread_safe_stats.ul_uplane_ota_delay_sum;
|
||||
out_stats->ul_uplane_ota_delay_count += ctx->thread_safe_stats.ul_uplane_ota_delay_count;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -739,7 +835,7 @@ static void unpack_iq(c16_t *txdataF, void *iqdata, int start_prb, int num_prb)
|
||||
}
|
||||
}
|
||||
|
||||
void read_dl_iq(void *context, uint32_t **txdataF, int nb_tx, int *frame, int *slot, int *symbol)
|
||||
void read_dl_iq(void *context, uint32_t **txdataF, int nb_tx, uint64_t *hyper_frame, int *frame, int *slot, int *symbol)
|
||||
{
|
||||
oru_packet_processor_context_t *ctx = (oru_packet_processor_context_t *)context;
|
||||
if (ctx == NULL)
|
||||
@@ -754,6 +850,7 @@ void read_dl_iq(void *context, uint32_t **txdataF, int nb_tx, int *frame, int *s
|
||||
uint64_t absolute_gps_symbol = job->absolute_symbol;
|
||||
int numerology = ctx->numerology;
|
||||
int num_symbols_per_frame = NR_NUMBER_OF_SUBFRAMES_PER_FRAME * (1 << numerology) * NR_SYMBOLS_PER_SLOT;
|
||||
*hyper_frame = (absolute_gps_symbol / num_symbols_per_frame) / 1024;
|
||||
*frame = (absolute_gps_symbol / num_symbols_per_frame) % 1024;
|
||||
*slot = (absolute_gps_symbol % num_symbols_per_frame) / NR_SYMBOLS_PER_SLOT;
|
||||
*symbol = absolute_gps_symbol % NR_SYMBOLS_PER_SLOT;
|
||||
@@ -834,11 +931,142 @@ void fill_data_section_header(struct data_section_hdr *data_section_hdr, int num
|
||||
data_section_hdr->fields.all_bits = rte_cpu_to_be_32(data_section_hdr->fields.all_bits);
|
||||
}
|
||||
|
||||
void write_ul_iq(void *context, uint32_t **txdataF, int nb_rx, int frame, int slot_in_frame, int symbol)
|
||||
int poll_ul_job(void *context, ul_job_t *job)
|
||||
{
|
||||
oru_packet_processor_context_t *ctx = (oru_packet_processor_context_t *)context;
|
||||
if (ctx == NULL || job == NULL) {
|
||||
return -1;
|
||||
}
|
||||
ul_job_t *dequeued_job = NULL;
|
||||
if (rte_ring_dequeue(ctx->ul_ready_jobs, (void **)&dequeued_job) == 0) {
|
||||
*job = *dequeued_job;
|
||||
rte_ring_enqueue(ctx->ul_free_jobs, (void *)dequeued_job);
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void write_ul_iq(void *context, uint32_t *rxdataF, int symbol, const ul_job_t *job)
|
||||
{
|
||||
oru_packet_processor_context_t *ctx = (oru_packet_processor_context_t *)context;
|
||||
if (ctx == NULL || job == NULL)
|
||||
return;
|
||||
AssertFatal(symbol >= job->symbol && symbol < job->symbol + job->num_symbols && symbol < NR_SYMBOLS_PER_SLOT,
|
||||
"Symbol %d outside of job range [%d, %d)\n",
|
||||
symbol,
|
||||
job->symbol,
|
||||
job->symbol + job->num_symbols);
|
||||
|
||||
// Delay from OTA symbol to packet send: current timer symbol minus the absolute symbol of this UL symbol.
|
||||
const int slots_per_frame = NR_NUMBER_OF_SUBFRAMES_PER_FRAME * (1 << ctx->numerology);
|
||||
const uint64_t ota_absolute_symbol = (uint64_t)job->hyper_frame * 1024ULL * slots_per_frame * NR_SYMBOLS_PER_SLOT
|
||||
+ (uint64_t)job->frame * slots_per_frame * NR_SYMBOLS_PER_SLOT
|
||||
+ (uint64_t)job->slot_in_frame * NR_SYMBOLS_PER_SLOT
|
||||
+ (uint64_t)symbol;
|
||||
int64_t delay = (int64_t)ctx->current_absolute_symbol - (int64_t)ota_absolute_symbol;
|
||||
atomic_fetch_add_explicit(&ctx->thread_safe_stats.ul_uplane_ota_delay_sum, delay, memory_order_relaxed);
|
||||
atomic_fetch_add_explicit(&ctx->thread_safe_stats.ul_uplane_ota_delay_count, 1, memory_order_relaxed);
|
||||
|
||||
int aarx = job->antenna_id;
|
||||
if (aarx < 0 || aarx >= MAX_ANTENNAS) {
|
||||
LOG_W(HW, "ORU: Invalid antenna index %d\n", aarx);
|
||||
return;
|
||||
}
|
||||
|
||||
const bool use_comp = (job->response_payload.comp_method != 0);
|
||||
|
||||
int section_id = job->response_payload.section_id;
|
||||
int total_ul_rbs = job->num_prb;
|
||||
int start_prb_base = job->start_prb;
|
||||
int frame = job->frame;
|
||||
int slot_in_frame = job->slot_in_frame;
|
||||
int mu = ctx->numerology;
|
||||
|
||||
struct rte_mbuf *mbufs[MAX_MBUFS_PER_SYMBOL];
|
||||
uint32_t num_mbufs = 0;
|
||||
|
||||
int rbs_sent = 0;
|
||||
size_t overhead = sizeof(struct rte_ether_hdr) + sizeof(struct xran_ecpri_hdr) + sizeof(struct radio_app_common_hdr)
|
||||
+ sizeof(struct data_section_hdr);
|
||||
if (use_comp) {
|
||||
overhead += sizeof(struct data_section_compression_hdr);
|
||||
}
|
||||
int max_prb_per_packet = (int)((ctx->mtu - overhead) / (NR_NB_SC_PER_RB * sizeof(int32_t)));
|
||||
|
||||
while (rbs_sent < total_ul_rbs) {
|
||||
int num_ul_rbs = total_ul_rbs - rbs_sent;
|
||||
if (num_ul_rbs > max_prb_per_packet) {
|
||||
num_ul_rbs = max_prb_per_packet;
|
||||
}
|
||||
|
||||
struct rte_mbuf *pkt = ctx->alloc_func(ctx->io_controller);
|
||||
if (pkt == NULL) {
|
||||
ctx->thread_safe_stats.out_of_mbufs++;
|
||||
break;
|
||||
}
|
||||
|
||||
size_t header_length = sizeof(struct xran_ecpri_hdr) + sizeof(struct radio_app_common_hdr) + sizeof(struct data_section_hdr);
|
||||
if (use_comp) {
|
||||
header_length += sizeof(struct data_section_compression_hdr);
|
||||
}
|
||||
const uint num_sc = num_ul_rbs * NR_NB_SC_PER_RB;
|
||||
size_t data_len = sizeof(int32_t) * num_sc;
|
||||
|
||||
char *buf = rte_pktmbuf_append(pkt, (uint16_t)(header_length + data_len));
|
||||
if (buf == NULL) {
|
||||
LOG_W(HW, "ORU: Failed to append data to mbuf (insufficient space)\n");
|
||||
rte_pktmbuf_free(pkt);
|
||||
break;
|
||||
}
|
||||
|
||||
if (num_mbufs == (MAX_MBUFS_PER_SYMBOL - 1)) {
|
||||
ctx->send_func(ctx->io_controller, mbufs, num_mbufs);
|
||||
ctx->thread_safe_stats.total_uplane_sent += num_mbufs;
|
||||
num_mbufs = 0;
|
||||
}
|
||||
mbufs[num_mbufs++] = pkt;
|
||||
|
||||
struct xran_ecpri_hdr *ecpri_header = (struct xran_ecpri_hdr *)buf;
|
||||
uint16_t ecpri_payload_size = (uint16_t)(header_length - 4 + data_len);
|
||||
fill_ecpri_header(ecpri_header, &ctx->eaxcid_config, ECPRI_IQ_DATA, ecpri_payload_size, 0, aarx, ctx->pusch_seq_id[aarx]++, 0);
|
||||
|
||||
struct radio_app_common_hdr *radio_app_header = (struct radio_app_common_hdr *)(ecpri_header + 1);
|
||||
fill_radio_app_header(radio_app_header, 0, XRAN_DIR_UL, frame, slot_in_frame, symbol, mu);
|
||||
|
||||
struct data_section_hdr *data_section_header = (struct data_section_hdr *)(radio_app_header + 1);
|
||||
fill_data_section_header(data_section_header, num_ul_rbs, start_prb_base + rbs_sent, section_id);
|
||||
|
||||
void *iq_data_start;
|
||||
if (use_comp) {
|
||||
struct data_section_compression_hdr *compression_header = (struct data_section_compression_hdr *)(data_section_header + 1);
|
||||
compression_header->ud_comp_hdr.ud_comp_meth = job->response_payload.comp_method;
|
||||
compression_header->ud_comp_hdr.ud_iq_width = XRAN_CONVERT_IQWIDTH(job->response_payload.iq_width);
|
||||
compression_header->rsrvd = 0;
|
||||
iq_data_start = (void *)(compression_header + 1);
|
||||
} else {
|
||||
iq_data_start = (void *)(data_section_header + 1);
|
||||
}
|
||||
|
||||
uint16_t *src = (uint16_t *)&rxdataF[(start_prb_base + rbs_sent) * NR_NB_SC_PER_RB];
|
||||
uint16_t *dst = (uint16_t *)iq_data_start;
|
||||
for (int i = 0; i < num_sc * 2; i++) {
|
||||
*dst++ = rte_cpu_to_be_16(*src++);
|
||||
}
|
||||
rbs_sent += num_ul_rbs;
|
||||
}
|
||||
|
||||
if (num_mbufs > 0) {
|
||||
ctx->send_func(ctx->io_controller, mbufs, num_mbufs);
|
||||
ctx->thread_safe_stats.total_uplane_sent += num_mbufs;
|
||||
}
|
||||
}
|
||||
|
||||
void write_prach_iq(void *context, uint32_t **txdataF, int nb_rx, int frame, int slot_in_frame, int symbol)
|
||||
{
|
||||
oru_packet_processor_context_t *ctx = (oru_packet_processor_context_t *)context;
|
||||
if (ctx == NULL)
|
||||
return;
|
||||
|
||||
int numerology = ctx->numerology;
|
||||
int num_symbols_per_frame = NR_NUMBER_OF_SUBFRAMES_PER_FRAME * (1 << numerology) * NR_SYMBOLS_PER_SLOT;
|
||||
uint32_t current_symbol_in_frame = ctx->current_absolute_symbol % num_symbols_per_frame;
|
||||
@@ -850,135 +1078,56 @@ void write_ul_iq(void *context, uint32_t **txdataF, int nb_rx, int frame, int sl
|
||||
diff -= num_symbols_per_frame;
|
||||
}
|
||||
uint64_t target_absolute_symbol = ctx->current_absolute_symbol + diff;
|
||||
bool is_ul_symbol = test_bit(ctx->ul_symbol_bitmask, target_absolute_symbol % ctx->symbol_bitmask_length);
|
||||
if (!is_ul_symbol) {
|
||||
ctx->thread_safe_stats.ul_tdd_mismatch++;
|
||||
return;
|
||||
}
|
||||
ul_symbol_job_t *job = &ctx->ul_symbol_jobs[target_absolute_symbol % NUM_CONCURRENT_UL_SYMBOL_WINDOWS];
|
||||
if (job->state == SYM_UL_IDLE) {
|
||||
ctx->thread_safe_stats.ul_cplane_missing++;
|
||||
return;
|
||||
}
|
||||
int mu = ctx->numerology;
|
||||
struct rte_mbuf *mbufs[MAX_MBUFS_PER_SYMBOL];
|
||||
uint32_t num_mbufs = 0;
|
||||
for (int aarx = 0; aarx < nb_rx; aarx++) {
|
||||
if (!job->per_antenna[aarx].cplane_received) {
|
||||
ctx->thread_safe_stats.ul_cplane_missing++;
|
||||
continue;
|
||||
}
|
||||
int section_id = job->per_antenna[aarx].section_id;
|
||||
int total_ul_rbs = job->per_antenna[aarx].num_prb;
|
||||
int start_prb_base = job->per_antenna[aarx].start_prb;
|
||||
|
||||
int rbs_sent = 0;
|
||||
size_t overhead = sizeof(struct rte_ether_hdr) + sizeof(struct xran_ecpri_hdr) + sizeof(struct radio_app_common_hdr)
|
||||
+ sizeof(struct data_section_hdr) + sizeof(struct data_section_compression_hdr);
|
||||
int max_prb_per_packet = (int)((ctx->mtu - overhead) / (NR_NB_SC_PER_RB * sizeof(int32_t)));
|
||||
|
||||
while (rbs_sent < total_ul_rbs) {
|
||||
int num_ul_rbs = total_ul_rbs - rbs_sent;
|
||||
if (num_ul_rbs > max_prb_per_packet) {
|
||||
num_ul_rbs = max_prb_per_packet;
|
||||
}
|
||||
|
||||
struct rte_mbuf *pkt = ctx->alloc_func(ctx->io_controller);
|
||||
if (pkt == NULL) {
|
||||
ctx->thread_safe_stats.out_of_mbufs++;
|
||||
break;
|
||||
}
|
||||
|
||||
size_t header_length = sizeof(struct xran_ecpri_hdr) + sizeof(struct radio_app_common_hdr) + sizeof(struct data_section_hdr)
|
||||
+ sizeof(struct data_section_compression_hdr);
|
||||
const uint num_sc = num_ul_rbs * NR_NB_SC_PER_RB;
|
||||
size_t data_len = sizeof(int32_t) * num_sc;
|
||||
|
||||
char *buf = rte_pktmbuf_append(pkt, (uint16_t)(header_length + data_len));
|
||||
if (buf == NULL) {
|
||||
LOG_W(HW, "ORU: Failed to append data to mbuf (insufficient space)\n");
|
||||
rte_pktmbuf_free(pkt);
|
||||
// Do not increment rbs_sent, just break and let the next symbol or antenna be processed,
|
||||
// or we could reduce max_prb_per_packet. Breaking is safer to prevent infinite loop.
|
||||
break;
|
||||
}
|
||||
|
||||
if (num_mbufs == (MAX_MBUFS_PER_SYMBOL - 1)) {
|
||||
ctx->send_func(ctx->io_controller, mbufs, num_mbufs);
|
||||
ctx->thread_safe_stats.total_uplane_sent += num_mbufs;
|
||||
num_mbufs = 0;
|
||||
}
|
||||
mbufs[num_mbufs++] = pkt;
|
||||
|
||||
struct xran_ecpri_hdr *ecpri_header = (struct xran_ecpri_hdr *)buf;
|
||||
// eCPRI payload size excludes the 4-byte common header
|
||||
uint16_t ecpri_payload_size = (uint16_t)(header_length - 4 + data_len);
|
||||
fill_ecpri_header(ecpri_header,
|
||||
&ctx->eaxcid_config,
|
||||
ECPRI_IQ_DATA,
|
||||
ecpri_payload_size,
|
||||
0,
|
||||
aarx,
|
||||
ctx->pusch_seq_id[aarx]++,
|
||||
0);
|
||||
|
||||
struct radio_app_common_hdr *radio_app_header = (struct radio_app_common_hdr *)(ecpri_header + 1);
|
||||
fill_radio_app_header(radio_app_header, 0, XRAN_DIR_UL, frame, slot_in_frame, symbol, mu);
|
||||
|
||||
struct data_section_hdr *data_section_header = (struct data_section_hdr *)(radio_app_header + 1);
|
||||
fill_data_section_header(data_section_header, num_ul_rbs, start_prb_base + rbs_sent, section_id);
|
||||
|
||||
struct data_section_compression_hdr *compression_header = (struct data_section_compression_hdr *)(data_section_header + 1);
|
||||
compression_header->ud_comp_hdr.ud_comp_meth = 0;
|
||||
compression_header->ud_comp_hdr.ud_iq_width = XRAN_CONVERT_IQWIDTH(16);
|
||||
compression_header->rsrvd = 0;
|
||||
|
||||
void *iq_data_start = (void *)(compression_header + 1);
|
||||
uint16_t *src = (uint16_t *)&txdataF[aarx][(start_prb_base + rbs_sent) * NR_NB_SC_PER_RB];
|
||||
uint16_t *dst = (uint16_t *)iq_data_start;
|
||||
for (int i = 0; i < num_sc * 2; i++) {
|
||||
*dst++ = rte_cpu_to_be_16(*src++);
|
||||
}
|
||||
rbs_sent += num_ul_rbs;
|
||||
}
|
||||
}
|
||||
ctx->send_func(ctx->io_controller, mbufs, num_mbufs);
|
||||
ctx->thread_safe_stats.total_uplane_sent += num_mbufs;
|
||||
for (int i = 0; i < MAX_ANTENNAS; i++) {
|
||||
job->per_antenna[i].cplane_received = false;
|
||||
}
|
||||
job->state = SYM_UL_IDLE;
|
||||
}
|
||||
|
||||
void write_prach_iq(void *context, uint32_t **txdataF, int nb_rx, int frame, int slot_in_frame, int symbol)
|
||||
{
|
||||
oru_packet_processor_context_t *ctx = (oru_packet_processor_context_t *)context;
|
||||
if (ctx == NULL)
|
||||
return;
|
||||
|
||||
int mu = ctx->numerology;
|
||||
uint64_t absolute_symbol = (frame * NR_NUMBER_OF_SUBFRAMES_PER_FRAME * (1 << mu) + slot_in_frame) * NR_SYMBOLS_PER_SLOT + symbol;
|
||||
uint32_t job_index = absolute_symbol % NUM_CONCURRENT_UL_SYMBOL_WINDOWS;
|
||||
prach_symbol_job_t *job = &ctx->prach_jobs[job_index];
|
||||
|
||||
if (job->absolute_symbol != absolute_symbol)
|
||||
return;
|
||||
|
||||
struct rte_mbuf *mbufs[MAX_MBUFS_PER_SYMBOL];
|
||||
uint32_t num_mbufs = 0;
|
||||
|
||||
for (int aarx = 0; aarx < nb_rx; aarx++) {
|
||||
if (!job->per_antenna[aarx].cplane_received)
|
||||
if (slot_in_frame < 0 || slot_in_frame >= MAX_SLOTS_PER_FRAME) {
|
||||
RATELIMIT(PRACH_ERR_LOG_RATELIMIT, { LOG_W(HW, "PRACH UP: Invalid slot_in_frame %d\n", slot_in_frame); });
|
||||
continue;
|
||||
}
|
||||
prach_job_t *job = &ctx->prach_jobs[slot_in_frame][aarx];
|
||||
if (!job->active || target_absolute_symbol < job->start_absolute_symbol
|
||||
|| target_absolute_symbol >= job->start_absolute_symbol + job->num_symbols) {
|
||||
ctx->thread_safe_stats.prach_cplane_missing++;
|
||||
if (!job->active) {
|
||||
ctx->thread_safe_stats.prach_cplane_missing_inactive++;
|
||||
RATELIMIT(PRACH_ERR_LOG_RATELIMIT,
|
||||
{ LOG_W(HW, "PRACH UP: Missing C-Plane - Inactive job for slot %d, aarx %d\n", slot_in_frame, aarx); });
|
||||
} else if (target_absolute_symbol < job->start_absolute_symbol) {
|
||||
ctx->thread_safe_stats.prach_cplane_missing_early++;
|
||||
RATELIMIT(PRACH_ERR_LOG_RATELIMIT, {
|
||||
LOG_W(HW,
|
||||
"PRACH UP: Missing C-Plane - Early symbol %lu (job start %lu) for slot %d, aarx %d\n",
|
||||
target_absolute_symbol,
|
||||
job->start_absolute_symbol,
|
||||
slot_in_frame,
|
||||
aarx);
|
||||
});
|
||||
} else {
|
||||
ctx->thread_safe_stats.prach_cplane_missing_stale++;
|
||||
RATELIMIT(PRACH_ERR_LOG_RATELIMIT, {
|
||||
LOG_W(HW,
|
||||
"PRACH UP: Missing C-Plane - Stale symbol %lu (job end %lu) for slot %d, aarx %d\n",
|
||||
target_absolute_symbol,
|
||||
job->start_absolute_symbol + job->num_symbols,
|
||||
slot_in_frame,
|
||||
aarx);
|
||||
});
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
int section_id = job->per_antenna[aarx].section_id;
|
||||
int num_ul_rbs = job->per_antenna[aarx].num_prb;
|
||||
int start_prb = job->per_antenna[aarx].start_prb;
|
||||
int filter_id = job->per_antenna[aarx].filter_id;
|
||||
int section_id = job->section_id;
|
||||
int num_ul_rbs = job->num_prb;
|
||||
int start_prb = job->start_prb;
|
||||
int filter_id = job->filter_id;
|
||||
|
||||
struct rte_mbuf *pkt = ctx->alloc_func(ctx->io_controller);
|
||||
if (pkt == NULL) {
|
||||
ctx->thread_safe_stats.prach_out_of_mbufs++;
|
||||
ctx->thread_safe_stats.out_of_mbufs++;
|
||||
RATELIMIT(PRACH_ERR_LOG_RATELIMIT, { LOG_W(HW, "PRACH UP: Failed to allocate mbuf\n"); });
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -988,7 +1137,10 @@ void write_prach_iq(void *context, uint32_t **txdataF, int nb_rx, int frame, int
|
||||
|
||||
char *buf = rte_pktmbuf_append(pkt, (uint16_t)(header_length + data_len));
|
||||
if (buf == NULL) {
|
||||
ctx->thread_safe_stats.prach_out_of_mbufs++;
|
||||
ctx->thread_safe_stats.out_of_mbufs++;
|
||||
rte_pktmbuf_free(pkt);
|
||||
RATELIMIT(PRACH_ERR_LOG_RATELIMIT, { LOG_W(HW, "PRACH UP: Failed to append data to mbuf\n"); });
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1007,7 +1159,7 @@ void write_prach_iq(void *context, uint32_t **txdataF, int nb_rx, int frame, int
|
||||
0);
|
||||
|
||||
struct radio_app_common_hdr *radio_app_header = (struct radio_app_common_hdr *)(ecpri_header + 1);
|
||||
fill_radio_app_header(radio_app_header, filter_id, XRAN_DIR_UL, frame, slot_in_frame, symbol, mu);
|
||||
fill_radio_app_header(radio_app_header, filter_id, XRAN_DIR_UL, frame, slot_in_frame, symbol, numerology);
|
||||
|
||||
struct data_section_hdr *data_section_header = (struct data_section_hdr *)(radio_app_header + 1);
|
||||
fill_data_section_header(data_section_header, num_ul_rbs, start_prb, section_id);
|
||||
@@ -1018,8 +1170,6 @@ void write_prach_iq(void *context, uint32_t **txdataF, int nb_rx, int frame, int
|
||||
for (int i = 0; i < prach_length * 2; i++) {
|
||||
*dst++ = rte_cpu_to_be_16(*src++);
|
||||
}
|
||||
|
||||
job->per_antenna[aarx].cplane_received = false;
|
||||
}
|
||||
|
||||
if (num_mbufs > 0) {
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
* SPDX-License-Identifier: LicenseRef-CSSL-1.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
@@ -17,8 +19,30 @@ typedef struct {
|
||||
uint64_t count;
|
||||
} txrx_histogram_t;
|
||||
|
||||
typedef struct {
|
||||
int section_id;
|
||||
int comp_method;
|
||||
int iq_width;
|
||||
} opaque_response_data_t;
|
||||
|
||||
typedef struct {
|
||||
opaque_response_data_t response_payload;
|
||||
uint64_t hyper_frame;
|
||||
int frame;
|
||||
int slot_in_frame;
|
||||
int symbol;
|
||||
int num_symbols;
|
||||
int antenna_id;
|
||||
int start_prb;
|
||||
int num_prb;
|
||||
} ul_job_t;
|
||||
|
||||
typedef struct {
|
||||
uint64_t total_cplane;
|
||||
uint64_t cplane_received_dl;
|
||||
uint64_t cplane_received_ul;
|
||||
uint64_t cplane_received_prach;
|
||||
uint64_t cplane_received_other;
|
||||
uint64_t total_uplane_received;
|
||||
uint64_t total_uplane_sent;
|
||||
uint64_t cplane_err_hdr; // apphdr or section extraction
|
||||
@@ -26,6 +50,9 @@ typedef struct {
|
||||
uint64_t cplane_err_early;
|
||||
uint64_t cplane_err_late;
|
||||
uint64_t cplane_err_dup; // duplicate cplane
|
||||
uint64_t cplane_err_dup_dl;
|
||||
uint64_t cplane_err_dup_ul;
|
||||
uint64_t cplane_err_dup_prach;
|
||||
uint64_t uplane_err_late;
|
||||
uint64_t uplane_err_early;
|
||||
uint64_t uplane_err_dup;
|
||||
@@ -35,10 +62,19 @@ typedef struct {
|
||||
uint64_t ul_tdd_mismatch;
|
||||
uint64_t out_of_mbufs;
|
||||
uint64_t ul_cplane_missing;
|
||||
uint64_t prach_cplane_missing;
|
||||
uint64_t prach_cplane_missing_ant;
|
||||
uint64_t prach_cplane_missing_inactive;
|
||||
uint64_t prach_cplane_missing_stale;
|
||||
uint64_t prach_cplane_missing_early;
|
||||
uint64_t prach_out_of_mbufs;
|
||||
uint64_t prach_jobs_pool_exhausted;
|
||||
txrx_histogram_t dl_uplane_hist;
|
||||
txrx_histogram_t dl_cplane_hist;
|
||||
txrx_histogram_t ul_cplane_hist;
|
||||
txrx_histogram_t prach_cplane_hist;
|
||||
int64_t ul_uplane_ota_delay_sum;
|
||||
uint64_t ul_uplane_ota_delay_count;
|
||||
} oru_packet_processor_stats_t;
|
||||
|
||||
typedef void *(*alloc_func_t)(void *io_controller);
|
||||
@@ -60,7 +96,7 @@ void *init_packet_processor(int numerology,
|
||||
void *io_controller,
|
||||
size_t mtu,
|
||||
int prach_eaxc_offset);
|
||||
void write_ul_iq(void *context, uint32_t **txdataF, int nb_rx, int frame, int slot_in_frame, int symbol);
|
||||
void write_ul_iq(void *context, uint32_t *rxdataF, int symbol, const ul_job_t *job);
|
||||
void write_prach_iq(void *context, uint32_t **txdataF, int nb_rx, int frame, int slot_in_frame, int symbol);
|
||||
void cleanup_packet_processor(void *context);
|
||||
void handle_absolute_symbol_tick(void *context, uint64_t absolute_symbol);
|
||||
@@ -68,8 +104,9 @@ void handle_uplane_packet(void *context, void *pkt);
|
||||
void handle_cplane_packet(void *context, void *pkt);
|
||||
void print_packet_processor_stats(void *context);
|
||||
void get_packet_processor_stats(void *context, oru_packet_processor_stats_t *out_stats);
|
||||
void read_dl_iq(void *context, uint32_t **txdataF, int nb_tx, int *frame, int *slot, int *symbol);
|
||||
void read_dl_iq(void *context, uint32_t **txdataF, int nb_tx, uint64_t *hyper_frame, int *frame, int *slot, int *symbol);
|
||||
int get_ready_job_count(void *context);
|
||||
int poll_ul_job(void *context, ul_job_t *job);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -25,10 +25,10 @@ target_link_libraries(test_oru_pcap PRIVATE oru_packet_processor log_headers ${d
|
||||
target_include_directories(test_oru_pcap PRIVATE ${dpdk_INCLUDE_DIRS} ${PCAP_INCLUDE_DIRS})
|
||||
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/run_oru_pcap_test.sh DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
add_test(NAME test_oru_pcap_1 COMMAND ${CMAKE_CURRENT_BINARY_DIR}/run_oru_pcap_test.sh https://gitlab.eurecom.fr/api/v4/projects/7026/packages/generic/fhi72-pcaps/1.0.0/capture-oai-odu-4x4-273prb-truncated.pcap.xz $<TARGET_FILE:test_oru_pcap> 1090 3 1 6 4 5 9600 4 -- ${DPDK_TEST_ARGS} "--file-prefix=test_oru_pcap_1")
|
||||
add_test(NAME test_oru_pcap_1 COMMAND ${CMAKE_CURRENT_BINARY_DIR}/run_oru_pcap_test.sh https://github.com/bpodrygajlo/openairinterface5g/releases/download/fhi72-pcaps/capture-oai-odu-4x4-273prb-truncated.pcap.xz $<TARGET_FILE:test_oru_pcap> 1090 3 1 6 4 5 9600 4 -- ${DPDK_TEST_ARGS} "--file-prefix=test_oru_pcap_1")
|
||||
set_property(TEST test_oru_pcap_1 PROPERTY LABELS fronthaul)
|
||||
|
||||
add_test(NAME test_oru_pcap_frag COMMAND ${CMAKE_CURRENT_BINARY_DIR}/run_oru_pcap_test.sh https://gitlab.eurecom.fr/api/v4/projects/7026/packages/generic/fhi72-pcaps/1.0.0/capture-oai-odu-4x4-273prb-truncated.pcap.xz $<TARGET_FILE:test_oru_pcap> 1090 3 1 6 4 5 1500 4 -- ${DPDK_TEST_ARGS} "--file-prefix=test_oru_pcap_frag")
|
||||
add_test(NAME test_oru_pcap_frag COMMAND ${CMAKE_CURRENT_BINARY_DIR}/run_oru_pcap_test.sh https://github.com/bpodrygajlo/openairinterface5g/releases/download/fhi72-pcaps/capture-oai-odu-4x4-273prb-truncated.pcap.xz $<TARGET_FILE:test_oru_pcap> 1090 3 1 6 4 5 1500 4 -- ${DPDK_TEST_ARGS} "--file-prefix=test_oru_pcap_frag")
|
||||
set_property(TEST test_oru_pcap_frag PROPERTY LABELS fronthaul)
|
||||
|
||||
add_dependencies(tests test_oru_pcap)
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <unistd.h>
|
||||
#include "common/config/config_userapi.h"
|
||||
#include <rte_eal.h>
|
||||
#include <assert.h>
|
||||
|
||||
// OAI Linkage Satisfiers
|
||||
void exit_function(const char *file, const char *function, const int line, const char *s, const int assertflag)
|
||||
@@ -84,20 +85,32 @@ int main(int argc, char **argv)
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Testing UTC Anchor Point and Hyper-frame
|
||||
printf("Testing UTC Anchor Point and Hyper-frame...\n");
|
||||
uint64_t hf;
|
||||
uint32_t f, s;
|
||||
struct timespec ts;
|
||||
if (oru_fh_get_utc_anchor_point(handle, &hf, &f, &s, &ts) < 0) {
|
||||
fprintf(stderr, "FAIL: oru_fh_get_utc_anchor_point failed\n");
|
||||
oru_fh_cleanup(handle);
|
||||
return 1;
|
||||
}
|
||||
printf("UTC Anchor Point: hf=%lu, f=%u, s=%u, ts=%ld.%09ld\n", hf, f, s, ts.tv_sec, ts.tv_nsec);
|
||||
assert(f < 1024);
|
||||
assert(s < (10 << cfg.numerology));
|
||||
|
||||
printf("Running live loop for 2 seconds...\n");
|
||||
uint32_t *txData[1];
|
||||
txData[0] = malloc(273 * 12 * sizeof(uint32_t));
|
||||
for (int i = 0; i < 2000; i++) {
|
||||
if (i % 400 == 0) {
|
||||
oru_fh_rx_send_pusch(handle, txData, 1, 0, i / 400, 0);
|
||||
}
|
||||
|
||||
uint64_t start_cycles = rte_get_timer_cycles();
|
||||
uint64_t target_cycles = start_cycles + (rte_get_timer_hz() / 1000);
|
||||
while (rte_get_timer_cycles() < target_cycles) {
|
||||
int f, s, sym;
|
||||
uint64_t hf;
|
||||
while (oru_fh_get_ready_jobs(handle) > 0) {
|
||||
oru_fh_tx_read_symbol(handle, txData, 1, &f, &s, &sym);
|
||||
oru_fh_tx_read_symbol(handle, txData, 1, &hf, &f, &s, &sym);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -235,8 +235,9 @@ void test_cplane_uplane_match()
|
||||
txdataF[0] = output_iq;
|
||||
|
||||
int frame, slot, symbol;
|
||||
uint64_t hyper_frame;
|
||||
do {
|
||||
read_dl_iq(ctx, txdataF, 1, &frame, &slot, &symbol);
|
||||
read_dl_iq(ctx, txdataF, 1, &hyper_frame, &frame, &slot, &symbol);
|
||||
} while (!(frame == (target_sym / num_symbols_per_frame) % 1024 && symbol == target_sym % 14));
|
||||
|
||||
assert(symbol == target_sym % 14);
|
||||
@@ -343,8 +344,9 @@ void test_frame_wrap_around()
|
||||
txdataF[0] = output_iq;
|
||||
|
||||
int frame, slot, symbol;
|
||||
uint64_t hyper_frame;
|
||||
do {
|
||||
read_dl_iq(ctx, txdataF, 1, &frame, &slot, &symbol);
|
||||
read_dl_iq(ctx, txdataF, 1, &hyper_frame, &frame, &slot, &symbol);
|
||||
} while (!(frame == (target_sym / num_symbols_per_frame) % 1024 && symbol == target_sym % 14));
|
||||
|
||||
assert(frame == (target_sym / num_symbols_per_frame) % 1024);
|
||||
@@ -456,9 +458,10 @@ void test_cplane_14_symbols()
|
||||
|
||||
for (int i = 0; i < 14; i++) {
|
||||
int frame, slot, symbol;
|
||||
uint64_t hyper_frame;
|
||||
uint64_t sym_i = target_sym + i;
|
||||
do {
|
||||
read_dl_iq(ctx, txdataF, 1, &frame, &slot, &symbol);
|
||||
read_dl_iq(ctx, txdataF, 1, &hyper_frame, &frame, &slot, &symbol);
|
||||
} while (!(frame == (sym_i / num_symbols_per_frame) % 1024 && symbol == sym_i % 14));
|
||||
|
||||
assert(frame == (sym_i / num_symbols_per_frame) % 1024);
|
||||
@@ -566,8 +569,9 @@ void test_other_bw_4ant_prb_offset()
|
||||
txdataF[3] = out_iq3;
|
||||
|
||||
int frame, slot, symbol;
|
||||
uint64_t hyper_frame;
|
||||
do {
|
||||
read_dl_iq(ctx, txdataF, 4, &frame, &slot, &symbol);
|
||||
read_dl_iq(ctx, txdataF, 4, &hyper_frame, &frame, &slot, &symbol);
|
||||
} while (!(frame == frameId && symbol == startSymbolId));
|
||||
|
||||
// Verify memory contents for each antenna
|
||||
@@ -611,7 +615,7 @@ void test_send_mbuf_no_frag(void *io_controller, struct rte_mbuf **mbufs, uint32
|
||||
sent_sec->fields.all_bits = rte_be_to_cpu_32(sent_sec->fields.all_bits);
|
||||
|
||||
size_t expected_header_len = sizeof(struct xran_ecpri_hdr) + sizeof(struct radio_app_common_hdr)
|
||||
+ sizeof(struct data_section_hdr) + sizeof(struct data_section_compression_hdr);
|
||||
+ sizeof(struct data_section_hdr);
|
||||
|
||||
// In this test, we expect exactly 20 PRBs in a single packet
|
||||
assert(sent_sec->fields.num_prbu == (uint8_t)XRAN_CONVERT_NUMPRBC(20));
|
||||
@@ -659,7 +663,7 @@ void test_send_mbuf_frag(void *io_controller, struct rte_mbuf **mbufs, uint32_t
|
||||
sent_sec->fields.all_bits = rte_be_to_cpu_32(sent_sec->fields.all_bits);
|
||||
|
||||
size_t expected_header_len = sizeof(struct xran_ecpri_hdr) + sizeof(struct radio_app_common_hdr)
|
||||
+ sizeof(struct data_section_hdr) + sizeof(struct data_section_compression_hdr);
|
||||
+ sizeof(struct data_section_hdr);
|
||||
|
||||
if (g_packets_sent == 1) {
|
||||
// First fragment: 30 PRBs
|
||||
@@ -688,7 +692,7 @@ void test_send_mbuf_large_mtu(void *io_controller, struct rte_mbuf **mbufs, uint
|
||||
sent_sec->fields.all_bits = rte_be_to_cpu_32(sent_sec->fields.all_bits);
|
||||
|
||||
size_t expected_header_len = sizeof(struct xran_ecpri_hdr) + sizeof(struct radio_app_common_hdr)
|
||||
+ sizeof(struct data_section_hdr) + sizeof(struct data_section_compression_hdr);
|
||||
+ sizeof(struct data_section_hdr);
|
||||
|
||||
// With MTU 9600, 100 PRBs should fit in a single packet
|
||||
assert(g_packets_sent == 1);
|
||||
@@ -721,7 +725,7 @@ void test_send_mbuf_prb_offset(void *io_controller, struct rte_mbuf **mbufs, uin
|
||||
|
||||
// Check data: should match the offset in txdataF
|
||||
uint32_t *iq =
|
||||
(uint32_t *)((uint8_t *)sent_sec + sizeof(struct data_section_hdr) + sizeof(struct data_section_compression_hdr));
|
||||
(uint32_t *)((uint8_t *)sent_sec + sizeof(struct data_section_hdr));
|
||||
assert(rte_be_to_cpu_32(iq[0]) == 0x10101010);
|
||||
|
||||
rte_pktmbuf_free(mbuf);
|
||||
@@ -779,15 +783,20 @@ void test_uplink_basic()
|
||||
|
||||
handle_cplane_packet(ctx, c_mbuf);
|
||||
|
||||
// 2. Call write_ul_iq
|
||||
uint32_t *txdataF[1];
|
||||
// 2. Poll the UL job created by handle_cplane_packet and call write_ul_iq
|
||||
ul_job_t job;
|
||||
int poll_ret = poll_ul_job(ctx, &job);
|
||||
assert(poll_ret == 0);
|
||||
assert(job.num_prb == 20);
|
||||
assert(job.start_prb == 0);
|
||||
assert(job.antenna_id == 0);
|
||||
|
||||
uint32_t iq_input[100 * 12];
|
||||
for (int i = 0; i < 100 * 12; i++) {
|
||||
iq_input[i] = 0x11223344;
|
||||
}
|
||||
txdataF[0] = iq_input;
|
||||
|
||||
write_ul_iq(ctx, txdataF, 1, frameId, slot_in_frame, startSymbolId);
|
||||
write_ul_iq(ctx, iq_input, startSymbolId, &job);
|
||||
|
||||
oru_packet_processor_stats_t stats;
|
||||
get_packet_processor_stats(ctx, &stats);
|
||||
@@ -850,15 +859,20 @@ void test_uplink_fragmentation()
|
||||
|
||||
handle_cplane_packet(ctx, c_mbuf);
|
||||
|
||||
// 2. Call write_ul_iq
|
||||
uint32_t *txdataF[1];
|
||||
// 2. Poll the UL job created by handle_cplane_packet and call write_ul_iq
|
||||
ul_job_t job;
|
||||
int poll_ret = poll_ul_job(ctx, &job);
|
||||
assert(poll_ret == 0);
|
||||
assert(job.num_prb == 40);
|
||||
assert(job.start_prb == 0);
|
||||
assert(job.antenna_id == 0);
|
||||
|
||||
uint32_t iq_input[100 * 12];
|
||||
for (int i = 0; i < 100 * 12; i++) {
|
||||
iq_input[i] = 0x11223344;
|
||||
}
|
||||
txdataF[0] = iq_input;
|
||||
|
||||
write_ul_iq(ctx, txdataF, 1, frameId, slot_in_frame, startSymbolId);
|
||||
write_ul_iq(ctx, iq_input, startSymbolId, &job);
|
||||
|
||||
oru_packet_processor_stats_t stats;
|
||||
get_packet_processor_stats(ctx, &stats);
|
||||
@@ -936,15 +950,20 @@ void test_uplink_large_mtu()
|
||||
|
||||
handle_cplane_packet(ctx, c_mbuf);
|
||||
|
||||
// 2. Call write_ul_iq
|
||||
uint32_t *txdataF[1];
|
||||
// 2. Poll the UL job created by handle_cplane_packet and call write_ul_iq
|
||||
ul_job_t job;
|
||||
int poll_ret = poll_ul_job(ctx, &job);
|
||||
assert(poll_ret == 0);
|
||||
assert(job.num_prb == 100);
|
||||
assert(job.start_prb == 0);
|
||||
assert(job.antenna_id == 0);
|
||||
|
||||
uint32_t iq_input[num_prb * 12];
|
||||
for (int i = 0; i < num_prb * 12; i++) {
|
||||
iq_input[i] = 0x55667788;
|
||||
}
|
||||
txdataF[0] = iq_input;
|
||||
|
||||
write_ul_iq(ctx, txdataF, 1, frameId, slot_in_frame, startSymbolId);
|
||||
write_ul_iq(ctx, iq_input, startSymbolId, &job);
|
||||
|
||||
oru_packet_processor_stats_t stats;
|
||||
get_packet_processor_stats(ctx, &stats);
|
||||
@@ -1021,14 +1040,19 @@ void test_uplink_prb_offset()
|
||||
|
||||
handle_cplane_packet(ctx, c_mbuf);
|
||||
|
||||
// 2. Call write_ul_iq
|
||||
uint32_t *txdataF[1];
|
||||
// 2. Poll the UL job created by handle_cplane_packet and call write_ul_iq
|
||||
ul_job_t job;
|
||||
int poll_ret = poll_ul_job(ctx, &job);
|
||||
assert(poll_ret == 0);
|
||||
assert(job.num_prb == 20);
|
||||
assert(job.start_prb == 10);
|
||||
assert(job.antenna_id == 0);
|
||||
|
||||
uint32_t iq_input[100 * 12];
|
||||
memset(iq_input, 0, sizeof(iq_input));
|
||||
iq_input[10 * 12] = 0x10101010; // Mark PRB 10
|
||||
txdataF[0] = iq_input;
|
||||
|
||||
write_ul_iq(ctx, txdataF, 1, frameId, slot_in_frame, startSymbolId);
|
||||
write_ul_iq(ctx, iq_input, startSymbolId, &job);
|
||||
|
||||
oru_packet_processor_stats_t stats;
|
||||
get_packet_processor_stats(ctx, &stats);
|
||||
@@ -1129,6 +1153,102 @@ void test_prach_generation()
|
||||
printf("PRACH generation passed!\n");
|
||||
}
|
||||
|
||||
void test_hyper_frame_calculation()
|
||||
{
|
||||
printf("Testing hyper-frame calculation...\n");
|
||||
int mu = 1; // 30kHz
|
||||
int slots_per_subframe = 1 << mu;
|
||||
void *ctx = init_packet_processor(mu, 273, 200, 400, 100, 300, 2, 2, 0, 0, 5, test_alloc_mbuf, test_send_mbuf, NULL, 1500, 0);
|
||||
assert(ctx != NULL);
|
||||
|
||||
int num_symbols_per_frame = 10 * slots_per_subframe * 14; // 280
|
||||
|
||||
// One hyper-frame has 1024 frames. So 1024 * 280 = 286720 symbols.
|
||||
// Target absolute symbol index: 3 * 286720 + 5 * 280 + 1 * 14 + 7 = 860160 + 1400 + 14 + 7 = 861581.
|
||||
uint64_t target_sym = 861581;
|
||||
uint64_t current_sym = target_sym - 7;
|
||||
handle_absolute_symbol_tick(ctx, current_sym);
|
||||
|
||||
// 1. Send C-plane packet for target_sym
|
||||
struct rte_mbuf *c_mbuf = rte_pktmbuf_alloc(mp);
|
||||
struct xran_ecpri_hdr *ecpri = (struct xran_ecpri_hdr *)rte_pktmbuf_append(c_mbuf, sizeof(struct xran_ecpri_hdr));
|
||||
ecpri->ecpri_xtc_id = xran_compose_cid(&g_eaxcid_config, 0, 0, 0, 0);
|
||||
|
||||
struct xran_cp_radioapp_section1_header *apphdr =
|
||||
(struct xran_cp_radioapp_section1_header *)rte_pktmbuf_append(c_mbuf, sizeof(struct xran_cp_radioapp_section1_header));
|
||||
memset(apphdr, 0, sizeof(*apphdr));
|
||||
apphdr->cmnhdr.field.dataDirection = XRAN_DIR_DL;
|
||||
apphdr->cmnhdr.field.payloadVer = XRAN_PAYLOAD_VER;
|
||||
|
||||
apphdr->cmnhdr.field.frameId = (target_sym / num_symbols_per_frame) % 256;
|
||||
int slot_in_frame = (target_sym % num_symbols_per_frame) / 14;
|
||||
apphdr->cmnhdr.field.subframeId = slot_in_frame / slots_per_subframe;
|
||||
apphdr->cmnhdr.field.slotId = slot_in_frame % slots_per_subframe;
|
||||
apphdr->cmnhdr.field.startSymbolId = target_sym % 14;
|
||||
apphdr->cmnhdr.sectionType = XRAN_CP_SECTIONTYPE_1;
|
||||
apphdr->cmnhdr.field.all_bits = rte_cpu_to_be_32(apphdr->cmnhdr.field.all_bits);
|
||||
|
||||
struct xran_cp_radioapp_section1 *sec =
|
||||
(struct xran_cp_radioapp_section1 *)rte_pktmbuf_append(c_mbuf, sizeof(struct xran_cp_radioapp_section1));
|
||||
memset(sec, 0, sizeof(*sec));
|
||||
sec->hdr.u.s1.numSymbol = 1;
|
||||
sec->hdr.u1.common.numPrbc = 1;
|
||||
*((uint64_t *)sec) = rte_be_to_cpu_64(*((uint64_t *)sec));
|
||||
|
||||
handle_cplane_packet(ctx, c_mbuf);
|
||||
|
||||
// 2. Send U-plane packet for target_sym
|
||||
current_sym += 3;
|
||||
handle_absolute_symbol_tick(ctx, current_sym);
|
||||
|
||||
struct rte_mbuf *u_mbuf = rte_pktmbuf_alloc(mp);
|
||||
struct xran_ecpri_hdr *u_ecpri = (struct xran_ecpri_hdr *)rte_pktmbuf_append(u_mbuf, sizeof(struct xran_ecpri_hdr));
|
||||
u_ecpri->ecpri_xtc_id = xran_compose_cid(&g_eaxcid_config, 0, 0, 0, 0);
|
||||
|
||||
struct radio_app_common_hdr *u_app =
|
||||
(struct radio_app_common_hdr *)rte_pktmbuf_append(u_mbuf, sizeof(struct radio_app_common_hdr));
|
||||
u_app->frame_id = (target_sym / num_symbols_per_frame) % 256;
|
||||
u_app->sf_slot_sym.subframe_id = slot_in_frame / slots_per_subframe;
|
||||
u_app->sf_slot_sym.slot_id = slot_in_frame % slots_per_subframe;
|
||||
u_app->sf_slot_sym.symb_id = target_sym % 14;
|
||||
u_app->sf_slot_sym.value = rte_cpu_to_be_16(u_app->sf_slot_sym.value);
|
||||
|
||||
struct data_section_hdr *u_data = (struct data_section_hdr *)rte_pktmbuf_append(u_mbuf, sizeof(struct data_section_hdr));
|
||||
u_data->fields.num_prbu = 1;
|
||||
u_data->fields.start_prbu = 0;
|
||||
u_data->fields.sect_id = 0;
|
||||
u_data->fields.all_bits = rte_cpu_to_be_32(u_data->fields.all_bits);
|
||||
|
||||
// IQ Data
|
||||
uint16_t *iq = (uint16_t *)rte_pktmbuf_append(u_mbuf, 1 * 12 * 4);
|
||||
assert(iq != NULL);
|
||||
iq[0] = 0xAAAA;
|
||||
|
||||
handle_uplane_packet(ctx, u_mbuf);
|
||||
|
||||
// 3. Advance to trigger window expiry and job completion
|
||||
current_sym += 10;
|
||||
handle_absolute_symbol_tick(ctx, current_sym);
|
||||
|
||||
uint32_t *txdataF[1] = {0};
|
||||
uint32_t output_iq[273 * 12] = {0};
|
||||
txdataF[0] = output_iq;
|
||||
|
||||
int frame, slot, symbol;
|
||||
uint64_t hyper_frame = 0xFFFFFFFF;
|
||||
do {
|
||||
read_dl_iq(ctx, txdataF, 1, &hyper_frame, &frame, &slot, &symbol);
|
||||
} while (!(frame == (target_sym / num_symbols_per_frame) % 1024 && symbol == target_sym % 14));
|
||||
|
||||
assert(hyper_frame == 3);
|
||||
assert(frame == 5);
|
||||
assert(slot == 1);
|
||||
assert(symbol == 7);
|
||||
|
||||
cleanup_packet_processor(ctx);
|
||||
printf("Hyper-frame calculation test passed!\n");
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
setup_dpdk(argc, argv);
|
||||
@@ -1155,6 +1275,8 @@ int main(int argc, char **argv)
|
||||
usleep(10000);
|
||||
test_prach_generation();
|
||||
usleep(10000);
|
||||
test_hyper_frame_calculation();
|
||||
usleep(10000);
|
||||
|
||||
printf("All tests passed!\n");
|
||||
return 0;
|
||||
|
||||
@@ -197,16 +197,23 @@ int main(int argc, char *argv[])
|
||||
|
||||
// For UL verification, we call write_ul_iq for every symbol.
|
||||
// It will internally check TDD and UL C-plane presence.
|
||||
ul_job_t job;
|
||||
int poll_ret = poll_ul_job(ctx, &job);
|
||||
if (poll_ret == 0) {
|
||||
for (int i = 0; i < job.num_symbols; i++) {
|
||||
write_ul_iq(ctx, txdataF[0], job.symbol + i, &job);
|
||||
}
|
||||
}
|
||||
int frame = (s / 280) % 1024;
|
||||
int slot = (s / 14) % 20;
|
||||
int sym = s % 14;
|
||||
write_ul_iq(ctx, txdataF, MAX_ANTENNAS, frame, slot, sym);
|
||||
write_prach_iq(ctx, txdataF, MAX_ANTENNAS, frame, slot, sym);
|
||||
|
||||
// Drain ready jobs to prevent ring overflow
|
||||
int f, sl, sy;
|
||||
uint64_t hf;
|
||||
while (get_ready_job_count(ctx) > 0) {
|
||||
read_dl_iq(ctx, txdataF, MAX_ANTENNAS, &f, &sl, &sy);
|
||||
read_dl_iq(ctx, txdataF, MAX_ANTENNAS, &hf, &f, &sl, &sy);
|
||||
}
|
||||
}
|
||||
last_tick_sym = current_sym;
|
||||
@@ -230,16 +237,11 @@ int main(int argc, char *argv[])
|
||||
// Flush remaining symbols
|
||||
for (int i = 0; i < 100; i++) {
|
||||
handle_absolute_symbol_tick(ctx, ++last_tick_sym);
|
||||
int frame = (last_tick_sym / 280) % 1024;
|
||||
int slot = (last_tick_sym / 14) % 20;
|
||||
int sym = last_tick_sym % 14;
|
||||
write_ul_iq(ctx, txdataF, MAX_ANTENNAS, frame, slot, sym);
|
||||
write_prach_iq(ctx, txdataF, MAX_ANTENNAS, frame, slot, sym);
|
||||
|
||||
// Drain ready jobs to prevent ring overflow during flush
|
||||
int f, sl, sy;
|
||||
uint64_t hf;
|
||||
while (get_ready_job_count(ctx) > 0) {
|
||||
read_dl_iq(ctx, txdataF, MAX_ANTENNAS, &f, &sl, &sy);
|
||||
read_dl_iq(ctx, txdataF, MAX_ANTENNAS, &hf, &f, &sl, &sy);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1747,10 +1747,13 @@ void stop_nr_nfapi_vnf()
|
||||
}
|
||||
}
|
||||
|
||||
void configure_nr_nfapi_vnf(eth_params_t params)
|
||||
void configure_nr_nfapi_vnf(const char *vnf_addr, uint16_t vnf_p5_port, uint16_t vnf_p7_port)
|
||||
{
|
||||
#ifndef ENABLE_AERIAL
|
||||
nfapi_setmode(NFAPI_MODE_VNF);
|
||||
#else
|
||||
UNUSED(vnf_addr);
|
||||
UNUSED(vnf_p7_port);
|
||||
#endif
|
||||
vnf_info *vnf = calloc(1, sizeof(vnf_info));
|
||||
memset(vnf->p7_vnfs, 0, sizeof(vnf->p7_vnfs));
|
||||
@@ -1759,22 +1762,21 @@ void configure_nr_nfapi_vnf(eth_params_t params)
|
||||
vnf->p7_vnfs[0].aperiodic_timing_enabled = 0;
|
||||
vnf->p7_vnfs[0].periodic_timing_period = 1;
|
||||
vnf->p7_vnfs[0].config = nfapi_vnf_p7_config_create();
|
||||
AssertFatal(params.remote_portc == 0 && params.remote_portd == 0, "remote ports not used, use 0\n");
|
||||
#ifndef ENABLE_AERIAL
|
||||
NFAPI_TRACE(NFAPI_TRACE_INFO,
|
||||
"[VNF] %s() vnf->p7_vnfs[0].config:%p VNF ADDRESS:%s:%d\n",
|
||||
__FUNCTION__,
|
||||
vnf->p7_vnfs[0].config,
|
||||
params.my_addr,
|
||||
params.my_portc);
|
||||
strcpy(vnf->p7_vnfs[0].local_addr, params.my_addr);
|
||||
vnf->p7_vnfs[0].local_port = params.my_portd;
|
||||
vnf_addr,
|
||||
vnf_p5_port);
|
||||
strcpy(vnf->p7_vnfs[0].local_addr, vnf_addr);
|
||||
vnf->p7_vnfs[0].local_port = vnf_p7_port;
|
||||
#endif
|
||||
vnf->p7_vnfs[0].mac = malloc(sizeof(mac_t));
|
||||
config = nfapi_vnf_config_create();
|
||||
config->malloc = malloc;
|
||||
config->free = free;
|
||||
config->vnf_p5_port = params.my_portc;
|
||||
config->vnf_p5_port = vnf_p5_port;
|
||||
config->vnf_ipv4 = 1;
|
||||
config->vnf_ipv6 = 0;
|
||||
config->pnf_list = 0;
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
|
||||
#ifndef NFAPI_VNF_H_
|
||||
#define NFAPI_VNF_H_
|
||||
#include <common_lib.h>
|
||||
|
||||
#include "nfapi_vnf_interface.h"
|
||||
typedef struct {
|
||||
@@ -130,7 +129,7 @@ typedef struct {
|
||||
} vnf_info;
|
||||
|
||||
void configure_nfapi_vnf(char *vnf_addr, int vnf_p5_port, char *pnf_ip_addr, int pnf_p7_port, int vnf_p7_port);
|
||||
void configure_nr_nfapi_vnf(eth_params_t params);
|
||||
void configure_nr_nfapi_vnf(const char *vnf_addr, uint16_t vnf_p5_port, uint16_t vnf_p7_port);
|
||||
void stop_nr_nfapi_vnf();
|
||||
nfapi_vnf_config_t *get_config();
|
||||
vnf_p7_t *get_p7_vnf();
|
||||
|
||||
@@ -463,6 +463,7 @@ typedef struct {
|
||||
uint8_t power_control_offset; // Ratio of PDSCH EPRE to NZP CSI-RSEPRE [3GPP TS 38.214, sec 5.2.2.3.1], Value: 0->23 representing -8 to 15 dB in 1dB steps; 255: L1 is configured with ProfileSSS
|
||||
uint8_t power_control_offset_ss; // Ratio of NZP CSI-RS EPRE to SSB/PBCH block EPRE [3GPP TS 38.214, sec 5.2.2.3.1], Values: 0: -3dB; 1: 0dB; 2: 3dB; 3: 6dB; 255: L1 is configured with ProfileSSS
|
||||
uint8_t measurement_bitmap; // bit 0 RSRP, bit 1 RI, bit 2 LI, bit 3 PMI, bit 4 CQI, bit 5 i1
|
||||
uint8_t last_trs_slot; // indicates to PHY if the slot is end of TRS burst
|
||||
} fapi_nr_dl_config_csirs_pdu_rel15_t;
|
||||
|
||||
typedef enum{vrb_to_prb_mapping_non_interleaved = 0, vrb_to_prb_mapping_interleaved = 1} vrb_to_prb_mapping_t;
|
||||
|
||||
@@ -67,7 +67,7 @@ int nr_get_ssb_start_symbol(const NR_DL_FRAME_PARMS *fp, uint8_t i_ssb)
|
||||
return symbol;
|
||||
}
|
||||
|
||||
static void set_scs_parameters(NR_DL_FRAME_PARMS *fp, int mu, int N_RB_DL, int ssb_case)
|
||||
void set_scs_parameters(NR_DL_FRAME_PARMS *fp, int mu, int N_RB_DL, int ssb_case)
|
||||
{
|
||||
switch(mu) {
|
||||
case NR_MU_0: //15kHz scs
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
#include "PHY/MODULATION/modulation_UE.h"
|
||||
#include "PHY/LTE_ESTIMATION/lte_estimation.h"
|
||||
#include "PHY/LTE_REFSIG/lte_refsig.h"
|
||||
#include "common_lib.h"
|
||||
#include "PHY/INIT/phy_init.h"
|
||||
|
||||
extern openair0_config_t openair0_cfg[];
|
||||
|
||||
@@ -7,8 +7,10 @@
|
||||
#include "PHY/NR_REFSIG/nr_mod_table.h"
|
||||
#include "executables/softmodem-common.h"
|
||||
#include <simde/x86/avx512.h>
|
||||
// Lacking declaration in present simde external package, will be detected as compilation error when they will add it
|
||||
// Lacking declaration in older implementations of simde external package, so let's keep it for now to be backwards compatible
|
||||
#if !defined(simde_mm512_extracti64x2_epi64)
|
||||
#define simde_mm512_extracti64x2_epi64(a...) _mm512_extracti64x2_epi64(a)
|
||||
#endif
|
||||
|
||||
// #define DEBUG_DLSCH_PRECODING_PRINT_WITH_TRIVIAL // TODO: For debug, to be removed if want to merge to develop
|
||||
// #define DEBUG_LAYER_MAPPING
|
||||
|
||||
@@ -235,9 +235,11 @@ int nr_dlsch_encoding(PHY_VARS_gNB *gNB,
|
||||
|
||||
for (int r = 0; r < TB_parameters->C; r++) {
|
||||
nrLDPC_segment_encoding_parameters_t *segment_parameters = &TB_parameters->segments[r];
|
||||
int E = nr_get_E(TB_parameters->G, TB_parameters->C, TB_parameters->Qm, rel15->nrOfLayers, r);
|
||||
if (E < 0)
|
||||
return -1;
|
||||
segment_parameters->c = dlsch->c[r];
|
||||
segment_parameters->E = nr_get_E(TB_parameters->G, TB_parameters->C, TB_parameters->Qm, rel15->nrOfLayers, r);
|
||||
|
||||
segment_parameters->E = E;
|
||||
reset_meas(&segment_parameters->ts_interleave);
|
||||
reset_meas(&segment_parameters->ts_rate_match);
|
||||
reset_meas(&segment_parameters->ts_ldpc_encode);
|
||||
|
||||
@@ -12,6 +12,202 @@
|
||||
#include "PHY/NR_TRANSPORT/nr_transport_common_proto.h"
|
||||
#include "openair1/PHY/NR_TRANSPORT/nr_prach.h"
|
||||
|
||||
typedef struct {
|
||||
int reps;
|
||||
int Ncp;
|
||||
int dftlen;
|
||||
int N_ZC;
|
||||
int k;
|
||||
dft_size_idx_t dftsize;
|
||||
int sample_offset_slot;
|
||||
} prach_ru_params_t;
|
||||
|
||||
static prach_ru_params_t get_prach_ru_params(prach_item_t *p,
|
||||
int prachStartSymbol,
|
||||
NR_DL_FRAME_PARMS *fp)
|
||||
{
|
||||
prach_ru_params_t par = {0};
|
||||
const int sum = fp->ofdm_symbol_size + fp->nb_prefix_samples;
|
||||
const int sum0 = fp->ofdm_symbol_size + fp->nb_prefix_samples0;
|
||||
if (prachStartSymbol == 0) {
|
||||
par.sample_offset_slot = 0;
|
||||
} else if (fp->slots_per_subframe == 1) {
|
||||
if (prachStartSymbol <= 7)
|
||||
par.sample_offset_slot = sum * (prachStartSymbol - 1) + sum0;
|
||||
else
|
||||
par.sample_offset_slot = sum * (prachStartSymbol - 2) + sum0 * 2;
|
||||
} else {
|
||||
if (!(p->slot % (fp->slots_per_subframe / 2)))
|
||||
par.sample_offset_slot = sum * (prachStartSymbol - 1) + sum0;
|
||||
else
|
||||
par.sample_offset_slot = sum * prachStartSymbol;
|
||||
}
|
||||
|
||||
int mu = p->numerology_index;
|
||||
|
||||
if (p->prach_sequence_length == 0) {
|
||||
switch (p->pdu.prach_format) {
|
||||
case 0:
|
||||
par.reps = 1;
|
||||
par.Ncp = 3168;
|
||||
par.dftlen = 24576;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
par.reps = 2;
|
||||
par.Ncp = 21024;
|
||||
par.dftlen = 24576;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
par.reps = 4;
|
||||
par.Ncp = 4688;
|
||||
par.dftlen = 24576;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
par.reps = 4;
|
||||
par.Ncp = 3168;
|
||||
par.dftlen = 6144;
|
||||
break;
|
||||
|
||||
default:
|
||||
AssertFatal(1 == 0, "Illegal prach format %d for length 839\n", p->pdu.prach_format);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
switch (p->pdu.prach_format) {
|
||||
case 4: // A1
|
||||
par.reps = 2;
|
||||
par.Ncp = 288 >> mu;
|
||||
break;
|
||||
|
||||
case 5: // A2
|
||||
par.reps = 4;
|
||||
par.Ncp = 576 >> mu;
|
||||
break;
|
||||
|
||||
case 6: // A3
|
||||
par.reps = 6;
|
||||
par.Ncp = 864 >> mu;
|
||||
break;
|
||||
|
||||
case 7: // B1
|
||||
par.reps = 2;
|
||||
par.Ncp = 216 >> mu;
|
||||
break;
|
||||
|
||||
case 8: // B4
|
||||
par.reps = 12;
|
||||
par.Ncp = 936 >> mu;
|
||||
break;
|
||||
|
||||
case 9: // C0
|
||||
par.reps = 1;
|
||||
par.Ncp = 1240 >> mu;
|
||||
break;
|
||||
|
||||
case 10: // C2
|
||||
par.reps = 4;
|
||||
par.Ncp = 2048 >> mu;
|
||||
break;
|
||||
|
||||
default:
|
||||
AssertFatal(1 == 0, "unknown prach format %x\n", p->pdu.prach_format);
|
||||
break;
|
||||
}
|
||||
par.dftlen = 2048 >> mu;
|
||||
}
|
||||
|
||||
if (p->numerology_index == 0) {
|
||||
if (prachStartSymbol == 0 || prachStartSymbol == 7)
|
||||
par.Ncp += 16;
|
||||
} else {
|
||||
if (p->slot % (fp->slots_per_subframe / 2) == 0 && prachStartSymbol == 0)
|
||||
par.Ncp += 16;
|
||||
}
|
||||
|
||||
switch(fp->samples_per_subframe) {
|
||||
case 7680:
|
||||
// 5 MHz @ 7.68 Ms/s
|
||||
par.Ncp >>= 2;
|
||||
par.dftlen >>= 2;
|
||||
break;
|
||||
|
||||
case 15360:
|
||||
// 10, 15 MHz @ 15.36 Ms/s
|
||||
par.Ncp >>= 1;
|
||||
par.dftlen >>= 1;
|
||||
break;
|
||||
|
||||
case 23040:
|
||||
// 20 MHz @ 23.04 Ms/s
|
||||
par.Ncp = (par.Ncp * 3) / 4;
|
||||
par.dftlen = (par.dftlen * 3) / 4;
|
||||
break;
|
||||
|
||||
case 30720:
|
||||
// 20, 25, 30 MHz @ 30.72 Ms/s
|
||||
break;
|
||||
|
||||
case 46080:
|
||||
// 40 MHz @ 46.08 Ms/s
|
||||
par.Ncp = (par.Ncp*3)/2;
|
||||
par.dftlen = (par.dftlen*3)/2;
|
||||
break;
|
||||
|
||||
case 61440:
|
||||
// 40, 50, 60 MHz @ 61.44 Ms/s
|
||||
par.Ncp <<= 1;
|
||||
par.dftlen <<= 1;
|
||||
break;
|
||||
|
||||
case 92160:
|
||||
// 50, 60, 70, 80, 90 MHz @ 92.16 Ms/s
|
||||
par.Ncp *= 3;
|
||||
par.dftlen *= 3;
|
||||
break;
|
||||
|
||||
case 122880:
|
||||
// 70, 80, 90, 100 MHz @ 122.88 Ms/s
|
||||
par.Ncp <<= 2;
|
||||
par.dftlen <<= 2;
|
||||
break;
|
||||
|
||||
case 184320:
|
||||
// 100 MHz @ 184.32 Ms/s
|
||||
par.Ncp = par.Ncp*6;
|
||||
par.dftlen = par.dftlen*6;
|
||||
break;
|
||||
|
||||
case 245760:
|
||||
// 200 MHz @ 245.76 Ms/s
|
||||
par.Ncp <<= 3;
|
||||
par.dftlen <<= 3;
|
||||
break;
|
||||
|
||||
default:
|
||||
AssertFatal(1==0,"sample rate %f MHz not supported for numerology %d\n", fp->samples_per_subframe / 1000.0, mu);
|
||||
}
|
||||
|
||||
par.dftsize = get_dft(par.dftlen);
|
||||
par.N_ZC = (p->prach_sequence_length == 0) ? 839 : 139;
|
||||
|
||||
const unsigned int K = get_prach_K(p->prach_sequence_length, p->pdu.prach_format, p->numerology_index, p->mu);
|
||||
const uint8_t kbar = get_PRACH_k_bar(p->mu, p->numerology_index);
|
||||
|
||||
int n_ra_prb = p->msg1_frequencystart;
|
||||
int k = (12*n_ra_prb) - 6*fp->N_RB_UL;
|
||||
|
||||
if (k<0) k+=(fp->ofdm_symbol_size);
|
||||
|
||||
k*=K;
|
||||
k+=kbar;
|
||||
par.k = k;
|
||||
|
||||
return par;
|
||||
}
|
||||
|
||||
void init_nr_prach(PHY_VARS_gNB *gNB)
|
||||
{
|
||||
int num_prach = 16;
|
||||
@@ -114,6 +310,38 @@ void nr_schedule_rx_prach(PHY_VARS_gNB *gNB, int SFN, int Slot, nfapi_nr_prach_p
|
||||
LOG_W(NR_PHY, "%4d.%2d PRACH occ queue is full: dropping PRACH request\n", SFN, Slot);
|
||||
}
|
||||
|
||||
static void rx_nr_prach_ru_internal_rep(prach_item_t *p,
|
||||
int ant_offset,
|
||||
int32_t **rxdata,
|
||||
NR_DL_FRAME_PARMS *fp,
|
||||
int N_TA_offset,
|
||||
int rep,
|
||||
const prach_ru_params_t *params,
|
||||
c16_t (*rxsigF)[NR_PRACH_SEQ_LEN_L])
|
||||
{
|
||||
AssertFatal(rep >= 0 && rep < params->reps, "rep %d is out of range (reps = %d)\n", rep, params->reps);
|
||||
|
||||
int slot2 = p->prach_sequence_length ? p->slot : p->slot;
|
||||
int sample_offset = get_samples_slot_timestamp(fp, slot2) + params->sample_offset_slot - N_TA_offset + params->Ncp + rep * params->dftlen;
|
||||
|
||||
for (int aa = 0; aa < p->nb_rx; aa++) {
|
||||
int idx = ant_offset + aa;
|
||||
c16_t *prach2 = (c16_t *)&rxdata[idx][sample_offset];
|
||||
|
||||
// do DFT for the specific repetition
|
||||
c16_t tmp[params->dftlen] __attribute__((aligned(32)));
|
||||
dft(params->dftsize, (int16_t *)prach2, (int16_t *)tmp, 1);
|
||||
// Coherent combining of PRACH repetitions (assumes channel does not change, to be revisted for "long" PRACH)
|
||||
LOG_D(PHY, "Doing PRACH combining of repetition %d/%d N_ZC %d\n", rep, params->reps, params->N_ZC);
|
||||
int k2 = params->k;
|
||||
for (int j = 0; j < params->N_ZC; j++, k2++) {
|
||||
if (k2 == params->dftlen)
|
||||
k2 = 0;
|
||||
rxsigF[aa][j] = c16add(rxsigF[aa][j], tmp[k2]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void rx_nr_prach_ru_internal(prach_item_t *p,
|
||||
int prachStartSymbol,
|
||||
int prachOccasion,
|
||||
@@ -122,229 +350,9 @@ static void rx_nr_prach_ru_internal(prach_item_t *p,
|
||||
int N_TA_offset,
|
||||
bool das)
|
||||
{
|
||||
int sample_offset_slot;
|
||||
const int sum = fp->ofdm_symbol_size + fp->nb_prefix_samples;
|
||||
const int sum0 = fp->ofdm_symbol_size + fp->nb_prefix_samples0;
|
||||
if (prachStartSymbol == 0) {
|
||||
sample_offset_slot = 0;
|
||||
} else if (fp->slots_per_subframe == 1) {
|
||||
if (prachStartSymbol <= 7)
|
||||
sample_offset_slot = sum * (prachStartSymbol - 1) + sum0;
|
||||
else
|
||||
sample_offset_slot = sum * (prachStartSymbol - 2) + sum0 * 2;
|
||||
} else {
|
||||
if (!(p->slot % (fp->slots_per_subframe / 2)))
|
||||
sample_offset_slot = sum * (prachStartSymbol - 1) + sum0;
|
||||
else
|
||||
sample_offset_slot = sum * prachStartSymbol;
|
||||
}
|
||||
|
||||
LOG_D(PHY,
|
||||
"frame %d, slot %d: doing rx_nr_prach_ru for format %d, numRA %d, prachStartSymbol %d, prachOccasion %d\n",
|
||||
p->frame,
|
||||
p->slot,
|
||||
p->pdu.prach_format,
|
||||
p->pdu.num_ra,
|
||||
prachStartSymbol,
|
||||
prachOccasion);
|
||||
int reps;
|
||||
int Ncp;
|
||||
int dftlen;
|
||||
int mu = p->numerology_index;
|
||||
|
||||
if (p->prach_sequence_length == 0) {
|
||||
LOG_D(PHY,
|
||||
"PRACH in %d.%d, format %d, msg1_frequencyStart %d\n",
|
||||
p->frame,
|
||||
p->slot,
|
||||
p->pdu.prach_format,
|
||||
p->msg1_frequencystart);
|
||||
switch (p->pdu.prach_format) {
|
||||
case 0:
|
||||
reps = 1;
|
||||
Ncp = 3168;
|
||||
dftlen = 24576;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
reps = 2;
|
||||
Ncp = 21024;
|
||||
dftlen = 24576;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
reps = 4;
|
||||
Ncp = 4688;
|
||||
dftlen = 24576;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
reps = 4;
|
||||
Ncp = 3168;
|
||||
dftlen = 6144;
|
||||
break;
|
||||
|
||||
default:
|
||||
AssertFatal(1 == 0, "Illegal prach format %d for length 839\n", p->pdu.prach_format);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
LOG_D(PHY,
|
||||
"PRACH in %d.%d, format %s, msg1_frequencyStart %d,startSymbol %d\n",
|
||||
p->frame,
|
||||
p->slot,
|
||||
prachfmt[p->pdu.prach_format],
|
||||
p->msg1_frequencystart,
|
||||
prachStartSymbol);
|
||||
switch (p->pdu.prach_format) {
|
||||
case 4: // A1
|
||||
reps = 2;
|
||||
Ncp = 288 >> mu;
|
||||
break;
|
||||
|
||||
case 5: // A2
|
||||
reps = 4;
|
||||
Ncp = 576 >> mu;
|
||||
break;
|
||||
|
||||
case 6: // A3
|
||||
reps = 6;
|
||||
Ncp = 864 >> mu;
|
||||
break;
|
||||
|
||||
case 7: // B1
|
||||
reps = 2;
|
||||
Ncp = 216 >> mu;
|
||||
break;
|
||||
|
||||
/*
|
||||
// B2 and B3 do not exist in FAPI
|
||||
case 4: //B2
|
||||
reps = 4;
|
||||
Ncp = 360 >> mu;
|
||||
break;
|
||||
|
||||
case 5: //B3
|
||||
reps = 6;
|
||||
Ncp = 504 >> mu;
|
||||
break;
|
||||
*/
|
||||
|
||||
case 8: // B4
|
||||
reps = 12;
|
||||
Ncp = 936 >> mu;
|
||||
break;
|
||||
|
||||
case 9: // C0
|
||||
reps = 1;
|
||||
Ncp = 1240 >> mu;
|
||||
break;
|
||||
|
||||
case 10: // C2
|
||||
reps = 4;
|
||||
Ncp = 2048 >> mu;
|
||||
break;
|
||||
|
||||
default:
|
||||
AssertFatal(1 == 0, "unknown prach format %x\n", p->pdu.prach_format);
|
||||
break;
|
||||
}
|
||||
dftlen = 2048 >> mu;
|
||||
}
|
||||
|
||||
//actually what we should be checking here is how often the current prach crosses a 0.5ms boundary.
|
||||
//I am not quite sure for which paramter set this would be the case,
|
||||
//so I will ignore it for now and just check if the prach starts on a 0.5ms boundary
|
||||
if (p->numerology_index == 0) {
|
||||
if (prachStartSymbol == 0 || prachStartSymbol == 7)
|
||||
Ncp += 16;
|
||||
} else {
|
||||
if (p->slot % (fp->slots_per_subframe / 2) == 0 && prachStartSymbol == 0)
|
||||
Ncp += 16;
|
||||
}
|
||||
|
||||
switch(fp->samples_per_subframe) {
|
||||
case 7680:
|
||||
// 5 MHz @ 7.68 Ms/s
|
||||
Ncp >>= 2;
|
||||
dftlen >>= 2;
|
||||
break;
|
||||
|
||||
case 15360:
|
||||
// 10, 15 MHz @ 15.36 Ms/s
|
||||
Ncp >>= 1;
|
||||
dftlen >>= 1;
|
||||
break;
|
||||
|
||||
case 23040:
|
||||
// 20 MHz @ 23.04 Ms/s
|
||||
Ncp = (Ncp * 3) / 4;
|
||||
dftlen = (dftlen * 3) / 4;
|
||||
break;
|
||||
|
||||
case 30720:
|
||||
// 20, 25, 30 MHz @ 30.72 Ms/s
|
||||
break;
|
||||
|
||||
case 46080:
|
||||
// 40 MHz @ 46.08 Ms/s
|
||||
Ncp = (Ncp*3)/2;
|
||||
dftlen = (dftlen*3)/2;
|
||||
break;
|
||||
|
||||
case 61440:
|
||||
// 40, 50, 60 MHz @ 61.44 Ms/s
|
||||
Ncp <<= 1;
|
||||
dftlen <<= 1;
|
||||
break;
|
||||
|
||||
case 92160:
|
||||
// 50, 60, 70, 80, 90 MHz @ 92.16 Ms/s
|
||||
Ncp *= 3;
|
||||
dftlen *= 3;
|
||||
break;
|
||||
|
||||
case 122880:
|
||||
// 70, 80, 90, 100 MHz @ 122.88 Ms/s
|
||||
Ncp <<= 2;
|
||||
dftlen <<= 2;
|
||||
break;
|
||||
|
||||
case 184320:
|
||||
// 100 MHz @ 184.32 Ms/s
|
||||
Ncp = Ncp*6;
|
||||
dftlen = dftlen*6;
|
||||
break;
|
||||
|
||||
case 245760:
|
||||
// 200 MHz @ 245.76 Ms/s
|
||||
Ncp <<= 3;
|
||||
dftlen <<= 3;
|
||||
break;
|
||||
|
||||
default:
|
||||
AssertFatal(1==0,"sample rate %f MHz not supported for numerology %d\n", fp->samples_per_subframe / 1000.0, mu);
|
||||
}
|
||||
|
||||
const dft_size_idx_t dftsize = get_dft(dftlen);
|
||||
|
||||
// Do forward transform
|
||||
if (LOG_DEBUGFLAG(DEBUG_PRACH)) {
|
||||
LOG_D(PHY, "rx_prach: Doing PRACH FFT for nb_rx:%d Ncp:%d dftlen:%d\n", p->nb_rx, Ncp, dftlen);
|
||||
}
|
||||
|
||||
const unsigned int K = get_prach_K(p->prach_sequence_length, p->pdu.prach_format, p->numerology_index, p->mu);
|
||||
const uint8_t kbar = get_PRACH_k_bar(p->mu, p->numerology_index);
|
||||
|
||||
int n_ra_prb = p->msg1_frequencystart;
|
||||
int k = (12*n_ra_prb) - 6*fp->N_RB_UL;
|
||||
|
||||
int N_ZC = (p->prach_sequence_length == 0) ? 839 : 139;
|
||||
|
||||
if (k<0) k+=(fp->ofdm_symbol_size);
|
||||
|
||||
k*=K;
|
||||
k+=kbar;
|
||||
prach_ru_params_t params = get_prach_ru_params(p, prachStartSymbol, fp);
|
||||
c16_t rxsigF_tmp[p->nb_rx][NR_PRACH_SEQ_LEN_L];
|
||||
memset(rxsigF_tmp, 0, sizeof(rxsigF_tmp));
|
||||
|
||||
const uint8_t num_beams = p->pdu.beamforming.dig_bf_interface;
|
||||
// When more than one beams, then each occasion is on one beam
|
||||
@@ -353,36 +361,20 @@ static void rx_nr_prach_ru_internal(prach_item_t *p,
|
||||
AssertFatal(prachOccasion < num_beams, "Num of PRACH Occasions must be same as number of beams in beamforming mode\n");
|
||||
ant_offset = prachOccasion * p->nb_rx;
|
||||
}
|
||||
|
||||
// TODO: Remove assumption of contiguous ports after DAS is properly handled in beamforming
|
||||
uint16_t ant_start =
|
||||
get_first_ant_idx(das,
|
||||
p->nb_rx,
|
||||
p->pdu.beamforming.prgs_list[0].dig_bf_interface_list[0].beam_idx,
|
||||
p->pdu.param_v4.numSpatialStreamIndices > 0 ? p->pdu.param_v4.spatialStreamIndices[ant_offset] : 0);
|
||||
for (int aa = 0; aa < p->nb_rx; aa++) {
|
||||
// Fixme: slot or slot makes no sense ???
|
||||
int slot2 = p->prach_sequence_length ? p->slot : p->slot;
|
||||
int idx = ant_start + aa;
|
||||
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;
|
||||
c16_t rxsigF_tmp[N_ZC];
|
||||
memset(rxsigF_tmp, 0, sizeof(rxsigF_tmp));
|
||||
for (int i = 0; i < reps; i++, prach2 += dftlen) {
|
||||
c16_t tmp[dftlen] __attribute__((aligned(32)));
|
||||
dft(dftsize, (int16_t *)prach2, (int16_t *)tmp, 1);
|
||||
// Coherent combining of PRACH repetitions (assumes channel does not change, to be revisted for "long" PRACH)
|
||||
LOG_D(PHY, "Doing PRACH combining of %d reptitions N_ZC %d\n", reps, N_ZC);
|
||||
// if (k+N_ZC > dftlen) { // PRACH signal is split around DC
|
||||
int k2 = k;
|
||||
for (int j = 0; j < N_ZC; j++, k2++) {
|
||||
if (k2 == dftlen)
|
||||
k2 = 0;
|
||||
rxsigF_tmp[j] = c16add(rxsigF_tmp[j], tmp[k2]);
|
||||
}
|
||||
}
|
||||
memcpy(p->prach_buf[aa][prachOccasion], rxsigF_tmp, sizeof(rxsigF_tmp));
|
||||
for (int rep = 0; rep < params.reps; rep++) {
|
||||
rx_nr_prach_ru_internal_rep(p, ant_start, rxdata, fp, N_TA_offset, rep, ¶ms, rxsigF_tmp);
|
||||
}
|
||||
|
||||
for (int aa = 0; aa < p->nb_rx; aa++) {
|
||||
memcpy(p->prach_buf[aa][prachOccasion], rxsigF_tmp[aa], sizeof(c16_t) * params.N_ZC);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -399,6 +391,20 @@ void rx_nr_prach_ru(prach_item_t *p, int32_t **rxdata, NR_DL_FRAME_PARMS *fp, in
|
||||
}
|
||||
}
|
||||
|
||||
void rx_nr_prach_ru_rep(prach_item_t *p,
|
||||
int32_t **rxdata,
|
||||
NR_DL_FRAME_PARMS *fp,
|
||||
int N_TA_offset,
|
||||
int rep,
|
||||
int prachOccasion,
|
||||
c16_t (*rxsigF)[NR_PRACH_SEQ_LEN_L])
|
||||
{
|
||||
int N_dur = get_nr_prach_duration(p->pdu.prach_format);
|
||||
int prachStartSymbol = p->pdu.prach_start_symbol + prachOccasion * N_dur;
|
||||
prach_ru_params_t params = get_prach_ru_params(p, prachStartSymbol, fp);
|
||||
rx_nr_prach_ru_internal_rep(p, 0, rxdata, fp, N_TA_offset, rep, ¶ms, rxsigF);
|
||||
}
|
||||
|
||||
rx_prach_out_t rx_nr_prach(const prach_item_t *in, int occasion)
|
||||
{
|
||||
rx_prach_out_t out = {};
|
||||
|
||||
@@ -19,13 +19,15 @@ nr_get_G(uint16_t nb_rb, uint16_t nb_symb_sch, uint8_t nb_re_dmrs, uint16_t leng
|
||||
return (G);
|
||||
}
|
||||
|
||||
uint32_t nr_get_E(uint32_t G, uint8_t C, uint8_t Qm, uint8_t Nl, uint8_t r)
|
||||
int nr_get_E(uint32_t G, uint8_t C, uint8_t Qm, uint8_t Nl, uint8_t r)
|
||||
{
|
||||
if (Nl <= 0 || Qm <= 0) {
|
||||
LOG_E(PHY, "Invalid input parameter in nr_get_E: Qm %d Nl %d\n", Qm, Nl);
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint32_t E;
|
||||
uint8_t Cprime = C; // assume CBGTI not present
|
||||
|
||||
AssertFatal(Nl > 0, "Nl is 0\n");
|
||||
AssertFatal(Qm > 0, "Qm is 0\n");
|
||||
if (r <= Cprime - ((G / (Nl * Qm)) % Cprime) - 1)
|
||||
E = Nl * Qm * (G / (Nl * Qm * Cprime));
|
||||
else
|
||||
|
||||
@@ -35,7 +35,7 @@ uint32_t nr_get_G(uint16_t nb_rb,
|
||||
uint8_t Qm,
|
||||
uint8_t Nl);
|
||||
|
||||
uint32_t nr_get_E(uint32_t G, uint8_t C, uint8_t Qm, uint8_t Nl, uint8_t r);
|
||||
int nr_get_E(uint32_t G, uint8_t C, uint8_t Qm, uint8_t Nl, uint8_t r);
|
||||
|
||||
void compute_nr_prach_seq(uint8_t short_sequence, uint8_t num_sequences, uint8_t rootSequenceIndex, c16_t X_u[64][839]);
|
||||
|
||||
|
||||
@@ -124,6 +124,13 @@ typedef struct rx_prach_out {
|
||||
rx_prach_out_t rx_nr_prach(const prach_item_t *, int occasion);
|
||||
|
||||
void rx_nr_prach_ru(prach_item_t *, int32_t **, NR_DL_FRAME_PARMS *frame_parms, int N_TA_offset, bool das);
|
||||
void rx_nr_prach_ru_rep(prach_item_t *p,
|
||||
int32_t **rxdata,
|
||||
NR_DL_FRAME_PARMS *fp,
|
||||
int N_TA_offset,
|
||||
int rep,
|
||||
int prachOccasion,
|
||||
c16_t (*rxsigF)[NR_PRACH_SEQ_LEN_L]);
|
||||
|
||||
void nr_fill_pucch(PHY_VARS_gNB *gNB,
|
||||
int frame,
|
||||
|
||||
@@ -226,11 +226,13 @@ int nr_ulsch_decoding(PHY_VARS_gNB *phy_vars_gNB,
|
||||
}
|
||||
|
||||
nrLDPC_TB_decoding_parameters_t *TB_parameters = &TBs[pusch_id];
|
||||
|
||||
int E = nr_get_E(TB_parameters->G, TB_parameters->C, TB_parameters->Qm, TB_parameters->nb_layers, 0);
|
||||
if (E < 0)
|
||||
return -1;
|
||||
TB_parameters->llr = ulsch_llr;
|
||||
TB_parameters->d = harq_process->d;
|
||||
TB_parameters->c = harq_process->c;
|
||||
TB_parameters->E = nr_get_E(TB_parameters->G, TB_parameters->C, TB_parameters->Qm, TB_parameters->nb_layers, 0);
|
||||
TB_parameters->E = E;
|
||||
TB_parameters->first_rE2 = TB_parameters->C;
|
||||
TB_parameters->E2 = TB_parameters->E;
|
||||
TB_parameters->R = nr_get_R_ldpc_decoder(TB_parameters->rv_index,
|
||||
|
||||
@@ -262,6 +262,8 @@ static int nr_csi_rs_channel_estimation(
|
||||
int16_t *log2_maxh,
|
||||
uint32_t *noise_power)
|
||||
{
|
||||
const int meas_bitmap = csirs_config_pdu->measurement_bitmap;
|
||||
AssertFatal(meas_bitmap != 1, "No need to do CSI-RS channel estimation for only RSRP measurment\n");
|
||||
*noise_power = 0;
|
||||
int maxh = 0;
|
||||
int count = 0;
|
||||
@@ -301,10 +303,16 @@ static int nr_csi_rs_channel_estimation(
|
||||
const c16_t *rx_csi_rs_signal = &csi_rs_received_signal[ant_rx][symbol_offset];
|
||||
c16_t tmp =
|
||||
c16MulConjShift(tx_csi_rs_signal[k_tx], rx_csi_rs_signal[k_rx], nr_csi_info->csi_rs_generated_signal_bits);
|
||||
// This is not just the LS estimation for each (k,l), but also the sum of the different contributions
|
||||
// for the sake of optimizing the memory used.
|
||||
csi_rs_ls_estimated_channel[ant_rx][port_tx][kinit_tx].r += tmp.r;
|
||||
csi_rs_ls_estimated_channel[ant_rx][port_tx][kinit_tx].i += tmp.i;
|
||||
if (csirs_config_pdu->csi_type != 0) {
|
||||
// This is not just the LS estimation for each (k,l), but also the sum of the different contributions
|
||||
// for the sake of optimizing the memory used.
|
||||
csi_rs_ls_estimated_channel[ant_rx][port_tx][kinit_tx].r += tmp.r;
|
||||
csi_rs_ls_estimated_channel[ant_rx][port_tx][kinit_tx].i += tmp.i;
|
||||
} else {
|
||||
// for tracking we want estimates of all sub carriers having CSI-RS
|
||||
csi_rs_ls_estimated_channel[ant_rx][port_tx][k_tx].r = tmp.r;
|
||||
csi_rs_ls_estimated_channel[ant_rx][port_tx][k_tx].i = tmp.i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -362,6 +370,10 @@ static int nr_csi_rs_channel_estimation(
|
||||
}
|
||||
}
|
||||
|
||||
// we need only ls estimates for tracking CSI. So stop here.
|
||||
if (meas_bitmap == 0)
|
||||
continue;
|
||||
|
||||
/// Power noise estimation
|
||||
AssertFatal(csirs_config_pdu->nr_of_rbs > 0, " nr_of_rbs needs to be greater than 0\n");
|
||||
uint16_t noise_real[fp->nb_antennas_rx][csi_mapping->ports][csirs_config_pdu->nr_of_rbs];
|
||||
@@ -406,9 +418,11 @@ static int nr_csi_rs_channel_estimation(
|
||||
|
||||
}
|
||||
|
||||
*noise_power /= (fp->nb_antennas_rx * csi_mapping->ports);
|
||||
*log2_maxh = log2_approx(maxh - 1);
|
||||
*log2_re = log2_approx(count - 1);
|
||||
if (meas_bitmap > 1) {
|
||||
*noise_power /= (fp->nb_antennas_rx * csi_mapping->ports);
|
||||
*log2_maxh = log2_approx(maxh - 1);
|
||||
*log2_re = log2_approx(count - 1);
|
||||
}
|
||||
|
||||
#ifdef NR_CSIRS_DEBUG
|
||||
LOG_I(NR_PHY, "Noise power estimation based on CSI-RS: %i\n", *noise_power);
|
||||
@@ -774,6 +788,61 @@ static void nr_csi_im_power_estimation(const PHY_VARS_NR_UE *ue,
|
||||
#endif
|
||||
}
|
||||
|
||||
static double get_cfo(const double phase_diff, const int sym0, const int sym1, const NR_DL_FRAME_PARMS *fp)
|
||||
{
|
||||
const double one_fs = 1.0 / (fp->samples_per_frame * 100);
|
||||
int sample_count = 0;
|
||||
for (int s = sym0 + 1; s <= sym1; s++) {
|
||||
const int prefix = (s % (7 * (1 << fp->numerology_index))) ? fp->nb_prefix_samples : fp->nb_prefix_samples0;
|
||||
sample_count += (fp->ofdm_symbol_size + prefix);
|
||||
}
|
||||
const double delta_time = sample_count * one_fs;
|
||||
const double cfo = phase_diff / (2 * M_PI * delta_time);
|
||||
return cfo;
|
||||
}
|
||||
|
||||
static void nr_ue_trs_processing(PHY_VARS_NR_UE *ue,
|
||||
const c16_t res0_est[][1][ue->frame_parms.ofdm_symbol_size],
|
||||
const c16_t res1_est[][1][ue->frame_parms.ofdm_symbol_size],
|
||||
const c16_t freq_interp_est[][1][ue->frame_parms.ofdm_symbol_size],
|
||||
const fapi_nr_dl_config_csirs_pdu_rel15_t *csirs_config_pdu,
|
||||
const csi_mapping_parms_t *csi_mapping,
|
||||
const int sym0,
|
||||
const int sym1,
|
||||
int *cfo,
|
||||
int *time_offset)
|
||||
{
|
||||
AssertFatal((sym0 > -1) && (sym1 > -1) && (sym1 > sym0), "Invalid symbol index for TRS estimation\n");
|
||||
const NR_DL_FRAME_PARMS *fp = &ue->frame_parms;
|
||||
// CFO estimation
|
||||
const int ant_rx = 0; // Estimate only on first antenna port
|
||||
cd_t phase_diff = {0.0};
|
||||
AssertFatal(csirs_config_pdu->freq_density == 3,
|
||||
"CSI-RS for tracking must have freq density of 3 but has %d\n",
|
||||
csirs_config_pdu->freq_density);
|
||||
AssertFatal(csi_mapping->kprime == 0 && csi_mapping->lprime == 0, "Invalid kprime, lprime for CSI-RS for tracking (row 1)\n");
|
||||
for (int rb = csirs_config_pdu->start_rb; rb < (csirs_config_pdu->start_rb + csirs_config_pdu->nr_of_rbs); rb++) {
|
||||
for (int cdm_id = 0; cdm_id < csi_mapping->size; cdm_id++) {
|
||||
uint16_t kinit = rb * NR_NB_SC_PER_RB;
|
||||
uint16_t k = kinit + csi_mapping->koverline[cdm_id];
|
||||
|
||||
const c16_t *res0 = res0_est[ant_rx][0];
|
||||
const c16_t *res1 = res1_est[ant_rx][0];
|
||||
phase_diff.r += res1[k].r * res0[k].r + res1[k].i * res0[k].i;
|
||||
phase_diff.i += res1[k].i * res0[k].r - res1[k].r * res0[k].i;
|
||||
}
|
||||
}
|
||||
*cfo = (int)get_cfo(atan2(phase_diff.i, phase_diff.r), sym0, sym1, fp);
|
||||
|
||||
if (time_offset) {
|
||||
// Time offset estimation
|
||||
__attribute__((aligned(32))) c16_t time_est[fp->ofdm_symbol_size];
|
||||
delay_t delay = {0};
|
||||
nr_est_delay(fp->ofdm_symbol_size, freq_interp_est[ant_rx][0], time_est, &delay);
|
||||
*time_offset = delay.delay_max_pos;
|
||||
}
|
||||
}
|
||||
|
||||
void nr_ue_csi_im_procedures(PHY_VARS_NR_UE *ue,
|
||||
const c16_t rxdataF[][ue->frame_parms.samples_per_slot_wCP],
|
||||
const fapi_nr_dl_config_csiim_pdu_rel15_t *csiim_config_pdu)
|
||||
@@ -796,7 +865,10 @@ void nr_ue_csi_im_procedures(PHY_VARS_NR_UE *ue,
|
||||
void nr_ue_csi_rs_procedures(PHY_VARS_NR_UE *ue,
|
||||
const UE_nr_rxtx_proc_t *proc,
|
||||
const c16_t rxdataF[][ue->frame_parms.samples_per_slot_wCP],
|
||||
fapi_nr_dl_config_csirs_pdu_rel15_t *csirs_config_pdu)
|
||||
fapi_nr_dl_config_csirs_pdu_rel15_t *csirs_config_pdu,
|
||||
c16_t trs_estimates[][1][ue->frame_parms.ofdm_symbol_size],
|
||||
const int res_idx,
|
||||
const int trs_sym0)
|
||||
{
|
||||
|
||||
#ifdef NR_CSIRS_DEBUG
|
||||
@@ -816,11 +888,6 @@ void nr_ue_csi_rs_procedures(PHY_VARS_NR_UE *ue,
|
||||
LOG_I(NR_PHY, "csirs_config_pdu->power_control_offset_ss = %i\n", csirs_config_pdu->power_control_offset_ss);
|
||||
#endif
|
||||
|
||||
if(csirs_config_pdu->csi_type == 0) {
|
||||
LOG_E(NR_PHY, "Handling of CSI-RS for tracking not handled yet at PHY\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if(csirs_config_pdu->csi_type == 2) {
|
||||
LOG_E(NR_PHY, "Handling of ZP CSI-RS not handled yet at PHY\n");
|
||||
return;
|
||||
@@ -870,29 +937,25 @@ void nr_ue_csi_rs_procedures(PHY_VARS_NR_UE *ue,
|
||||
&rsrp_dBm,
|
||||
rxdataF);
|
||||
|
||||
|
||||
if (csirs_config_pdu->measurement_bitmap == 0) {
|
||||
LOG_D(NR_PHY, "No CSI-RS measurements configured\n");
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t noise_power = 0;
|
||||
int16_t log2_re = 0;
|
||||
int16_t log2_maxh = 0;
|
||||
// if we need to measure only RSRP no need to do channel estimation
|
||||
if (csirs_config_pdu->measurement_bitmap > 1)
|
||||
if (csirs_config_pdu->measurement_bitmap != 1) {
|
||||
const bool use_trs_buff = (csirs_config_pdu->csi_type == 0 && res_idx == 0);
|
||||
nr_csi_rs_channel_estimation(frame_parms,
|
||||
csirs_config_pdu,
|
||||
csi_info,
|
||||
(const c16_t **)csi_info->csi_rs_generated_signal,
|
||||
csi_rs_received_signal,
|
||||
&mapping_parms,
|
||||
CDM_group_size,
|
||||
csi_rs_ls_estimated_channel,
|
||||
csi_rs_estimated_channel_freq,
|
||||
&log2_re,
|
||||
&log2_maxh,
|
||||
&noise_power);
|
||||
csirs_config_pdu,
|
||||
csi_info,
|
||||
(const c16_t **)csi_info->csi_rs_generated_signal,
|
||||
csi_rs_received_signal,
|
||||
&mapping_parms,
|
||||
CDM_group_size,
|
||||
(use_trs_buff) ? trs_estimates : csi_rs_ls_estimated_channel,
|
||||
csi_rs_estimated_channel_freq,
|
||||
&log2_re,
|
||||
&log2_maxh,
|
||||
&noise_power);
|
||||
}
|
||||
|
||||
uint8_t rank_indicator = 0;
|
||||
// bit 1 in bitmap to indicate RI measurment
|
||||
@@ -926,9 +989,34 @@ void nr_ue_csi_rs_procedures(PHY_VARS_NR_UE *ue,
|
||||
nr_csi_rs_cqi_estimation(precoded_sinr_dB, &cqi);
|
||||
}
|
||||
|
||||
int trs_cfo = 0;
|
||||
const bool do_trs_est = (csirs_config_pdu->csi_type == 0) && (res_idx == 1);
|
||||
if (do_trs_est) {
|
||||
start_meas_nr_ue_phy(ue, TRS_PROCESSING);
|
||||
nr_ue_trs_processing(ue,
|
||||
trs_estimates,
|
||||
csi_rs_ls_estimated_channel,
|
||||
csi_rs_estimated_channel_freq,
|
||||
csirs_config_pdu,
|
||||
&mapping_parms,
|
||||
trs_sym0,
|
||||
csirs_config_pdu->symb_l0,
|
||||
&trs_cfo,
|
||||
NULL); // Time offset not estimated because it is corrected using PBCH DMRS
|
||||
stop_meas_nr_ue_phy(ue, TRS_PROCESSING);
|
||||
}
|
||||
|
||||
switch (csirs_config_pdu->measurement_bitmap) {
|
||||
case 1 :
|
||||
LOG_I(NR_PHY, "[UE %d] RSRP = %i dBm\n", ue->Mod_id, rsrp_dBm);
|
||||
case 0:
|
||||
if (do_trs_est)
|
||||
LOG_I(NR_PHY,
|
||||
"%d.%d TRS estimated CFO: %d Hz\n",
|
||||
proc->frame_rx,
|
||||
proc->nr_slot_rx,
|
||||
trs_cfo);
|
||||
break;
|
||||
case 1:
|
||||
LOG_I(NR_PHY, "%d.%d [UE %d] RSRP = %i dBm\n", proc->frame_rx, proc->nr_slot_rx, ue->Mod_id, rsrp_dBm);
|
||||
break;
|
||||
case 26 :
|
||||
LOG_I(NR_PHY, "RI = %i i1 = %i.%i.%i, i2 = %i, SINR = %i dB, CQI = %i\n",
|
||||
@@ -942,6 +1030,10 @@ void nr_ue_csi_rs_procedures(PHY_VARS_NR_UE *ue,
|
||||
AssertFatal(false, "Not supported measurement configuration\n");
|
||||
}
|
||||
|
||||
if (!ue->cont_fo_comp && do_trs_est && csirs_config_pdu->last_trs_slot) {
|
||||
trs_freq_correction(ue, trs_cfo);
|
||||
}
|
||||
|
||||
// Send CSI measurements to MAC
|
||||
if (!ue->if_inst || !ue->if_inst->dl_indication)
|
||||
return;
|
||||
|
||||
@@ -147,9 +147,12 @@ void nr_dlsch_decoding(PHY_VARS_NR_UE *phy_vars_ue,
|
||||
TB_parameters.C,
|
||||
TB_parameters.Qm,
|
||||
TB_parameters.llr);
|
||||
int E = nr_get_E(TB_parameters.G, TB_parameters.C, TB_parameters.Qm, TB_parameters.nb_layers, 0);
|
||||
if (E < 0)
|
||||
return;
|
||||
TB_parameters.c = harq_process->c;
|
||||
TB_parameters.d = harq_process->d;
|
||||
TB_parameters.E = nr_get_E(TB_parameters.G, TB_parameters.C, TB_parameters.Qm, TB_parameters.nb_layers, 0);
|
||||
TB_parameters.E = E;
|
||||
TB_parameters.E2 = TB_parameters.E;
|
||||
TB_parameters.first_rE2 = TB_parameters.C;
|
||||
for (int r = 1; r < TB_parameters.C; r++) {
|
||||
|
||||
@@ -193,8 +193,8 @@ static void nr_dlsch_extract_rbs(uint32_t rxdataF_sz,
|
||||
uint32_t csi_res_odd = (csi_res_bitmap >> 16) & 0xfff;
|
||||
AssertFatal((dmrs_rb_bitmap & csi_res_even) == 0, "DMRS RE overlapping with CSI RE, it shouldn't happen\n");
|
||||
AssertFatal((dmrs_rb_bitmap & csi_res_odd) == 0, "DMRS RE overlapping with CSI RE, it shouldn't happen\n");
|
||||
uint32_t dmrs_csi_overlap_even = csi_res_even + dmrs_rb_bitmap;
|
||||
uint32_t dmrs_csi_overlap_odd = csi_res_odd + dmrs_rb_bitmap;
|
||||
uint32_t dmrs_csi_overlap_even = csi_res_even | dmrs_rb_bitmap;
|
||||
uint32_t dmrs_csi_overlap_odd = csi_res_odd | dmrs_rb_bitmap;
|
||||
int8_t validDmrsEst;
|
||||
if (chest_time_type == 0)
|
||||
validDmrsEst = get_valid_dmrs_idx_for_channel_est(dlsch_config->dlDmrsSymbPos, symbol);
|
||||
@@ -203,16 +203,17 @@ static void nr_dlsch_extract_rbs(uint32_t rxdataF_sz,
|
||||
|
||||
int pos = 0;
|
||||
int block_start, block_end;
|
||||
int offset = 0;
|
||||
while (find_next_rb_block(freq_alloc->bitmap, dlsch_config->BWPSize, &pos, &block_start, &block_end)) {
|
||||
int start_rb = block_start + dlsch_config->BWPStart;
|
||||
int nb_rb = block_end - block_start + 1;
|
||||
const int start_re = (fp->first_carrier_offset + start_rb * NR_NB_SC_PER_RB) % fp->ofdm_symbol_size;
|
||||
for (int aarx = 0; aarx < fp->nb_antennas_rx; aarx++) {
|
||||
c16_t *rxF_ext = rxdataF_ext[aarx];
|
||||
c16_t *rxF_ext = rxdataF_ext[aarx] + offset;
|
||||
c16_t *rxF = &rxdataF[aarx][symbol * fp->ofdm_symbol_size];
|
||||
for (int l = 0; l < Nl; l++) {
|
||||
int32_t *dl_ch0 = &dl_ch_estimates[(l * fp->nb_antennas_rx) + aarx][validDmrsEst * fp->ofdm_symbol_size];
|
||||
int32_t *dl_ch0_ext = dl_ch_estimates_ext[(l * fp->nb_antennas_rx) + aarx];
|
||||
int32_t *dl_ch0_ext = dl_ch_estimates_ext[(l * fp->nb_antennas_rx) + aarx] + offset;
|
||||
if (pilots == 0 && csi_res_bitmap == 0) { // data symbol only
|
||||
if (l == 0) {
|
||||
if (start_re + nb_rb * NR_NB_SC_PER_RB <= fp->ofdm_symbol_size) {
|
||||
@@ -247,6 +248,7 @@ static void nr_dlsch_extract_rbs(uint32_t rxdataF_sz,
|
||||
}
|
||||
}
|
||||
}
|
||||
offset += nb_rb * NR_NB_SC_PER_RB;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -835,205 +837,199 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue,
|
||||
//----------------------------------------------------------
|
||||
const bool meas_enabled = cpumeas(CPUMEAS_GETSTATE);
|
||||
int nb_rb_pdsch = freq_alloc->num_rbs;
|
||||
{
|
||||
start_meas_nr_ue_phy(ue, DLSCH_EXTRACT_RBS_STATS);
|
||||
__attribute__((aligned(32))) c16_t rxdataF_ext[nbRx][rx_size_symbol];
|
||||
memset(rxdataF_ext, 0, sizeof(rxdataF_ext));
|
||||
|
||||
uint32_t csi_res_bitmap = build_csi_overlap_bitmap(dlsch_config, symbol);
|
||||
start_meas_nr_ue_phy(ue, DLSCH_EXTRACT_RBS_STATS);
|
||||
__attribute__((aligned(32))) c16_t rxdataF_ext[nbRx][rx_size_symbol];
|
||||
memset(rxdataF_ext, 0, sizeof(rxdataF_ext));
|
||||
|
||||
LOG_D(PHY, "%d.%d symbol %d csi overlap bitmap %d\n", frame, nr_slot_rx, symbol, csi_res_bitmap);
|
||||
uint32_t csi_res_bitmap = build_csi_overlap_bitmap(dlsch_config, symbol);
|
||||
LOG_D(PHY, "%d.%d symbol %d csi overlap bitmap %d\n", frame, nr_slot_rx, symbol, csi_res_bitmap);
|
||||
|
||||
nr_dlsch_extract_rbs(fp->samples_per_slot_wCP,
|
||||
rxdataF,
|
||||
rx_size_symbol,
|
||||
pdsch_est_size,
|
||||
dl_ch_estimates,
|
||||
rxdataF_ext,
|
||||
dl_ch_estimates_ext,
|
||||
symbol,
|
||||
pilots,
|
||||
dlsch_config,
|
||||
freq_alloc,
|
||||
nl,
|
||||
fp,
|
||||
csi_res_bitmap,
|
||||
ue->chest_time);
|
||||
stop_meas_nr_ue_phy(ue, DLSCH_EXTRACT_RBS_STATS);
|
||||
if (scope_req->copy_chanest_to_scope) {
|
||||
size_t size = sizeof(c16_t) * nb_rb_pdsch * NR_NB_SC_PER_RB;
|
||||
int copy_index = symbol - dlsch_config->start_symbol;
|
||||
int offset = copy_index * size;
|
||||
UEscopeCopyUnsafe(ue, pdschChanEstimates, dl_ch_estimates_ext[0], size, offset, copy_index);
|
||||
nr_dlsch_extract_rbs(fp->samples_per_slot_wCP,
|
||||
rxdataF,
|
||||
rx_size_symbol,
|
||||
pdsch_est_size,
|
||||
dl_ch_estimates,
|
||||
rxdataF_ext,
|
||||
dl_ch_estimates_ext,
|
||||
symbol,
|
||||
pilots,
|
||||
dlsch_config,
|
||||
freq_alloc,
|
||||
nl,
|
||||
fp,
|
||||
csi_res_bitmap,
|
||||
ue->chest_time);
|
||||
stop_meas_nr_ue_phy(ue, DLSCH_EXTRACT_RBS_STATS);
|
||||
if (scope_req->copy_chanest_to_scope) {
|
||||
size_t size = sizeof(c16_t) * nb_rb_pdsch * NR_NB_SC_PER_RB;
|
||||
int copy_index = symbol - dlsch_config->start_symbol;
|
||||
int offset = copy_index * size;
|
||||
UEscopeCopyUnsafe(ue, pdschChanEstimates, dl_ch_estimates_ext[0], size, offset, copy_index);
|
||||
}
|
||||
if (meas_enabled) {
|
||||
LOG_D(PHY,
|
||||
"[AbsSFN %u.%d] Slot%d Symbol %d: Pilot/Data extraction %5.2f \n",
|
||||
frame,
|
||||
nr_slot_rx,
|
||||
slot,
|
||||
symbol,
|
||||
ue->phy_cpu_stats.cpu_time_stats[DLSCH_EXTRACT_RBS_STATS].p_time / (cpuf * 1000.0));
|
||||
}
|
||||
if (ue->phy_sim_pdsch_rxdataF_ext)
|
||||
memcpy(ue->phy_sim_pdsch_rxdataF_ext + symbol * sizeof(rxdataF_ext), rxdataF_ext, sizeof(rxdataF_ext));
|
||||
|
||||
nb_re_pdsch = (pilots == 1) ?
|
||||
((config_type == NFAPI_NR_DMRS_TYPE1) ? nb_rb_pdsch * (12 - 6 * dlsch_config->n_dmrs_cdm_groups) :
|
||||
nb_rb_pdsch * (12 - 4 * dlsch_config->n_dmrs_cdm_groups)):
|
||||
(nb_rb_pdsch * 12);
|
||||
// Subtract CSI-RS REs from PDSCH RE count
|
||||
if (csi_res_bitmap != 0) {
|
||||
uint32_t csi_re_count = 0;
|
||||
uint32_t csi_res_even = csi_res_bitmap & 0xfff;
|
||||
uint32_t csi_res_odd = (csi_res_bitmap >> 16) & 0xfff;
|
||||
uint32_t count_even = count_bits(&csi_res_even, 1);
|
||||
uint32_t count_odd = count_bits(&csi_res_odd, 1);
|
||||
int start = freq_alloc->first_rb + dlsch_config->BWPStart;
|
||||
int end = freq_alloc->last_rb + 1;
|
||||
for (int rb = start; rb < end; rb++) {
|
||||
if ((freq_alloc->bitmap[rb / 32] >> (rb % 32)) & 0x01)
|
||||
csi_re_count += (rb % 2 == 0) ? count_even : count_odd;
|
||||
}
|
||||
if (meas_enabled) {
|
||||
LOG_D(PHY,
|
||||
"[AbsSFN %u.%d] Slot%d Symbol %d: Pilot/Data extraction %5.2f \n",
|
||||
nb_re_pdsch = (nb_re_pdsch > csi_re_count) ? (nb_re_pdsch - csi_re_count) : 0;
|
||||
if (csi_re_count > 0) {
|
||||
LOG_D(NR_PHY,
|
||||
"[CSI OVERLAP] Frame/Slot %d.%d Symbol %d: CSI-RS overlapping PDSCH - %d CSI-RS REs skipped, %d data REs extracted\n",
|
||||
frame,
|
||||
nr_slot_rx,
|
||||
slot,
|
||||
symbol,
|
||||
ue->phy_cpu_stats.cpu_time_stats[DLSCH_EXTRACT_RBS_STATS].p_time / (cpuf * 1000.0));
|
||||
csi_re_count,
|
||||
nb_re_pdsch);
|
||||
}
|
||||
if (ue->phy_sim_pdsch_rxdataF_ext)
|
||||
memcpy(ue->phy_sim_pdsch_rxdataF_ext + symbol * sizeof(rxdataF_ext), rxdataF_ext, sizeof(rxdataF_ext));
|
||||
}
|
||||
|
||||
nb_re_pdsch = (pilots == 1) ? ((config_type == NFAPI_NR_DMRS_TYPE1) ? nb_rb_pdsch * (12 - 6 * dlsch_config->n_dmrs_cdm_groups)
|
||||
: nb_rb_pdsch * (12 - 4 * dlsch_config->n_dmrs_cdm_groups))
|
||||
: (nb_rb_pdsch * 12);
|
||||
// Subtract CSI-RS REs from PDSCH RE count
|
||||
if (csi_res_bitmap != 0) {
|
||||
uint32_t csi_re_count = 0;
|
||||
uint32_t csi_res_even = csi_res_bitmap & 0xfff;
|
||||
uint32_t csi_res_odd = (csi_res_bitmap >> 16) & 0xfff;
|
||||
uint32_t count_even = count_bits(&csi_res_even, 1);
|
||||
uint32_t count_odd = count_bits(&csi_res_odd, 1);
|
||||
int start = freq_alloc->first_rb + dlsch_config->BWPStart;
|
||||
int end = freq_alloc->last_rb + 1;
|
||||
for (int rb = start; rb < end; rb++) {
|
||||
if ((freq_alloc->bitmap[rb / 32] >> (rb % 32)) & 0x01)
|
||||
csi_re_count += (rb % 2 == 0) ? count_even : count_odd;
|
||||
if (scope_req->copy_rxdataF_to_scope) {
|
||||
size_t size = sizeof(c16_t) * nb_re_pdsch;
|
||||
int copy_index = symbol - dlsch_config->start_symbol;
|
||||
UEscopeCopyUnsafe(ue, pdschRxdataF, rxdataF_ext[0], size, scope_req->scope_rxdataF_offset, copy_index);
|
||||
scope_req->scope_rxdataF_offset += size;
|
||||
}
|
||||
//----------------------------------------------------------
|
||||
//--------------------- Channel Scaling --------------------
|
||||
//----------------------------------------------------------
|
||||
start_meas_nr_ue_phy(ue, DLSCH_CHANNEL_SCALE_STATS);
|
||||
nr_scale_channel(rx_size_symbol, dl_ch_estimates_ext, 0, nb_re_pdsch, nl, nbRx, 0);
|
||||
stop_meas_nr_ue_phy(ue, DLSCH_CHANNEL_SCALE_STATS);
|
||||
if (meas_enabled) {
|
||||
LOG_D(PHY,
|
||||
"[AbsSFN %u.%d] Slot%d Symbol %d: Channel Scale %5.2f \n",
|
||||
frame,
|
||||
nr_slot_rx,
|
||||
slot,
|
||||
symbol,
|
||||
ue->phy_cpu_stats.cpu_time_stats[DLSCH_CHANNEL_SCALE_STATS].p_time / (cpuf * 1000.0));
|
||||
}
|
||||
|
||||
//----------------------------------------------------------
|
||||
//--------------------- Channel Level Calc. ----------------
|
||||
//----------------------------------------------------------
|
||||
start_meas_nr_ue_phy(ue, DLSCH_CHANNEL_LEVEL_STATS);
|
||||
if (first_symbol_flag) {
|
||||
int32_t avg[nl * nbRx];
|
||||
if (nb_re_pdsch)
|
||||
nr_channel_level(0, rx_size_symbol, (c16_t (*)[rx_size_symbol])dl_ch_estimates_ext, nbRx, nl, avg, nb_re_pdsch);
|
||||
else
|
||||
LOG_E(NR_PHY, "Average channel level is 0: nb_rb_pdsch = %d, nb_re_pdsch = %d\n", nb_rb_pdsch, nb_re_pdsch);
|
||||
int avgs = 0;
|
||||
int32_t median[MAX_ANT][MAX_ANT];
|
||||
for (int l = 0; l < nl; l++)
|
||||
for (int aarx = 0; aarx < nbRx; aarx++) {
|
||||
avgs = cmax(avgs, avg[l * nbRx + aarx]);
|
||||
LOG_D(PHY, "nb_rb %d avg_%d_%d Power per SC is %d\n", nb_rb_pdsch, aarx, l, avg[l * nbRx + aarx]);
|
||||
LOG_D(PHY, "avgs Power per SC is %d\n", avgs);
|
||||
median[l][aarx] = avg[l * nbRx + aarx];
|
||||
}
|
||||
nb_re_pdsch = (nb_re_pdsch > csi_re_count) ? (nb_re_pdsch - csi_re_count) : 0;
|
||||
if (csi_re_count > 0) {
|
||||
LOG_D(NR_PHY,
|
||||
"[CSI OVERLAP] Frame/Slot %d.%d Symbol %d: CSI-RS overlapping PDSCH - %d CSI-RS REs skipped, %d data REs extracted\n",
|
||||
frame,
|
||||
nr_slot_rx,
|
||||
symbol,
|
||||
csi_re_count,
|
||||
nb_re_pdsch);
|
||||
}
|
||||
}
|
||||
|
||||
if (scope_req->copy_rxdataF_to_scope) {
|
||||
size_t size = sizeof(c16_t) * nb_re_pdsch;
|
||||
int copy_index = symbol - dlsch_config->start_symbol;
|
||||
UEscopeCopyUnsafe(ue, pdschRxdataF, rxdataF_ext[0], size, scope_req->scope_rxdataF_offset, copy_index);
|
||||
scope_req->scope_rxdataF_offset += size;
|
||||
}
|
||||
//----------------------------------------------------------
|
||||
//--------------------- Channel Scaling --------------------
|
||||
//----------------------------------------------------------
|
||||
start_meas_nr_ue_phy(ue, DLSCH_CHANNEL_SCALE_STATS);
|
||||
nr_scale_channel(rx_size_symbol, dl_ch_estimates_ext, 0, nb_re_pdsch, nl, nbRx, 0);
|
||||
stop_meas_nr_ue_phy(ue, DLSCH_CHANNEL_SCALE_STATS);
|
||||
if (meas_enabled) {
|
||||
LOG_D(PHY,
|
||||
"[AbsSFN %u.%d] Slot%d Symbol %d: Channel Scale %5.2f \n",
|
||||
frame,
|
||||
nr_slot_rx,
|
||||
slot,
|
||||
symbol,
|
||||
ue->phy_cpu_stats.cpu_time_stats[DLSCH_CHANNEL_SCALE_STATS].p_time / (cpuf * 1000.0));
|
||||
}
|
||||
|
||||
//----------------------------------------------------------
|
||||
//--------------------- Channel Level Calc. ----------------
|
||||
//----------------------------------------------------------
|
||||
start_meas_nr_ue_phy(ue, DLSCH_CHANNEL_LEVEL_STATS);
|
||||
if (first_symbol_flag) {
|
||||
int32_t avg[nl * nbRx];
|
||||
if (nb_re_pdsch)
|
||||
nr_channel_level(0, rx_size_symbol, (c16_t(*)[rx_size_symbol])dl_ch_estimates_ext, nbRx, nl, avg, nb_re_pdsch);
|
||||
else
|
||||
LOG_E(NR_PHY, "Average channel level is 0: nb_rb_pdsch = %d, nb_re_pdsch = %d\n", nb_rb_pdsch, nb_re_pdsch);
|
||||
int avgs = 0;
|
||||
int32_t median[MAX_ANT][MAX_ANT];
|
||||
for (int l = 0; l < nl; l++)
|
||||
if (nl > 1) {
|
||||
nr_dlsch_channel_level_median(rx_size_symbol, dl_ch_estimates_ext, median, nl, nbRx, nb_re_pdsch);
|
||||
for (int l = 0; l < nl; l++) {
|
||||
for (int aarx = 0; aarx < nbRx; aarx++) {
|
||||
avgs = cmax(avgs, avg[l * nbRx + aarx]);
|
||||
LOG_D(PHY, "nb_rb %d avg_%d_%d Power per SC is %d\n", nb_rb_pdsch, aarx, l, avg[l * nbRx + aarx]);
|
||||
LOG_D(PHY, "avgs Power per SC is %d\n", avgs);
|
||||
median[l][aarx] = avg[l * nbRx + aarx];
|
||||
}
|
||||
if (nl > 1) {
|
||||
nr_dlsch_channel_level_median(rx_size_symbol, dl_ch_estimates_ext, median, nl, nbRx, nb_re_pdsch);
|
||||
for (int l = 0; l < nl; l++) {
|
||||
for (int aarx = 0; aarx < nbRx; aarx++) {
|
||||
avgs = cmax(avgs, median[l][aarx]);
|
||||
}
|
||||
avgs = cmax(avgs, median[l][aarx]);
|
||||
}
|
||||
}
|
||||
// Output shift: half channel energy (log2|h|^2/2) + MRC antenna gain.
|
||||
// Single-layer adds +1 guard bit (raw peak); multi-layer uses median so no guard needed.
|
||||
if (nl == 1)
|
||||
*log2_maxh = (log2_approx(avgs) >> 1) + 1 + log2_approx(nbRx >> 1);
|
||||
else
|
||||
*log2_maxh = (log2_approx(avgs) >> 1) + log2_approx(nbRx >> 1);
|
||||
|
||||
LOG_D(PHY, "[DLSCH] AbsSubframe %d.%d log2_maxh = %d (%d)\n", frame % 1024, nr_slot_rx, *log2_maxh, avgs);
|
||||
}
|
||||
// Output shift: half channel energy (log2|h|^2/2) + MRC antenna gain.
|
||||
// Single-layer adds +1 guard bit (raw peak); multi-layer uses median so no guard needed.
|
||||
if (nl == 1)
|
||||
*log2_maxh = (log2_approx(avgs) >> 1) + 1 + log2_approx(nbRx >> 1);
|
||||
else
|
||||
*log2_maxh = (log2_approx(avgs) >> 1) + log2_approx(nbRx >> 1);
|
||||
LOG_D(PHY, "[DLSCH] AbsSubframe %d.%d log2_maxh = %d (%d)\n", frame % 1024, nr_slot_rx, *log2_maxh, avgs);
|
||||
#if T_TRACER
|
||||
T(T_UE_PHY_PDSCH_ENERGY,
|
||||
T_INT(gNB_id),
|
||||
T_INT(frame % 1024),
|
||||
T_INT(nr_slot_rx),
|
||||
T_INT(avg[0]), // layer 0, antenna 0
|
||||
T_INT(nbRx > 1 ? avg[1] : 0), // layer 0, antenna 1
|
||||
T_INT(nl > 1 ? avg[nbRx] : 0), // layer 1, antenna 0
|
||||
T_INT(nl > 1 && nbRx > 1 ? avg[nbRx + 1] : 0)); // layer 1, antenna 1
|
||||
#endif
|
||||
}
|
||||
stop_meas_nr_ue_phy(ue, DLSCH_CHANNEL_LEVEL_STATS);
|
||||
if (meas_enabled) {
|
||||
LOG_D(PHY,
|
||||
"[AbsSFN %u.%d] Slot%d Symbol %d first_symbol_flag %d: Channel Level %5.2f \n",
|
||||
frame,
|
||||
nr_slot_rx,
|
||||
slot,
|
||||
symbol,
|
||||
first_symbol_flag,
|
||||
ue->phy_cpu_stats.cpu_time_stats[DLSCH_CHANNEL_LEVEL_STATS].p_time / (cpuf * 1000.0));
|
||||
}
|
||||
|
||||
//----------------------------------------------------------
|
||||
//--------------------- channel compensation ---------------
|
||||
//----------------------------------------------------------
|
||||
start_meas_nr_ue_phy(ue, DLSCH_CHANNEL_COMPENSATION_STATS);
|
||||
nr_channel_compensation(rx_size_symbol,
|
||||
nbRx,
|
||||
nl,
|
||||
rxdataF_ext,
|
||||
chFext,
|
||||
dl_ch_mag[symbol],
|
||||
dl_ch_magb[symbol],
|
||||
dl_ch_magr[symbol],
|
||||
p_rxComp,
|
||||
need_rho ? (c16_t(*)[nl][rx_size_symbol])rho_dl[symbol] : NULL,
|
||||
dlsch->cw_info.qamModOrder,
|
||||
0, // symbol already baked into p_rxComp
|
||||
*log2_maxh);
|
||||
stop_meas_nr_ue_phy(ue, DLSCH_CHANNEL_COMPENSATION_STATS);
|
||||
if (meas_enabled) {
|
||||
LOG_D(PHY,
|
||||
"[AbsSFN %u.%d] Slot%d Symbol %d log2_maxh %d Channel Comp %5.2f \n",
|
||||
frame,
|
||||
nr_slot_rx,
|
||||
slot,
|
||||
symbol,
|
||||
*log2_maxh,
|
||||
ue->phy_cpu_stats.cpu_time_stats[DLSCH_CHANNEL_COMPENSATION_STATS].p_time / (cpuf * 1000.0));
|
||||
}
|
||||
// Please keep it: useful for debugging
|
||||
#ifdef DEBUG_PDSCH_RX
|
||||
char filename[50];
|
||||
|
||||
snprintf(filename, 50, "rxdataF0_symb_%d_nr_slot_rx_%d.m", symbol, nr_slot_rx);
|
||||
write_output(filename, "rxdataF0", &rxdataF[0][symbol * fp->ofdm_symbol_size], fp->ofdm_symbol_size, 1, 1);
|
||||
|
||||
snprintf(filename, 50, "dl_ch_estimates0_symb_%d_nr_slot_rx_%d.m", symbol, nr_slot_rx);
|
||||
write_output(filename, "dl_ch_estimates0", &dl_ch_estimates[0][symbol * fp->ofdm_symbol_size], fp->ofdm_symbol_size, 1, 1);
|
||||
|
||||
snprintf(filename, 50, "rxdataF_ext0_symb_%d_nr_slot_rx_%d.m", symbol, nr_slot_rx);
|
||||
write_output(filename, "rxdataF_ext0", &rxdataF_ext[0][0], rx_size_symbol, 1, 1);
|
||||
|
||||
snprintf(filename, 50, "dl_ch_estimates_ext0_symb_%d_nr_slot_rx_%d.m", symbol, nr_slot_rx);
|
||||
write_output(filename, "dl_ch_estimates_ext0", &dl_ch_estimates_ext[0][0], rx_size_symbol, 1, 1);
|
||||
|
||||
snprintf(filename, 50, "rxdataF_comp00_symb_%d_nr_slot_rx_%d.m", symbol, nr_slot_rx);
|
||||
write_output(filename, "rxdataF_comp00", rxdataF_comp[symbol][0], rx_size_symbol, 1, 1);
|
||||
T(T_UE_PHY_PDSCH_ENERGY,
|
||||
T_INT(gNB_id),
|
||||
T_INT(frame % 1024),
|
||||
T_INT(nr_slot_rx),
|
||||
T_INT(avg[0]), // layer 0, antenna 0
|
||||
T_INT(nbRx > 1 ? avg[1] : 0), // layer 0, antenna 1
|
||||
T_INT(nl > 1 ? avg[nbRx] : 0), // layer 1, antenna 0
|
||||
T_INT(nl > 1 && nbRx > 1 ? avg[nbRx + 1] : 0)); // layer 1, antenna 1
|
||||
#endif
|
||||
}
|
||||
stop_meas_nr_ue_phy(ue, DLSCH_CHANNEL_LEVEL_STATS);
|
||||
if (meas_enabled) {
|
||||
LOG_D(PHY,
|
||||
"[AbsSFN %u.%d] Slot%d Symbol %d first_symbol_flag %d: Channel Level %5.2f \n",
|
||||
frame,
|
||||
nr_slot_rx,
|
||||
slot,
|
||||
symbol,
|
||||
first_symbol_flag,
|
||||
ue->phy_cpu_stats.cpu_time_stats[DLSCH_CHANNEL_LEVEL_STATS].p_time / (cpuf * 1000.0));
|
||||
}
|
||||
|
||||
//----------------------------------------------------------
|
||||
//--------------------- channel compensation ---------------
|
||||
//----------------------------------------------------------
|
||||
start_meas_nr_ue_phy(ue, DLSCH_CHANNEL_COMPENSATION_STATS);
|
||||
nr_channel_compensation(rx_size_symbol,
|
||||
nbRx,
|
||||
nl,
|
||||
rxdataF_ext,
|
||||
chFext,
|
||||
dl_ch_mag[symbol],
|
||||
dl_ch_magb[symbol],
|
||||
dl_ch_magr[symbol],
|
||||
p_rxComp,
|
||||
need_rho ? (c16_t(*)[nl][rx_size_symbol])rho_dl[symbol] : NULL,
|
||||
dlsch->cw_info.qamModOrder,
|
||||
0, // symbol already baked into p_rxComp
|
||||
*log2_maxh);
|
||||
stop_meas_nr_ue_phy(ue, DLSCH_CHANNEL_COMPENSATION_STATS);
|
||||
if (meas_enabled) {
|
||||
LOG_D(PHY,
|
||||
"[AbsSFN %u.%d] Slot%d Symbol %d log2_maxh %d Channel Comp %5.2f \n",
|
||||
frame,
|
||||
nr_slot_rx,
|
||||
slot,
|
||||
symbol,
|
||||
*log2_maxh,
|
||||
ue->phy_cpu_stats.cpu_time_stats[DLSCH_CHANNEL_COMPENSATION_STATS].p_time / (cpuf * 1000.0));
|
||||
}
|
||||
// Please keep it: useful for debugging
|
||||
#ifdef DEBUG_PDSCH_RX
|
||||
char filename[50];
|
||||
snprintf(filename, 50, "rxdataF0_symb_%d_nr_slot_rx_%d.m", symbol, nr_slot_rx);
|
||||
write_output(filename, "rxdataF0", &rxdataF[0][symbol * fp->ofdm_symbol_size], fp->ofdm_symbol_size, 1, 1);
|
||||
snprintf(filename, 50, "dl_ch_estimates0_symb_%d_nr_slot_rx_%d.m", symbol, nr_slot_rx);
|
||||
write_output(filename, "dl_ch_estimates0", &dl_ch_estimates[0][symbol * fp->ofdm_symbol_size], fp->ofdm_symbol_size, 1, 1);
|
||||
snprintf(filename, 50, "rxdataF_ext0_symb_%d_nr_slot_rx_%d.m", symbol, nr_slot_rx);
|
||||
write_output(filename, "rxdataF_ext0", &rxdataF_ext[0][0], rx_size_symbol, 1, 1);
|
||||
snprintf(filename, 50, "dl_ch_estimates_ext0_symb_%d_nr_slot_rx_%d.m", symbol, nr_slot_rx);
|
||||
write_output(filename, "dl_ch_estimates_ext0", &dl_ch_estimates_ext[0][0], rx_size_symbol, 1, 1);
|
||||
snprintf(filename, 50, "rxdataF_comp00_symb_%d_nr_slot_rx_%d.m", symbol, nr_slot_rx);
|
||||
write_output(filename, "rxdataF_comp00", &rxdataF_comp[0][0][symbol * rx_size_symbol], rx_size_symbol, 1, 1);
|
||||
#endif
|
||||
|
||||
// MRC is performed inline by nr_channel_compensation; apply MMSE for multi-layer
|
||||
start_meas_nr_ue_phy(ue, DLSCH_MRC_MMSE_STATS);
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
#include "SCHED_NR_UE/defs.h"
|
||||
#include "common/utils/nr/nr_common.h"
|
||||
|
||||
#include "common_lib.h"
|
||||
#include <math.h>
|
||||
|
||||
#include "PHY/NR_REFSIG/pss_nr.h"
|
||||
@@ -333,6 +332,8 @@ static void nr_scan_ssb(void *arg)
|
||||
continue;
|
||||
}
|
||||
|
||||
ssbInfo->pssCorrAvgPower = search_params.pss_res.avg;
|
||||
ssbInfo->pssCorrPeakPower = search_params.pss_res.peak;
|
||||
ssbInfo->ssbOffset = search_params.pss_res.pos - search_params.nb_prefix_samples;
|
||||
ssbInfo->nidCell = search_params.sss_res.nid_cell;
|
||||
|
||||
|
||||
@@ -156,17 +156,14 @@ int nr_ulsch_encoding(PHY_VARS_NR_UE *ue,
|
||||
|
||||
for (int r = 0; r < TB_parameters->C; r++) {
|
||||
nrLDPC_segment_encoding_parameters_t *segment_parameters = &TB_parameters->segments[r];
|
||||
int E = nr_get_E(TB_parameters->G, TB_parameters->C, TB_parameters->Qm, TB_parameters->nb_layers, r);
|
||||
if (E < 0)
|
||||
return -1;
|
||||
segment_parameters->c = harq_process->c[r];
|
||||
segment_parameters->E = nr_get_E(TB_parameters->G,
|
||||
TB_parameters->C,
|
||||
TB_parameters->Qm,
|
||||
TB_parameters->nb_layers,
|
||||
r);
|
||||
|
||||
segment_parameters->E = E;
|
||||
reset_meas(&segment_parameters->ts_interleave);
|
||||
reset_meas(&segment_parameters->ts_rate_match);
|
||||
reset_meas(&segment_parameters->ts_ldpc_encode);
|
||||
|
||||
} // TB_parameters->C
|
||||
} // pusch_id
|
||||
|
||||
|
||||
@@ -882,15 +882,23 @@ static void map_overlapped_ack(uci_on_pusch_bit_type_t *template,
|
||||
const int32_t num_ack_remaining = G_ack - ack_bits_marked;
|
||||
if (num_ack_remaining <= 0)
|
||||
continue;
|
||||
const uint32_t d_factor_re = get_d_factor_re(num_ack_remaining, num_reserved_bits_on_sym);
|
||||
for (uint32_t i = 0; i < num_reserved_bits_on_sym && ack_bits_marked < G_ack; i += d_factor_re) {
|
||||
uint32_t pos = reserved_indices_on_this_sym[i];
|
||||
int bit_in_group = pos % Qm;
|
||||
if (template[pos] == BIT_TYPE_ULSCH) // puncturing ULSCH
|
||||
template[pos] = (bit_in_group >= placeholder_start) ? BIT_TYPE_ACK_PLACEHOLDER : BIT_TYPE_ACK_RESERVED;
|
||||
else // puncturing CSIp2
|
||||
template[pos] = (bit_in_group >= placeholder_start) ? BIT_TYPE_ACK_PLACEHOLDER_CSI2 : BIT_TYPE_ACK_RESERVED_CSI2;
|
||||
ack_bits_marked++;
|
||||
AssertFatal(num_reserved_bits_on_sym % Qm == 0,
|
||||
"reserved bits on symbol (%u) not a multiple of Qm (%d)\n",
|
||||
num_reserved_bits_on_sym,
|
||||
Qm);
|
||||
const uint32_t num_reserved_re = num_reserved_bits_on_sym / Qm;
|
||||
const uint32_t num_ack_re_remaining = num_ack_remaining / Qm;
|
||||
const uint32_t d_factor_re = get_d_factor_re(num_ack_re_remaining, num_reserved_re);
|
||||
for (uint32_t re = 0; re < num_reserved_re && ack_bits_marked < G_ack; re += d_factor_re) {
|
||||
for (int b = 0; b < Qm; b++) {
|
||||
uint32_t pos = reserved_indices_on_this_sym[re * Qm + b];
|
||||
int bit_in_group = pos % Qm;
|
||||
if (template[pos] == BIT_TYPE_ULSCH) // puncturing ULSCH
|
||||
template[pos] = (bit_in_group >= placeholder_start) ? BIT_TYPE_ACK_PLACEHOLDER : BIT_TYPE_ACK_RESERVED;
|
||||
else // puncturing CSIp2
|
||||
template[pos] = (bit_in_group >= placeholder_start) ? BIT_TYPE_ACK_PLACEHOLDER_CSI2 : BIT_TYPE_ACK_RESERVED_CSI2;
|
||||
ack_bits_marked++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -733,26 +733,15 @@ void nr_generate_pucch2(c16_t **txdataF,
|
||||
const int seq_sz = ((startingPRB + pucch_pdu->prb_size) * NR_PUCCH_DMRS_RB * DMRS_MOD_ORDER + 31) / 32;
|
||||
uint32_t *seq = gold_cache(temp_x2, seq_sz);
|
||||
for (int rb=0; rb<pucch_pdu->prb_size; rb++) {
|
||||
//startingPRB = startingPRB + rb;
|
||||
const bool nb_rb_is_even = frame_parms->N_RB_DL & 1;
|
||||
const bool nb_rb_is_even = !(frame_parms->N_RB_DL & 1);
|
||||
const int halfRBs = frame_parms->N_RB_DL / 2;
|
||||
const int baseRB = rb + startingPRB;
|
||||
int re_offset = (l + startingSymbolIndex) * frame_parms->ofdm_symbol_size + 12 * baseRB;
|
||||
if (nb_rb_is_even) {
|
||||
if (baseRB < halfRBs) // if number RBs in bandwidth is even and current PRB is lower band
|
||||
re_offset += frame_parms->first_carrier_offset;
|
||||
else
|
||||
re_offset -= halfRBs;
|
||||
} else {
|
||||
if (baseRB < halfRBs) // if number RBs in bandwidth is odd and current PRB is lower band
|
||||
re_offset += frame_parms->first_carrier_offset;
|
||||
else if (baseRB > halfRBs) // if number RBs in bandwidth is odd and current PRB is upper band
|
||||
re_offset += -halfRBs + 6;
|
||||
else
|
||||
re_offset += frame_parms->first_carrier_offset;
|
||||
}
|
||||
int re_offset = (l + startingSymbolIndex) * frame_parms->ofdm_symbol_size + NR_NB_SC_PER_RB * baseRB;
|
||||
if (baseRB > halfRBs)
|
||||
re_offset -= (nb_rb_is_even) ? (halfRBs * NR_NB_SC_PER_RB) : (halfRBs * NR_NB_SC_PER_RB + 6);
|
||||
else
|
||||
re_offset += frame_parms->first_carrier_offset;
|
||||
|
||||
//txptr = &txdataF[0][re_offset];
|
||||
int k=0;
|
||||
#ifdef DEBUG_NR_PUCCH_TX
|
||||
int kk=0;
|
||||
|
||||
@@ -46,13 +46,12 @@
|
||||
|
||||
#define INITIAL_SSS_NR (7)
|
||||
|
||||
static void init_context_sss_nr(int amp, int16_t d_sss[N_ID_2_NUMBER][N_ID_1_NUMBER][LENGTH_SSS_NR])
|
||||
static void init_context_sss_nr(int amp, int N_ID_2, int16_t d_sss[N_ID_1_NUMBER][LENGTH_SSS_NR])
|
||||
{
|
||||
int16_t x0[LENGTH_SSS_NR];
|
||||
int16_t x1[LENGTH_SSS_NR];
|
||||
int16_t dss_current;
|
||||
int m0, m1;
|
||||
int nid_2_num = get_softmodem_params()->sl_mode == 0 ? N_ID_2_NUMBER : N_ID_2_NUMBER_SL;
|
||||
|
||||
const int x0_initial[INITIAL_SSS_NR] = { 1, 0, 0, 0, 0, 0, 0 };
|
||||
const int x1_initial[INITIAL_SSS_NR] = { 1, 0, 0, 0, 0, 0, 0 };
|
||||
@@ -65,21 +64,19 @@ static void init_context_sss_nr(int amp, int16_t d_sss[N_ID_2_NUMBER][N_ID_1_NUM
|
||||
x1[i + 7] = (x1[i + 1] + x1[i]) % (2);
|
||||
}
|
||||
|
||||
for (int N_ID_2 = 0; N_ID_2 < nid_2_num; N_ID_2++) {
|
||||
for (int N_ID_1 = 0; N_ID_1 < N_ID_1_NUMBER; N_ID_1++) {
|
||||
m0 = 15 * (N_ID_1 / 112) + (5 * N_ID_2);
|
||||
m1 = N_ID_1 % 112;
|
||||
for (int n = 0; n < LENGTH_SSS_NR; n++) {
|
||||
dss_current = (1 - 2 * x0 [(n + m0) % (LENGTH_SSS_NR)]) * (1 - 2 * x1[(n + m1) % (LENGTH_SSS_NR)]);
|
||||
for (int N_ID_1 = 0; N_ID_1 < N_ID_1_NUMBER; N_ID_1++) {
|
||||
m0 = 15 * (N_ID_1 / 112) + (5 * N_ID_2);
|
||||
m1 = N_ID_1 % 112;
|
||||
for (int n = 0; n < LENGTH_SSS_NR; n++) {
|
||||
dss_current = (1 - 2 * x0[(n + m0) % (LENGTH_SSS_NR)]) * (1 - 2 * x1[(n + m1) % (LENGTH_SSS_NR)]);
|
||||
/* Modulation of SSS is a BPSK TS 36.211 chapter 5.1.2 BPSK */
|
||||
#if 1
|
||||
d_sss[N_ID_2][N_ID_1][n] = dss_current;// * amp;
|
||||
(void) amp;
|
||||
d_sss[N_ID_1][n] = dss_current; // * amp;
|
||||
(void)amp;
|
||||
#else
|
||||
(void) amp;
|
||||
d_sss[N_ID_2][N_ID_1][n] = (dss_current * SHRT_MAX)>>SCALING_PSS_NR;
|
||||
(void)amp;
|
||||
d_sss[N_ID_1][n] = (dss_current * SHRT_MAX) >> SCALING_PSS_NR;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -191,8 +188,8 @@ sss_detection_result_t rx_sss_nr(nr_sss_params_t *params,
|
||||
c16_t pss_ext[params->nb_antennas_rx][LENGTH_PSS_NR];
|
||||
c16_t sss_ext[params->nb_antennas_rx][LENGTH_SSS_NR];
|
||||
const int Nid2 = GET_NID2(pss->nid2);
|
||||
int16_t d_sss[N_ID_2_NUMBER][N_ID_1_NUMBER][LENGTH_SSS_NR];
|
||||
init_context_sss_nr(AMP, d_sss);
|
||||
int16_t d_sss[N_ID_1_NUMBER][LENGTH_SSS_NR];
|
||||
init_context_sss_nr(AMP, Nid2, d_sss);
|
||||
|
||||
pss_sss_extract_nr(params, pss_ext, sss_ext, rxdataF); /* subframe */
|
||||
|
||||
@@ -234,7 +231,7 @@ sss_detection_result_t rx_sss_nr(nr_sss_params_t *params,
|
||||
(c64_t){round(cos(M_PI / 3 / 15 * (phase_to_try[idx])) * 32767), round(sin(M_PI / 3 / 15 * (phase_to_try[idx])) * 32767)};
|
||||
for (int n1 = Nid1_start; n1 < Nid1_end; n1++) { // all possible Nid1 values
|
||||
int64_t metric = 0;
|
||||
int16_t *d = d_sss[Nid2][n1];
|
||||
int16_t *d = d_sss[n1];
|
||||
for (int i = 0; i < LENGTH_SSS_NR; i++) {
|
||||
// metric is only real part because sss is a pure real signal (imaginary is 0)
|
||||
metric += d[i] * (rot.r * sss_comp[i].r - rot.i * sss_comp[i].i);
|
||||
@@ -277,7 +274,7 @@ sss_detection_result_t rx_sss_nr(nr_sss_params_t *params,
|
||||
|
||||
int Nid1 = GET_NID1(res.nid_cell);
|
||||
LOG_D(PHY, "Nid2 %d Nid1 %d metric %d, phase_max %d \n", Nid2, Nid1, res.metric, res.phase);
|
||||
int16_t *d = d_sss[Nid2][Nid1];
|
||||
int16_t *d = d_sss[Nid1];
|
||||
c32_t sig_sum = {};
|
||||
for (int i = 0; i < LENGTH_SSS_NR; i++) {
|
||||
sig_sum.r += d[i] * sss_comp[i].r;
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#ifndef CALIB_SCOPE_H
|
||||
#define CALIB_SCOPE_H
|
||||
|
||||
#include "common_lib.h"
|
||||
|
||||
void CalibrationInitScope(void **samplesRx, openair0_device_t *rfdevice);
|
||||
#endif
|
||||
|
||||
@@ -107,8 +107,6 @@ int main(int argc, char **argv) {
|
||||
.eth_params=NULL,
|
||||
//! record player data, definition in record_player.h
|
||||
.recplay_state=NULL,
|
||||
/* !brief Indicates if device already initialized */
|
||||
.is_init=0,
|
||||
/*!brief Can be used by driver to hold internal structure*/
|
||||
.priv=NULL,
|
||||
/* Functions API, which are called by the application*/
|
||||
|
||||
@@ -24,13 +24,13 @@
|
||||
#define MAX_KBYTES_WRITTEN_PER_SESSION (1000 * 1000)
|
||||
|
||||
ImScopeDataWrapper scope_array[EXTRA_SCOPE_TYPES];
|
||||
typedef struct alignas(hardware_destructive_interference_size) ImScopeDumpInstruction {
|
||||
typedef struct ImScopeDumpInstruction {
|
||||
int slot;
|
||||
int frame;
|
||||
const char *cause;
|
||||
} ImScopeDumpInstruction;
|
||||
|
||||
std::atomic<ImScopeDumpInstruction> dump_instruction;
|
||||
alignas(hardware_destructive_interference_size) std::atomic<ImScopeDumpInstruction> dump_instruction;
|
||||
ImScopeDumpInstruction void_instruction({-1, -1, nullptr});
|
||||
|
||||
extern "C" void imscope_record_autoinit(void *dataptr)
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
#include <malloc.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include "common_lib.h"
|
||||
#include "openair2/PHY_INTERFACE/IF_Module_NB_IoT.h"
|
||||
#include "defs_eNB.h"
|
||||
//#include <complex.h>
|
||||
@@ -93,7 +92,6 @@ static inline void* malloc16_clear( size_t size )
|
||||
#include "PHY/LTE_TRANSPORT/defs_NB_IoT.h"
|
||||
#include <pthread.h>
|
||||
|
||||
#include "radio/COMMON/common_lib.h"
|
||||
#include "common/openairinterface5g_limits.h"
|
||||
|
||||
#define NUM_DCI_MAX_NB_IoT 32
|
||||
|
||||
@@ -29,7 +29,6 @@
|
||||
#include <malloc.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include "common_lib.h"
|
||||
#include <common/utils/LOG/log.h>
|
||||
#include "assertions.h"
|
||||
|
||||
|
||||
@@ -30,7 +30,6 @@
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "common_lib.h"
|
||||
#include "defs_common.h"
|
||||
#include "defs_RU.h"
|
||||
#include "impl_defs_top.h"
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user