mirror of
https://gitlab.eurecom.fr/oai/openairinterface5g.git
synced 2026-07-13 12:40:28 +00:00
Compare commits
26 Commits
pre-commit
...
fix-rx-win
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8890ec7387 | ||
|
|
1720267638 | ||
|
|
9df46ef247 | ||
|
|
0c8fd99cc0 | ||
|
|
0ae66ec46b | ||
|
|
e969caf9af | ||
|
|
3c95ba0239 | ||
|
|
b6b93e9991 | ||
|
|
b2b823c40c | ||
|
|
59f4ec8196 | ||
|
|
aa574dd721 | ||
|
|
ce42bcd30a | ||
|
|
477df2c2bc | ||
|
|
aa0468dff9 | ||
|
|
1643bd61f6 | ||
|
|
2e96acf0d0 | ||
|
|
ca02b456f5 | ||
|
|
cb1785519e | ||
|
|
fd32d3afdc | ||
|
|
20c91b235d | ||
|
|
7951aab40d | ||
|
|
6b2b62ed85 | ||
|
|
012f968dc9 | ||
|
|
4d70d4f254 | ||
|
|
d84d4cc209 | ||
|
|
ae1e9bb892 |
@@ -5,3 +5,5 @@ common/utils/T/T_IDs.h
|
||||
common/utils/T/T_messages.txt.h
|
||||
common/utils/T/genids
|
||||
common/utils/T/genids.o
|
||||
.cache
|
||||
.git
|
||||
|
||||
@@ -1827,13 +1827,14 @@ add_executable(nr-oru
|
||||
${OPENAIR_DIR}/openair1/SCHED_NR/nr_prach_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 SCHED_RU_LIB PHY_COMMON PHY_RU PHY_NR shlib_loader z dl
|
||||
radio_common softmodem_common)
|
||||
target_link_libraries(nr-oru PRIVATE pthread m CONFIG_LIB rt ${T_LIB} utils
|
||||
barrier actor)
|
||||
target_link_libraries(nr-oru PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs nr_phy_common time_management)
|
||||
target_link_libraries(nr-oru PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs nr_phy_common time_management PHY_NR MAC_NR_COMMON)
|
||||
|
||||
# nr-softmodem
|
||||
###################################################
|
||||
|
||||
142
ci-scripts/xml_files/container_5g_oai-nr-oru.xml
Normal file
142
ci-scripts/xml_files/container_5g_oai-nr-oru.xml
Normal file
@@ -0,0 +1,142 @@
|
||||
<!--
|
||||
|
||||
Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The OpenAirInterface Software Alliance licenses this file to You under
|
||||
the OAI Public License, Version 1.1 (the "License"); you may not use this file
|
||||
except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.openairinterface.org/?page_id=698
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||
contact@openairinterface.org
|
||||
|
||||
-->
|
||||
<testCaseList>
|
||||
<htmlTabRef>oai-nr-oru</htmlTabRef>
|
||||
<htmlTabName>1x1 </htmlTabName>
|
||||
<htmlTabIcon>wrench</htmlTabIcon>
|
||||
|
||||
<testCase>
|
||||
<class>Pull_Local_Registry</class>
|
||||
<desc>Pull Images from Local Registry</desc>
|
||||
<node>localhost</node>
|
||||
<images>oai-gnb oai-nr-ue oai-nr-oru</images>
|
||||
</testCase>
|
||||
|
||||
<testCase>
|
||||
<class>Create_Workspace</class>
|
||||
<desc>Create new Workspace</desc>
|
||||
<node>localhost</node>
|
||||
</testCase>
|
||||
|
||||
<testCase>
|
||||
<class>Custom_Script</class>
|
||||
<desc>Setup sriov and network interfaces</desc>
|
||||
<node>cacofonix</node>
|
||||
<script>yaml_files/sa_fhi_7.2_oaioru_1x1_gnb/setup.sh</script>
|
||||
</testCase>
|
||||
|
||||
<testCase>
|
||||
<class>Deploy_Object</class>
|
||||
<desc>Deploy OAI 5G CoreNetwork</desc>
|
||||
<node>localhost</node>
|
||||
<yaml_path>ci-scripts/yaml_files/sa_fhi_7.2_oaioru_1x1_gnb</yaml_path>
|
||||
<services>mysql oai-amf oai-smf oai-upf oai-ext-dn</services>
|
||||
</testCase>
|
||||
|
||||
<testCase>
|
||||
<class>Deploy_Object</class>
|
||||
<desc>Deploy OAI O-RU</desc>
|
||||
<node>localhost</node>
|
||||
<yaml_path>ci-scripts/yaml_files/sa_fhi_7.2_oaioru_1x1_gnb</yaml_path>
|
||||
<services>oai-nr-oru</services>
|
||||
</testCase>
|
||||
|
||||
<testCase>
|
||||
<class>Deploy_Object</class>
|
||||
<desc>Deploy OAI 5G gNB 7.2</desc>
|
||||
<node>localhost</node>
|
||||
<yaml_path>ci-scripts/yaml_files/sa_fhi_7.2_oaioru_1x1_gnb</yaml_path>
|
||||
<services>oai-gnb</services>
|
||||
</testCase>
|
||||
|
||||
<testCase>
|
||||
<class>Deploy_Object</class>
|
||||
<desc>Deploy OAI 5G NR-UE</desc>
|
||||
<node>localhost</node>
|
||||
<yaml_path>ci-scripts/yaml_files/sa_fhi_7.2_oaioru_1x1_gnb</yaml_path>
|
||||
<services>oai-nr-ue</services>
|
||||
</testCase>
|
||||
|
||||
<testCase>
|
||||
<class>Attach_UE</class>
|
||||
<desc>Attach OAI UE (Wait for IP)</desc>
|
||||
<id>rfsim5g_ue</id>
|
||||
<node>localhost</node>
|
||||
</testCase>
|
||||
|
||||
<testCase>
|
||||
<class>Ping</class>
|
||||
<desc>Ping ext-dn from NR-UE</desc>
|
||||
<id>rfsim5g_ue</id>
|
||||
<node>localhost</node>
|
||||
<svr_id>rfsim5g_ext_dn</svr_id>
|
||||
<svr_node>localhost</svr_node>
|
||||
<ping_args>-c 20 -i 0.25</ping_args>
|
||||
<ping_packetloss_threshold>5</ping_packetloss_threshold>
|
||||
</testCase>
|
||||
|
||||
<testCase>
|
||||
<class>Ping</class>
|
||||
<desc>Ping NR-UE from ext-dn</desc>
|
||||
<id>rfsim5g_ext_dn</id>
|
||||
<node>localhost</node>
|
||||
<svr_id>rfsim5g_ue</svr_id>
|
||||
<svr_node>localhost</svr_node>
|
||||
<ping_args>-c 20 -i 0.25</ping_args>
|
||||
<ping_packetloss_threshold>5</ping_packetloss_threshold>
|
||||
</testCase>
|
||||
|
||||
<testCase>
|
||||
<class>Detach_UE</class>
|
||||
<desc>Detach OAI UE</desc>
|
||||
<id>rfsim5g_ue</id>
|
||||
<node>localhost</node>
|
||||
</testCase>
|
||||
|
||||
<testCase>
|
||||
<class>Undeploy_Object</class>
|
||||
<always_exec>true</always_exec>
|
||||
<desc>Undeploy all OAI 5G stack</desc>
|
||||
<node>localhost</node>
|
||||
<yaml_path>ci-scripts/yaml_files/sa_fhi_7.2_oaioru_1x1_gnb/</yaml_path>
|
||||
<analysis>
|
||||
<services>oai-gnb=EndsWithBye oai-nr-ue oai-nr-oru</services>
|
||||
</analysis>
|
||||
</testCase>
|
||||
|
||||
<testCase>
|
||||
<class>Custom_Script</class>
|
||||
<desc>Setup sriov and network interfaces VVDN</desc>
|
||||
<node>cacofonix</node>
|
||||
<script>yaml_files/sa_fhi_7.2_oaioru_1x1_gnb/cleanup.sh</script>
|
||||
</testCase>
|
||||
|
||||
<testCase>
|
||||
<class>Clean_Test_Server_Images</class>
|
||||
<always_exec>true</always_exec>
|
||||
<desc>Clean Test Images on Test Server</desc>
|
||||
<node>localhost</node>
|
||||
<images>oai-gnb oai-nr-ue oai-nr-oru</images>
|
||||
</testCase>
|
||||
|
||||
</testCaseList>
|
||||
5
ci-scripts/yaml_files/sa_fhi_7.2_oaioru_1x1_gnb/cleanup.sh
Executable file
5
ci-scripts/yaml_files/sa_fhi_7.2_oaioru_1x1_gnb/cleanup.sh
Executable file
@@ -0,0 +1,5 @@
|
||||
set -e
|
||||
sudo cpupower idle-set -E > /dev/null
|
||||
sudo sysctl kernel.sched_rt_runtime_us=950000
|
||||
sudo sysctl kernel.timer_migration=1
|
||||
exit 0
|
||||
108
ci-scripts/yaml_files/sa_fhi_7.2_oaioru_1x1_gnb/cn.yml
Normal file
108
ci-scripts/yaml_files/sa_fhi_7.2_oaioru_1x1_gnb/cn.yml
Normal file
@@ -0,0 +1,108 @@
|
||||
services:
|
||||
mysql:
|
||||
container_name: "rfsim5g-mysql"
|
||||
image: mysql:8.0
|
||||
init: true
|
||||
volumes:
|
||||
- ./../5g_rfsimulator/oai_db.sql:/docker-entrypoint-initdb.d/oai_db.sql
|
||||
- ./../5g_rfsimulator/mysql-healthcheck.sh:/tmp/mysql-healthcheck.sh
|
||||
environment:
|
||||
- TZ=Europe/Paris
|
||||
- MYSQL_DATABASE=oai_db
|
||||
- MYSQL_USER=test
|
||||
- MYSQL_PASSWORD=test
|
||||
- MYSQL_ROOT_PASSWORD=linux
|
||||
healthcheck:
|
||||
test: /bin/bash -c "/tmp/mysql-healthcheck.sh"
|
||||
start_period: 10s
|
||||
start_interval: 500ms
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 30
|
||||
networks:
|
||||
public_net:
|
||||
ipv4_address: 192.168.101.131
|
||||
oai-amf:
|
||||
container_name: "rfsim5g-oai-amf"
|
||||
image: oaisoftwarealliance/oai-amf:v2.1.10
|
||||
environment:
|
||||
- TZ=Europe/paris
|
||||
volumes:
|
||||
- ./../5g_rfsimulator/mini_nonrf_config.yaml:/openair-amf/etc/config.yaml
|
||||
depends_on:
|
||||
- mysql
|
||||
networks:
|
||||
public_net:
|
||||
ipv4_address: 192.168.101.132
|
||||
oai-smf:
|
||||
container_name: "rfsim5g-oai-smf"
|
||||
image: oaisoftwarealliance/oai-smf:v2.1.10
|
||||
environment:
|
||||
- TZ=Europe/Paris
|
||||
volumes:
|
||||
- ./../5g_rfsimulator/mini_nonrf_config.yaml:/openair-smf/etc/config.yaml
|
||||
depends_on:
|
||||
- oai-amf
|
||||
networks:
|
||||
public_net:
|
||||
ipv4_address: 192.168.101.133
|
||||
oai-upf:
|
||||
container_name: "rfsim5g-oai-upf"
|
||||
image: oaisoftwarealliance/oai-upf:v2.1.10
|
||||
init: true
|
||||
environment:
|
||||
- TZ=Europe/Paris
|
||||
volumes:
|
||||
- ./../5g_rfsimulator/mini_nonrf_config.yaml:/openair-upf/etc/config.yaml
|
||||
depends_on:
|
||||
- oai-smf
|
||||
cap_add:
|
||||
- NET_ADMIN
|
||||
- SYS_ADMIN
|
||||
cap_drop:
|
||||
- ALL
|
||||
privileged: true
|
||||
networks:
|
||||
public_net:
|
||||
ipv4_address: 192.168.101.134
|
||||
interface_name: eth0
|
||||
traffic_net:
|
||||
ipv4_address: 192.168.102.134
|
||||
interface_name: eth1
|
||||
oai-ext-dn:
|
||||
privileged: true
|
||||
container_name: rfsim5g-oai-ext-dn
|
||||
image: oaisoftwarealliance/trf-gen-cn5g:focal
|
||||
init: true
|
||||
entrypoint: /bin/bash -c \
|
||||
"iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE;"\
|
||||
"ip route add 12.1.1.0/24 via 192.168.102.134 dev eth0; sleep infinity"
|
||||
depends_on:
|
||||
- oai-upf
|
||||
networks:
|
||||
traffic_net:
|
||||
ipv4_address: 192.168.102.135
|
||||
healthcheck:
|
||||
test: /bin/bash -c "ping -c 2 192.168.102.134"
|
||||
start_period: 10s
|
||||
start_interval: 500ms
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
networks:
|
||||
public_net:
|
||||
driver: bridge
|
||||
name: rfsim5g-oai-public-net
|
||||
ipam:
|
||||
config:
|
||||
- subnet: 192.168.101.128/26
|
||||
driver_opts:
|
||||
com.docker.network.bridge.name: "rfsim5g-public"
|
||||
traffic_net:
|
||||
driver: bridge
|
||||
name: rfsim5g-oai-traffic-net
|
||||
ipam:
|
||||
config:
|
||||
- subnet: 192.168.102.128/26
|
||||
driver_opts:
|
||||
com.docker.network.bridge.name: "rfsim5g-traffic"
|
||||
@@ -0,0 +1,113 @@
|
||||
include:
|
||||
- cn.yml
|
||||
services:
|
||||
mysql:
|
||||
cpuset: "5,6,30,31"
|
||||
oai-amf:
|
||||
cpuset: "5,6,30,31"
|
||||
oai-smf:
|
||||
cpuset: "5,6,30,31"
|
||||
oai-upf:
|
||||
cpuset: "5,6,30,31"
|
||||
oai-ext-dn:
|
||||
cpuset: "5,6,30,31"
|
||||
oai-gnb:
|
||||
image: ${REGISTRY-oaisoftwarealliance/}oai-gnb-fhi72:${TAG:-develop}
|
||||
cap_add:
|
||||
- IPC_LOCK
|
||||
- SYS_NICE
|
||||
cap_drop:
|
||||
- ALL
|
||||
container_name: oai-gnb
|
||||
environment:
|
||||
TZ: Europe/Paris
|
||||
USE_ADDITIONAL_OPTIONS: --gNBs.[0].min_rxtxtime 6
|
||||
devices:
|
||||
- /dev/vfio:/dev/vfio/
|
||||
volumes:
|
||||
- ./gnb.conf:/opt/oai-gnb/etc/gnb.conf
|
||||
- /dev/hugepages:/dev/hugepages
|
||||
cpuset: "7,8,9,10,11,12,13,14"
|
||||
networks:
|
||||
oai-net:
|
||||
ipv4_address: 172.21.18.20
|
||||
public_net:
|
||||
ipv4_address: 192.168.101.140
|
||||
healthcheck:
|
||||
test: /bin/bash -c "ps aux | grep -v grep | grep -c nr-softmodem"
|
||||
start_period: 10s
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 10
|
||||
oai-nr-oru:
|
||||
image: ${REGISTRY-oaisoftwarealliance/}oai-nr-oru:${TAG:-develop}
|
||||
cap_add:
|
||||
- IPC_LOCK
|
||||
- SYS_NICE
|
||||
cap_drop:
|
||||
- ALL
|
||||
container_name: oai-nr-oru
|
||||
environment:
|
||||
TZ: Europe/Paris
|
||||
USE_ADDITIONAL_OPTIONS: --vrtsim.role server
|
||||
devices:
|
||||
- /dev/vfio:/dev/vfio/
|
||||
volumes:
|
||||
- ./nr-oru.conf:/opt/nr-oru/etc/nr-oru.conf
|
||||
- /dev/hugepages:/dev/hugepages
|
||||
- tmp_data:/tmp/
|
||||
cpuset: "15,16,17,18,19,20,21,22"
|
||||
networks:
|
||||
oai-net:
|
||||
ipv4_address: 172.21.18.21
|
||||
healthcheck:
|
||||
test: /bin/bash -c "ps aux | grep -v grep | grep -c nr-oru"
|
||||
start_period: 15s
|
||||
start_interval: 500ms
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 10
|
||||
ipc: host
|
||||
oai-nr-ue:
|
||||
image: ${REGISTRY-oaisoftwarealliance/}${NRUE_IMG:-oai-nr-ue}:${TAG:-develop}
|
||||
container_name: rfsim5g-oai-nr-ue
|
||||
cap_drop:
|
||||
- ALL
|
||||
cap_add:
|
||||
- NET_ADMIN # for interface bringup
|
||||
- NET_RAW # for ping
|
||||
environment:
|
||||
USE_ADDITIONAL_OPTIONS: -r 106 --numerology 1 --band 77 -C 4049760000 --ssb 516 --uicc0.imsi 208990100001100 --log_config.global_log_options level,nocolor,time --device.name vrtsim
|
||||
depends_on:
|
||||
- oai-nr-oru
|
||||
devices:
|
||||
- /dev/net/tun:/dev/net/tun
|
||||
volumes:
|
||||
- ./nr-ue.conf:/opt/oai-nr-ue/etc/nr-ue.conf
|
||||
- tmp_data:/tmp/
|
||||
cpuset: "23,24,25,26,27,28,29"
|
||||
networks:
|
||||
public_net:
|
||||
ipv4_address: 192.168.101.150
|
||||
healthcheck:
|
||||
test: /bin/bash -c "pgrep nr-uesoftmodem"
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
start_period: 10s
|
||||
start_interval: 500ms
|
||||
ipc: host
|
||||
networks:
|
||||
oai-net:
|
||||
driver: macvlan
|
||||
name: oai-net
|
||||
ipam:
|
||||
config:
|
||||
- subnet: "172.21.16.0/22"
|
||||
ip_range: "172.21.18.20/32"
|
||||
gateway: "172.21.19.254"
|
||||
driver_opts:
|
||||
com.docker.network.bridge.name: "oai-net"
|
||||
parent: enp5s0f0np0
|
||||
volumes:
|
||||
tmp_data:
|
||||
270
ci-scripts/yaml_files/sa_fhi_7.2_oaioru_1x1_gnb/gnb.conf
Normal file
270
ci-scripts/yaml_files/sa_fhi_7.2_oaioru_1x1_gnb/gnb.conf
Normal file
@@ -0,0 +1,270 @@
|
||||
Active_gNBs = ( "gNB-OAI");
|
||||
# Asn1_verbosity, choice in: none, info, annoying
|
||||
Asn1_verbosity = "none";
|
||||
|
||||
gNBs =
|
||||
(
|
||||
{
|
||||
////////// Identification parameters:
|
||||
gNB_ID = 0xe00;
|
||||
gNB_name = "gNB-OAI";
|
||||
|
||||
// Tracking area code, 0x0000 and 0xfffe are reserved values
|
||||
tracking_area_code = 1;
|
||||
plmn_list = ({ mcc = 208; mnc = 99; mnc_length = 2; snssaiList = ({ sst = 1; }) });
|
||||
|
||||
nr_cellid = 12345678L;
|
||||
|
||||
////////// Physical parameters:
|
||||
|
||||
pdsch_AntennaPorts_XP = 1;
|
||||
pdsch_AntennaPorts_N1 = 1;
|
||||
maxMIMO_layers = 1;
|
||||
pusch_AntennaPorts = 1;
|
||||
do_CSIRS = 0;
|
||||
do_SRS = 0;
|
||||
sib1_tda = 15;
|
||||
|
||||
servingCellConfigCommon = (
|
||||
{
|
||||
#spCellConfigCommon
|
||||
|
||||
physCellId = 0;
|
||||
# n_TimingAdvanceOffset = 0;
|
||||
# downlinkConfigCommon
|
||||
#frequencyInfoDL
|
||||
# center frequency = 4049.76 MHz
|
||||
# selected SSB frequency = 4049.76 MHz
|
||||
absoluteFrequencySSB = 669984;
|
||||
dl_frequencyBand = 77;
|
||||
# frequency point A = 4030.68 MHz
|
||||
dl_absoluteFrequencyPointA = 668712;
|
||||
#scs-SpecificCarrierList
|
||||
dl_offstToCarrier = 0;
|
||||
# subcarrierSpacing
|
||||
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
|
||||
dl_subcarrierSpacing = 1;
|
||||
dl_carrierBandwidth = 106;
|
||||
#initialDownlinkBWP
|
||||
#genericParameters
|
||||
initialDLBWPlocationAndBandwidth = 28875; #38.101-1 Table 5.3.2-1
|
||||
#
|
||||
# subcarrierSpacing
|
||||
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
|
||||
initialDLBWPsubcarrierSpacing = 1;
|
||||
#pdcch-ConfigCommon
|
||||
initialDLBWPcontrolResourceSetZero = 11;
|
||||
initialDLBWPsearchSpaceZero = 0;
|
||||
|
||||
#uplinkConfigCommon
|
||||
#frequencyInfoUL
|
||||
ul_frequencyBand = 77;
|
||||
#scs-SpecificCarrierList
|
||||
ul_offstToCarrier = 0;
|
||||
# subcarrierSpacing
|
||||
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
|
||||
ul_subcarrierSpacing = 1;
|
||||
ul_carrierBandwidth = 106;
|
||||
pMax = 23;
|
||||
#initialUplinkBWP
|
||||
#genericParameters
|
||||
initialULBWPlocationAndBandwidth = 28875;
|
||||
# subcarrierSpacing
|
||||
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
|
||||
initialULBWPsubcarrierSpacing = 1;
|
||||
#rach-ConfigCommon
|
||||
#rach-ConfigGeneric
|
||||
prach_ConfigurationIndex = 157;
|
||||
#prach_msg1_FDM
|
||||
#0 = one, 1=two, 2=four, 3=eight
|
||||
prach_msg1_FDM = 0;
|
||||
prach_msg1_FrequencyStart = 0;
|
||||
zeroCorrelationZoneConfig = 0;
|
||||
preambleReceivedTargetPower = -100;
|
||||
#preamblTransMax (0...10) = (3,4,5,6,7,8,10,20,50,100,200)
|
||||
preambleTransMax = 7;
|
||||
#powerRampingStep
|
||||
# 0=dB0,1=dB2,2=dB4,3=dB6
|
||||
powerRampingStep = 2;
|
||||
#ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR
|
||||
#1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen
|
||||
ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4;
|
||||
#one (0..15) 4,8,12,16,...60,64
|
||||
ssb_perRACH_OccasionAndCB_PreamblesPerSSB = 15;
|
||||
#ra_ContentionResolutionTimer
|
||||
#(0..7) 8,16,24,32,40,48,56,64
|
||||
ra_ContentionResolutionTimer = 7;
|
||||
rsrp_ThresholdSSB = 19;
|
||||
#prach-RootSequenceIndex_PR
|
||||
#1 = 839, 2 = 139
|
||||
prach_RootSequenceIndex_PR = 2;
|
||||
prach_RootSequenceIndex = 1;
|
||||
# SCS for msg1, can only be 15 for 30 kHz < 6 GHz, takes precendence over the one derived from prach-ConfigIndex
|
||||
#
|
||||
msg1_SubcarrierSpacing = 1,
|
||||
# restrictedSetConfig
|
||||
# 0=unrestricted, 1=restricted type A, 2=restricted type B
|
||||
restrictedSetConfig = 0,
|
||||
|
||||
# this is the offset between the last PRACH preamble power and the Msg3 PUSCH, 2 times the field value in dB
|
||||
msg3_DeltaPreamble = 2;
|
||||
p0_NominalWithGrant = -100;
|
||||
|
||||
# pucch-ConfigCommon setup :
|
||||
# pucchGroupHopping
|
||||
# 0 = neither, 1= group hopping, 2=sequence hopping
|
||||
pucchGroupHopping = 0;
|
||||
hoppingId = 0;
|
||||
p0_nominal = -96;
|
||||
|
||||
ssb_PositionsInBurst_Bitmap = 0x1;
|
||||
|
||||
# ssb_periodicityServingCell
|
||||
# 0 = ms5, 1=ms10, 2=ms20, 3=ms40, 4=ms80, 5=ms160, 6=spare2, 7=spare1
|
||||
ssb_periodicityServingCell = 2;
|
||||
|
||||
# dmrs_TypeA_position
|
||||
# 0 = pos2, 1 = pos3
|
||||
dmrs_TypeA_Position = 0;
|
||||
|
||||
# subcarrierSpacing
|
||||
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
|
||||
subcarrierSpacing = 1;
|
||||
|
||||
|
||||
#tdd-UL-DL-ConfigurationCommon
|
||||
# subcarrierSpacing
|
||||
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
|
||||
referenceSubcarrierSpacing = 1;
|
||||
# pattern1
|
||||
# dl_UL_TransmissionPeriodicity
|
||||
# 0=ms0p5, 1=ms0p625, 2=ms1, 3=ms1p25, 4=ms2, 5=ms2p5, 6=ms5, 7=ms10
|
||||
dl_UL_TransmissionPeriodicity = 5;
|
||||
nrofDownlinkSlots = 3;
|
||||
nrofDownlinkSymbols = 6;
|
||||
nrofUplinkSlots = 1;
|
||||
nrofUplinkSymbols = 4;
|
||||
|
||||
ssPBCH_BlockPower = 0;
|
||||
}
|
||||
|
||||
);
|
||||
|
||||
|
||||
# ------- SCTP definitions
|
||||
SCTP :
|
||||
{
|
||||
# Number of streams to use in input/output
|
||||
SCTP_INSTREAMS = 2;
|
||||
SCTP_OUTSTREAMS = 2;
|
||||
};
|
||||
|
||||
////////// AMF parameters:
|
||||
amf_ip_address = ({ ipv4 = "192.168.101.132"; });
|
||||
|
||||
NETWORK_INTERFACES :
|
||||
{
|
||||
GNB_IPV4_ADDRESS_FOR_NG_AMF = "192.168.101.140";
|
||||
GNB_IPV4_ADDRESS_FOR_NGU = "192.168.101.140";
|
||||
GNB_PORT_FOR_S1U = 2152; # Spec 2152
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
MACRLCs = (
|
||||
{
|
||||
num_cc = 1;
|
||||
tr_s_preference = "local_L1";
|
||||
tr_n_preference = "local_RRC";
|
||||
pusch_TargetSNRx10 = 200;
|
||||
pucch_TargetSNRx10 = 200;
|
||||
# dl_bler_target_upper = .35;
|
||||
# dl_bler_target_lower = .15;
|
||||
ul_bler_target_upper = .35;
|
||||
ul_bler_target_lower = .15;
|
||||
pusch_FailureThres = 100;
|
||||
}
|
||||
);
|
||||
|
||||
L1s = (
|
||||
{
|
||||
num_cc = 1;
|
||||
tr_n_preference = "local_mac";
|
||||
prach_dtx_threshold = 110;
|
||||
pucch0_dtx_threshold = 80;
|
||||
pusch_dtx_threshold = -100;
|
||||
# thread_pool_size = 8;
|
||||
tx_amp_backoff_dB = 36;
|
||||
L1_rx_thread_core = -1;
|
||||
L1_tx_thread_core = -1;
|
||||
phase_compensation = 0; # needs to match O-RU configuration
|
||||
}
|
||||
);
|
||||
|
||||
RUs = (
|
||||
{
|
||||
local_rf = "no";
|
||||
nb_tx = 1;
|
||||
nb_rx = 1;
|
||||
att_tx = 0;
|
||||
att_rx = 0;
|
||||
bands = [77];
|
||||
max_pdschReferenceSignalPower = -27;
|
||||
max_rxgain = 75;
|
||||
sf_extension = 0;
|
||||
eNB_instances = [0];
|
||||
sl_ahead = 5;
|
||||
tr_preference = "raw_if4p5"; # important: activate FHI7.2
|
||||
do_precoding = 0; # needs to match O-RU configuration
|
||||
}
|
||||
);
|
||||
|
||||
security = {
|
||||
# preferred ciphering algorithms
|
||||
# the first one of the list that an UE supports in chosen
|
||||
# valid values: nea0, nea1, nea2, nea3
|
||||
ciphering_algorithms = ( "nea0" );
|
||||
|
||||
# preferred integrity algorithms
|
||||
# the first one of the list that an UE supports in chosen
|
||||
# valid values: nia0, nia1, nia2, nia3
|
||||
integrity_algorithms = ( "nia2", "nia0" );
|
||||
|
||||
# setting 'drb_ciphering' to "no" disables ciphering for DRBs, no matter
|
||||
# what 'ciphering_algorithms' configures; same thing for 'drb_integrity'
|
||||
drb_ciphering = "yes";
|
||||
drb_integrity = "no";
|
||||
};
|
||||
|
||||
log_config :
|
||||
{
|
||||
global_log_level = "info";
|
||||
hw_log_level = "info";
|
||||
phy_log_level = "info";
|
||||
mac_log_level = "info";
|
||||
rlc_log_level = "info";
|
||||
pdcp_log_level = "info";
|
||||
rrc_log_level = "info";
|
||||
ngap_log_level = "info";
|
||||
f1ap_log_level = "info";
|
||||
};
|
||||
|
||||
fhi_72 = {
|
||||
dpdk_devices = ("0000:05:02.2", "0000:05:02.3"); # one VF can be used as well
|
||||
dpdk_iova_mode = "VA";
|
||||
system_core = 7;
|
||||
io_core = 8;
|
||||
worker_cores = (9);
|
||||
ru_addr = ("00:11:22:33:64:66", "00:11:22:33:64:67");
|
||||
mtu = 9600;
|
||||
fh_config = ({
|
||||
T1a_cp_dl = (285, 470);
|
||||
T1a_cp_ul = (285, 429);
|
||||
T1a_up = (300, 450);
|
||||
Ta4 = (400, 440);
|
||||
ru_config = {
|
||||
iq_width = 16;
|
||||
iq_width_prach = 16;
|
||||
};
|
||||
});
|
||||
};
|
||||
70
ci-scripts/yaml_files/sa_fhi_7.2_oaioru_1x1_gnb/nr-oru.conf
Normal file
70
ci-scripts/yaml_files/sa_fhi_7.2_oaioru_1x1_gnb/nr-oru.conf
Normal file
@@ -0,0 +1,70 @@
|
||||
# Asn1_verbosity, choice in: none, info, annoying
|
||||
Asn1_verbosity = "none";
|
||||
|
||||
ORUs = (
|
||||
{
|
||||
tx_bw = [106];
|
||||
rx_bw = [106];
|
||||
carrier_tx = [4049760];
|
||||
carrier_rx = [4049760];
|
||||
prach_config_index = 157;
|
||||
prach_msg1_start = 0;
|
||||
tdd_period = 5;
|
||||
num_dl_slots = 3;
|
||||
num_dl_symbols = 6;
|
||||
num_ul_slots = 1;
|
||||
num_ul_symbols = 4;
|
||||
numerology = 1;
|
||||
tp_cores = [-1, -1, -1, -1, -1, -1]
|
||||
});
|
||||
|
||||
RUs = (
|
||||
{
|
||||
local_rf = "no";
|
||||
nb_tx = 1;
|
||||
nb_rx = 1;
|
||||
att_tx = 0;
|
||||
att_rx = 0;
|
||||
bands = [77];
|
||||
max_pdschReferenceSignalPower = -27;
|
||||
max_rxgain = 75;
|
||||
sf_extension = 0;
|
||||
eNB_instances = [0];
|
||||
sl_ahead = 5;
|
||||
tr_preference = "raw_if4p5"; # important: activate FHI7.2
|
||||
do_precoding = 0; # needs to match O-RU configuration
|
||||
});
|
||||
|
||||
|
||||
log_config :
|
||||
{
|
||||
global_log_level = "info";
|
||||
hw_log_level = "info";
|
||||
phy_log_level = "info";
|
||||
mac_log_level = "info";
|
||||
rlc_log_level = "info";
|
||||
pdcp_log_level = "info";
|
||||
rrc_log_level = "info";
|
||||
ngap_log_level = "info";
|
||||
f1ap_log_level = "info";
|
||||
};
|
||||
|
||||
fhi_72 = {
|
||||
dpdk_devices = ("0000:05:02.0", "0000:05:02.1"); # one VF can be used as well
|
||||
dpdk_iova_mode = "VA";
|
||||
system_core = 17;
|
||||
io_core = 18;
|
||||
worker_cores = (19);
|
||||
du_addr = ("00:11:22:33:64:68", "00:11:22:33:64:69");
|
||||
mtu = 9600;
|
||||
app_id = "RU";
|
||||
file_prefix = "ru";
|
||||
fh_config = ({
|
||||
Ta3_up = (200, 470);
|
||||
T2a_up = (350, 1200);
|
||||
ru_config = {
|
||||
iq_width = 16;
|
||||
iq_width_prach = 16;
|
||||
};
|
||||
});
|
||||
};
|
||||
37
ci-scripts/yaml_files/sa_fhi_7.2_oaioru_1x1_gnb/setup.sh
Executable file
37
ci-scripts/yaml_files/sa_fhi_7.2_oaioru_1x1_gnb/setup.sh
Executable file
@@ -0,0 +1,37 @@
|
||||
set -e
|
||||
# Set these in the DU config
|
||||
RU_U_PLANE_MAC=00:11:22:33:64:66
|
||||
RU_C_PLANE_MAC=00:11:22:33:64:67
|
||||
DU_U_PLANE_MAC=00:11:22:33:64:68
|
||||
DU_C_PLANE_MAC=00:11:22:33:64:69
|
||||
U_VLAN=3
|
||||
C_VLAN=4
|
||||
|
||||
sudo cpupower idle-set -D 0 > /dev/null
|
||||
sudo sysctl kernel.sched_rt_runtime_us=-1
|
||||
sudo sysctl kernel.timer_migration=0
|
||||
|
||||
MTU=9216
|
||||
IF=enp5s0f0np0
|
||||
sudo ethtool -G $IF rx 8160 tx 8160
|
||||
echo 0 | sudo tee /sys/bus/pci/devices/0000\:05\:00.0/sriov_numvfs
|
||||
echo 4 | sudo tee /sys/bus/pci/devices/0000\:05\:00.0/sriov_numvfs
|
||||
|
||||
# this next 2 lines is for C/U planes
|
||||
sudo ip link set $IF vf 0 mac $RU_U_PLANE_MAC vlan $U_VLAN qos 0 spoofchk off mtu $MTU
|
||||
sudo ip link set $IF vf 1 mac $RU_C_PLANE_MAC vlan $C_VLAN qos 0 spoofchk off mtu $MTU
|
||||
# this next 2 lines is for DU C/U planes
|
||||
sudo ip link set $IF vf 2 mac $DU_U_PLANE_MAC vlan $U_VLAN qos 0 spoofchk off mtu $MTU
|
||||
sudo ip link set $IF vf 3 mac $DU_C_PLANE_MAC vlan $C_VLAN qos 0 spoofchk off mtu $MTU
|
||||
|
||||
sleep 1
|
||||
sudo /usr/local/bin/dpdk-devbind.py --unbind 05:02.0
|
||||
sudo /usr/local/bin/dpdk-devbind.py --unbind 05:02.1
|
||||
sudo /usr/local/bin/dpdk-devbind.py --unbind 05:02.2
|
||||
sudo /usr/local/bin/dpdk-devbind.py --unbind 05:02.3
|
||||
sudo modprobe vfio-pci
|
||||
sudo /usr/local/bin/dpdk-devbind.py --bind vfio-pci 05:02.0
|
||||
sudo /usr/local/bin/dpdk-devbind.py --bind vfio-pci 05:02.1
|
||||
sudo /usr/local/bin/dpdk-devbind.py --bind vfio-pci 05:02.2
|
||||
sudo /usr/local/bin/dpdk-devbind.py --bind vfio-pci 05:02.3
|
||||
exit 0
|
||||
308
cmake_targets/tools/oran_fhi_integration_patches/F/oru.patch
Normal file
308
cmake_targets/tools/oran_fhi_integration_patches/F/oru.patch
Normal file
@@ -0,0 +1,308 @@
|
||||
diff --git a/fhi_lib/lib/api/xran_fh_o_ru.h b/fhi_lib/lib/api/xran_fh_o_ru.h
|
||||
index 7812399..8bdb539 100644
|
||||
--- a/fhi_lib/lib/api/xran_fh_o_ru.h
|
||||
+++ b/fhi_lib/lib/api/xran_fh_o_ru.h
|
||||
@@ -28,7 +28,7 @@
|
||||
* @author Intel Corporation
|
||||
*
|
||||
**/
|
||||
-
|
||||
+#pragma once
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
@@ -48,6 +48,27 @@ extern "C" {
|
||||
#include <getopt.h>
|
||||
#include <unistd.h>
|
||||
#include "xran_fh_o_du.h"
|
||||
+#include "xran_transport.h"
|
||||
+
|
||||
+typedef int (*process_uplane_fn)(struct rte_mbuf *pkt, void *handle,
|
||||
+ struct xran_eaxc_info *p_cid,
|
||||
+ uint16_t xport_id,
|
||||
+ struct xran_sense_of_time *sense_of_time);
|
||||
+typedef int32_t (*process_cplane_fn)(struct rte_mbuf *pkt, void *handle, uint16_t xport_id,
|
||||
+ struct xran_sense_of_time *sense_of_time);
|
||||
+typedef void (*sym_ota_fn)(void * handle, struct xran_sense_of_time *sense_of_time);
|
||||
+
|
||||
+void xran_hook_install(void *pHandle, process_uplane_fn process_uplane_fn_p,
|
||||
+ void *process_uplane_fn_args,
|
||||
+ process_cplane_fn process_cplane_fn_p,
|
||||
+ void *process_cplane_fn_args,
|
||||
+ sym_ota_fn sym_ota_fn_p,
|
||||
+ void *sym_ota_fn_args,
|
||||
+ int mu);
|
||||
+void xran_hook_schedule_packet(void *pHandle, struct rte_mbuf *mbuf, int port,
|
||||
+ enum xran_pkt_dir direction, int ru_port_id,
|
||||
+ int slot, int symbol);
|
||||
+int xran_hook_send_packet(void *pHandle, struct rte_mbuf *mbuf, int port, enum xran_pkt_dir direction, int ru_port_id);
|
||||
|
||||
/**
|
||||
* @ingroup
|
||||
@@ -78,4 +99,4 @@ int32_t xran_5g_bfw_config(void * pHandle, struct xran_buffer_list *pSrcRxCpBuff
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
-#endif
|
||||
\ No newline at end of file
|
||||
+#endif
|
||||
diff --git a/fhi_lib/lib/api/xran_pkt.h b/fhi_lib/lib/api/xran_pkt.h
|
||||
index 314b8d6..478f092 100644
|
||||
--- a/fhi_lib/lib/api/xran_pkt.h
|
||||
+++ b/fhi_lib/lib/api/xran_pkt.h
|
||||
@@ -339,6 +339,11 @@ struct xran_pkt_comm_hdr
|
||||
struct xran_ecpri_hdr ecpri_hdr; /**< eCPRI Transport Header */
|
||||
} __rte_packed;
|
||||
|
||||
+enum xran_mbuf_mem_op_id {
|
||||
+ MBUF_KEEP,
|
||||
+ MBUF_FREE
|
||||
+};
|
||||
+
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
diff --git a/fhi_lib/lib/ethernet/ethdi.h b/fhi_lib/lib/ethernet/ethdi.h
|
||||
index 5a5bf80..e32620c 100644
|
||||
--- a/fhi_lib/lib/ethernet/ethdi.h
|
||||
+++ b/fhi_lib/lib/ethernet/ethdi.h
|
||||
@@ -117,11 +117,6 @@ struct xran_ethdi_ctx {
|
||||
uint64_t rx_vf_queue_cnt[XRAN_VF_MAX][XRAN_VF_QUEUE_MAX];
|
||||
};
|
||||
|
||||
-enum xran_mbuf_mem_op_id {
|
||||
- MBUF_KEEP,
|
||||
- MBUF_FREE
|
||||
-};
|
||||
-
|
||||
extern enum xran_if_state xran_if_current_state;
|
||||
|
||||
static inline struct xran_ethdi_ctx *xran_ethdi_get_ctx(void)
|
||||
diff --git a/fhi_lib/lib/src/xran_dev.c b/fhi_lib/lib/src/xran_dev.c
|
||||
index c939edc..9037091 100644
|
||||
--- a/fhi_lib/lib/src/xran_dev.c
|
||||
+++ b/fhi_lib/lib/src/xran_dev.c
|
||||
@@ -502,3 +502,118 @@ xran_init_vfs_mapping(void *pHandle)
|
||||
|
||||
return (XRAN_STATUS_SUCCESS);
|
||||
}
|
||||
+
|
||||
+#define MAX_PACKETS_SENT_PER_SYMBOL 16 // has to be power of 2
|
||||
+
|
||||
+// Process the scheduled packets, done once per symbol at OTA time
|
||||
+void xran_hook_process_tx_packets(void* pHandle, int port, int slot, int symbol) {
|
||||
+ struct xran_device_ctx *p_dev_ctx = (struct xran_device_ctx *)pHandle;
|
||||
+ int ring_index = slot % XRAN_N_FE_BUF_LEN;
|
||||
+ struct rte_ring *ring = p_dev_ctx->hook_cfg.tx_rings[port][ring_index][symbol];
|
||||
+ void* mbufs[MAX_PACKETS_SENT_PER_SYMBOL];
|
||||
+ int dequeued = rte_ring_dequeue_burst(ring, mbufs, MAX_PACKETS_SENT_PER_SYMBOL, NULL);
|
||||
+ struct xran_ethdi_ctx *ctx = xran_ethdi_get_ctx();
|
||||
+ struct rte_ring *tx_ring = ctx->tx_ring[port];
|
||||
+ int enqueued = rte_ring_enqueue_burst(tx_ring, mbufs, dequeued, NULL);
|
||||
+ if (enqueued != dequeued) {
|
||||
+ rte_panic("Expected to be able to enqueue all the packets on the TX ring\n");
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+typedef struct {
|
||||
+ void* pHandle;
|
||||
+ int port;
|
||||
+ sym_ota_fn sym_ota_fn;
|
||||
+ void *sym_ota_fn_args;
|
||||
+} callback_args_t;
|
||||
+
|
||||
+int32_t send_packets(void* arg, struct xran_sense_of_time* p_sense_of_time) {
|
||||
+ callback_args_t *cb_args = arg;
|
||||
+ int mu = xran_get_conf_numerology(cb_args->pHandle);
|
||||
+ int slot_in_frame = p_sense_of_time->nSlotIdx + p_sense_of_time->nSubframeIdx * (1 << mu);
|
||||
+ xran_hook_process_tx_packets(cb_args->pHandle, cb_args->port, slot_in_frame, p_sense_of_time->nSymIdx);
|
||||
+ if (cb_args->sym_ota_fn) {
|
||||
+ cb_args->sym_ota_fn(cb_args->sym_ota_fn_args, p_sense_of_time);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+void xran_hook_install(
|
||||
+ void *pHandle,
|
||||
+ process_uplane_fn process_uplane_fn_p,
|
||||
+ void *process_uplane_fn_args,
|
||||
+ process_cplane_fn process_cplane_fn_p,
|
||||
+ void *process_cplane_fn_args,
|
||||
+ sym_ota_fn sym_ota_fn_p,
|
||||
+ void *sym_ota_fn_args,
|
||||
+ int mu)
|
||||
+{
|
||||
+ static bool installed = false;
|
||||
+ if (installed) rte_panic("Can only install once for one numerology\n");
|
||||
+ installed = true;
|
||||
+
|
||||
+ // Workaround - indicate XRAN memory is ready so packet processor starts
|
||||
+ struct xran_device_ctx *p_dev_ctx = (struct xran_device_ctx *)pHandle;
|
||||
+ p_dev_ctx->xran2phy_mem_ready = 1;
|
||||
+
|
||||
+ if (mu != xran_get_conf_numerology(pHandle)) {
|
||||
+ rte_panic("Can only use numerlogy %d as configured during init\n", xran_get_conf_numerology(pHandle));
|
||||
+ }
|
||||
+
|
||||
+ p_dev_ctx->hook_cfg.process_uplane_fn = process_uplane_fn_p;
|
||||
+ p_dev_ctx->hook_cfg.process_uplane_fn_args = process_uplane_fn_args;
|
||||
+ p_dev_ctx->hook_cfg.process_cplane_fn = process_cplane_fn_p;
|
||||
+ p_dev_ctx->hook_cfg.process_cplane_fn_args = process_cplane_fn_args;
|
||||
+
|
||||
+ struct xran_ethdi_ctx *ctx = xran_ethdi_get_ctx();
|
||||
+ for (int port = 0; port < ctx->io_cfg.num_vfs; port++) {
|
||||
+ int ring_index = 0;
|
||||
+ for (int slot = 0; slot < XRAN_N_FE_BUF_LEN; slot++) {
|
||||
+ for (int symbol = 0; symbol < XRAN_SYMBOLNUMBER_MAX; symbol++) {
|
||||
+ char ring_name[RTE_RING_NAMESIZE];
|
||||
+ snprintf(ring_name, RTE_DIM(ring_name), "%s_%d_%d", "hook_tx_ring", port, ring_index++);
|
||||
+ struct rte_ring *ring = rte_ring_create(ring_name, MAX_PACKETS_SENT_PER_SYMBOL, SOCKET_ID_ANY, RING_F_SC_DEQ);
|
||||
+ if (ring == NULL) rte_panic("Cannot allocate rte_ring\n");
|
||||
+ p_dev_ctx->hook_cfg.tx_rings[port][slot][symbol] = ring;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ // Setup a callback each OTA symbol to send packets from per-symbol rings into the TX ring
|
||||
+ static struct xran_sense_of_time xran_sense_of_time[XRAN_SYMBOLNUMBER_MAX];
|
||||
+ static callback_args_t cb_args = {0};
|
||||
+ cb_args.port = 0;
|
||||
+ cb_args.pHandle = pHandle;
|
||||
+ cb_args.sym_ota_fn = sym_ota_fn_p;
|
||||
+ cb_args.sym_ota_fn_args = sym_ota_fn_args;
|
||||
+ for (int i = 0; i < XRAN_SYMBOLNUMBER_MAX; i++) {
|
||||
+ xran_reg_sym_cb(pHandle, send_packets, &cb_args, &xran_sense_of_time[i], i, XRAN_CB_SYM_OTA_TIME);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+// Schedule packet for slot and symbol
|
||||
+void xran_hook_schedule_packet(void *pHandle, struct rte_mbuf *mbuf, int port,
|
||||
+ enum xran_pkt_dir direction, int ru_port_id,
|
||||
+ int slot, int symbol) {
|
||||
+ void *ret = rte_pktmbuf_prepend(mbuf, sizeof(struct rte_ether_hdr));
|
||||
+ if (ret == NULL) rte_panic("not enough headroom for ethernet header");
|
||||
+ struct xran_device_ctx *p_dev_ctx = (struct xran_device_ctx *)pHandle;
|
||||
+ int vf_id = xran_map_ecpriPcid_to_vf(pHandle, direction, 0, ru_port_id);
|
||||
+ struct xran_ethdi_ctx *ctx = xran_ethdi_get_ctx();
|
||||
+
|
||||
+ mbuf->port = ctx->io_cfg.port[vf_id];
|
||||
+ xran_add_eth_hdr_vlan(&ctx->entities[vf_id][ID_O_RU], ETHER_TYPE_ECPRI, mbuf);
|
||||
+
|
||||
+ struct rte_ring *ring = p_dev_ctx->hook_cfg.tx_rings[port][slot][symbol];
|
||||
+ int res = rte_ring_enqueue(ring, mbuf);
|
||||
+ if (res != 0) rte_panic("Cannot enqueue to ring");
|
||||
+}
|
||||
+
|
||||
+int xran_hook_send_packet(void *pHandle, struct rte_mbuf *mbuf, int port, enum xran_pkt_dir direction, int ru_port_id) {
|
||||
+ void *ret = rte_pktmbuf_prepend(mbuf, sizeof(struct rte_ether_hdr));
|
||||
+ if (ret == NULL) rte_panic("not enough headroom for ethernet header");
|
||||
+ int vf_id = xran_map_ecpriPcid_to_vf(pHandle, direction, 0, ru_port_id);
|
||||
+ if (xran_ethdi_mbuf_send(mbuf, ETHER_TYPE_ECPRI, vf_id) == 1) {
|
||||
+ return 0;
|
||||
+ }
|
||||
+ return 1;
|
||||
+}
|
||||
diff --git a/fhi_lib/lib/src/xran_dev.h b/fhi_lib/lib/src/xran_dev.h
|
||||
index 778b38d..9a19ab5 100644
|
||||
--- a/fhi_lib/lib/src/xran_dev.h
|
||||
+++ b/fhi_lib/lib/src/xran_dev.h
|
||||
@@ -40,6 +40,7 @@ extern "C" {
|
||||
#include <rte_timer.h>
|
||||
|
||||
#include "xran_fh_o_du.h"
|
||||
+#include "xran_fh_o_ru.h"
|
||||
#include "xran_prach_cfg.h"
|
||||
#include "xran_up_api.h"
|
||||
#include "xran_cp_api.h"
|
||||
@@ -186,6 +187,17 @@ struct xran_prb_elm_proc_info_t {
|
||||
uint8_t numSymsRemaining; /**< Number of symbols for DL CP transmission remaining in this slot */
|
||||
};
|
||||
|
||||
+typedef struct {
|
||||
+ // Used to replace XRAN packet processing functions
|
||||
+ process_uplane_fn process_uplane_fn;
|
||||
+ void *process_uplane_fn_args;
|
||||
+ process_cplane_fn process_cplane_fn;
|
||||
+ void *process_cplane_fn_args;
|
||||
+
|
||||
+ // Used to schedule TX in the future.
|
||||
+ struct rte_ring *tx_rings[XRAN_VF_MAX][XRAN_N_FE_BUF_LEN][XRAN_SYMBOLNUMBER_MAX];
|
||||
+} hook_cfg_t;
|
||||
+
|
||||
struct __rte_cache_aligned xran_device_ctx
|
||||
{
|
||||
uint8_t sector_id;
|
||||
@@ -326,6 +338,7 @@ struct __rte_cache_aligned xran_device_ctx
|
||||
uint8_t technology[XRAN_MAX_DSS_PERIODICITY]; /**< technology array represents slot is LTE(0)/NR(1) */
|
||||
/* Keeps track of how many sections are processed while parsing C-plan packet */
|
||||
uint8_t sectiondb_elm[XRAN_MAX_SECTIONDB_CTX][XRAN_DIR_MAX][XRAN_COMPONENT_CARRIERS_MAX][XRAN_MAX_ANTENNA_NR * 2 + XRAN_MAX_ANT_ARRAY_ELM_NR];
|
||||
+ hook_cfg_t hook_cfg;
|
||||
};
|
||||
|
||||
struct xran_eaxcid_config *xran_get_conf_eAxC(void *pHandle);
|
||||
diff --git a/fhi_lib/lib/src/xran_main.c b/fhi_lib/lib/src/xran_main.c
|
||||
index db03d94..1dfb5f7 100644
|
||||
--- a/fhi_lib/lib/src/xran_main.c
|
||||
+++ b/fhi_lib/lib/src/xran_main.c
|
||||
@@ -1680,9 +1680,31 @@ int32_t handle_ecpri_ethertype(struct rte_mbuf* pkt_q[], uint16_t xport_id, stru
|
||||
}
|
||||
else
|
||||
{
|
||||
+ struct xran_sense_of_time sense_of_time;
|
||||
+ if (p_dev_ctx->hook_cfg.process_uplane_fn || p_dev_ctx->hook_cfg.process_cplane_fn) {
|
||||
+ int mu = p_dev_ctx->fh_cfg.frame_conf.nNumerology;
|
||||
+ int32_t slots = xran_lib_ota_sym_idx[p_dev_ctx->xran_port_id] / XRAN_NUM_OF_SYMBOL_PER_SLOT;
|
||||
+ int num_slots_per_frame = 10 << mu;
|
||||
+ int num_slots_per_subframe = 1 << mu;
|
||||
+ int frame = slots / num_slots_per_frame;
|
||||
+ int subframe = (slots % num_slots_per_frame) / num_slots_per_subframe;
|
||||
+ int slot = slots - frame * num_slots_per_frame - subframe * num_slots_per_subframe;
|
||||
+ int symbol = xran_lib_ota_sym_idx[p_dev_ctx->xran_port_id] % XRAN_NUM_OF_SYMBOL_PER_SLOT;
|
||||
+ sense_of_time.tti_counter = xran_lib_ota_sym_idx[p_dev_ctx->xran_port_id];
|
||||
+ sense_of_time.nFrameIdx = xran_getSfnSecStart() + frame;
|
||||
+ sense_of_time.nSymIdx = symbol;
|
||||
+ sense_of_time.nSubframeIdx = subframe;
|
||||
+ sense_of_time.nSlotIdx = slot;
|
||||
+ sense_of_time.type_of_event = XRAN_CB_SYM_OTA_TIME;
|
||||
+ sense_of_time.nSecond = timing_get_current_second();
|
||||
+ }
|
||||
for (i = 0; i < num_data; i++)
|
||||
{
|
||||
- ret = process_mbuf(pkt_data[i], (void*)p_dev_ctx, p_cid);
|
||||
+ if (p_dev_ctx->hook_cfg.process_uplane_fn) {
|
||||
+ ret = p_dev_ctx->hook_cfg.process_uplane_fn(pkt_data[i], p_dev_ctx->hook_cfg.process_uplane_fn_args, p_cid, xport_id, &sense_of_time);
|
||||
+ } else {
|
||||
+ ret = process_mbuf(pkt_data[i], (void*)p_dev_ctx, p_cid);
|
||||
+ }
|
||||
if (ret == MBUF_FREE)
|
||||
rte_pktmbuf_free(pkt_data[i]);
|
||||
}
|
||||
@@ -1692,7 +1714,11 @@ int32_t handle_ecpri_ethertype(struct rte_mbuf* pkt_q[], uint16_t xport_id, stru
|
||||
t1 = MLogXRANTick();
|
||||
if (p_dev_ctx->fh_init.io_cfg.id == O_RU)
|
||||
{
|
||||
- ret = process_cplane(pkt_control[i], (void*)p_dev_ctx);
|
||||
+ if (p_dev_ctx->hook_cfg.process_cplane_fn) {
|
||||
+ ret = p_dev_ctx->hook_cfg.process_cplane_fn(pkt_control[i], p_dev_ctx->hook_cfg.process_cplane_fn_args, xport_id, &sense_of_time);
|
||||
+ } else {
|
||||
+ ret = process_cplane(pkt_control[i], (void*)p_dev_ctx);
|
||||
+ }
|
||||
p_dev_ctx->fh_counters.rx_counter++;
|
||||
if (ret == MBUF_FREE)
|
||||
rte_pktmbuf_free(pkt_control[i]);
|
||||
@@ -3987,10 +4013,12 @@ xran_start(void *pHandle)
|
||||
char buff[100];
|
||||
int i;
|
||||
struct xran_device_ctx * p_xran_dev_ctx = xran_dev_get_ctx();
|
||||
- struct xran_prb_map * prbMap0 = (struct xran_prb_map *) p_xran_dev_ctx->sFrontHaulRxPrbMapBbuIoBufCtrl[0][0][0].sBufferList.pBuffers->pData;
|
||||
- for(i = 0; i < XRAN_MAX_SECTIONS_PER_SLOT && i < prbMap0->nPrbElm; i++)
|
||||
- {
|
||||
- p_xran_dev_ctx->numSetBFWs_arr[i] = prbMap0->prbMap[i].bf_weight.numSetBFWs;
|
||||
+ if (p_xran_dev_ctx->sFrontHaulRxPrbMapBbuIoBufCtrl[0][0][0].sBufferList.pBuffers) {
|
||||
+ struct xran_prb_map * prbMap0 = (struct xran_prb_map *) p_xran_dev_ctx->sFrontHaulRxPrbMapBbuIoBufCtrl[0][0][0].sBufferList.pBuffers->pData;
|
||||
+ for(i = 0; i < XRAN_MAX_SECTIONS_PER_SLOT && i < prbMap0->nPrbElm; i++)
|
||||
+ {
|
||||
+ p_xran_dev_ctx->numSetBFWs_arr[i] = prbMap0->prbMap[i].bf_weight.numSetBFWs;
|
||||
+ }
|
||||
}
|
||||
|
||||
if(xran_get_if_state() == XRAN_RUNNING) {
|
||||
@@ -1229,6 +1229,49 @@ unsigned int get_prach_K(int prach_sequence_length, int prach_fmt_id, int pusch_
|
||||
return K;
|
||||
}
|
||||
|
||||
// Based on 38.211 Table 6.3.3.1-1 and Table 6.3.3.1-2.
|
||||
uint32_t get_prach_num_reps(int prach_fmt_id)
|
||||
{
|
||||
switch (prach_fmt_id) {
|
||||
case 0:
|
||||
return 1;
|
||||
break;
|
||||
case 1:
|
||||
return 2;
|
||||
break;
|
||||
case 2:
|
||||
return 4;
|
||||
break;
|
||||
case 3:
|
||||
return 4;
|
||||
break;
|
||||
case 4: // A1
|
||||
return 2;
|
||||
break;
|
||||
case 5: // A2
|
||||
return 4;
|
||||
break;
|
||||
case 6: // A3
|
||||
return 6;
|
||||
break;
|
||||
case 7: // B1
|
||||
return 2;
|
||||
break;
|
||||
case 8: // B4
|
||||
return 12;
|
||||
break;
|
||||
case 9: // C0
|
||||
return 1;
|
||||
break;
|
||||
case 10: // C2
|
||||
return 4;
|
||||
break;
|
||||
default:
|
||||
AssertFatal(0, "Invalid PRACH format %d\n", prach_fmt_id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int get_delay_idx(int delay, int max_delay_comp)
|
||||
{
|
||||
int delay_idx = max_delay_comp + delay;
|
||||
|
||||
@@ -326,6 +326,7 @@ unsigned short get_N_b_srs(int c_srs, int b_srs);
|
||||
uint8_t get_long_prach_dur(unsigned int format, unsigned int num_slots_subframe);
|
||||
uint8_t get_PRACH_k_bar(unsigned int delta_f_RA_PRACH, unsigned int delta_f_PUSCH);
|
||||
unsigned int get_prach_K(int prach_sequence_length, int prach_fmt_id, int pusch_mu, int prach_mu);
|
||||
uint32_t get_prach_num_reps(int prach_fmt_id);
|
||||
|
||||
int get_slot_idx_in_period(const int slot, const frame_structure_t *fs);
|
||||
|
||||
|
||||
96
doc/tutorial_resources/oru/README.md
Normal file
96
doc/tutorial_resources/oru/README.md
Normal file
@@ -0,0 +1,96 @@
|
||||
# Description
|
||||
|
||||
This document describes the steps needed to run the O-RU + gNB + NR UE on a single server.
|
||||
|
||||
# Limitations
|
||||
|
||||
The RU does not support fragmentation or compression at this point, therefore the bandwidth is currently limited.
|
||||
|
||||
# Dependecies
|
||||
|
||||
The O-RU requires a patch applied on top of the usual OAI patch to xran library release F. The patch is available
|
||||
under `cmake_targets/tools/oran_fhi_integration_patches/F/oru.patch`.
|
||||
|
||||
The O-RU was tested with dpdk 22.
|
||||
|
||||
## Using a locally installed DPDK
|
||||
|
||||
Instead of installing dpdk globally you can install it in a local directory, e.g.
|
||||
|
||||
```bash
|
||||
meson --prefix=<your dpdk install directory> build
|
||||
cd build
|
||||
ninja
|
||||
ninja install
|
||||
```
|
||||
|
||||
Building xran
|
||||
|
||||
```bash
|
||||
cd fhi_lib/lib/
|
||||
WIRELESS_SDK_TOOLCHAIN=gcc RTE_SDK=<your dpdk directory> XRAN_DIR=<your xran directory> make XRAN_LIB_SO=1
|
||||
```
|
||||
|
||||
In the next step you'll add an extra argument to `cmake` command
|
||||
|
||||
# Configuration
|
||||
|
||||
Use `setup_ru_ifs.sh` as a basis for your own vf setup script.
|
||||
|
||||
# Compilation
|
||||
|
||||
Assuming your build directory is `cmake_targets/build`
|
||||
|
||||
```bash
|
||||
cmake ../../ -GNinja -DOAI_FHI72=ON -Dxran_LOCATION=<your xran directory>/fhi_lib/lib
|
||||
```
|
||||
|
||||
OR if using local dpdk installation
|
||||
|
||||
```bash
|
||||
make ../../ -GNinja -DOAI_FHI72=ON -Dxran_LOCATION=<your xran directory>/fhi_lib/lib -DCMAKE_PREFIX_PATH=<your dpdk install directory>
|
||||
```
|
||||
|
||||
Verify DPDK version in stdout:
|
||||
```
|
||||
-- Checking for module 'libdpdk'
|
||||
-- Found libdpdk, version 22.11.11
|
||||
```
|
||||
|
||||
```bash
|
||||
cmake --build . --target nr-softmodem nr-uesoftmodem ldpc params_libconfig nr-oru oran_fhlib_5g vrtsim
|
||||
```
|
||||
|
||||
# Setup
|
||||
|
||||
You need to setup your VFs to enable packet routing between them. An example config with comments is added in this folder.
|
||||
|
||||
# Test commands
|
||||
|
||||
## My local setup
|
||||
|
||||
```bash
|
||||
sudo ./nr-oru -O ../../targets/PROJECTS/GENERIC-NR-5GC/CONF/ru.band77.mu1.106rb.2x2.conf --vrtsim.role server
|
||||
```
|
||||
|
||||
```bash
|
||||
sudo ./nr-softmodem -O ../../targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band77.106prb.fhi72.2x2-nr-oru.conf --gNBs.[0].min_rxtxtime 6
|
||||
```
|
||||
|
||||
```bash
|
||||
sudo -E LD_LIBRARY_PATH=. ./nr-uesoftmodem -C 4049760000 -r 106 --numerology 1 --ssb 516 --band 77 --device.name vrtsim
|
||||
```
|
||||
|
||||
## Example from peafowl (using locally installed dpdk)
|
||||
|
||||
```bash
|
||||
sudo -E LD_LIBRARY_PATH=/home/bpodrygajlo/dpdk-stable-22.11.11/install/lib/x86_64-linux-gnu taskset -c 15-23 ./nr-oru -O ../../targets/PROJECTS/GENERIC-NR-5GC/CONF/ru.band77.mu1.106rb.2x2.conf --vrtsim.role server --fhi_72.dpdk_devices 0000:01:01.0,0000:01:01.1
|
||||
```
|
||||
|
||||
```bash
|
||||
sudo -E LD_LIBRARY_PATH=/home/bpodrygajlo/dpdk-stable-22.11.11/install/lib/x86_64-linux-gnu taskset -c 24-31 ./nr-softmodem -O ../../targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band77.106prb.fhi72.2x2-nr-oru.conf --gNBs.[0].min_rxtxtime 6 --fhi_72.dpdk_devices 0000:01:01.2,0000:01:01.3
|
||||
```
|
||||
|
||||
```bash
|
||||
sudo -E LD_LIBRARY_PATH=. taskset -c -c 7-14 ./nr-uesoftmodem -C 4049760000 -r 106 --numerology 1 --ssb 516 --band 77 --device.name vrtsim
|
||||
```
|
||||
42
doc/tutorial_resources/oru/setup_ifs_peafowl.sh
Executable file
42
doc/tutorial_resources/oru/setup_ifs_peafowl.sh
Executable file
@@ -0,0 +1,42 @@
|
||||
#!/bin/sh
|
||||
#### 100G interface --> enp1s0f0 | VFs pcie-address --> 01:01.0, 01:01.1
|
||||
#### 25G interface (PTP) --> enp193s0f1 | VFs pcie-address --> c1:11.0,c1:11.1
|
||||
set -x
|
||||
|
||||
# Set these in the DU config
|
||||
RU_U_PLANE_MAC=00:11:22:33:64:66
|
||||
RU_C_PLANE_MAC=00:11:22:33:64:67
|
||||
# Set these in the RU config
|
||||
DU_U_PLANE_MAC=00:11:22:33:64:68
|
||||
DU_C_PLANE_MAC=00:11:22:33:64:69
|
||||
|
||||
U_VLAN=4
|
||||
C_VLAN=5
|
||||
|
||||
MTU=9600
|
||||
IF=enp1s0f0
|
||||
|
||||
## It will be something like this --> $DPDK_INST/bin
|
||||
DPDK_DEVBIND_PREFIX="${DPDK_DEVBIND_PREFIX:-}"
|
||||
|
||||
sudo ethtool -G $IF rx 8160 tx 8160
|
||||
sudo sh -c "echo 0 > /sys/class/net/$IF/device/sriov_numvfs"
|
||||
sudo sh -c "echo 4 > /sys/class/net/$IF/device/sriov_numvfs"
|
||||
sudo modprobe -r iavf
|
||||
sudo modprobe iavf
|
||||
# this next 2 lines is for C/U planes
|
||||
sudo ip link set $IF vf 0 mac $RU_U_PLANE_MAC vlan $U_VLAN spoofchk off mtu $MTU
|
||||
sudo ip link set $IF vf 1 mac $RU_C_PLANE_MAC vlan $C_VLAN spoofchk off mtu $MTU
|
||||
sudo ip link set $IF vf 2 mac $DU_U_PLANE_MAC vlan $U_VLAN spoofchk off mtu $MTU
|
||||
sudo ip link set $IF vf 3 mac $DU_C_PLANE_MAC vlan $C_VLAN spoofchk off mtu $MTU
|
||||
sleep 1
|
||||
sudo ${DPDK_DEVBIND_PREFIX}dpdk-devbind.py --unbind 0000:01:01.0
|
||||
sudo ${DPDK_DEVBIND_PREFIX}dpdk-devbind.py --unbind 0000:01:01.1
|
||||
sudo ${DPDK_DEVBIND_PREFIX}dpdk-devbind.py --unbind 0000:01:01.2
|
||||
sudo ${DPDK_DEVBIND_PREFIX}dpdk-devbind.py --unbind 0000:01:01.3
|
||||
sudo modprobe vfio-pci
|
||||
sudo ${DPDK_DEVBIND_PREFIX}dpdk-devbind.py --bind vfio-pci 0000:01:01.0
|
||||
sudo ${DPDK_DEVBIND_PREFIX}dpdk-devbind.py --bind vfio-pci 0000:01:01.1
|
||||
sudo ${DPDK_DEVBIND_PREFIX}dpdk-devbind.py --bind vfio-pci 0000:01:01.2
|
||||
sudo ${DPDK_DEVBIND_PREFIX}dpdk-devbind.py --bind vfio-pci 0000:01:01.3
|
||||
sleep 5
|
||||
38
doc/tutorial_resources/oru/setup_ru_ifs.sh
Executable file
38
doc/tutorial_resources/oru/setup_ru_ifs.sh
Executable file
@@ -0,0 +1,38 @@
|
||||
#!/bin/bash
|
||||
set -x
|
||||
# Set these in the DU config
|
||||
RU_U_PLANE_MAC=00:11:22:33:64:66
|
||||
RU_C_PLANE_MAC=00:11:22:33:64:67
|
||||
# Set these in the RU config
|
||||
DU_U_PLANE_MAC=00:11:22:33:64:68
|
||||
DU_C_PLANE_MAC=00:11:22:33:64:69
|
||||
|
||||
# Using separate VLANs, it helps with capturing on some configurations
|
||||
U_VLAN=3
|
||||
C_VLAN=4
|
||||
|
||||
MTU=9216
|
||||
IF=enp5s0f0np0
|
||||
echo 0 | sudo tee /sys/bus/pci/devices/0000\:05\:00.0/sriov_numvfs
|
||||
echo 4 | sudo tee /sys/bus/pci/devices/0000\:05\:00.0/sriov_numvfs
|
||||
|
||||
|
||||
# this next 2 lines is for C/U planes
|
||||
sudo ip link set $IF vf 0 mac $RU_U_PLANE_MAC vlan $U_VLAN qos 0 spoofchk off mtu $MTU
|
||||
sudo ip link set $IF vf 1 mac $RU_C_PLANE_MAC vlan $C_VLAN qos 0 spoofchk off mtu $MTU
|
||||
# this next 2 lines is for DU C/U planes
|
||||
sudo ip link set $IF vf 2 mac $DU_U_PLANE_MAC vlan $U_VLAN qos 0 spoofchk off mtu $MTU
|
||||
sudo ip link set $IF vf 3 mac $DU_C_PLANE_MAC vlan $C_VLAN qos 0 spoofchk off mtu $MTU
|
||||
|
||||
# bind to vfio-pci
|
||||
sleep 1
|
||||
sudo /usr/local/bin/dpdk-devbind.py --unbind 05:02.0
|
||||
sudo /usr/local/bin/dpdk-devbind.py --unbind 05:02.1
|
||||
sudo /usr/local/bin/dpdk-devbind.py --unbind 05:02.2
|
||||
sudo /usr/local/bin/dpdk-devbind.py --unbind 05:02.3
|
||||
sudo modprobe vfio-pci
|
||||
sudo /usr/local/bin/dpdk-devbind.py --bind vfio-pci 05:02.0
|
||||
sudo /usr/local/bin/dpdk-devbind.py --bind vfio-pci 05:02.1
|
||||
sudo /usr/local/bin/dpdk-devbind.py --bind vfio-pci 05:02.2
|
||||
sudo /usr/local/bin/dpdk-devbind.py --bind vfio-pci 05:02.3
|
||||
sleep 5
|
||||
@@ -43,7 +43,6 @@ RUN apt-get update && \
|
||||
|
||||
RUN rm -Rf /oai-ran
|
||||
WORKDIR /oai-ran
|
||||
COPY . .
|
||||
|
||||
## Download and build DPDK
|
||||
RUN wget http://fast.dpdk.org/rel/dpdk-20.11.9.tar.xz && \
|
||||
@@ -53,15 +52,30 @@ RUN wget http://fast.dpdk.org/rel/dpdk-20.11.9.tar.xz && \
|
||||
ninja -C build && \
|
||||
ninja install -C build
|
||||
|
||||
COPY ./cmake_targets/tools/oran_fhi_integration_patches/F/oaioran_F.patch ./cmake_targets/tools/oran_fhi_integration_patches/F/oru.patch /tmp/
|
||||
|
||||
## Build Fronthaul library
|
||||
RUN git clone https://gerrit.o-ran-sc.org/r/o-du/phy.git /opt/phy && \
|
||||
cd /opt/phy && \
|
||||
git checkout oran_f_release_v1.0 &&\
|
||||
git apply /oai-ran/cmake_targets/tools/oran_fhi_integration_patches/F/oaioran_F.patch && \
|
||||
git apply /tmp/oaioran_F.patch && \
|
||||
git apply /tmp/oru.patch && \
|
||||
cd /opt/phy/fhi_lib/lib && \
|
||||
WIRELESS_SDK_TOOLCHAIN=gcc RTE_SDK=/oai-ran/dpdk-stable-20.11.9/ XRAN_DIR=/opt/phy/fhi_lib make XRAN_LIB_SO=1
|
||||
|
||||
COPY . .
|
||||
|
||||
FROM ran-base AS ran-build-fhi72
|
||||
|
||||
## Build FlexRIC for SM Models
|
||||
RUN mkdir -p openair2/E2AP/flexric/build && \
|
||||
cd openair2/E2AP/flexric/build && \
|
||||
cmake -GNinja -DCMAKE_BUILD_TYPE=Release \
|
||||
-DKPM_VERSION=$KPM_VERSION \
|
||||
-DE2AP_VERSION=$E2AP_VERSION .. && \
|
||||
ninja && \
|
||||
ninja install
|
||||
|
||||
## Build and install OAI
|
||||
#run build_oai to build the target image
|
||||
RUN /bin/sh oaienv && \
|
||||
@@ -76,12 +90,3 @@ RUN /bin/sh oaienv && \
|
||||
ldd ran_build/build/nr-softmodem && \
|
||||
ldd ran_build/build/liboran_fhlib_5g.so && \
|
||||
ldd /opt/phy/fhi_lib/lib/build/libxran.so
|
||||
|
||||
## Build FlexRIC for SM Models
|
||||
RUN mkdir -p openair2/E2AP/flexric/build && \
|
||||
cd openair2/E2AP/flexric/build && \
|
||||
cmake -GNinja -DCMAKE_BUILD_TYPE=Release \
|
||||
-DKPM_VERSION=$KPM_VERSION \
|
||||
-DE2AP_VERSION=$E2AP_VERSION .. && \
|
||||
ninja && \
|
||||
ninja install
|
||||
|
||||
@@ -57,11 +57,10 @@ COPY ./docker/scripts/nr_oru_entrypoint.sh ./entrypoint.sh
|
||||
|
||||
COPY --from=ran-build \
|
||||
/oai-ran/cmake_targets/ran_build/build/liboai_transpro.so \
|
||||
/oai-ran/cmake_targets/ran_build/build/libcoding.so \
|
||||
/oai-ran/cmake_targets/ran_build/build/libparams_libconfig.so \
|
||||
/oai-ran/cmake_targets/ran_build/build/libdfts.so \
|
||||
/oai-ran/cmake_targets/ran_build/build/libldpc*.so \
|
||||
/oai-ran/cmake_targets/ran_build/build/libparams_yaml.so \
|
||||
/oai-ran/cmake_targets/ran_build/build/libvrtsim.so \
|
||||
/usr/local/lib/
|
||||
|
||||
## Libxran library
|
||||
@@ -77,10 +76,8 @@ RUN ldconfig && \
|
||||
ldd /opt/nr-oru/bin/nr-oru && \
|
||||
echo "---- ldd on shared libraries ----" && \
|
||||
ldd /usr/local/lib/liboai_transpro.so \
|
||||
/usr/local/lib/libcoding.so \
|
||||
/usr/local/lib/libparams_libconfig.so \
|
||||
/usr/local/lib/libdfts.so \
|
||||
/usr/local/lib/libldpc*.so \
|
||||
/opt/phy/fhi_lib/lib/build/libxran.so
|
||||
|
||||
WORKDIR /opt/nr-oru
|
||||
|
||||
@@ -38,6 +38,9 @@
|
||||
#include "nfapi/oai_integration/vendor_ext.h"
|
||||
#include <executables/softmodem-common.h>
|
||||
#include <executables/thread-common.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;
|
||||
@@ -54,6 +57,8 @@ extern void kill_NR_RU_proc(int inst);
|
||||
extern void set_function_spec_param(RU_t *ru);
|
||||
extern void start_NR_RU();
|
||||
extern void init_NR_RU(configmodule_interface_t *cfg, char *);
|
||||
void fill_rf_config(RU_t *ru, char *rf_config_file);
|
||||
void fill_split7_2_config(split7_config_t *split7, const nfapi_nr_config_request_scf_t *config, const NR_DL_FRAME_PARMS *fp);
|
||||
|
||||
int64_t uplink_frequency_offset[MAX_NUM_CCs][4];
|
||||
|
||||
@@ -61,6 +66,7 @@ void nfapi_setmode(nfapi_mode_t nfapi_mode)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
void exit_function(const char *file, const char *function, const int line, const char *s, const int assert)
|
||||
{
|
||||
if (s != NULL) {
|
||||
@@ -68,26 +74,14 @@ void exit_function(const char *file, const char *function, const int line, const
|
||||
}
|
||||
close_log_mem();
|
||||
oai_exit = 1;
|
||||
RU_t *ru = RC.ru[0];
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
pthread_mutex_destroy(ru->ru_mutex);
|
||||
pthread_cond_destroy(ru->ru_cond);
|
||||
if (assert) {
|
||||
if (assert)
|
||||
abort();
|
||||
} else {
|
||||
sleep(1); // allow lte-softmodem threads to exit first
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
}
|
||||
|
||||
void stop_ru(int sig)
|
||||
{
|
||||
exit_function(__FILE__, __FUNCTION__, __LINE__, "interrupted", false);
|
||||
}
|
||||
|
||||
static void get_options(configmodule_interface_t *cfg)
|
||||
@@ -129,14 +123,6 @@ struct timespec timespec_sub(struct timespec, struct timespec)
|
||||
return t;
|
||||
};
|
||||
|
||||
void perform_symbol_rotation(NR_DL_FRAME_PARMS *fp, double f0, c16_t *symbol_rotation)
|
||||
{
|
||||
return;
|
||||
}
|
||||
void init_timeshift_rotation(NR_DL_FRAME_PARMS *fp)
|
||||
{
|
||||
return;
|
||||
};
|
||||
int beam_index_allocation(bool das,
|
||||
int fapi_beam_index,
|
||||
NR_gNB_COMMON *common_vars,
|
||||
@@ -186,6 +172,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));
|
||||
@@ -193,26 +180,87 @@ 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;
|
||||
oru.num_sync_messages_needed = 2;
|
||||
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);
|
||||
ru->if_south = LOCAL_RF;
|
||||
nr_phy_init_RU(oru.ru);
|
||||
fill_rf_config(ru, ru->rf_config_file);
|
||||
fill_split7_2_config(&ru->openair0_cfg.split7, &ru->config, fp);
|
||||
ru->N_TA_offset = set_default_nta_offset(fp->freq_range, fp->samples_per_subframe);
|
||||
|
||||
/* 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);
|
||||
|
||||
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 potocol\n", ru->idx, ret);
|
||||
ret = ru->nr_start_if(ru, NULL);
|
||||
AssertFatal(ret == 0, "Could not start xran\n");
|
||||
|
||||
LOG_I(PHY, "starting vrtsim\n");
|
||||
ret = openair0_load(&ru->rfdevice, "vrtsim", &ru->openair0_cfg, NULL);
|
||||
AssertFatal(ret == 0, "RU %u: openair0_load() ret %d: cannot initialize vrtsim\n", ru->idx, ret);
|
||||
ret = ru->rfdevice.trx_start_func(&ru->rfdevice);
|
||||
AssertFatal(ret == 0, "RU %u: trx_start_func() ret %d: cannot start vrtsim\n", ru->idx, ret);
|
||||
|
||||
signal(SIGINT, stop_ru);
|
||||
signal(SIGTERM, stop_ru);
|
||||
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);
|
||||
threadCreate(&oru.oru_sync_thread, oru_sync_thread, (void *)&oru, "oru_sync_thread", -1, OAI_PRIORITY_RT_MAX);
|
||||
|
||||
while (oai_exit == 0)
|
||||
sleep(1);
|
||||
// stop threads
|
||||
|
||||
kill_NR_RU_proc(0);
|
||||
ret = pthread_join(oru.oru_sync_thread, NULL);
|
||||
AssertFatal(ret == 0, "pthread_join failed %d\n", ret);
|
||||
ret = pthread_join(oru.north_read_thread, NULL);
|
||||
AssertFatal(ret == 0, "pthread_join failed %d\n", ret);
|
||||
ret = pthread_join(oru.south_read_thread, NULL);
|
||||
AssertFatal(ret == 0, "pthread_join failed %d\n", ret);
|
||||
LOG_I(PHY, "Threads joined\n");
|
||||
|
||||
end_configmodule(uniqCfg);
|
||||
|
||||
if (ru->rfdevice.trx_end_func) {
|
||||
ru->rfdevice.trx_end_func(&ru->rfdevice);
|
||||
ru->rfdevice.trx_end_func = NULL;
|
||||
if (ru->ifdevice.trx_stop_func) {
|
||||
ru->ifdevice.trx_stop_func(&ru->ifdevice);
|
||||
}
|
||||
|
||||
if (ru->ifdevice.trx_end_func) {
|
||||
ru->ifdevice.trx_end_func(&ru->ifdevice);
|
||||
ru->ifdevice.trx_end_func = NULL;
|
||||
}
|
||||
|
||||
sleep(1);
|
||||
|
||||
if (ru->rfdevice.trx_stop_func) {
|
||||
ru->rfdevice.trx_stop_func(&ru->rfdevice);
|
||||
}
|
||||
if (ru->rfdevice.trx_end_func) {
|
||||
ru->rfdevice.trx_end_func(&ru->rfdevice);
|
||||
}
|
||||
|
||||
logClean();
|
||||
end_configmodule(uniqCfg);
|
||||
printf("Bye.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
752
executables/nr-oru.c
Normal file
752
executables/nr-oru.c
Normal file
@@ -0,0 +1,752 @@
|
||||
/*
|
||||
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The OpenAirInterface Software Alliance licenses this file to You under
|
||||
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.openairinterface.org/?page_id=698
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*-------------------------------------------------------------------------------
|
||||
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
#include "PHY/defs_RU.h"
|
||||
#include "assertions.h"
|
||||
#include "common/config/config_userapi.h"
|
||||
#include "nr-oru.h"
|
||||
#include "openair1/PHY/defs_nr_common.h"
|
||||
#include "openair1/PHY/MODULATION/nr_modulation.h"
|
||||
#include "openair1/SCHED_NR/sched_nr.h"
|
||||
#include "openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h"
|
||||
#include "thread-pool.h"
|
||||
|
||||
#define CONFIG_SECTION_ORU "ORUs.[0]"
|
||||
|
||||
// clang-format off
|
||||
#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 CONFIG_STRING_ORU_TP_CORES "tp_cores"
|
||||
|
||||
#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"
|
||||
#define HLP_ORU_TP_CORES "CPU cores used for threadpool"
|
||||
|
||||
#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}, \
|
||||
{CONFIG_STRING_ORU_TP_CORES, HLP_ORU_TP_CORES, 0, .iptr=NULL, .defintarrayval=DEFTPCORES, TYPE_INTARRAY, 4}, \
|
||||
}
|
||||
// clang-format on
|
||||
|
||||
extern void set_scs_parameters(NR_DL_FRAME_PARMS *fp, int mu, int N_RB_DL, int ssb_case);
|
||||
typedef struct {
|
||||
openair0_timestamp_t sample;
|
||||
int slot;
|
||||
int frame;
|
||||
int symbol;
|
||||
} initial_sync_t;
|
||||
|
||||
typedef struct {
|
||||
int frame_unwrap;
|
||||
int last_frame;
|
||||
int64_t sync_offset;
|
||||
} sync_params_t;
|
||||
|
||||
typedef struct {
|
||||
RU_t *ru;
|
||||
NR_DL_FRAME_PARMS *fp;
|
||||
int slot;
|
||||
int start_symbol;
|
||||
int num_symbols;
|
||||
int aatx;
|
||||
c16_t *txdataF;
|
||||
task_ans_t *task_ans;
|
||||
} dl_symbol_process_t;
|
||||
|
||||
typedef struct {
|
||||
ORU_t *oru;
|
||||
int frame;
|
||||
int slot;
|
||||
int symbol;
|
||||
int aarx;
|
||||
} pusch_symbol_job_t;
|
||||
|
||||
extern void tx_rf_symbols(RU_t *ru, int frame, int slot, uint64_t timestamp, int start_symbol, int num_symbols);
|
||||
static void receive_pusch(void *args);
|
||||
|
||||
extern void rx_nr_prach_ru_internal(prach_item_t *p,
|
||||
int beam_id,
|
||||
int prachStartSymbol,
|
||||
int prachOccasion,
|
||||
int32_t **rxdata,
|
||||
NR_DL_FRAME_PARMS *fp,
|
||||
int N_TA_offset,
|
||||
int rep_index,
|
||||
uint reps);
|
||||
|
||||
static void oru_downlink_processing(ORU_t *oru,
|
||||
c16_t *txDataF_ptr[oru->ru->nb_tx],
|
||||
int frame,
|
||||
int slot,
|
||||
int start_symbol,
|
||||
int num_symbols,
|
||||
openair0_timestamp_t timestamp_tx);
|
||||
|
||||
int get_oru_options(ORU_t *oru)
|
||||
{
|
||||
int DEFBW[] = {273};
|
||||
int DEFCARRIER[] = {3430560};
|
||||
int DEFTPCORES[] = {-1, -1, -1, -1};
|
||||
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) {
|
||||
printf("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;
|
||||
|
||||
int* tp_cores = gpd(param, nump, CONFIG_STRING_ORU_TP_CORES)->iptr;
|
||||
int num_tp_cores = gpd(param, nump, CONFIG_STRING_ORU_TP_CORES)->numelt;
|
||||
AssertFatal(num_tp_cores > 0, "No threadpool cores specified\n");
|
||||
|
||||
char tpool_config[(3 + 1) * num_tp_cores + 1];
|
||||
char* tpool_config_p = tpool_config;
|
||||
for (int i = 0; i < num_tp_cores; i++) {
|
||||
int ret = snprintf(tpool_config_p, 4, "%d,", tp_cores[i]);
|
||||
AssertFatal(ret > 0, "snprintf failed\n");
|
||||
tpool_config_p += ret;
|
||||
}
|
||||
*tpool_config_p = '\0';
|
||||
|
||||
LOG_A(PHY, "ORU threadpool cores: %s\n", tpool_config);
|
||||
initTpool(tpool_config, &oru->tpool, false);
|
||||
|
||||
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;
|
||||
if (p < oru->num_DL_slots) {
|
||||
ru->config.tdd_table.max_tdd_periodicity_list[n].max_num_of_symbol_per_slot_list =
|
||||
malloc(sizeof(*ru->config.tdd_table.max_tdd_periodicity_list[n].max_num_of_symbol_per_slot_list)
|
||||
* NR_SYMBOLS_PER_SLOT);
|
||||
for (s = 0; s < 14; s++)
|
||||
ru->config.tdd_table.max_tdd_periodicity_list[n].max_num_of_symbol_per_slot_list[s].slot_config.value = 0;
|
||||
} else if (p == oru->num_DL_slots) {
|
||||
ru->config.tdd_table.max_tdd_periodicity_list[n].max_num_of_symbol_per_slot_list =
|
||||
malloc(sizeof(*ru->config.tdd_table.max_tdd_periodicity_list[n].max_num_of_symbol_per_slot_list)
|
||||
* NR_SYMBOLS_PER_SLOT);
|
||||
for (s = 0; s < oru->num_DL_symbols; s++)
|
||||
ru->config.tdd_table.max_tdd_periodicity_list[n].max_num_of_symbol_per_slot_list[s].slot_config.value = 0;
|
||||
for (; s < NR_SYMBOLS_PER_SLOT - oru->num_UL_symbols; s++)
|
||||
ru->config.tdd_table.max_tdd_periodicity_list[n].max_num_of_symbol_per_slot_list[s].slot_config.value = 2;
|
||||
for (; s < NR_SYMBOLS_PER_SLOT; s++)
|
||||
ru->config.tdd_table.max_tdd_periodicity_list[n].max_num_of_symbol_per_slot_list[s].slot_config.value = 1;
|
||||
} else {
|
||||
ru->config.tdd_table.max_tdd_periodicity_list[n].max_num_of_symbol_per_slot_list =
|
||||
malloc(sizeof(*ru->config.tdd_table.max_tdd_periodicity_list[n].max_num_of_symbol_per_slot_list)
|
||||
* NR_SYMBOLS_PER_SLOT);
|
||||
for (s = 0; s < NR_SYMBOLS_PER_SLOT; s++)
|
||||
ru->config.tdd_table.max_tdd_periodicity_list[n].max_num_of_symbol_per_slot_list[s].slot_config.value = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void initialize_sync_params(NR_DL_FRAME_PARMS *fp, sync_params_t *sync_params, initial_sync_t *initial_sync)
|
||||
{
|
||||
sync_params->frame_unwrap = 0;
|
||||
sync_params->last_frame = initial_sync->frame;
|
||||
sync_params->sync_offset = initial_sync->sample;
|
||||
sync_params->sync_offset -=
|
||||
(uint64_t)(initial_sync->frame) * fp->samples_per_subframe * 10 + get_samples_slot_timestamp(fp, initial_sync->slot);
|
||||
}
|
||||
|
||||
static openair0_timestamp_t get_timestamp(ORU_t *oru, sense_of_time_t *sense_of_time, sync_params_t *sync_params)
|
||||
{
|
||||
if (sync_params->last_frame > sense_of_time->frame) {
|
||||
sync_params->frame_unwrap++;
|
||||
}
|
||||
sync_params->last_frame = sense_of_time->frame;
|
||||
NR_DL_FRAME_PARMS *fp = oru->ru->nr_frame_parms;
|
||||
int num_frames = sense_of_time->frame + sync_params->frame_unwrap * 1024;
|
||||
|
||||
uint64_t timestamp = (uint64_t)(num_frames)*fp->samples_per_subframe * 10 + get_samples_slot_timestamp(fp, sense_of_time->slot)
|
||||
+ get_samples_symbol_timestamp(fp, sense_of_time->slot, sense_of_time->symbol);
|
||||
|
||||
timestamp += sync_params->sync_offset;
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
void receive_prach(ORU_t *oru, int frame, int slot, 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;
|
||||
|
||||
|
||||
rx_nr_prach_ru_internal(&oru->prach_item,
|
||||
0,
|
||||
oru->prach_info.start_symbol,
|
||||
0,
|
||||
ru->common.rxdata,
|
||||
fp,
|
||||
ru->N_TA_offset,
|
||||
prach_symbol,
|
||||
1);
|
||||
for (int aarx = 0; aarx < fp->nb_antennas_rx; aarx++) {
|
||||
ru->ifdevice.xran_api.write_prach((uint32_t *)oru->prach_item.rxsigF[0][aarx], aarx, frame, slot, prach_symbol);
|
||||
}
|
||||
}
|
||||
|
||||
// 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 *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;
|
||||
|
||||
AssertFatal(ru->ifdevice.xran_api.north_in_func != NULL, "No fronthaul interface at north port");
|
||||
__attribute__((aligned(32))) c16_t txDataF[ru->nb_tx][fp->ofdm_symbol_size * 14];
|
||||
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];
|
||||
}
|
||||
ru->common.txdataF_BF = (int32_t **)txDataF_ptr;
|
||||
|
||||
notifiedFIFO_elt_t *elt = pullNotifiedFIFO(&oru->sync_fifo);
|
||||
initial_sync_t *initial_sync = NotifiedFifoData(elt);
|
||||
sync_params_t sync_params;
|
||||
initialize_sync_params(fp, &sync_params, initial_sync);
|
||||
LOG_A(PHY,
|
||||
"ORU North read thread started at frame %d, slot %d, symbol %d\n",
|
||||
initial_sync->frame,
|
||||
initial_sync->slot,
|
||||
initial_sync->symbol);
|
||||
delNotifiedFIFO_elt(elt);
|
||||
|
||||
while (!oai_exit) {
|
||||
int num_symbols = 0;
|
||||
sense_of_time_t sense_of_time;
|
||||
ru->ifdevice.xran_api.north_in_func((uint32_t **)txDataF_ptr, ru->nb_tx, &sense_of_time, &num_symbols);
|
||||
openair0_timestamp_t timestamp_tx = get_timestamp(oru, &sense_of_time, &sync_params);
|
||||
if ((sense_of_time.frame % 256 == 0) && sense_of_time.slot == 0) {
|
||||
LOG_I(PHY,
|
||||
"[RU_thread] read data: frame %d, slot %d, start_symbol %d, num_symbols %d\n",
|
||||
sense_of_time.frame,
|
||||
sense_of_time.slot,
|
||||
sense_of_time.symbol,
|
||||
num_symbols);
|
||||
}
|
||||
nfapi_nr_config_request_scf_t *cfg = &ru->config;
|
||||
int slot_type = nr_slot_select(cfg, sense_of_time.frame, sense_of_time.slot % fp->slots_per_frame);
|
||||
if (slot_type != NR_UPLINK_SLOT)
|
||||
oru_downlink_processing(oru,
|
||||
txDataF_ptr,
|
||||
sense_of_time.frame,
|
||||
sense_of_time.slot,
|
||||
sense_of_time.symbol,
|
||||
num_symbols,
|
||||
timestamp_tx);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void rx_initial_sync(ORU_t *oru, int *slot, int *frame)
|
||||
{
|
||||
RU_t *ru = oru->ru;
|
||||
NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms;
|
||||
|
||||
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;
|
||||
initial_sync_t initial_sync;
|
||||
while (!oai_exit) {
|
||||
int samples_read = ru->rfdevice.trx_read_func(&ru->rfdevice, ×tamp, rxp, num_samples, ru->nb_rx);
|
||||
AssertFatal(samples_read == num_samples, "Unexpected number of samples received\n");
|
||||
notifiedFIFO_elt_t *elt = pollNotifiedFIFO(&oru->sync_fifo);
|
||||
if (elt) {
|
||||
memcpy(&initial_sync, NotifiedFifoData(elt), sizeof(initial_sync));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Synchornize to ORAN timing
|
||||
int next_slot = initial_sync.slot;
|
||||
int next_frame = initial_sync.frame;
|
||||
openair0_timestamp_t next_sample = timestamp + num_samples;
|
||||
int64_t diff = next_sample - initial_sync.sample;
|
||||
LOG_I(PHY,
|
||||
"Sychronizing to frame slot %d.%d, sample %ld next_sample %ld diff %ld\n",
|
||||
next_frame,
|
||||
next_slot,
|
||||
initial_sync.sample,
|
||||
next_sample,
|
||||
diff);
|
||||
|
||||
uint64_t samples_to_sync_by = 0;
|
||||
if (diff < 0) {
|
||||
samples_to_sync_by = -diff;
|
||||
} else {
|
||||
while (diff > 0) {
|
||||
uint32_t samples_per_slot = get_samples_per_slot(next_slot, fp);
|
||||
samples_to_sync_by += samples_per_slot;
|
||||
diff -= samples_per_slot;
|
||||
next_slot++;
|
||||
if (next_slot == fp->slots_per_frame) {
|
||||
next_slot = 0;
|
||||
next_frame++;
|
||||
if (next_frame == 1024) {
|
||||
next_frame = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
samples_to_sync_by += diff;
|
||||
}
|
||||
|
||||
LOG_I(PHY, "Thrashing %lu samples to sync to slot %d, frame %d\n", samples_to_sync_by, next_slot, next_frame);
|
||||
while (!oai_exit && samples_to_sync_by > 0) {
|
||||
int samples_to_read = min(num_samples, samples_to_sync_by);
|
||||
int samples_read = ru->rfdevice.trx_read_func(&ru->rfdevice, ×tamp, rxp, samples_to_read, ru->nb_rx);
|
||||
AssertFatal(samples_to_read == samples_read, "Unexpected number of samples received\n");
|
||||
samples_to_sync_by -= samples_to_read;
|
||||
}
|
||||
*slot = next_slot;
|
||||
*frame = next_frame;
|
||||
}
|
||||
|
||||
void *oru_south_read_thread(void *arg)
|
||||
{
|
||||
ORU_t *oru = arg;
|
||||
|
||||
int slot;
|
||||
int frame;
|
||||
rx_initial_sync(oru, &slot, &frame);
|
||||
LOG_A(PHY, "ORU South read thread started at frame %d, slot %d\n", frame, slot);
|
||||
|
||||
RU_t *ru = oru->ru;
|
||||
NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms;
|
||||
|
||||
const int max_pusch_jobs = 300;
|
||||
pusch_symbol_job_t pusch_job_pool[max_pusch_jobs];
|
||||
uint32_t pusch_job_index = 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);
|
||||
|
||||
if (rx_slot_type == NR_UPLINK_SLOT || rx_slot_type == NR_MIXED_SLOT) {
|
||||
|
||||
nfapi_nr_config_request_scf_t *config = &ru->config;
|
||||
nfapi_nr_tdd_table_t *tdd_table = &config->tdd_table;
|
||||
AssertFatal(tdd_table->tdd_period.tl.tag == NFAPI_NR_CONFIG_TDD_PERIOD_TAG, "");
|
||||
int nb_periods_per_frame = get_nb_periods_per_frame(tdd_table->tdd_period.value);
|
||||
int n_tdd_period = fp->slots_per_frame / nb_periods_per_frame;
|
||||
nfapi_nr_max_num_of_symbol_per_slot_t *max_num_of_symbol_per_slot_list =
|
||||
config->tdd_table.max_tdd_periodicity_list[slot % n_tdd_period].max_num_of_symbol_per_slot_list;
|
||||
if (max_num_of_symbol_per_slot_list[symbol].slot_config.value != 1)
|
||||
continue;
|
||||
|
||||
int prach_symbol = get_prach_symbol(oru, frame, slot, symbol, ru->numerology);
|
||||
if (prach_symbol != -1) {
|
||||
receive_prach(oru, frame, slot, prach_symbol);
|
||||
}
|
||||
for (int aarx = 0; aarx < fp->nb_antennas_rx; aarx++) {
|
||||
pusch_symbol_job_t *job = &pusch_job_pool[pusch_job_index++ % max_pusch_jobs];
|
||||
job->oru = oru;
|
||||
job->aarx = aarx;
|
||||
job->frame = frame;
|
||||
job->slot = slot;
|
||||
job->symbol = symbol;
|
||||
task_t task = {.func = receive_pusch, .args = job};
|
||||
pushTpool(&oru->tpool, task);
|
||||
}
|
||||
stop_meas(&oru->rx);
|
||||
}
|
||||
}
|
||||
slot++;
|
||||
if (slot == fp->slots_per_frame) {
|
||||
slot = 0;
|
||||
frame++;
|
||||
if (frame == 1024) {
|
||||
frame = 0;
|
||||
}
|
||||
}
|
||||
if (frame % 256 == 0 && slot == 0) {
|
||||
LOG_I(PHY,
|
||||
"[ORU south] read data: frame %d, slot %d\n", frame, slot);
|
||||
}
|
||||
}
|
||||
|
||||
// Perform RX processing
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void perform_initial_sync(ORU_t *oru, sense_of_time_t *sense_of_time, initial_sync_t *initial_sync)
|
||||
{
|
||||
initial_sync->frame = sense_of_time->frame;
|
||||
initial_sync->slot = sense_of_time->slot;
|
||||
initial_sync->symbol = sense_of_time->symbol;
|
||||
initial_sync->sample = oru->ru->rfdevice.get_timestamp(&oru->ru->rfdevice, &sense_of_time->ts);
|
||||
LOG_I(PHY,
|
||||
"RU synchronized: frame, slot %d.%d, symbol %d, sample: %ld\n",
|
||||
initial_sync->frame,
|
||||
initial_sync->slot,
|
||||
initial_sync->symbol,
|
||||
initial_sync->sample);
|
||||
}
|
||||
|
||||
void *oru_sync_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;
|
||||
|
||||
AssertFatal(ru->ifdevice.xran_api.north_in_func != NULL, "No fronthaul interface at north port");
|
||||
__attribute__((aligned(32))) c16_t txDataF[ru->nb_tx][ceil_mod(fp->ofdm_symbol_size * 14, 32)];
|
||||
c16_t *txDataF_ptr[ru->nb_tx];
|
||||
for (int aatx = 0; aatx < ru->nb_tx; aatx++) {
|
||||
txDataF_ptr[aatx] = txDataF[aatx];
|
||||
}
|
||||
|
||||
initial_sync_t initial_sync;
|
||||
while (!oai_exit) {
|
||||
int num_symbols = 0;
|
||||
sense_of_time_t sense_of_time;
|
||||
ru->ifdevice.xran_api.north_in_func((uint32_t **)txDataF_ptr, ru->nb_tx, &sense_of_time, &num_symbols);
|
||||
if (sense_of_time.symbol == 0) {
|
||||
perform_initial_sync(oru, &sense_of_time, &initial_sync);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < oru->num_sync_messages_needed; i++) {
|
||||
notifiedFIFO_elt_t *sync_msg = newNotifiedFIFO_elt(sizeof(initial_sync_t), 0, NULL, NULL);
|
||||
initial_sync_t *initial_sync_p = NotifiedFifoData(sync_msg);
|
||||
*initial_sync_p = initial_sync;
|
||||
pushNotifiedFIFO(&oru->sync_fifo, sync_msg);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void dl_symbol_process(void *arg)
|
||||
{
|
||||
dl_symbol_process_t *args = (dl_symbol_process_t *)arg;
|
||||
apply_nr_rotation_TX(args->fp,
|
||||
args->txdataF,
|
||||
false,
|
||||
args->fp->symbol_rotation[0],
|
||||
args->slot,
|
||||
args->fp->N_RB_DL,
|
||||
args->start_symbol,
|
||||
args->num_symbols);
|
||||
nr_feptx0(args->ru, args->slot, args->start_symbol, args->num_symbols, args->aatx);
|
||||
completed_task_ans(args->task_ans);
|
||||
}
|
||||
|
||||
static void oru_downlink_processing(ORU_t *oru,
|
||||
c16_t *txDataF_ptr[oru->ru->nb_tx],
|
||||
int frame,
|
||||
int slot,
|
||||
int start_symbol,
|
||||
int num_symbols,
|
||||
openair0_timestamp_t timestamp_tx)
|
||||
{
|
||||
RU_t *ru = oru->ru;
|
||||
start_meas(&ru->tx_fhaul);
|
||||
NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms;
|
||||
int num_paralell_workers_per_antenna = num_symbols > 4 ? 2 : 1; // Ensure at least quarter slot parallelization
|
||||
task_t tasks[ru->nb_tx][num_paralell_workers_per_antenna];
|
||||
dl_symbol_process_t dl_process_args[ru->nb_tx][num_paralell_workers_per_antenna];
|
||||
task_ans_t task_ans;
|
||||
init_task_ans(&task_ans, num_paralell_workers_per_antenna * ru->nb_tx);
|
||||
for (int aatx = 0; aatx < ru->nb_tx; aatx++) {
|
||||
for (int i = 0; i < num_paralell_workers_per_antenna; i++) {
|
||||
tasks[aatx][i].func = dl_symbol_process;
|
||||
tasks[aatx][i].args = (void *)&dl_process_args[aatx][i];
|
||||
dl_process_args[aatx][i].ru = ru;
|
||||
dl_process_args[aatx][i].fp = fp;
|
||||
dl_process_args[aatx][i].slot = slot;
|
||||
dl_process_args[aatx][i].start_symbol = start_symbol + num_symbols / num_paralell_workers_per_antenna * i;
|
||||
dl_process_args[aatx][i].num_symbols =
|
||||
min(num_symbols / num_paralell_workers_per_antenna, num_symbols - (num_symbols / num_paralell_workers_per_antenna) * i);
|
||||
dl_process_args[aatx][i].aatx = aatx;
|
||||
dl_process_args[aatx][i].txdataF = txDataF_ptr[aatx];
|
||||
dl_process_args[aatx][i].task_ans = &task_ans;
|
||||
pushTpool(&oru->tpool, tasks[aatx][i]);
|
||||
}
|
||||
}
|
||||
LOG_D(PHY,
|
||||
"[RU_thread] transmit data: frame %d, slot %d, start_symbol %d, num_symbols %d, timestamp %ld\n",
|
||||
frame,
|
||||
slot,
|
||||
start_symbol,
|
||||
num_symbols,
|
||||
timestamp_tx);
|
||||
join_task_ans(&task_ans);
|
||||
tx_rf_symbols(ru, frame, slot, timestamp_tx, start_symbol, num_symbols);
|
||||
stop_meas(&ru->tx_fhaul);
|
||||
}
|
||||
|
||||
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;
|
||||
prach_item->beams[0] = 0; // TODO: Beamforming not supported yet
|
||||
|
||||
// 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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void receive_pusch(void *args)
|
||||
{
|
||||
pusch_symbol_job_t *job = args;
|
||||
ORU_t *oru = job->oru;
|
||||
int frame = job->frame;
|
||||
int slot = job->slot;
|
||||
int symbol = job->symbol;
|
||||
int aarx = job->aarx;
|
||||
RU_t *ru = oru->ru;
|
||||
NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms;
|
||||
|
||||
c16_t rxdataF[fp->ofdm_symbol_size] __attribute__((aligned(32)));
|
||||
|
||||
nr_symbol_fep_ul(fp, (c16_t *)ru->common.rxdata[aarx], rxdataF, symbol, slot, ru->N_TA_offset);
|
||||
apply_nr_rotation_symbol_RX(fp,
|
||||
rxdataF,
|
||||
fp->symbol_rotation[link_type_ul],
|
||||
fp->N_RB_UL,
|
||||
slot,
|
||||
symbol);
|
||||
ru->ifdevice.xran_api.write_pusch((uint32_t *)rxdataF, aarx, frame, slot, symbol);
|
||||
}
|
||||
78
executables/nr-oru.h
Normal file
78
executables/nr-oru.h
Normal file
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The OpenAirInterface Software Alliance licenses this file to You under
|
||||
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.openairinterface.org/?page_id=698
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*-------------------------------------------------------------------------------
|
||||
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
#ifndef __NR_ORU_H__
|
||||
#define __NR_ORU_H__
|
||||
#include "PHY/defs_nr_common.h"
|
||||
#include "openair1/PHY/defs_RU.h"
|
||||
#include "thread-pool.h"
|
||||
#include "common/utils/nr/nr_common.h"
|
||||
#include "openair2/LAYER2/NR_MAC_COMMON/nr_prach_config.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;
|
||||
pthread_t oru_sync_thread;
|
||||
int num_sync_messages_needed;
|
||||
notifiedFIFO_t sync_fifo;
|
||||
tpool_t tpool;
|
||||
|
||||
// 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 *oru_sync_thread(void *arg);
|
||||
void prepare_prach_item(ORU_t *oru);
|
||||
|
||||
#endif
|
||||
@@ -516,7 +516,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;
|
||||
@@ -543,22 +543,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);
|
||||
@@ -570,9 +571,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)
|
||||
@@ -583,8 +586,9 @@ void tx_rf(RU_t *ru, int frame,int slot, uint64_t timestamp)
|
||||
|
||||
int nt = ru->nb_tx * ru->num_beams_period;
|
||||
void *txp[nt];
|
||||
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,
|
||||
@@ -608,7 +612,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
|
||||
@@ -671,7 +680,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;
|
||||
|
||||
@@ -84,7 +84,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
|
||||
|
||||
@@ -125,13 +125,15 @@ prach_item_t *nr_schedule_rx_prach(PHY_VARS_gNB *gNB, int SFN, int Slot, nfapi_n
|
||||
return prach;
|
||||
}
|
||||
|
||||
static void rx_nr_prach_ru_internal(prach_item_t *p,
|
||||
int beam_id,
|
||||
int prachStartSymbol,
|
||||
int prachOccasion,
|
||||
int32_t **rxdata,
|
||||
NR_DL_FRAME_PARMS *fp,
|
||||
int N_TA_offset)
|
||||
void rx_nr_prach_ru_internal(prach_item_t *p,
|
||||
int beam_id,
|
||||
int prachStartSymbol,
|
||||
int prachOccasion,
|
||||
int32_t **rxdata,
|
||||
NR_DL_FRAME_PARMS *fp,
|
||||
int N_TA_offset,
|
||||
int rep_index,
|
||||
uint reps)
|
||||
{
|
||||
int sample_offset_slot;
|
||||
const int sum = fp->ofdm_symbol_size + fp->nb_prefix_samples;
|
||||
@@ -158,7 +160,6 @@ static void rx_nr_prach_ru_internal(prach_item_t *p,
|
||||
p->pdu.num_ra,
|
||||
prachStartSymbol,
|
||||
prachOccasion);
|
||||
int reps;
|
||||
int Ncp;
|
||||
int dftlen;
|
||||
int mu = p->numerology_index;
|
||||
@@ -172,25 +173,21 @@ static void rx_nr_prach_ru_internal(prach_item_t *p,
|
||||
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;
|
||||
@@ -209,22 +206,18 @@ static void rx_nr_prach_ru_internal(prach_item_t *p,
|
||||
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;
|
||||
|
||||
@@ -242,17 +235,14 @@ static void rx_nr_prach_ru_internal(prach_item_t *p,
|
||||
*/
|
||||
|
||||
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;
|
||||
|
||||
@@ -366,18 +356,25 @@ static void rx_nr_prach_ru_internal(prach_item_t *p,
|
||||
// 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) {
|
||||
for (int i = 0; i < reps; i++) {
|
||||
c16_t tmp[dftlen] __attribute__((aligned(32)));
|
||||
dft(dftsize, (int16_t *)prach2, (int16_t *)tmp, 1);
|
||||
dft(dftsize, (int16_t *)(prach2 + (rep_index + i) * dftlen), (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]);
|
||||
if (i == 0) {
|
||||
for (int j = 0; j < N_ZC; j++, k2++) {
|
||||
if (k2 == dftlen)
|
||||
k2 = 0;
|
||||
rxsigF_tmp[j] = tmp[k2];
|
||||
}
|
||||
} else {
|
||||
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->rxsigF[prachOccasion][aa], rxsigF_tmp, sizeof(rxsigF_tmp));
|
||||
@@ -394,7 +391,15 @@ void rx_nr_prach_ru(prach_item_t *p, int32_t **rxdata, NR_DL_FRAME_PARMS *fp, in
|
||||
// comment FK: the standard 38.211 section 5.3.2 has one extra term +14*N_RA_slot. This is because there prachStartSymbol is
|
||||
// given wrt to start of the 15kHz slot or 60kHz slot. Here we work slot based, so this function is anyway only called in slots
|
||||
// where there is PRACH. Its up to the MAC to schedule another PRACH PDU in the case there are there N_RA_slot \in {0,1}.
|
||||
rx_nr_prach_ru_internal(p, beam_id, prachStartSymbol, prach_oc, rxdata, fp, N_TA_offset);
|
||||
rx_nr_prach_ru_internal(p,
|
||||
beam_id,
|
||||
prachStartSymbol,
|
||||
prach_oc,
|
||||
rxdata,
|
||||
fp,
|
||||
N_TA_offset,
|
||||
0,
|
||||
get_prach_num_reps(p->pdu.prach_format));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -165,6 +165,19 @@ int openair0_transport_load(openair0_device_t *device, openair0_config_t *openai
|
||||
return rc;
|
||||
}
|
||||
|
||||
int openair0_load(openair0_device_t *device, char *name, openair0_config_t *openair0_cfg, eth_params_t *eth_params)
|
||||
{
|
||||
loader_shlibfunc_t shlib_fdesc[1];
|
||||
int ret = 0;
|
||||
|
||||
shlib_fdesc[0].fname = eth_params == NULL ? "device_init" : "transport_init";
|
||||
|
||||
ret = load_module_shlib(name, shlib_fdesc, 1, NULL);
|
||||
AssertFatal((ret >= 0), "Library %s couldn't be loaded\n", name);
|
||||
|
||||
return ((devfunc_t)shlib_fdesc[0].fptr)(device, openair0_cfg, eth_params);
|
||||
}
|
||||
|
||||
static void writerEnqueue(re_order_t *ctx, openair0_timestamp_t timestamp, void **txp, int nsamps, int nbAnt, int flags)
|
||||
{
|
||||
pthread_mutex_lock(&ctx->mutex_store);
|
||||
|
||||
@@ -382,6 +382,14 @@ typedef struct {
|
||||
} queue[WRITE_QUEUE_SZ];
|
||||
} re_order_t;
|
||||
|
||||
/*! \brief Provides a way to map between a symbol and a timespec */
|
||||
typedef struct {
|
||||
int frame;
|
||||
int slot;
|
||||
int symbol;
|
||||
struct timespec ts;
|
||||
} sense_of_time_t;
|
||||
|
||||
/*!\brief structure holds the parameters to configure RF devices */
|
||||
struct openair0_device {
|
||||
/*!tx write thread*/
|
||||
@@ -571,6 +579,10 @@ struct openair0_device {
|
||||
*/
|
||||
int (*trx_stop_func)(openair0_device_t *device);
|
||||
|
||||
/*! \brief Get timestamp from timespec
|
||||
*/
|
||||
openair0_timestamp_t (*get_timestamp)(openair0_device_t *device, struct timespec *ts);
|
||||
|
||||
/* Functions API related to UE*/
|
||||
|
||||
/*! \brief Set RX feaquencies
|
||||
@@ -657,6 +669,38 @@ struct openair0_device {
|
||||
*/
|
||||
time_stats_t tx_fhaul;
|
||||
re_order_t reOrder;
|
||||
|
||||
// Function pointers used for oran
|
||||
struct {
|
||||
/*! \brief O-RU only: reads DL FD IQ. Data is put into the beginning of txdataF buffer regardless
|
||||
* of the returned start_symbol. maximum number of symbols returned is 7
|
||||
* \param txdataF An array of nb_tx buffers to write the samples to
|
||||
* \param nb_tx number of TX antennas and number of buffer in txDataF_BF
|
||||
* \param sense_of_time frame, slot and symbol with mapping to clock_gettime result
|
||||
* \param num_symbols number of symbols
|
||||
*/
|
||||
void (*north_in_func)(uint32_t **txdataF, int nb_tx, sense_of_time_t* sense_of_time, int *num_symbols);
|
||||
|
||||
/*!
|
||||
* \brief Write prach data for one PRACH symbol
|
||||
* \param prachF Frequency domain PRACH data size 139 (only short format support)
|
||||
* \param aarx
|
||||
* \param frame
|
||||
* \param slot
|
||||
* \param symbol
|
||||
*/
|
||||
void (*write_prach)(uint32_t *prachF, int aarx, int frame, int slot, int symbol);
|
||||
|
||||
/*!
|
||||
* \brief Write data for one PUSCH symbol
|
||||
* \param prachF Frequency domain PUSCH data
|
||||
* \param aarx
|
||||
* \param frame
|
||||
* \param slot
|
||||
* \param symbol
|
||||
*/
|
||||
void (*write_pusch)(uint32_t *prachF, int aarx, int frame, int slot, int symbol);
|
||||
} xran_api;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
@@ -698,6 +742,7 @@ const char *get_devname(int devtype);
|
||||
int openair0_device_load(openair0_device_t *device, openair0_config_t *openair0_cfg);
|
||||
/*! \brief Initialize transport protocol . It returns 0 if OK */
|
||||
int openair0_transport_load(openair0_device_t *device, openair0_config_t *openair0_cfg, eth_params_t *eth_params);
|
||||
int openair0_load(openair0_device_t *device, char *name, openair0_config_t *openair0_cfg, eth_params_t *eth_params);
|
||||
|
||||
/*! \brief Set RX frequencies
|
||||
* \param device the hardware to use
|
||||
|
||||
@@ -11,6 +11,7 @@ pkg_check_modules(numa REQUIRED numa)
|
||||
|
||||
add_library(oran_fhlib_5g MODULE
|
||||
oran_isolate.c
|
||||
oaioran_ru.c
|
||||
oaioran.c
|
||||
oran-config.c
|
||||
oran-init.c
|
||||
@@ -33,7 +34,7 @@ add_compile_options(-Wno-packed-not-aligned)
|
||||
|
||||
set_target_properties(oran_fhlib_5g PROPERTIES COMPILE_FLAGS "-fvisibility=hidden -march=native")
|
||||
target_link_libraries(oran_fhlib_5g PRIVATE xran::xran ${dpdk_LINK_LIBRARIES} pthread dl rt m numa)
|
||||
target_link_libraries(oran_fhlib_5g PRIVATE log_headers)
|
||||
target_link_libraries(oran_fhlib_5g PRIVATE log_headers MAC_NR_COMMON)
|
||||
target_include_directories(oran_fhlib_5g PRIVATE ${dpdk_INCLUDE_DIRS})
|
||||
if (CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64")
|
||||
find_package(armral REQUIRED)
|
||||
|
||||
876
radio/fhi_72/oaioran_ru.c
Normal file
876
radio/fhi_72/oaioran_ru.c
Normal file
@@ -0,0 +1,876 @@
|
||||
/*
|
||||
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The OpenAirInterface Software Alliance licenses this file to You under
|
||||
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.openairinterface.org/?page_id=698
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*-------------------------------------------------------------------------------
|
||||
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
#include "assertions.h"
|
||||
#include "nr/nr_common.h"
|
||||
#include "utils.h"
|
||||
#include <asm-generic/errno.h>
|
||||
#include <netinet/in.h>
|
||||
#include <rte_ring.h>
|
||||
#include <rte_ring_core.h>
|
||||
#include <rte_ring_elem.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include "xran_fh_o_du.h"
|
||||
#include "xran_fh_o_ru.h"
|
||||
#include "xran_compression.h"
|
||||
#include "armral_bfp_compression.h"
|
||||
#include <xran_pkt.h>
|
||||
#include <xran_pkt_cp.h>
|
||||
#include <xran_pkt_up.h>
|
||||
#include <xran_transport.h>
|
||||
|
||||
#if defined(__arm__) || defined(__aarch64__)
|
||||
#else
|
||||
// xran_cp_api.h uses SIMD, but does not include it
|
||||
#include <immintrin.h>
|
||||
#endif
|
||||
#include "xran_cp_api.h"
|
||||
#include "xran_sync_api.h"
|
||||
#include "oran_isolate.h"
|
||||
#include "xran_up_api.h"
|
||||
#include "oran-init.h"
|
||||
#include "oaioran.h"
|
||||
#include <rte_ethdev.h>
|
||||
|
||||
#include "oran-config.h" // for g_kbar
|
||||
|
||||
#include "common/utils/threadPool/notified_fifo.h"
|
||||
|
||||
#define RATE_LIMIT(n) if (({ static int _counter = 0; _counter++ % (n) == 0; }))
|
||||
#define ETHER_TYPE_ECPRI 0xAEFE
|
||||
#define MAX_NUM_ANTENNAS 4
|
||||
#define XRAN_GET_MU_FROM_SECT_ID(sectId) (sectId/XRAN_MAX_SECTIONS_PER_SLOT)
|
||||
|
||||
notifiedFIFO_t ru_dl_sync_fifo;
|
||||
extern volatile bool first_call_set;
|
||||
|
||||
#define UPLANE_DATA_RING_SIZE 1024
|
||||
#define NUM_UPLANE_DATA_ELEMENTS (UPLANE_DATA_RING_SIZE - 1)
|
||||
#define UPLANE_SYMBOL_RING_SIZE 16
|
||||
#define MAX_UPLANE_PACKETS_PER_SYMBOL (UPLANE_SYMBOL_RING_SIZE - 1)
|
||||
|
||||
typedef struct {
|
||||
int frame;
|
||||
int slot;
|
||||
int symbol;
|
||||
int num_symbols;
|
||||
struct timespec ts;
|
||||
} ru_dl_sync_info_t;
|
||||
|
||||
typedef struct {
|
||||
uint16_t cb_symbol_mask;
|
||||
int num_symbols[NR_SYMBOLS_PER_SLOT];
|
||||
int start_symbol[NR_SYMBOLS_PER_SLOT];
|
||||
int symbol_diff;
|
||||
int numerology;
|
||||
} oran_symbol_callback_args_t;
|
||||
|
||||
typedef struct {
|
||||
void *iq_data;
|
||||
void *mbuf_to_free;
|
||||
int start_prb;
|
||||
int num_prb;
|
||||
int iq_width;
|
||||
int comp_meth;
|
||||
int aatx;
|
||||
} uplane_data_t;
|
||||
|
||||
typedef struct {
|
||||
uplane_data_t uplane_data_pool[NUM_UPLANE_DATA_ELEMENTS];
|
||||
struct rte_ring *uplane_data_ring;
|
||||
struct rte_ring **uplane_symbol_rings;
|
||||
_Atomic(uint64_t) up_not_processed;
|
||||
_Atomic(uint64_t) up_symbol_pool_exhausted;
|
||||
_Atomic(uint64_t) up_received;
|
||||
_Atomic(uint64_t) up_processed;
|
||||
_Atomic(uint64_t) up_pool_exhausted;
|
||||
_Atomic(uint64_t) up_dropped;
|
||||
_Atomic(uint64_t) up_late;
|
||||
_Atomic(uint64_t) up_early;
|
||||
_Atomic(uint64_t) up_malformed;
|
||||
_Atomic(uint64_t) up_arrival_histogram[128];
|
||||
} packet_processor_context_t;
|
||||
|
||||
static packet_processor_context_t packet_processor_context;
|
||||
|
||||
static void init_packet_processor_context(packet_processor_context_t *context, int mu)
|
||||
{
|
||||
memset(context, 0, sizeof(packet_processor_context_t));
|
||||
context->uplane_data_ring = rte_ring_create("uplane_data_ring", UPLANE_DATA_RING_SIZE, rte_socket_id(), 0);
|
||||
AssertFatal(context->uplane_data_ring != NULL, "Failed to create ring uplane_data_ring\n");
|
||||
for (int i = 0; i < NUM_UPLANE_DATA_ELEMENTS; i++) {
|
||||
int ret = rte_ring_enqueue(context->uplane_data_ring, &context->uplane_data_pool[i]);
|
||||
AssertFatal(ret == 0,
|
||||
"Failed to push element %d/%d to uplane_data_ring, ring_size %d entries %d free entries %d return value %d \n",
|
||||
i,
|
||||
NUM_UPLANE_DATA_ELEMENTS,
|
||||
UPLANE_DATA_RING_SIZE,
|
||||
rte_ring_count(context->uplane_data_ring),
|
||||
rte_ring_free_count(context->uplane_data_ring),
|
||||
ret);
|
||||
}
|
||||
LOG_I(HW, "Enqueued %d elements to uplane_data_ring\n", NUM_UPLANE_DATA_ELEMENTS);
|
||||
int num_slots_per_frame = 10 << mu;
|
||||
int num_symbol_rings = NR_SYMBOLS_PER_SLOT * num_slots_per_frame;
|
||||
context->uplane_symbol_rings = malloc(sizeof(struct rte_ring *) * num_symbol_rings);
|
||||
for (int i = 0; i < num_symbol_rings; i++) {
|
||||
char name[128];
|
||||
snprintf(name, sizeof(name), "up_symbol_%d", i);
|
||||
struct rte_ring *ring = rte_ring_create(name, UPLANE_SYMBOL_RING_SIZE, rte_socket_id(), 0);
|
||||
AssertFatal(ring != NULL, "Failed to create ring %s\n", name);
|
||||
context->uplane_symbol_rings[i] = ring;
|
||||
}
|
||||
}
|
||||
|
||||
static void clear_old_uplane_packets(packet_processor_context_t *context, int slot_in_frame, int symbol)
|
||||
{
|
||||
uplane_data_t *uplane_data[MAX_UPLANE_PACKETS_PER_SYMBOL];
|
||||
struct rte_ring *ring = context->uplane_symbol_rings[slot_in_frame * NR_SYMBOLS_PER_SLOT + symbol];
|
||||
int dequeued = rte_ring_dequeue_burst(ring, (void **)&uplane_data, MAX_UPLANE_PACKETS_PER_SYMBOL, NULL);
|
||||
if (dequeued > 0) {
|
||||
context->up_not_processed += dequeued;
|
||||
context->up_dropped += dequeued;
|
||||
for (int i = 0; i < dequeued; i++) {
|
||||
rte_pktmbuf_free(uplane_data[i]->mbuf_to_free);
|
||||
}
|
||||
int enqueued = rte_ring_enqueue_burst(context->uplane_data_ring, (void **)uplane_data, dequeued, NULL);
|
||||
AssertFatal(enqueued == dequeued, "Failed to push elements to uplane_data_ring\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void enqueue_uplane_packet(packet_processor_context_t *context,
|
||||
void *iq_data,
|
||||
void *mbuf_to_free,
|
||||
int start_prb,
|
||||
int num_prb,
|
||||
int iq_width,
|
||||
int comp_meth,
|
||||
int slot_in_frame,
|
||||
int symbol,
|
||||
int aatx)
|
||||
{
|
||||
uplane_data_t *uplane_data;
|
||||
context->up_received++;
|
||||
int ret = rte_ring_dequeue(context->uplane_data_ring, (void **)&uplane_data);
|
||||
if (ret == 0) {
|
||||
uplane_data->iq_data = iq_data;
|
||||
uplane_data->mbuf_to_free = mbuf_to_free;
|
||||
uplane_data->start_prb = start_prb;
|
||||
uplane_data->num_prb = num_prb;
|
||||
uplane_data->iq_width = iq_width;
|
||||
uplane_data->comp_meth = comp_meth;
|
||||
uplane_data->aatx = aatx;
|
||||
struct rte_ring *ring = context->uplane_symbol_rings[slot_in_frame * NR_SYMBOLS_PER_SLOT + symbol];
|
||||
int ret = rte_ring_enqueue(ring, uplane_data);
|
||||
if (ret != 0) {
|
||||
context->up_symbol_pool_exhausted++;
|
||||
context->up_dropped++;
|
||||
rte_pktmbuf_free(mbuf_to_free);
|
||||
ret = rte_ring_enqueue(context->uplane_data_ring, uplane_data);
|
||||
AssertFatal(ret == 0, "Failed to push elements to uplane_data_ring\n");
|
||||
}
|
||||
} else {
|
||||
context->up_pool_exhausted++;
|
||||
context->up_dropped++;
|
||||
rte_pktmbuf_free(mbuf_to_free);
|
||||
}
|
||||
}
|
||||
|
||||
static int32_t pull_uplane_packet_data(packet_processor_context_t *context,
|
||||
uplane_data_t **uplane_data,
|
||||
int num_data,
|
||||
int slot_in_frame,
|
||||
int symbol)
|
||||
{
|
||||
struct rte_ring *ring = context->uplane_symbol_rings[slot_in_frame * NR_SYMBOLS_PER_SLOT + symbol];
|
||||
int ret = rte_ring_dequeue_burst(ring, (void **)uplane_data, num_data, NULL);
|
||||
if (ret > 0) {
|
||||
context->up_processed += ret;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void push_uplane_packet_data(packet_processor_context_t *context, uplane_data_t **uplane_data, int num_data)
|
||||
{
|
||||
int enqueued = rte_ring_enqueue_burst(context->uplane_data_ring, (void **)uplane_data, num_data, NULL);
|
||||
AssertFatal(enqueued == num_data, "Failed to push elements to uplane_data_ring\n");
|
||||
}
|
||||
|
||||
static void print_statistics(packet_processor_context_t *context)
|
||||
{
|
||||
if (context->up_pool_exhausted > 0) {
|
||||
LOG_W(HW, "Packets lost due to pool exhaustion: %lu\n", context->up_pool_exhausted);
|
||||
context->up_pool_exhausted = 0;
|
||||
}
|
||||
if (context->up_symbol_pool_exhausted > 0) {
|
||||
LOG_W(HW, "Packets lost due to symbol pool exhaustion: %lu\n", context->up_symbol_pool_exhausted);
|
||||
context->up_symbol_pool_exhausted = 0;
|
||||
}
|
||||
if (context->up_not_processed > 0) {
|
||||
LOG_W(HW, "Packets not processed by the application layer (application layer too slow): %lu\n", context->up_not_processed);
|
||||
context->up_not_processed = 0;
|
||||
}
|
||||
if (context->up_late > 0) {
|
||||
LOG_W(HW, "Packets late: %lu\n", context->up_late);
|
||||
context->up_late = 0;
|
||||
}
|
||||
if (context->up_early > 0) {
|
||||
LOG_W(HW, "Packets early: %lu\n", context->up_early);
|
||||
context->up_early = 0;
|
||||
}
|
||||
if (context->up_malformed > 0) {
|
||||
LOG_W(HW, "Packets malformed (packet couldn't be processed): %lu\n", context->up_malformed);
|
||||
context->up_malformed = 0;
|
||||
}
|
||||
LOG_I(HW, "RU: packets received %lu\n", context->up_received);
|
||||
LOG_I(HW, "RU: packets processed %lu\n", context->up_processed);
|
||||
LOG_I(HW, "RU: packets dropped %lu\n", context->up_dropped);
|
||||
|
||||
bool printed_header = false;
|
||||
for (int i = 0; i < 128; i++) {
|
||||
uint64_t count = context->up_arrival_histogram[i];
|
||||
if (count > 0) {
|
||||
if (!printed_header) {
|
||||
LOG_I(HW, "RU: packet arrival histogram (diff in symbols):\n");
|
||||
printed_header = true;
|
||||
}
|
||||
LOG_I(HW, " %3d symbols early: %lu\n", i, count);
|
||||
context->up_arrival_histogram[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
int section_id;
|
||||
int num_prb;
|
||||
int start_prb;
|
||||
int slot;
|
||||
int frame;
|
||||
int mu;
|
||||
int filter_id;
|
||||
} oran_prach_cplane_config_t;
|
||||
|
||||
typedef struct {
|
||||
int section_id;
|
||||
int num_prb;
|
||||
int start_prb;
|
||||
} oran_pusch_cplane_config_t;
|
||||
|
||||
static oran_pusch_cplane_config_t pusch_config[MAX_NUM_ANTENNAS][20][14];
|
||||
|
||||
oran_prach_cplane_config_t prach_config_per_antenna[MAX_NUM_ANTENNAS] = {0};
|
||||
static uint8_t prach_seq_id[MAX_NUM_ANTENNAS] = {0};
|
||||
static _Atomic(uint8_t) pusch_seq_id[MAX_NUM_ANTENNAS] = {0};
|
||||
|
||||
extern int32_t xran_ethdi_mbuf_send(struct rte_mbuf *mb, uint16_t ethertype, uint16_t vf_id);
|
||||
extern uint16_t xran_map_ecpriPcid_to_vf(void *p_dev_ctx, int32_t dir, int32_t cc_id, int32_t ru_port_id);
|
||||
|
||||
void symbol_callback(void *args, struct xran_sense_of_time *p_sense_of_time)
|
||||
{
|
||||
if (!first_call_set) {
|
||||
return;
|
||||
}
|
||||
|
||||
oran_symbol_callback_args_t *callback_args = args;
|
||||
int num_slots_per_subframe = 1 << callback_args->numerology;
|
||||
int num_slots_per_frame = 10 << callback_args->numerology;
|
||||
int slot_in_frame = p_sense_of_time->nSlotIdx + p_sense_of_time->nSubframeIdx * num_slots_per_subframe;
|
||||
clear_old_uplane_packets(&packet_processor_context, slot_in_frame, p_sense_of_time->nSymIdx);
|
||||
|
||||
if ((callback_args->cb_symbol_mask & (1 << p_sense_of_time->nSymIdx)) == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
int num_symbols = callback_args->num_symbols[p_sense_of_time->nSymIdx];
|
||||
int start_symbol = callback_args->start_symbol[p_sense_of_time->nSymIdx];
|
||||
|
||||
// Adjust timing by symbol_diff
|
||||
int slot_index_increments = (p_sense_of_time->nSymIdx + callback_args->symbol_diff) / NR_SYMBOLS_PER_SLOT;
|
||||
|
||||
int target_slot_in_frame =
|
||||
p_sense_of_time->nSlotIdx + p_sense_of_time->nSubframeIdx * num_slots_per_subframe + slot_index_increments;
|
||||
int frame = p_sense_of_time->nFrameIdx;
|
||||
while (target_slot_in_frame >= num_slots_per_frame) {
|
||||
target_slot_in_frame -= num_slots_per_frame;
|
||||
frame++;
|
||||
if (frame >= 1024) {
|
||||
frame = 0;
|
||||
}
|
||||
}
|
||||
|
||||
const struct xran_fh_config *fh_cfg = get_xran_fh_config(0);
|
||||
int mu = fh_cfg->frame_conf.nNumerology;
|
||||
AssertFatal(mu == 1, "Only numerology 1 supported for RU\n");
|
||||
|
||||
LOG_D(HW,
|
||||
"Callback triggered at frame.slot.symbol %d.%d.%d targets %d.%d.%d, num_symbols %d, symbol_diff %d\n",
|
||||
p_sense_of_time->nFrameIdx,
|
||||
slot_in_frame,
|
||||
p_sense_of_time->nSymIdx,
|
||||
frame,
|
||||
target_slot_in_frame,
|
||||
start_symbol,
|
||||
num_symbols,
|
||||
callback_args->symbol_diff);
|
||||
|
||||
notifiedFIFO_elt_t *req = newNotifiedFIFO_elt(sizeof(ru_dl_sync_info_t), 0, NULL, NULL);
|
||||
ru_dl_sync_info_t *info = NotifiedFifoData(req);
|
||||
info->frame = frame;
|
||||
info->slot = target_slot_in_frame;
|
||||
info->symbol = start_symbol;
|
||||
info->num_symbols = num_symbols;
|
||||
|
||||
int slot_duration_uS[] = {1000, 500, 250, 125};
|
||||
uint64_t slot_in_second_offset_nS = ((uint64_t)p_sense_of_time->tti_counter * slot_duration_uS[mu]) * 1000UL;
|
||||
|
||||
float symbol_duration_nS = ((float)slot_duration_uS[mu] * 1000) / 14.0f;
|
||||
uint64_t symbol_in_slot_offset_nS = (uint64_t)((p_sense_of_time->nSymIdx + callback_args->symbol_diff) * symbol_duration_nS);
|
||||
|
||||
info->ts.tv_sec = p_sense_of_time->nSecond;
|
||||
info->ts.tv_nsec = slot_in_second_offset_nS + symbol_in_slot_offset_nS;
|
||||
if (info->ts.tv_nsec >= 1000000000UL) {
|
||||
info->ts.tv_sec += 1;
|
||||
info->ts.tv_nsec -= 1000000000UL;
|
||||
}
|
||||
|
||||
AssertFatal(info->ts.tv_nsec < 1000000000UL, "ORAN: Invalid tv_nsec %ld\n", info->ts.tv_nsec);
|
||||
|
||||
pushNotifiedFIFO(&ru_dl_sync_fifo, req);
|
||||
}
|
||||
|
||||
int xran_oru_tx_read_slot(uint32_t **txdataF, int nb_tx, int *frame, int *slot, int *symbol, int *num_symbols, struct timespec *ts)
|
||||
{
|
||||
notifiedFIFO_elt_t *res = pullNotifiedFIFO(&ru_dl_sync_fifo);
|
||||
ru_dl_sync_info_t *info = NotifiedFifoData(res);
|
||||
|
||||
*slot = info->slot;
|
||||
*frame = info->frame;
|
||||
*symbol = info->symbol;
|
||||
*num_symbols = info->num_symbols;
|
||||
*ts = info->ts;
|
||||
delNotifiedFIFO_elt(res);
|
||||
|
||||
if (*frame % 256 == 0 && *slot == 0 && *symbol == 0) {
|
||||
print_statistics(&packet_processor_context);
|
||||
}
|
||||
|
||||
const struct xran_fh_config *fh_cfg = get_xran_fh_config(0);
|
||||
int nPRBs = fh_cfg->nDLRBs;
|
||||
int fftsize = 1 << fh_cfg->nDLFftSize;
|
||||
|
||||
int first_carrier_offset = fftsize - (nPRBs * NR_NB_SC_PER_RB / 2);
|
||||
int num_sc_first_copy = (fftsize - first_carrier_offset);
|
||||
int num_sc_second_copy = nPRBs * NR_NB_SC_PER_RB - num_sc_first_copy;
|
||||
|
||||
c16_t tx_data_sym[nb_tx][nPRBs * NR_NB_SC_PER_RB];
|
||||
for (int sym = *symbol; sym < *symbol + *num_symbols; sym++) {
|
||||
uplane_data_t *uplane_data[MAX_UPLANE_PACKETS_PER_SYMBOL];
|
||||
int num_packets = pull_uplane_packet_data(&packet_processor_context, uplane_data, MAX_UPLANE_PACKETS_PER_SYMBOL, *slot, sym);
|
||||
if (num_packets) {
|
||||
memset(tx_data_sym, 0, sizeof(tx_data_sym));
|
||||
for (int i = 0; i < num_packets; i++) {
|
||||
int start_prb = uplane_data[i]->start_prb;
|
||||
int num_prb = uplane_data[i]->num_prb;
|
||||
int comp_meth = uplane_data[i]->comp_meth;
|
||||
int aatx = uplane_data[i]->aatx;
|
||||
void *iq_data = uplane_data[i]->iq_data;
|
||||
AssertFatal(comp_meth == XRAN_COMPMETHOD_NONE, "Compression not supported\n");
|
||||
uint16_t *source = (uint16_t *)iq_data;
|
||||
int16_t *destination = (int16_t *)&tx_data_sym[aatx][start_prb * NR_NB_SC_PER_RB];
|
||||
for (int j = 0; j < num_prb * NR_NB_SC_PER_RB * 2; j++) {
|
||||
destination[j] = (int16_t)ntohs(source[j]);
|
||||
}
|
||||
rte_pktmbuf_free(uplane_data[i]->mbuf_to_free);
|
||||
}
|
||||
push_uplane_packet_data(&packet_processor_context, uplane_data, num_packets);
|
||||
}
|
||||
|
||||
if (num_packets) {
|
||||
for (int aatx = 0; aatx < nb_tx; aatx++) {
|
||||
memcpy(&txdataF[aatx][fftsize * sym + first_carrier_offset], tx_data_sym[aatx], num_sc_first_copy * sizeof(c16_t));
|
||||
memcpy(&txdataF[aatx][fftsize * sym], &tx_data_sym[aatx][num_sc_first_copy], num_sc_second_copy * sizeof(c16_t));
|
||||
}
|
||||
} else {
|
||||
for (int aatx = 0; aatx < nb_tx; aatx++) {
|
||||
memset(&txdataF[aatx][sym * fftsize], 0, sizeof(c16_t) * fftsize);
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int process_ru_uplane(struct rte_mbuf *pkt,
|
||||
void *handle,
|
||||
struct xran_eaxc_info *p_cid,
|
||||
uint16_t port_id,
|
||||
struct xran_sense_of_time *p_sense_of_time)
|
||||
{
|
||||
if (!first_call_set) {
|
||||
return MBUF_FREE;
|
||||
}
|
||||
const struct xran_fh_config *fh_cfg = get_xran_fh_config(port_id);
|
||||
void *iq_data_start = NULL;
|
||||
uint8_t CC_ID = 0xFF;
|
||||
uint8_t Ant_ID = 0xFF;
|
||||
uint8_t frame_id;
|
||||
uint8_t subframe_id;
|
||||
uint8_t slot_id;
|
||||
uint8_t symb_id;
|
||||
uint8_t filter_id;
|
||||
union ecpri_seq_id seq_id;
|
||||
uint16_t num_prbu;
|
||||
uint16_t start_prbu;
|
||||
uint16_t sym_inc;
|
||||
uint16_t rb;
|
||||
uint16_t sect_id;
|
||||
int expect_comp = fh_cfg->ru_conf.compMeth != XRAN_COMPMETHOD_NONE;
|
||||
enum xran_comp_hdr_type staticComp = fh_cfg->ru_conf.xranCompHdrType;
|
||||
uint8_t compMeth = XRAN_COMPMETHOD_NONE;
|
||||
uint8_t iqWidth = 0;
|
||||
uint8_t is_prach;
|
||||
int ret = xran_extract_iq_samples(pkt,
|
||||
&iq_data_start,
|
||||
&CC_ID,
|
||||
&Ant_ID,
|
||||
&frame_id,
|
||||
&subframe_id,
|
||||
&slot_id,
|
||||
&symb_id,
|
||||
&filter_id,
|
||||
&seq_id,
|
||||
&num_prbu,
|
||||
&start_prbu,
|
||||
&sym_inc,
|
||||
&rb,
|
||||
§_id,
|
||||
expect_comp,
|
||||
staticComp,
|
||||
&compMeth,
|
||||
&iqWidth,
|
||||
&is_prach);
|
||||
if (ret == 0) {
|
||||
packet_processor_context.up_malformed++;
|
||||
packet_processor_context.up_dropped++;
|
||||
return MBUF_FREE;
|
||||
}
|
||||
LOG_D(HW,
|
||||
"ORAN: U-plane packet received. CC_ID %d, Ant_ID %d, frame_id %d, subframe_id %d, slot_id %d, symb_id %d, filter_id %d, "
|
||||
"num_prbu %d, start_prbu %d, sym_inc %d, rb %d, sect_id %d, compMeth %d, iqWidth %d, is_prach %d\n",
|
||||
CC_ID,
|
||||
Ant_ID,
|
||||
frame_id,
|
||||
subframe_id,
|
||||
slot_id,
|
||||
symb_id,
|
||||
filter_id,
|
||||
num_prbu,
|
||||
start_prbu,
|
||||
sym_inc,
|
||||
rb,
|
||||
sect_id,
|
||||
compMeth,
|
||||
iqWidth,
|
||||
is_prach);
|
||||
|
||||
AssertFatal(compMeth == XRAN_COMPMETHOD_NONE, "Compression not supported\n");
|
||||
int mu = fh_cfg->frame_conf.nNumerology;
|
||||
int slots_per_subframe = 1 << mu;
|
||||
int current_symbol_index = NR_SYMBOLS_PER_SLOT * (p_sense_of_time->nSlotIdx + p_sense_of_time->nSubframeIdx * slots_per_subframe) + p_sense_of_time->nSymIdx;
|
||||
int target_symbol_index = NR_SYMBOLS_PER_SLOT * (slot_id + subframe_id * slots_per_subframe) + symb_id;
|
||||
int diff = target_symbol_index - current_symbol_index;
|
||||
int max_sym = NR_SYMBOLS_PER_SLOT * NR_NUMBER_OF_SUBFRAMES_PER_FRAME * slots_per_subframe;
|
||||
if (diff < -max_sym / 2) {
|
||||
diff += max_sym;
|
||||
} else if (diff > max_sym / 2) {
|
||||
diff -= max_sym;
|
||||
}
|
||||
|
||||
packet_processor_context.up_arrival_histogram[min(max(diff, 0), 127)]++;
|
||||
|
||||
int slot_duration_uS = 1000 / (1 << mu);
|
||||
int symbol_duration_uS = slot_duration_uS / NR_SYMBOLS_PER_SLOT;
|
||||
int rx_window_start = fh_cfg->T2a_max_up / symbol_duration_uS;
|
||||
int rx_window_end = fh_cfg->T2a_min_up / symbol_duration_uS;
|
||||
if (diff < rx_window_end) {
|
||||
packet_processor_context.up_late++;
|
||||
return MBUF_FREE;
|
||||
} else if (diff > rx_window_start) {
|
||||
packet_processor_context.up_early++;
|
||||
}
|
||||
|
||||
|
||||
int slot_in_frame = slot_id + subframe_id * slots_per_subframe;
|
||||
enqueue_uplane_packet(&packet_processor_context,
|
||||
iq_data_start,
|
||||
pkt,
|
||||
start_prbu,
|
||||
num_prbu,
|
||||
iqWidth,
|
||||
compMeth,
|
||||
slot_in_frame,
|
||||
symb_id,
|
||||
Ant_ID);
|
||||
|
||||
return MBUF_KEEP;
|
||||
}
|
||||
|
||||
int32_t process_ru_cplane(struct rte_mbuf *pkt, void *handle, uint16_t port_id, struct xran_sense_of_time *p_sense_of_time)
|
||||
{
|
||||
const struct xran_fh_config *fh_cfg = get_xran_fh_config(port_id);
|
||||
struct xran_ecpri_hdr *ecpri_hdr;
|
||||
struct xran_recv_packet_info xran_recv_packet_info;
|
||||
int ret = xran_parse_ecpri_hdr(pkt, &ecpri_hdr, &xran_recv_packet_info);
|
||||
if (ret != XRAN_STATUS_SUCCESS) {
|
||||
return MBUF_FREE;
|
||||
}
|
||||
struct xran_cp_radioapp_common_header *apphdr = (void *)rte_pktmbuf_adj(pkt, sizeof(struct xran_ecpri_hdr));
|
||||
if (apphdr == NULL) {
|
||||
LOG_W(HW, "issue extracting apphdr\n");
|
||||
return MBUF_FREE;
|
||||
}
|
||||
apphdr->field.all_bits = rte_be_to_cpu_32(apphdr->field.all_bits);
|
||||
if (apphdr->field.payloadVer != XRAN_PAYLOAD_VER) {
|
||||
LOG_W(HW, "Invalid payloadVer field %d\n", apphdr->field.payloadVer);
|
||||
return MBUF_FREE;
|
||||
}
|
||||
|
||||
switch (apphdr->sectionType) {
|
||||
case XRAN_CP_SECTIONTYPE_3: {
|
||||
struct xran_cp_radioapp_section3_header *hdr = (struct xran_cp_radioapp_section3_header *)apphdr;
|
||||
if (hdr->cmnhdr.numOfSections != 1) {
|
||||
LOG_W(HW, "Only support one section\n");
|
||||
return MBUF_FREE;
|
||||
}
|
||||
|
||||
hdr->timeOffset = rte_be_to_cpu_16(hdr->timeOffset);
|
||||
hdr->cpLength = rte_be_to_cpu_16(hdr->cpLength);
|
||||
|
||||
struct xran_cp_radioapp_section3 *section = (void *)rte_pktmbuf_adj(pkt, sizeof(struct xran_cp_radioapp_section3_header));
|
||||
if (section == NULL) {
|
||||
LOG_W(HW, "Issue extracting section\n");
|
||||
return MBUF_FREE;
|
||||
}
|
||||
*((uint64_t *)section) = rte_be_to_cpu_64(*((uint64_t *)section));
|
||||
int mu = hdr->frameStructure.uScs;
|
||||
int aarx = xran_recv_packet_info.eaxc.ruPortId - fh_cfg->prach_conf.eAxC_offset;
|
||||
oran_prach_cplane_config_t prach_config = {
|
||||
.frame = hdr->cmnhdr.field.frameId,
|
||||
.slot = hdr->cmnhdr.field.slotId + hdr->cmnhdr.field.subframeId + hdr->cmnhdr.field.subframeId * hdr->frameStructure.uScs,
|
||||
.num_prb = section->hdr.u1.common.numPrbc,
|
||||
.start_prb = section->hdr.u1.common.startPrbc,
|
||||
.section_id = section->hdr.u1.common.sectionId,
|
||||
.mu = mu,
|
||||
.filter_id = hdr->cmnhdr.field.filterIndex
|
||||
};
|
||||
prach_config_per_antenna[aarx] = prach_config;
|
||||
return MBUF_FREE;
|
||||
}
|
||||
case XRAN_CP_SECTIONTYPE_1: {
|
||||
struct xran_cp_radioapp_section1_header *hdr = (struct xran_cp_radioapp_section1_header *)apphdr;
|
||||
struct xran_cp_radioapp_section1 *section = (void *)rte_pktmbuf_adj(pkt, sizeof(struct xran_cp_radioapp_section1_header));
|
||||
if (section == NULL) {
|
||||
LOG_W(HW, "Issue extracting section\n");
|
||||
return MBUF_FREE;
|
||||
}
|
||||
*((uint64_t *)section) = rte_be_to_cpu_64(*((uint64_t *)section));
|
||||
if (hdr->cmnhdr.field.dataDirection == XRAN_DIR_DL) {
|
||||
// For now skip DL
|
||||
return MBUF_FREE;
|
||||
}
|
||||
//int frame = hdr->cmnhdr.field.frameId;
|
||||
int section_id = section->hdr.u1.common.sectionId;
|
||||
int mu = fh_cfg->frame_conf.nNumerology;
|
||||
int slot = hdr->cmnhdr.field.slotId + hdr->cmnhdr.field.subframeId * (1 << mu);
|
||||
uint32_t start_symbol = hdr->cmnhdr.field.startSymbolId;
|
||||
int startPrbc = section->hdr.u1.common.startPrbc;
|
||||
int numPrbc = section->hdr.u1.common.numPrbc;
|
||||
int num_symbols = section->hdr.u.s1.numSymbol;
|
||||
int aarx = xran_recv_packet_info.eaxc.ruPortId;
|
||||
if (start_symbol + num_symbols > 14) {
|
||||
LOG_W(HW, "Invalid symbol index >= 14 start_symbol %d num_symbols %d\n", start_symbol, num_symbols);
|
||||
}
|
||||
LOG_D(HW,
|
||||
"section_id %d mu %d slot %d frame %d startprb %d num_prb %d start_sym %u num_sym %d\n",
|
||||
section_id,
|
||||
mu,
|
||||
slot,
|
||||
hdr->cmnhdr.field.frameId,
|
||||
startPrbc,
|
||||
numPrbc,
|
||||
start_symbol,
|
||||
num_symbols);
|
||||
for (int symbol = start_symbol; symbol < start_symbol + num_symbols && symbol < 14; symbol++) {
|
||||
pusch_config[aarx][slot][symbol].section_id = section_id;
|
||||
pusch_config[aarx][slot][symbol].start_prb = startPrbc;
|
||||
pusch_config[aarx][slot][symbol].num_prb = numPrbc;
|
||||
}
|
||||
return MBUF_FREE;
|
||||
}
|
||||
default:
|
||||
return MBUF_FREE;
|
||||
}
|
||||
}
|
||||
|
||||
void init_oru_packet_processor(void *handle, int callbacks_per_slot)
|
||||
{
|
||||
AssertFatal(callbacks_per_slot <= NR_SYMBOLS_PER_SLOT,
|
||||
"Can do at most %d callbacks per slot",
|
||||
NR_SYMBOLS_PER_SLOT);
|
||||
static bool installed = false;
|
||||
AssertFatal(!installed, "Cannot init oru twice\n");
|
||||
installed = true;
|
||||
for (int aarx = 0; aarx < MAX_NUM_ANTENNAS; aarx++) {
|
||||
prach_config_per_antenna[aarx].section_id = -1;
|
||||
prach_config_per_antenna[aarx].num_prb = -1;
|
||||
prach_config_per_antenna[aarx].start_prb = -1;
|
||||
prach_config_per_antenna[aarx].slot = -1;
|
||||
prach_config_per_antenna[aarx].frame = -1;
|
||||
}
|
||||
for (int aarx = 0; aarx < MAX_NUM_ANTENNAS; aarx++) {
|
||||
for (int slot = 0; slot < 20; slot++) {
|
||||
for (int symbol = 0; symbol < 14; symbol++) {
|
||||
pusch_config[aarx][slot][symbol].section_id = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Represents RX window end
|
||||
const struct xran_fh_config *fh_cfg = get_xran_fh_config(0);
|
||||
int mu = fh_cfg->frame_conf.nNumerology;
|
||||
init_packet_processor_context(&packet_processor_context, mu);
|
||||
uint32_t T2a_min = fh_cfg->T2a_min_up;
|
||||
int slot_duration_uS[] = {1000, 500, 250, 125};
|
||||
float symbol_duration_nS = ((float)slot_duration_uS[mu] * 1000) / 14.0f;
|
||||
uint32_t symbol_offset = (float)(T2a_min * 1000) / symbol_duration_nS;
|
||||
AssertFatal(symbol_offset > 0, "The amount of time after RX window end for O-RU is 0. Adjust T2a_min_up %u [uS]\n", T2a_min);
|
||||
LOG_I(HW, "Installing %d callbacks %d symbols before OTA\n", callbacks_per_slot, symbol_offset);
|
||||
|
||||
static oran_symbol_callback_args_t args = {0};
|
||||
args.numerology = mu;
|
||||
|
||||
int symbols_per_callback = NR_SYMBOLS_PER_SLOT / callbacks_per_slot;
|
||||
|
||||
int start_symbol = 0;
|
||||
for (int i = 0; i < callbacks_per_slot; i++) {
|
||||
int extra_symbols = 0;
|
||||
if (i == callbacks_per_slot - 1) {
|
||||
// Extend last callback to include leftover symbols
|
||||
extra_symbols += NR_SYMBOLS_PER_SLOT % callbacks_per_slot;
|
||||
}
|
||||
int num_sybmols_this_callback = symbols_per_callback + extra_symbols;
|
||||
int end_symbol = start_symbol + num_sybmols_this_callback - 1;
|
||||
int callback_symbol = (end_symbol - symbol_offset + NR_SYMBOLS_PER_SLOT) % NR_SYMBOLS_PER_SLOT;
|
||||
args.cb_symbol_mask |= (1U << callback_symbol);
|
||||
args.num_symbols[callback_symbol] = num_sybmols_this_callback;
|
||||
args.start_symbol[callback_symbol] = start_symbol;
|
||||
args.symbol_diff = symbol_offset;
|
||||
start_symbol += symbols_per_callback;
|
||||
}
|
||||
xran_hook_install(handle, process_ru_uplane, NULL, process_ru_cplane, NULL, symbol_callback, &args, mu);
|
||||
}
|
||||
|
||||
extern void *xran_ethdi_mbuf_alloc(void);
|
||||
|
||||
void fill_ecpri_header(struct xran_ecpri_hdr *ecpri_header,
|
||||
uint8_t ecpri_mesg_type,
|
||||
size_t ecpri_payload_size,
|
||||
uint8_t CC_ID,
|
||||
uint8_t Ant_ID,
|
||||
uint8_t seq_id,
|
||||
uint8_t oxu_port_id)
|
||||
{
|
||||
ecpri_header->cmnhdr.data.data_num_1 = 0x0;
|
||||
ecpri_header->cmnhdr.bits.ecpri_ver = XRAN_ECPRI_VER;
|
||||
ecpri_header->cmnhdr.bits.ecpri_mesg_type = ecpri_mesg_type;
|
||||
ecpri_header->cmnhdr.bits.ecpri_payl_size = rte_cpu_to_be_16(ecpri_payload_size);
|
||||
ecpri_header->ecpri_xtc_id = xran_compose_cid(0, 0, CC_ID, Ant_ID);
|
||||
ecpri_header->ecpri_seq_id.bits.seq_id = seq_id;
|
||||
ecpri_header->ecpri_seq_id.bits.e_bit = 1;
|
||||
ecpri_header->ecpri_seq_id.bits.sub_seq_id = 0;
|
||||
/// No byteswap for ecpri_seq_id. Possibly because of inverse definition in xran
|
||||
}
|
||||
|
||||
void fill_radio_app_header(struct radio_app_common_hdr *radio_app_header,
|
||||
int filter_id,
|
||||
int direction,
|
||||
int frame,
|
||||
int slot,
|
||||
int symbol,
|
||||
int mu)
|
||||
{
|
||||
radio_app_header->frame_id = frame & 0xff;
|
||||
radio_app_header->sf_slot_sym.slot_id = slot % (1 << mu);
|
||||
radio_app_header->sf_slot_sym.subframe_id = slot / (1 << mu);
|
||||
radio_app_header->sf_slot_sym.symb_id = symbol;
|
||||
radio_app_header->sf_slot_sym.value = rte_cpu_to_be_16(radio_app_header->sf_slot_sym.value);
|
||||
radio_app_header->data_feature.data_direction = direction;
|
||||
radio_app_header->data_feature.payl_ver = 1;
|
||||
radio_app_header->data_feature.filter_id = filter_id;
|
||||
}
|
||||
|
||||
void fill_data_section_header(struct data_section_hdr *data_section_hdr, int num_prb, int start_prb, int section_id)
|
||||
{
|
||||
data_section_hdr->fields.all_bits = 0;
|
||||
data_section_hdr->fields.num_prbu = (uint8_t)XRAN_CONVERT_NUMPRBC(num_prb);
|
||||
data_section_hdr->fields.start_prbu = (start_prb & 0x03ff);
|
||||
data_section_hdr->fields.sect_id = section_id;
|
||||
data_section_hdr->fields.all_bits = rte_cpu_to_be_32(data_section_hdr->fields.all_bits);
|
||||
}
|
||||
|
||||
void xran_oru_send_prach(uint32_t *prachF, int aarx, int frame, int slot, int symbol)
|
||||
{
|
||||
const struct xran_fh_config *fh_cfg = get_xran_fh_config(0);
|
||||
uint8_t mu = fh_cfg->frame_conf.nNumerology;
|
||||
|
||||
AssertFatal(fh_cfg->ru_conf.compMeth_PRACH == XRAN_COMPMETHOD_NONE, "Compression not supported\n");
|
||||
// TODO: With compression, have to add compression header to header_len
|
||||
size_t header_length = sizeof(struct xran_ecpri_hdr) + sizeof(struct radio_app_common_hdr) + sizeof(struct data_section_hdr);
|
||||
|
||||
// TODO: For compression, have to re-evaluate data size;
|
||||
// TODO: Only support short format PRACH
|
||||
const uint prach_length = 139;
|
||||
size_t data_len = sizeof(int32_t) * prach_length;
|
||||
|
||||
oran_prach_cplane_config_t *prach_config = &prach_config_per_antenna[aarx];
|
||||
if (prach_config->section_id == -1) {
|
||||
RATE_LIMIT(1000)
|
||||
LOG_W(HW, "PRACH was not yet configured by the O-DU\n");
|
||||
return;
|
||||
}
|
||||
if (prach_config->frame != (frame & 0xff) || prach_config->slot != slot) {
|
||||
RATE_LIMIT(1000)
|
||||
LOG_W(HW,
|
||||
"PRACH was not configured for frame.slot %d.%d, configuration is for frame.slot %d.%d\n",
|
||||
frame,
|
||||
slot,
|
||||
prach_config->frame,
|
||||
prach_config->slot);
|
||||
return;
|
||||
}
|
||||
|
||||
struct rte_mbuf *mbuf = xran_ethdi_mbuf_alloc();
|
||||
AssertFatal(mbuf != NULL, "out of mbufs\n");
|
||||
char *buf = rte_pktmbuf_append(mbuf, header_length + data_len);
|
||||
AssertFatal(buf, "incorrect mbuf size\n");
|
||||
|
||||
struct xran_ecpri_hdr *ecpri_header = (struct xran_ecpri_hdr *)rte_pktmbuf_mtod(mbuf, char *);
|
||||
uint16_t ecpri_payload_size = xran_get_ecpri_hdr_size() + sizeof(struct radio_app_common_hdr) + sizeof(struct data_section_hdr) + data_len;
|
||||
fill_ecpri_header(ecpri_header, ECPRI_IQ_DATA, ecpri_payload_size, 0, aarx + fh_cfg->prach_conf.eAxC_offset, prach_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, prach_config->filter_id, XRAN_DIR_UL, frame, slot, symbol, mu);
|
||||
|
||||
struct data_section_hdr *data_section_header = (struct data_section_hdr *)(radio_app_header + 1);
|
||||
fill_data_section_header(data_section_header, prach_config->num_prb, prach_config->start_prb, prach_config->section_id);
|
||||
|
||||
void *iq_data_start = (void *)(data_section_header + 1);
|
||||
int16_t *dest = (int16_t *)iq_data_start;
|
||||
uint16_t *src = (uint16_t *)prachF;
|
||||
for (int i = 0; i < prach_length * 2; i++) {
|
||||
dest[i + g_kbar] = (int16_t)htons(src[i]);
|
||||
}
|
||||
|
||||
buf = rte_pktmbuf_prepend(mbuf, sizeof(struct rte_ether_hdr));
|
||||
AssertFatal(buf != NULL, "incorrect mbuf size\n");
|
||||
|
||||
int vf_id = xran_map_ecpriPcid_to_vf(gxran_handle, XRAN_DIR_UL, 0, aarx + fh_cfg->prach_conf.eAxC_offset);
|
||||
int ret = xran_ethdi_mbuf_send(mbuf, ETHER_TYPE_ECPRI, vf_id);
|
||||
AssertFatal(ret == 1, "Error sending mbuf\n");
|
||||
}
|
||||
|
||||
void xran_oru_send_pusch(uint32_t *puschF, int aarx, int frame, int slot, int symbol)
|
||||
{
|
||||
const struct xran_fh_config *fh_cfg = get_xran_fh_config(0);
|
||||
const struct xran_frame_config *frame_conf = &fh_cfg->frame_conf;
|
||||
if (frame_conf->nFrameDuplexType == 1) {
|
||||
int slot_in_pattern = slot % frame_conf->nTddPeriod;
|
||||
AssertFatal(frame_conf->sSlotConfig[slot_in_pattern].nSymbolType[symbol] == 1, "Attempting to send PUSCH on non-UL slot\n");
|
||||
}
|
||||
|
||||
int section_id = pusch_config[aarx][slot][symbol].section_id;
|
||||
|
||||
if (section_id == -1) {
|
||||
RATE_LIMIT(1000)
|
||||
LOG_W(HW, "PUSCH was not yet configured by the O-DU frame %d, slot %d, symbol %d, aarx %d\n", frame, slot, symbol, aarx);
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t mu = fh_cfg->frame_conf.nNumerology;
|
||||
const int num_ul_rbs = fh_cfg->nULRBs;
|
||||
int num_prb = pusch_config[aarx][slot][symbol].num_prb;
|
||||
int start_prb = pusch_config[aarx][slot][symbol].start_prb;
|
||||
AssertFatal(num_prb == num_ul_rbs && start_prb == 0, "only support full bandwidth reception\n");
|
||||
|
||||
AssertFatal(fh_cfg->ru_conf.compMeth == XRAN_COMPMETHOD_NONE, "Compression not supported\n");
|
||||
// TODO: With compression, have to add compression header to header_len
|
||||
size_t header_length = sizeof(struct xran_ecpri_hdr) + sizeof(struct radio_app_common_hdr) + sizeof(struct data_section_hdr);
|
||||
|
||||
// TODO: For compression, have to re-evaluate data size;
|
||||
const uint num_sc = num_ul_rbs * NR_NB_SC_PER_RB;
|
||||
size_t data_len = sizeof(int32_t) * num_sc;
|
||||
|
||||
struct rte_mbuf *mbuf = xran_ethdi_mbuf_alloc();
|
||||
AssertFatal(mbuf != NULL, "out of mbufs\n");
|
||||
char *buf = rte_pktmbuf_append(mbuf, header_length + data_len);
|
||||
AssertFatal(buf, "incorrect mbuf size\n");
|
||||
|
||||
struct xran_ecpri_hdr *ecpri_header = (struct xran_ecpri_hdr *)rte_pktmbuf_mtod(mbuf, char *);
|
||||
uint16_t ecpri_payload_size = xran_get_ecpri_hdr_size() + sizeof(struct radio_app_common_hdr) + sizeof(struct data_section_hdr) + data_len;
|
||||
fill_ecpri_header(ecpri_header, ECPRI_IQ_DATA, ecpri_payload_size, 0, aarx, 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, symbol, mu);
|
||||
|
||||
struct data_section_hdr *data_section_header = (struct data_section_hdr *)(radio_app_header + 1);
|
||||
fill_data_section_header(data_section_header, fh_cfg->nULRBs, 0, section_id);
|
||||
|
||||
// TODO: O-DU expect compression header here even though the standard says it's not required
|
||||
struct data_section_compression_hdr *compression_header = (struct data_section_compression_hdr *)(data_section_header + 1);
|
||||
compression_header->ud_comp_hdr.ud_comp_meth = XRAN_COMPMETHOD_NONE;
|
||||
compression_header->ud_comp_hdr.ud_iq_width = XRAN_CONVERT_IQWIDTH(16);
|
||||
compression_header->rsrvd = 0;
|
||||
|
||||
int fftsize = 1 << fh_cfg->nULFftSize;
|
||||
int first_carrier_offset = fftsize - (fh_cfg->nULRBs * NR_NB_SC_PER_RB / 2);
|
||||
int num_sc_first_copy = (fftsize - first_carrier_offset);
|
||||
int num_sc_second_copy = fh_cfg->nULRBs * NR_NB_SC_PER_RB - num_sc_first_copy;
|
||||
void *iq_data_start = (void *)(compression_header + 1);
|
||||
int16_t* dest = (int16_t*)iq_data_start;
|
||||
uint16_t* src = (uint16_t*)&puschF[first_carrier_offset];
|
||||
for (int i = 0; i < num_sc_first_copy * 2; i++) {
|
||||
*dest++ = (int16_t)htons(src[i]);
|
||||
}
|
||||
src = (uint16_t*)puschF;
|
||||
for (int i = 0; i < num_sc_second_copy * 2; i++) {
|
||||
*dest++ = (int16_t)htons(src[i]);
|
||||
}
|
||||
|
||||
buf = rte_pktmbuf_prepend(mbuf, sizeof(struct rte_ether_hdr));
|
||||
AssertFatal(buf != NULL, "incorrect mbuf size\n");
|
||||
|
||||
int vf_id = xran_map_ecpriPcid_to_vf(gxran_handle, XRAN_DIR_UL, 0, aarx);
|
||||
int ret = xran_ethdi_mbuf_send(mbuf, ETHER_TYPE_ECPRI, vf_id);
|
||||
AssertFatal(ret == 1, "Error sending mbuf\n");
|
||||
}
|
||||
38
radio/fhi_72/oaioran_ru.h
Normal file
38
radio/fhi_72/oaioran_ru.h
Normal file
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The OpenAirInterface Software Alliance licenses this file to You under
|
||||
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.openairinterface.org/?page_id=698
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*-------------------------------------------------------------------------------
|
||||
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
#ifndef __OAIORAN_RU_H__
|
||||
#define __OAIORAN_RU_H__
|
||||
#include <stdint.h>
|
||||
#include "common/utils/threadPool/notified_fifo.h"
|
||||
|
||||
// Initialize o-ru packet processor
|
||||
// handle - xran handle
|
||||
// callbacks_per_slot - number of callbacks per slot. using any value other than 14
|
||||
// causes additional delay as the symbols will be delivered in batches
|
||||
void init_oru_packet_processor(void* handle, int callbacks_per_slot);
|
||||
|
||||
// Read samples DL IQ samples for frame slot symbol for all antennas
|
||||
int xran_oru_tx_read_slot(uint32_t **txdataF, int nb_tx, int *frame, int *slot, int *symbol, int *num_symbols, struct timespec *ts);
|
||||
void xran_oru_send_prach(uint32_t *prachF, int aarx, int frame, int slot, int symbol);
|
||||
void xran_oru_send_pusch(uint32_t *puschF, int aarx, int frame, int slot, int symbol);
|
||||
|
||||
#endif
|
||||
@@ -20,6 +20,7 @@
|
||||
*/
|
||||
|
||||
#include "oran-config.h"
|
||||
#include "common/config/config_userapi.h"
|
||||
#include "oran-params.h"
|
||||
#include "common/utils/assertions.h"
|
||||
#include "common_lib.h"
|
||||
@@ -890,7 +891,13 @@ static bool set_maxmin_pd(const paramdef_t *pd, int num, const char *name, uint1
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool set_fh_config(void *mplane_api, int ru_idx, int num_rus, enum xran_category xran_cat, const openair0_config_t *oai0, struct xran_fh_config *fh_config)
|
||||
static bool set_fh_config(void *mplane_api,
|
||||
int ru_idx,
|
||||
int num_rus,
|
||||
enum xran_category xran_cat,
|
||||
const openair0_config_t *oai0,
|
||||
struct xran_fh_config *fh_config,
|
||||
bool is_du)
|
||||
{
|
||||
AssertFatal(num_rus == 1 || num_rus == 2, "only support 1 or 2 RUs as of now\n");
|
||||
AssertFatal(ru_idx < num_rus, "illegal ru_idx %d: must be < %d\n", ru_idx, num_rus);
|
||||
@@ -950,15 +957,47 @@ static bool set_fh_config(void *mplane_api, int ru_idx, int num_rus, enum xran_c
|
||||
fh_config->ttiCb = NULL; // check tti_to_phy_cb(), tx_cp_dl_cb() and tx_cp_ul_cb => first_call
|
||||
fh_config->ttiCbParam = NULL; // check tti_to_phy_cb(), tx_cp_dl_cb() and tx_cp_ul_cb => first_call
|
||||
|
||||
/* DU delay profile */
|
||||
if (!set_maxmin_pd(fhp, nfh, ORAN_FH_CONFIG_T1A_CP_DL, &fh_config->T1a_min_cp_dl, &fh_config->T1a_max_cp_dl)) // E - min not used in xran, max yes; F - both min and max are used in xran
|
||||
return false;
|
||||
if (!set_maxmin_pd(fhp, nfh, ORAN_FH_CONFIG_T1A_CP_UL, &fh_config->T1a_min_cp_ul, &fh_config->T1a_max_cp_ul)) // both E and F - min not used in xran, max yes
|
||||
return false;
|
||||
if (!set_maxmin_pd(fhp, nfh, ORAN_FH_CONFIG_T1A_UP, &fh_config->T1a_min_up, &fh_config->T1a_max_up)) // both E and F - min not used in xran, max yes
|
||||
return false;
|
||||
if (!set_maxmin_pd(fhp, nfh, ORAN_FH_CONFIG_TA4, &fh_config->Ta4_min, &fh_config->Ta4_max)) // both E and F - min not used in xran, max yes
|
||||
return false;
|
||||
if (is_du) {
|
||||
/* DU delay profile */
|
||||
if (!set_maxmin_pd(fhp,
|
||||
nfh,
|
||||
ORAN_FH_CONFIG_T1A_CP_DL,
|
||||
&fh_config->T1a_min_cp_dl,
|
||||
&fh_config->T1a_max_cp_dl)) // E - min not used in xran, max yes; F - both min and max are used in xran
|
||||
return false;
|
||||
if (!set_maxmin_pd(fhp,
|
||||
nfh,
|
||||
ORAN_FH_CONFIG_T1A_CP_UL,
|
||||
&fh_config->T1a_min_cp_ul,
|
||||
&fh_config->T1a_max_cp_ul)) // both E and F - min not used in xran, max yes
|
||||
return false;
|
||||
if (!set_maxmin_pd(fhp,
|
||||
nfh,
|
||||
ORAN_FH_CONFIG_T1A_UP,
|
||||
&fh_config->T1a_min_up,
|
||||
&fh_config->T1a_max_up)) // both E and F - min not used in xran, max yes
|
||||
return false;
|
||||
if (!set_maxmin_pd(fhp,
|
||||
nfh,
|
||||
ORAN_FH_CONFIG_TA4,
|
||||
&fh_config->Ta4_min,
|
||||
&fh_config->Ta4_max)) // both E and F - min not used in xran, max yes
|
||||
return false;
|
||||
} else {
|
||||
/* RU delay profile */
|
||||
if (!set_maxmin_pd(fhp,
|
||||
nfh,
|
||||
ORAN_FH_CONFIG_TA3,
|
||||
&fh_config->Ta3_min,
|
||||
&fh_config->Ta3_max)) // both E and F - min not used in xran, max yes
|
||||
return false;
|
||||
if (!set_maxmin_pd(fhp,
|
||||
nfh,
|
||||
ORAN_FH_CONFIG_T2A,
|
||||
&fh_config->T2a_min_up,
|
||||
&fh_config->T2a_max_up)) // both E and F - min not used in xran, max yes
|
||||
return false;
|
||||
}
|
||||
|
||||
fh_config->enableCP = 1; // enable C-plane
|
||||
fh_config->prachEnable = 1; // enable PRACH
|
||||
@@ -1038,14 +1077,15 @@ bool get_xran_config(void *mplane_api, const struct openair0_config *openair0_cf
|
||||
ru_session_list_t *ru_session_list = (ru_session_list_t *)mplane_api;
|
||||
for (int32_t o_xu_id = 0; o_xu_id < fh_init->xran_ports; o_xu_id++) {
|
||||
xran_mplane_t *xran_mplane = &ru_session_list->ru_session[o_xu_id].xran_mplane;
|
||||
if (!set_fh_config(xran_mplane, o_xu_id, fh_init->xran_ports, xran_cat, openair0_cfg, &fh_config[o_xu_id])) {
|
||||
if (!set_fh_config(xran_mplane, o_xu_id, fh_init->xran_ports, xran_cat, openair0_cfg, &fh_config[o_xu_id], true)) {
|
||||
MP_LOG_I("could not read FHI 7.2/RU-specific config\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#else
|
||||
bool is_du = fh_init->io_cfg.id == 0;
|
||||
for (int32_t o_xu_id = 0; o_xu_id < fh_init->xran_ports; o_xu_id++) {
|
||||
if (!set_fh_config(NULL, o_xu_id, fh_init->xran_ports, xran_cat, openair0_cfg, &fh_config[o_xu_id])) {
|
||||
if (!set_fh_config(NULL, o_xu_id, fh_init->xran_ports, xran_cat, openair0_cfg, &fh_config[o_xu_id], is_du)) {
|
||||
printf("could not read FHI 7.2/RU-specific config\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -19,6 +19,9 @@
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <sched.h>
|
||||
#include "oaioran_ru.h"
|
||||
#include "xran_fh_o_du.h"
|
||||
#include "xran_pkt.h"
|
||||
#include "xran_pkt_up.h"
|
||||
@@ -398,12 +401,29 @@ int *oai_oran_initialize(struct xran_fh_init *xran_fh_init, struct xran_fh_confi
|
||||
int32_t xret = 0;
|
||||
|
||||
print_fh_init(xran_fh_init);
|
||||
cpu_set_t cpuset;
|
||||
CPU_ZERO(&cpuset);
|
||||
int ret = pthread_getaffinity_np(pthread_self(), sizeof(cpuset), &cpuset);
|
||||
AssertFatal(ret != -1, "sched_getaffinity() failed errno %d (%s)", errno, strerror(errno));
|
||||
|
||||
xret = xran_init(0, NULL, xran_fh_init, NULL, &gxran_handle);
|
||||
if (xret != XRAN_STATUS_SUCCESS) {
|
||||
printf("xran_init failed %d\n", xret);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
cpu_set_t cpuset_after;
|
||||
CPU_ZERO(&cpuset_after);
|
||||
ret = pthread_getaffinity_np(pthread_self(), sizeof(cpuset_after), &cpuset_after);
|
||||
AssertFatal(ret != -1, "sched_getaffinity() failed errno %d (%s)", errno, strerror(errno));
|
||||
if (!CPU_EQUAL(&cpuset_after, &cpuset))
|
||||
{
|
||||
LOG_W(HW, "XRAN modifed affinity. Correcting affinity of caller\n");
|
||||
ret = pthread_setaffinity_np(pthread_self(), sizeof(cpuset), &cpuset);
|
||||
AssertFatal(ret == 0, "Error in pthread_setaffinity_np(): ret: %d (%s)", ret, strerror(ret));
|
||||
}
|
||||
|
||||
bool is_du = xran_fh_init->io_cfg.id == 0;
|
||||
/** process all the O-RU|O-DU for use case */
|
||||
for (int32_t o_xu_id = 0; o_xu_id < xran_fh_init->xran_ports; o_xu_id++) {
|
||||
print_fh_config(&xran_fh_config[o_xu_id]);
|
||||
@@ -441,6 +461,12 @@ int *oai_oran_initialize(struct xran_fh_init *xran_fh_init, struct xran_fh_confi
|
||||
memcpy(&g_fh_init, xran_fh_init, sizeof(*xran_fh_init));
|
||||
memcpy(&g_fh_config, xran_fh_config, sizeof(*xran_fh_config) * xran_fh_init->xran_ports);
|
||||
|
||||
if (!is_du) {
|
||||
// Use half-slot parallelization
|
||||
const int callback_per_slot = 2;
|
||||
init_oru_packet_processor(gxran_handle, callback_per_slot);
|
||||
}
|
||||
|
||||
return (void *)gxran_handle;
|
||||
}
|
||||
|
||||
|
||||
@@ -112,6 +112,8 @@
|
||||
#define ORAN_FH_CONFIG_T1A_CP_UL "T1a_cp_ul"
|
||||
#define ORAN_FH_CONFIG_T1A_UP "T1a_up"
|
||||
#define ORAN_FH_CONFIG_TA4 "Ta4"
|
||||
#define ORAN_FH_CONFIG_TA3 "Ta3_up"
|
||||
#define ORAN_FH_CONFIG_T2A "T2a_up"
|
||||
|
||||
#define ORAN_FH_HLP_CPLT " parameter of RU in list form (Min&Max, length 2!)\n"
|
||||
|
||||
@@ -119,10 +121,12 @@
|
||||
#define ORAN_FH_DESC { \
|
||||
{ORAN_CONFIG_RunSlotPrbMapBySymbol, "RunSlotPrbMapBySymbol\n", PARAMFLAG_BOOL, .uptr=NULL, .defuintval=0, TYPE_UINT, 0}, \
|
||||
{ORAN_CONFIG_LiteOnIgnoreUPSectionId, "Liteon Ignore Section Id\n", PARAMFLAG_BOOL, .uptr=NULL, .defuintval=0, TYPE_UINT, 0}, \
|
||||
{ORAN_FH_CONFIG_T1A_CP_DL, "T1a_cp_dl" ORAN_FH_HLP_CPLT, PARAMFLAG_MANDATORY, .uptr=NULL, .defintarrayval=0, TYPE_UINTARRAY, 0}, \
|
||||
{ORAN_FH_CONFIG_T1A_CP_UL, "T1a_cp_ul" ORAN_FH_HLP_CPLT, PARAMFLAG_MANDATORY, .uptr=NULL, .defintarrayval=0, TYPE_UINTARRAY, 0}, \
|
||||
{ORAN_FH_CONFIG_T1A_UP, "T1a_up" ORAN_FH_HLP_CPLT, PARAMFLAG_MANDATORY, .uptr=NULL, .defintarrayval=0, TYPE_UINTARRAY, 0}, \
|
||||
{ORAN_FH_CONFIG_TA4, "Ta4" ORAN_FH_HLP_CPLT, PARAMFLAG_MANDATORY, .uptr=NULL, .defintarrayval=0, TYPE_UINTARRAY, 0}, \
|
||||
{ORAN_FH_CONFIG_T1A_CP_DL, "T1a_cp_dl" ORAN_FH_HLP_CPLT, 0, .uptr=NULL, .defintarrayval=0, TYPE_UINTARRAY, 0}, \
|
||||
{ORAN_FH_CONFIG_T1A_CP_UL, "T1a_cp_ul" ORAN_FH_HLP_CPLT, 0, .uptr=NULL, .defintarrayval=0, TYPE_UINTARRAY, 0}, \
|
||||
{ORAN_FH_CONFIG_T1A_UP, "T1a_up" ORAN_FH_HLP_CPLT, 0, .uptr=NULL, .defintarrayval=0, TYPE_UINTARRAY, 0}, \
|
||||
{ORAN_FH_CONFIG_TA4, "Ta4" ORAN_FH_HLP_CPLT, 0, .uptr=NULL, .defintarrayval=0, TYPE_UINTARRAY, 0}, \
|
||||
{ORAN_FH_CONFIG_TA3, "Ta3" ORAN_FH_HLP_CPLT, 0, .uptr=NULL, .defintarrayval=0, TYPE_UINTARRAY, 0}, \
|
||||
{ORAN_FH_CONFIG_T2A, "T2a" ORAN_FH_HLP_CPLT, 0, .uptr=NULL, .defintarrayval=0, TYPE_UINTARRAY, 0}, \
|
||||
}
|
||||
// clang-format on
|
||||
|
||||
|
||||
53
radio/fhi_72/oran_debug.c
Normal file
53
radio/fhi_72/oran_debug.c
Normal file
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The OpenAirInterface Software Alliance licenses this file to You under
|
||||
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.openairinterface.org/?page_id=698
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*-------------------------------------------------------------------------------
|
||||
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
#include "oran_debug.h"
|
||||
#include "openair1/PHY/TOOLS/tools_defs.h"
|
||||
|
||||
void dump_nonzero_symbol(c16_t *txdataF, uint32_t ofdm_symbol_size, int frame, int slot, int symbol, const char* loc)
|
||||
{
|
||||
float signal_energy = signal_energy_nodc(txdataF, ofdm_symbol_size);
|
||||
if (signal_energy > 1) {
|
||||
// Prepare a buffer to hold the formatted string for the symbol
|
||||
const int num_chars_per_sample = 4 + 6 * 2;
|
||||
char symbol_buf[ofdm_symbol_size * num_chars_per_sample]; // Enough for "(r,i) " per sample
|
||||
int offset = 0;
|
||||
bool is_zero_block = true;
|
||||
for (int i = 0; i < ofdm_symbol_size; i++) {
|
||||
bool is_zero = txdataF[i].r == 0 && txdataF[i].i == 0;
|
||||
if (is_zero_block && !is_zero) {
|
||||
offset += snprintf(symbol_buf + offset, sizeof(symbol_buf) - offset, "[sc %d]: ", i);
|
||||
is_zero_block = false;
|
||||
}
|
||||
if (!is_zero_block && is_zero) {
|
||||
is_zero_block = true;
|
||||
}
|
||||
if (!is_zero) {
|
||||
offset += snprintf(symbol_buf + offset, sizeof(symbol_buf) - offset, "(%d,%d) ", txdataF[i].r, txdataF[i].i);
|
||||
}
|
||||
}
|
||||
symbol_buf[offset] = '\0';
|
||||
struct timespec ts;
|
||||
clock_gettime(CLOCK_REALTIME, &ts);
|
||||
|
||||
LOG_D(HW, "dump_nonzero_symbol: Frame.Slot.Symbol %d.%d.%d (%s) signal_energy %.3f time %ld.%09ld samples: %s\n", frame, slot, symbol, loc, 10 * log10(signal_energy), ts.tv_sec, ts.tv_nsec, symbol_buf);
|
||||
}
|
||||
}
|
||||
@@ -33,6 +33,7 @@
|
||||
#include "openair1/PHY/NR_TRANSPORT/nr_transport_proto.h"
|
||||
#include "oaioran.h"
|
||||
#include "oran-config.h"
|
||||
#include "oaioran_ru.h"
|
||||
|
||||
// include the following file for VERSIONX, version of xran lib, to print it during
|
||||
// startup. Only relevant for printing, if it ever makes problem, remove this
|
||||
@@ -211,6 +212,11 @@ int trx_oran_ctlrecv(openair0_device_t *device, void *msg, ssize_t msg_len)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void oran_fh_if4p5_north_in(uint32_t **txdataF, int nb_tx, sense_of_time_t* sense_of_time, int *num_symbols) {
|
||||
int ret = xran_oru_tx_read_slot(txdataF, nb_tx, &sense_of_time->frame, &sense_of_time->slot, &sense_of_time->symbol, num_symbols, &sense_of_time->ts);
|
||||
AssertFatal(ret == 0, "ORAN: Error reading slot");
|
||||
}
|
||||
|
||||
void oran_fh_if4p5_south_in(RU_t *ru, int *frame, int *slot)
|
||||
{
|
||||
prach_item_t *prach_id = find_nr_prach(&ru->gNB_list[0]->prach_list, *frame, *slot, SEARCH_EXIST);
|
||||
@@ -401,6 +407,9 @@ __attribute__((__visibility__("default"))) int transport_init(openair0_device_t
|
||||
device->get_internal_parameter = get_internal_parameter;
|
||||
device->priv = eth;
|
||||
device->openair0_cfg = &openair0_cfg[0];
|
||||
device->xran_api.north_in_func = oran_fh_if4p5_north_in;
|
||||
device->xran_api.write_prach = xran_oru_send_prach;
|
||||
device->xran_api.write_pusch = xran_oru_send_pusch;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1094,6 +1094,14 @@ static int vrtsim_set_beams2(openair0_device_t *device, int *beam_ids, int num_b
|
||||
return 0;
|
||||
}
|
||||
|
||||
openair0_timestamp_t vrtsim_get_timestamp(openair0_device_t *device, struct timespec *ts)
|
||||
{
|
||||
vrtsim_state_t *vrtsim_state = (vrtsim_state_t *)device->priv;
|
||||
uint64_t diff = (ts->tv_sec - vrtsim_state->start_ts.tv_sec) * 1000000000 + (ts->tv_nsec - vrtsim_state->start_ts.tv_nsec);
|
||||
double diff_samples = vrtsim_state->sample_rate * vrtsim_state->timescale * diff / 1e9;
|
||||
return diff_samples > 0 ? diff_samples : 0;
|
||||
}
|
||||
|
||||
__attribute__((__visibility__("default"))) int device_init(openair0_device_t *device, openair0_config_t *openair0_cfg)
|
||||
{
|
||||
randominit();
|
||||
@@ -1113,6 +1121,9 @@ __attribute__((__visibility__("default"))) int device_init(openair0_device_t *de
|
||||
device->trx_write_beams_func = vrtsim_write_beams;
|
||||
device->trx_set_beams = vrtsim_set_beams;
|
||||
device->trx_set_beams2 = vrtsim_set_beams2;
|
||||
if (vrtsim_state->role == ROLE_SERVER) {
|
||||
device->get_timestamp = vrtsim_get_timestamp;
|
||||
}
|
||||
|
||||
device->type = RFSIMULATOR;
|
||||
device->openair0_cfg = &openair0_cfg[0];
|
||||
|
||||
@@ -0,0 +1,271 @@
|
||||
Active_gNBs = ( "gNB-OAI");
|
||||
# Asn1_verbosity, choice in: none, info, annoying
|
||||
Asn1_verbosity = "none";
|
||||
|
||||
gNBs =
|
||||
(
|
||||
{
|
||||
////////// Identification parameters:
|
||||
gNB_ID = 0xe00;
|
||||
gNB_name = "gNB-OAI";
|
||||
|
||||
// Tracking area code, 0x0000 and 0xfffe are reserved values
|
||||
tracking_area_code = 1;
|
||||
plmn_list = ({ mcc = 001; mnc = 01; mnc_length = 2; snssaiList = ({ sst = 1; }) });
|
||||
|
||||
nr_cellid = 12345678L;
|
||||
|
||||
////////// Physical parameters:
|
||||
|
||||
pdsch_AntennaPorts_XP = 2;
|
||||
pdsch_AntennaPorts_N1 = 1;
|
||||
maxMIMO_layers = 1;
|
||||
pusch_AntennaPorts = 2;
|
||||
do_CSIRS = 0;
|
||||
do_SRS = 0;
|
||||
sib1_tda = 15;
|
||||
|
||||
servingCellConfigCommon = (
|
||||
{
|
||||
#spCellConfigCommon
|
||||
|
||||
physCellId = 0;
|
||||
# n_TimingAdvanceOffset = 0;
|
||||
# downlinkConfigCommon
|
||||
#frequencyInfoDL
|
||||
# center frequency = 4049.76 MHz
|
||||
# selected SSB frequency = 4049.76 MHz
|
||||
absoluteFrequencySSB = 669984;
|
||||
dl_frequencyBand = 77;
|
||||
# frequency point A = 4030.68 MHz
|
||||
dl_absoluteFrequencyPointA = 668712;
|
||||
#scs-SpecificCarrierList
|
||||
dl_offstToCarrier = 0;
|
||||
# subcarrierSpacing
|
||||
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
|
||||
dl_subcarrierSpacing = 1;
|
||||
dl_carrierBandwidth = 106;
|
||||
#initialDownlinkBWP
|
||||
#genericParameters
|
||||
initialDLBWPlocationAndBandwidth = 28875; #38.101-1 Table 5.3.2-1
|
||||
#
|
||||
# subcarrierSpacing
|
||||
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
|
||||
initialDLBWPsubcarrierSpacing = 1;
|
||||
#pdcch-ConfigCommon
|
||||
initialDLBWPcontrolResourceSetZero = 11;
|
||||
initialDLBWPsearchSpaceZero = 0;
|
||||
|
||||
#uplinkConfigCommon
|
||||
#frequencyInfoUL
|
||||
ul_frequencyBand = 77;
|
||||
#scs-SpecificCarrierList
|
||||
ul_offstToCarrier = 0;
|
||||
# subcarrierSpacing
|
||||
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
|
||||
ul_subcarrierSpacing = 1;
|
||||
ul_carrierBandwidth = 106;
|
||||
pMax = 23;
|
||||
#initialUplinkBWP
|
||||
#genericParameters
|
||||
initialULBWPlocationAndBandwidth = 28875;
|
||||
# subcarrierSpacing
|
||||
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
|
||||
initialULBWPsubcarrierSpacing = 1;
|
||||
#rach-ConfigCommon
|
||||
#rach-ConfigGeneric
|
||||
prach_ConfigurationIndex = 157;
|
||||
#prach_msg1_FDM
|
||||
#0 = one, 1=two, 2=four, 3=eight
|
||||
prach_msg1_FDM = 0;
|
||||
prach_msg1_FrequencyStart = 0;
|
||||
zeroCorrelationZoneConfig = 0;
|
||||
preambleReceivedTargetPower = -100;
|
||||
#preamblTransMax (0...10) = (3,4,5,6,7,8,10,20,50,100,200)
|
||||
preambleTransMax = 7;
|
||||
#powerRampingStep
|
||||
# 0=dB0,1=dB2,2=dB4,3=dB6
|
||||
powerRampingStep = 2;
|
||||
#ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR
|
||||
#1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen
|
||||
ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4;
|
||||
#one (0..15) 4,8,12,16,...60,64
|
||||
ssb_perRACH_OccasionAndCB_PreamblesPerSSB = 15;
|
||||
#ra_ContentionResolutionTimer
|
||||
#(0..7) 8,16,24,32,40,48,56,64
|
||||
ra_ContentionResolutionTimer = 7;
|
||||
rsrp_ThresholdSSB = 19;
|
||||
#prach-RootSequenceIndex_PR
|
||||
#1 = 839, 2 = 139
|
||||
prach_RootSequenceIndex_PR = 2;
|
||||
prach_RootSequenceIndex = 1;
|
||||
# SCS for msg1, can only be 15 for 30 kHz < 6 GHz, takes precendence over the one derived from prach-ConfigIndex
|
||||
#
|
||||
msg1_SubcarrierSpacing = 1,
|
||||
# restrictedSetConfig
|
||||
# 0=unrestricted, 1=restricted type A, 2=restricted type B
|
||||
restrictedSetConfig = 0,
|
||||
|
||||
# this is the offset between the last PRACH preamble power and the Msg3 PUSCH, 2 times the field value in dB
|
||||
msg3_DeltaPreamble = 2;
|
||||
p0_NominalWithGrant = -100;
|
||||
|
||||
# pucch-ConfigCommon setup :
|
||||
# pucchGroupHopping
|
||||
# 0 = neither, 1= group hopping, 2=sequence hopping
|
||||
pucchGroupHopping = 0;
|
||||
hoppingId = 0;
|
||||
p0_nominal = -96;
|
||||
|
||||
ssb_PositionsInBurst_Bitmap = 0x1;
|
||||
|
||||
# ssb_periodicityServingCell
|
||||
# 0 = ms5, 1=ms10, 2=ms20, 3=ms40, 4=ms80, 5=ms160, 6=spare2, 7=spare1
|
||||
ssb_periodicityServingCell = 2;
|
||||
|
||||
# dmrs_TypeA_position
|
||||
# 0 = pos2, 1 = pos3
|
||||
dmrs_TypeA_Position = 0;
|
||||
|
||||
# subcarrierSpacing
|
||||
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
|
||||
subcarrierSpacing = 1;
|
||||
|
||||
|
||||
#tdd-UL-DL-ConfigurationCommon
|
||||
# subcarrierSpacing
|
||||
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
|
||||
referenceSubcarrierSpacing = 1;
|
||||
# pattern1
|
||||
# dl_UL_TransmissionPeriodicity
|
||||
# 0=ms0p5, 1=ms0p625, 2=ms1, 3=ms1p25, 4=ms2, 5=ms2p5, 6=ms5, 7=ms10
|
||||
dl_UL_TransmissionPeriodicity = 5;
|
||||
nrofDownlinkSlots = 3;
|
||||
nrofDownlinkSymbols = 6;
|
||||
nrofUplinkSlots = 1;
|
||||
nrofUplinkSymbols = 4;
|
||||
|
||||
ssPBCH_BlockPower = 0;
|
||||
}
|
||||
|
||||
);
|
||||
|
||||
|
||||
# ------- SCTP definitions
|
||||
SCTP :
|
||||
{
|
||||
# Number of streams to use in input/output
|
||||
SCTP_INSTREAMS = 2;
|
||||
SCTP_OUTSTREAMS = 2;
|
||||
};
|
||||
|
||||
////////// AMF parameters:
|
||||
amf_ip_address = ({ ipv4 = "192.168.70.132"; });
|
||||
|
||||
|
||||
NETWORK_INTERFACES :
|
||||
{
|
||||
GNB_IPV4_ADDRESS_FOR_NG_AMF = "192.168.70.129/24";
|
||||
GNB_IPV4_ADDRESS_FOR_NGU = "192.168.70.129/24";
|
||||
GNB_PORT_FOR_S1U = 2152; # Spec 2152
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
MACRLCs = (
|
||||
{
|
||||
num_cc = 1;
|
||||
tr_s_preference = "local_L1";
|
||||
tr_n_preference = "local_RRC";
|
||||
pusch_TargetSNRx10 = 200;
|
||||
pucch_TargetSNRx10 = 200;
|
||||
# dl_bler_target_upper = .35;
|
||||
# dl_bler_target_lower = .15;
|
||||
ul_bler_target_upper = .35;
|
||||
ul_bler_target_lower = .15;
|
||||
pusch_FailureThres = 100;
|
||||
}
|
||||
);
|
||||
|
||||
L1s = (
|
||||
{
|
||||
num_cc = 1;
|
||||
tr_n_preference = "local_mac";
|
||||
prach_dtx_threshold = 110;
|
||||
pucch0_dtx_threshold = 80;
|
||||
pusch_dtx_threshold = -100;
|
||||
# thread_pool_size = 8;
|
||||
tx_amp_backoff_dB = 36;
|
||||
L1_rx_thread_core = 11;
|
||||
L1_tx_thread_core = 12;
|
||||
phase_compensation = 0; # needs to match O-RU configuration
|
||||
}
|
||||
);
|
||||
|
||||
RUs = (
|
||||
{
|
||||
local_rf = "no";
|
||||
nb_tx = 2;
|
||||
nb_rx = 2;
|
||||
att_tx = 0;
|
||||
att_rx = 0;
|
||||
bands = [77];
|
||||
max_pdschReferenceSignalPower = -27;
|
||||
max_rxgain = 75;
|
||||
sf_extension = 0;
|
||||
eNB_instances = [0];
|
||||
ru_thread_core = 10;
|
||||
sl_ahead = 5;
|
||||
tr_preference = "raw_if4p5"; # important: activate FHI7.2
|
||||
do_precoding = 0; # needs to match O-RU configuration
|
||||
}
|
||||
);
|
||||
|
||||
security = {
|
||||
# preferred ciphering algorithms
|
||||
# the first one of the list that an UE supports in chosen
|
||||
# valid values: nea0, nea1, nea2, nea3
|
||||
ciphering_algorithms = ( "nea0" );
|
||||
|
||||
# preferred integrity algorithms
|
||||
# the first one of the list that an UE supports in chosen
|
||||
# valid values: nia0, nia1, nia2, nia3
|
||||
integrity_algorithms = ( "nia2", "nia0" );
|
||||
|
||||
# setting 'drb_ciphering' to "no" disables ciphering for DRBs, no matter
|
||||
# what 'ciphering_algorithms' configures; same thing for 'drb_integrity'
|
||||
drb_ciphering = "yes";
|
||||
drb_integrity = "no";
|
||||
};
|
||||
|
||||
log_config :
|
||||
{
|
||||
global_log_level = "info";
|
||||
hw_log_level = "info";
|
||||
phy_log_level = "info";
|
||||
mac_log_level = "info";
|
||||
rlc_log_level = "info";
|
||||
pdcp_log_level = "info";
|
||||
rrc_log_level = "info";
|
||||
ngap_log_level = "info";
|
||||
f1ap_log_level = "info";
|
||||
};
|
||||
|
||||
fhi_72 = {
|
||||
dpdk_devices = ("0000:05:02.2", "0000:05:02.3"); # one VF can be used as well
|
||||
system_core = 7;
|
||||
io_core = 8;
|
||||
worker_cores = (9);
|
||||
ru_addr = ("00:11:22:33:64:66", "00:11:22:33:64:67");
|
||||
mtu = 9600;
|
||||
fh_config = ({
|
||||
T1a_cp_dl = (285, 470);
|
||||
T1a_cp_ul = (285, 429);
|
||||
T1a_up = (300, 450);
|
||||
Ta4 = (400, 440);
|
||||
ru_config = {
|
||||
iq_width = 16;
|
||||
iq_width_prach = 16;
|
||||
};
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,70 @@
|
||||
# Asn1_verbosity, choice in: none, info, annoying
|
||||
Asn1_verbosity = "none";
|
||||
|
||||
ORUs = (
|
||||
{
|
||||
tx_bw = [106];
|
||||
rx_bw = [106];
|
||||
carrier_tx = [4049760];
|
||||
carrier_rx = [4049760];
|
||||
prach_config_index = 157;
|
||||
prach_msg1_start = 0;
|
||||
tdd_period = 5;
|
||||
num_dl_slots = 3;
|
||||
num_dl_symbols = 6;
|
||||
num_ul_slots = 1;
|
||||
num_ul_symbols = 4;
|
||||
numerology = 1;
|
||||
tp_cores = [-1, -1, -1, -1, -1, -1]
|
||||
});
|
||||
|
||||
RUs = (
|
||||
{
|
||||
local_rf = "no";
|
||||
nb_tx = 2;
|
||||
|
||||
nb_rx = 2;
|
||||
att_tx = 0;
|
||||
att_rx = 0;
|
||||
bands = [77];
|
||||
max_pdschReferenceSignalPower = -27;
|
||||
max_rxgain = 75;
|
||||
sf_extension = 0;
|
||||
eNB_instances = [0];
|
||||
sl_ahead = 5;
|
||||
tr_preference = "raw_if4p5"; # important: activate FHI7.2
|
||||
do_precoding = 0; # needs to match O-RU configuration
|
||||
});
|
||||
|
||||
|
||||
log_config :
|
||||
{
|
||||
global_log_level = "info";
|
||||
hw_log_level = "info";
|
||||
phy_log_level = "info";
|
||||
mac_log_level = "info";
|
||||
rlc_log_level = "info";
|
||||
pdcp_log_level = "info";
|
||||
rrc_log_level = "info";
|
||||
ngap_log_level = "info";
|
||||
f1ap_log_level = "info";
|
||||
};
|
||||
|
||||
fhi_72 = {
|
||||
dpdk_devices = ("0000:05:02.0", "0000:05:02.1"); # one VF can be used as well
|
||||
system_core = 25;
|
||||
io_core = 26;
|
||||
worker_cores = (27);
|
||||
du_addr = ("00:11:22:33:64:68", "00:11:22:33:64:69");
|
||||
mtu = 9600;
|
||||
file_prefix = "ru";
|
||||
app_id = "RU";
|
||||
fh_config = ({
|
||||
Ta3_up = (200, 470);
|
||||
T2a_up = (350, 1200);
|
||||
ru_config = {
|
||||
iq_width = 16;
|
||||
iq_width_prach = 16;
|
||||
};
|
||||
});
|
||||
};
|
||||
Reference in New Issue
Block a user