mirror of
https://gitlab.eurecom.fr/oai/openairinterface5g.git
synced 2026-07-17 14:40:31 +00:00
Compare commits
141 Commits
power-refe
...
bugfix-sda
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1b85b63ff0 | ||
|
|
23d22d6c95 | ||
|
|
4da30019be | ||
|
|
8f93424e53 | ||
|
|
d623cbed7d | ||
|
|
f5b0d9603b | ||
|
|
884e60da69 | ||
|
|
3d5177e5f7 | ||
|
|
94e82200e3 | ||
|
|
84b9272979 | ||
|
|
a3ef5293fb | ||
|
|
ba2a0c4d1e | ||
|
|
c0d9212afc | ||
|
|
b89b3abd13 | ||
|
|
4834d93006 | ||
|
|
2f7eb6ebf9 | ||
|
|
b487c4deb2 | ||
|
|
c9ad10f9f9 | ||
|
|
59be08e3e6 | ||
|
|
7cbedb1575 | ||
|
|
9bccad31b5 | ||
|
|
32d1026b16 | ||
|
|
18372ae27e | ||
|
|
6e67c1ac20 | ||
|
|
315ed8e564 | ||
|
|
ba2d1a880d | ||
|
|
570c1b5639 | ||
|
|
b99fcdf289 | ||
|
|
1aa6aab120 | ||
|
|
5f8aeaacc9 | ||
|
|
1ab8a58a2f | ||
|
|
5ac3f59d61 | ||
|
|
a19c786600 | ||
|
|
3fe601fa6b | ||
|
|
73b89726ad | ||
|
|
c6271a23e4 | ||
|
|
51661bd83c | ||
|
|
5c4595e699 | ||
|
|
bbcb31f64b | ||
|
|
1666dced3e | ||
|
|
516a618816 | ||
|
|
6e371b9e48 | ||
|
|
61778f3d55 | ||
|
|
2c164336bc | ||
|
|
9e787a0ba2 | ||
|
|
a48e64f6f8 | ||
|
|
7ee6feac42 | ||
|
|
e6da64b1a3 | ||
|
|
bf6dff025b | ||
|
|
65e9ad7fdf | ||
|
|
33ad0f917e | ||
|
|
54990c2bc1 | ||
|
|
1893974d1d | ||
|
|
7c0dc93087 | ||
|
|
2e7fa8e8b1 | ||
|
|
1cdd684e24 | ||
|
|
ac3f9f3e32 | ||
|
|
c1f225abc1 | ||
|
|
2ee056bf45 | ||
|
|
34fc1bb254 | ||
|
|
7731f5bd2d | ||
|
|
49b3e2ee69 | ||
|
|
f3eb713084 | ||
|
|
b790fb235d | ||
|
|
e085fb5fee | ||
|
|
98d4dff509 | ||
|
|
5c5dbdf2d3 | ||
|
|
07f8158378 | ||
|
|
42a4292149 | ||
|
|
b3a1e3d2e8 | ||
|
|
7c4eabdb6e | ||
|
|
75b237fb90 | ||
|
|
890a6c702e | ||
|
|
9185c29e33 | ||
|
|
f3724ec451 | ||
|
|
e73f1f6220 | ||
|
|
463942d90e | ||
|
|
7edf52ca5b | ||
|
|
a9e9dfbd06 | ||
|
|
3b22c4a566 | ||
|
|
2228c3966f | ||
|
|
08da0bd2cc | ||
|
|
e4cb8be023 | ||
|
|
97ca739be2 | ||
|
|
5e8f649963 | ||
|
|
c633fa5855 | ||
|
|
6af70bd4b9 | ||
|
|
04213f2981 | ||
|
|
535d8e7765 | ||
|
|
556396e56e | ||
|
|
135b522cf4 | ||
|
|
cb175569eb | ||
|
|
ec65c7cbaa | ||
|
|
e7b46342d5 | ||
|
|
26dcb876f5 | ||
|
|
bc5f2ec99e | ||
|
|
d334a75c8a | ||
|
|
4adadedeb9 | ||
|
|
4b23c7ea65 | ||
|
|
49d302960c | ||
|
|
2ab747eaa6 | ||
|
|
4296bfe34f | ||
|
|
b381d7ffae | ||
|
|
b9f5746df4 | ||
|
|
9e4aefda6b | ||
|
|
8d294d71b8 | ||
|
|
67482f5d85 | ||
|
|
6e06c817f4 | ||
|
|
997790f656 | ||
|
|
a9132a2f79 | ||
|
|
4e3a7ad56e | ||
|
|
29ed144764 | ||
|
|
d6585f3750 | ||
|
|
18469302d8 | ||
|
|
84712f5f92 | ||
|
|
aac4642910 | ||
|
|
616568a79d | ||
|
|
312f296b60 | ||
|
|
2b9782caa1 | ||
|
|
5af4b89203 | ||
|
|
d16507055f | ||
|
|
dd827c7bd8 | ||
|
|
9e4df97d84 | ||
|
|
f1811b5934 | ||
|
|
afd49e703c | ||
|
|
2d35fc90ac | ||
|
|
b421d6eaa9 | ||
|
|
25bc1bd89a | ||
|
|
ab3bb36357 | ||
|
|
699afafc6f | ||
|
|
96b0cae63e | ||
|
|
b9a6d93bfa | ||
|
|
05d393a399 | ||
|
|
683670ed91 | ||
|
|
52f0bbc165 | ||
|
|
8e253e3435 | ||
|
|
bc27d1e691 | ||
|
|
0f9220b5ef | ||
|
|
6504c038b2 | ||
|
|
f24a576d81 | ||
|
|
a59cfae18c |
@@ -823,6 +823,7 @@ set(PHY_SRC_COMMON
|
||||
${OPENAIR1_DIR}/PHY/TOOLS/sqrt.c
|
||||
${OPENAIR1_DIR}/PHY/TOOLS/lut.c
|
||||
${OPENAIR1_DIR}/PHY/TOOLS/simde_operations.c
|
||||
${OPENAIR1_DIR}/PHY/TOOLS/get_sin_cos.c
|
||||
)
|
||||
|
||||
set(PHY_SRC
|
||||
@@ -1834,6 +1835,7 @@ target_link_libraries(nr-softmodem PRIVATE
|
||||
ITTI ${NAS_UE_LIB} lte_rrc nr_rrc
|
||||
ngap s1ap L2_LTE_NR L2_NR MAC_NR_COMMON NFAPI_LIB NFAPI_VNF_LIB NFAPI_PNF_LIB NFAPI_USER_LIB SIMU
|
||||
x2ap f1ap m2ap m3ap e1ap shlib_loader
|
||||
time_management
|
||||
-Wl,--end-group z dl)
|
||||
|
||||
target_link_libraries(nr-softmodem PRIVATE pthread m CONFIG_LIB rt sctp)
|
||||
@@ -1866,6 +1868,7 @@ add_executable(nr-cuup
|
||||
target_link_libraries(nr-cuup PRIVATE
|
||||
CONFIG_LIB ITTI SCTP_CLIENT
|
||||
GTPV1U e1ap f1ap
|
||||
time_management
|
||||
z sctp dl pthread shlib_loader ${T_LIB})
|
||||
target_link_libraries(nr-cuup PRIVATE asn1_lte_rrc_hdrs asn1_nr_rrc_hdrs)
|
||||
if(E2_AGENT)
|
||||
@@ -1897,6 +1900,7 @@ target_link_libraries(nr-uesoftmodem PRIVATE
|
||||
nr_rrc SECURITY UTIL HASHTABLE SCHED_RU_LIB SCHED_NR_UE_LIB
|
||||
PHY_COMMON PHY_NR_COMMON PHY_NR_UE NR_L2_UE MAC_NR_COMMON NFAPI_LIB
|
||||
ITTI SIMU shlib_loader
|
||||
time_management
|
||||
-Wl,--end-group z dl)
|
||||
|
||||
target_link_libraries(nr-uesoftmodem PRIVATE pthread m CONFIG_LIB rt nr_ue_phy_meas)
|
||||
|
||||
@@ -77,8 +77,8 @@ oc-cn5g-20897:
|
||||
Undeploy: "! scripts/oc-cn5g-undeploy.sh /opt/oai-cn5g-fed-develop-2025-jan oaicicd-core-for-fhi72"
|
||||
LogCollect: "! scripts/oc-cn5g-logcollect.sh /opt/oai-cn5g-fed-develop-2025-jan oaicicd-core-for-fhi72 %%log_dir%%"
|
||||
|
||||
oc-cn5g-20897-aerial2:
|
||||
Host: aerial2
|
||||
oc-cn5g-20897-aerial:
|
||||
Host: gracehopper1-oai
|
||||
NetworkScript: echo "inet 172.21.6.105"
|
||||
RunIperf3Server: False
|
||||
Deploy: "! scripts/oc-cn5g-deploy.sh /opt/oai-cn5g-fed-develop-2025-jan oaicicd-core-for-nvidia-aerial"
|
||||
|
||||
@@ -49,7 +49,7 @@ class CoreNetwork:
|
||||
self._host = c.get('Host').strip()
|
||||
if self._host == "%%current_host%%":
|
||||
if node is None:
|
||||
raise Exception(f"core network {self} requires node, but none provided (cannot replace %%current_host%%)")
|
||||
raise Exception(f"core network {cn_name} requires node, but none provided (cannot replace %%current_host%%)")
|
||||
self._host = node
|
||||
if d is not None:
|
||||
raise Exception("directory handling not implemented")
|
||||
@@ -66,7 +66,7 @@ class CoreNetwork:
|
||||
logging.info(f'initialized core {self} from {filename}')
|
||||
|
||||
def __str__(self):
|
||||
return f"{self._cn_name}@{self._host} [IP: {self.getIP()}]"
|
||||
return f"{self._cn_name}@{self._host}"
|
||||
|
||||
def __repr__(self):
|
||||
return self.__str__()
|
||||
@@ -162,6 +162,9 @@ class CoreNetwork:
|
||||
def getCmdPrefix(self):
|
||||
return self._cmd_prefix or ""
|
||||
|
||||
def getName(self):
|
||||
return self._cn_name
|
||||
|
||||
def getHost(self):
|
||||
return self._host
|
||||
|
||||
|
||||
@@ -464,7 +464,7 @@ class OaiCiTest():
|
||||
return (False, f"UE {ue.getName()} has no IP address")
|
||||
svrIP = cn.getIP()
|
||||
if not svrIP:
|
||||
return (False, f"Iperf server {ue.getName()} has no IP address")
|
||||
return (False, f"Iperf server {cn.getName()} has no IP address")
|
||||
|
||||
iperf_opt = self.iperf_args
|
||||
jsonReport = "--json"
|
||||
@@ -862,7 +862,7 @@ class OaiCiTest():
|
||||
success, output = cn.deploy()
|
||||
logging.info(f"deployment core network {core_name} success {success}, output:\n{output}")
|
||||
if success:
|
||||
msg = f"Started {cn}"
|
||||
msg = f"Started {cn} [{cn.getIP()}]"
|
||||
HTML.CreateHtmlTestRowQueue(core_name, 'OK', [msg])
|
||||
else:
|
||||
msg = f"deployment of core network {core_name} FAILED"
|
||||
|
||||
@@ -186,8 +186,8 @@ gNBs =
|
||||
|
||||
NETWORK_INTERFACES :
|
||||
{
|
||||
GNB_IPV4_ADDRESS_FOR_NG_AMF = "172.21.16.131";
|
||||
GNB_IPV4_ADDRESS_FOR_NGU = "172.21.16.131";
|
||||
GNB_IPV4_ADDRESS_FOR_NG_AMF = "172.21.16.202";
|
||||
GNB_IPV4_ADDRESS_FOR_NGU = "172.21.16.202";
|
||||
GNB_PORT_FOR_S1U = 2152; # Spec 2152
|
||||
};
|
||||
|
||||
|
||||
@@ -20,6 +20,8 @@ gNBs =
|
||||
min_rxtxtime = 6;
|
||||
num_dlharq = 32;
|
||||
num_ulharq = 32;
|
||||
cu_sibs = [2];
|
||||
du_sibs = [19];
|
||||
|
||||
servingCellConfigCommon = (
|
||||
{
|
||||
@@ -49,7 +51,7 @@ gNBs =
|
||||
initialDLBWPsubcarrierSpacing = 0;
|
||||
#pdcch-ConfigCommon
|
||||
initialDLBWPcontrolResourceSetZero = 2;
|
||||
initialDLBWPsearchSpaceZero = 0;
|
||||
initialDLBWPsearchSpaceZero = 2;
|
||||
|
||||
#uplinkConfigCommon
|
||||
#frequencyInfoUL
|
||||
@@ -149,7 +151,7 @@ gNBs =
|
||||
#ext2
|
||||
#ntn_Config_r17
|
||||
cellSpecificKoffset_r17 = 40;
|
||||
ta-Common-r17 = 4634000; # 18.87 ms
|
||||
ta-Common-r17 = 4627000; # 18.84 ms
|
||||
ta-CommonDrift-r17 = -230000; # -46 µs/s
|
||||
positionX-r17 = 0;
|
||||
positionY-r17 = -2166908; # -2816980.4 m
|
||||
@@ -235,15 +237,6 @@ RUs = (
|
||||
}
|
||||
);
|
||||
|
||||
THREAD_STRUCT = (
|
||||
{
|
||||
#three config for level of parallelism "PARALLEL_SINGLE_THREAD", "PARALLEL_RU_L1_SPLIT", or "PARALLEL_RU_L1_TRX_SPLIT"
|
||||
parallel_config = "PARALLEL_RU_L1_TRX_SPLIT";
|
||||
#two option for worker "WORKER_DISABLE" or "WORKER_ENABLE"
|
||||
worker_config = "WORKER_DISABLE";
|
||||
}
|
||||
);
|
||||
|
||||
rfsimulator :
|
||||
{
|
||||
serveraddr = "server";
|
||||
@@ -296,6 +289,4 @@ log_config :
|
||||
rlc_log_level ="info";
|
||||
pdcp_log_level ="info";
|
||||
rrc_log_level ="info";
|
||||
ngap_log_level ="debug";
|
||||
f1ap_log_level ="debug";
|
||||
};
|
||||
|
||||
@@ -19,6 +19,8 @@ gNBs =
|
||||
sib1_tda = 5;
|
||||
min_rxtxtime = 6;
|
||||
disable_harq = 1;
|
||||
cu_sibs = [2];
|
||||
du_sibs = [19];
|
||||
|
||||
servingCellConfigCommon = (
|
||||
{
|
||||
@@ -48,7 +50,7 @@ gNBs =
|
||||
initialDLBWPsubcarrierSpacing = 0;
|
||||
#pdcch-ConfigCommon
|
||||
initialDLBWPcontrolResourceSetZero = 2;
|
||||
initialDLBWPsearchSpaceZero = 0;
|
||||
initialDLBWPsearchSpaceZero = 2;
|
||||
|
||||
#uplinkConfigCommon
|
||||
#frequencyInfoUL
|
||||
@@ -233,15 +235,6 @@ RUs = (
|
||||
}
|
||||
);
|
||||
|
||||
THREAD_STRUCT = (
|
||||
{
|
||||
#three config for level of parallelism "PARALLEL_SINGLE_THREAD", "PARALLEL_RU_L1_SPLIT", or "PARALLEL_RU_L1_TRX_SPLIT"
|
||||
parallel_config = "PARALLEL_RU_L1_TRX_SPLIT";
|
||||
#two option for worker "WORKER_DISABLE" or "WORKER_ENABLE"
|
||||
worker_config = "WORKER_DISABLE";
|
||||
}
|
||||
);
|
||||
|
||||
rfsimulator :
|
||||
{
|
||||
serveraddr = "server";
|
||||
@@ -277,6 +270,4 @@ log_config :
|
||||
rlc_log_level ="info";
|
||||
pdcp_log_level ="info";
|
||||
rrc_log_level ="info";
|
||||
ngap_log_level ="debug";
|
||||
f1ap_log_level ="debug";
|
||||
};
|
||||
|
||||
35
ci-scripts/conf_files/nrue.uicc.ntn-leo.conf
Normal file
35
ci-scripts/conf_files/nrue.uicc.ntn-leo.conf
Normal file
@@ -0,0 +1,35 @@
|
||||
uicc0 = {
|
||||
imsi = "208990100001100";
|
||||
key = "fec86ba6eb707ed08905757b1bb44b8f";
|
||||
opc= "C42449363BBAD02B66D16BC975D77CC1";
|
||||
dnn= "oai";
|
||||
nssai_sst=1;
|
||||
}
|
||||
|
||||
position0 = {
|
||||
x = 0.0;
|
||||
y = 0.0;
|
||||
z = 6377900.0;
|
||||
}
|
||||
|
||||
thread-pool = "-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1"
|
||||
|
||||
#/* configuration for channel modelisation */
|
||||
#/* To be included in main config file when */
|
||||
#/* channel modelisation is used (rfsimulator with chanmod options enabled) */
|
||||
channelmod = {
|
||||
max_chan = 10;
|
||||
modellist = "modellist_rfsimu_1";
|
||||
modellist_rfsimu_1 = (
|
||||
{ # DL, modify on UE side
|
||||
model_name = "rfsimu_channel_enB0"
|
||||
type = "SAT_LEO_TRANS";
|
||||
noise_power_dB = -100;
|
||||
},
|
||||
{ # UL, modify on gNB side
|
||||
model_name = "rfsimu_channel_ue0"
|
||||
type = "SAT_LEO_TRANS";
|
||||
noise_power_dB = -100;
|
||||
}
|
||||
);
|
||||
};
|
||||
118
ci-scripts/xml_files/container_5g_rfsim_ntn_leo.xml
Normal file
118
ci-scripts/xml_files/container_5g_rfsim_ntn_leo.xml
Normal file
@@ -0,0 +1,118 @@
|
||||
<!--
|
||||
|
||||
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>rfsim-5gnr-ntn-Leo</htmlTabRef>
|
||||
<htmlTabName>Monolithic SA NTN LEO gNB</htmlTabName>
|
||||
<htmlTabIcon>wrench</htmlTabIcon>
|
||||
<TestCaseRequestedList>
|
||||
111111
|
||||
100001
|
||||
800813
|
||||
000001
|
||||
000002
|
||||
000003
|
||||
020001
|
||||
020002
|
||||
100001
|
||||
222222
|
||||
</TestCaseRequestedList>
|
||||
<TestCaseExclusionList></TestCaseExclusionList>
|
||||
|
||||
<testCase id="111111">
|
||||
<class>Pull_Local_Registry</class>
|
||||
<desc>Pull Images from Local Registry</desc>
|
||||
<svr_id>0</svr_id>
|
||||
<images>oai-gnb-asan oai-nr-ue-asan</images>
|
||||
</testCase>
|
||||
|
||||
<testCase id="800813">
|
||||
<class>Create_Workspace</class>
|
||||
<desc>Create new Workspace</desc>
|
||||
<eNB_instance>0</eNB_instance>
|
||||
<eNB_serverId>0</eNB_serverId>
|
||||
</testCase>
|
||||
<testCase id="000001">
|
||||
<class>Deploy_Object</class>
|
||||
<desc>Deploy OAI 5G CoreNetwork</desc>
|
||||
<yaml_path>ci-scripts/yaml_files/5g_rfsimulator_ntn_leo</yaml_path>
|
||||
<services>mysql oai-amf oai-smf oai-upf oai-ext-dn</services>
|
||||
<eNB_instance>0</eNB_instance>
|
||||
<eNB_serverId>0</eNB_serverId>
|
||||
</testCase>
|
||||
|
||||
<testCase id="000002">
|
||||
<class>Deploy_Object</class>
|
||||
<desc>Deploy OAI 5G gNB+nrUE RF sim SA</desc>
|
||||
<yaml_path>ci-scripts/yaml_files/5g_rfsimulator_ntn_leo</yaml_path>
|
||||
<services>oai-gnb oai-nr-ue</services>
|
||||
<eNB_instance>0</eNB_instance>
|
||||
<eNB_serverId>0</eNB_serverId>
|
||||
</testCase>
|
||||
|
||||
<testCase id="000003">
|
||||
<class>Attach_UE</class>
|
||||
<desc>Attach OAI UE (Wait for IP)</desc>
|
||||
<id>rfsim5g_ue</id>
|
||||
<nodes>cacofonix</nodes>
|
||||
</testCase>
|
||||
|
||||
<testCase id="020001">
|
||||
<class>Ping</class>
|
||||
<desc>Ping ext-dn from NR-UE</desc>
|
||||
<id>rfsim5g_ue</id>
|
||||
<nodes>cacofonix</nodes>
|
||||
<svr_id>rfsim5g_ext_dn</svr_id>
|
||||
<svr_node>cacofonix</svr_node>
|
||||
<ping_args>-c 20 -i 0.25</ping_args>
|
||||
<ping_packetloss_threshold>5</ping_packetloss_threshold>
|
||||
</testCase>
|
||||
|
||||
<testCase id="020002">
|
||||
<class>Ping</class>
|
||||
<desc>Ping NR-UE from ext-dn</desc>
|
||||
<id>rfsim5g_ext_dn</id>
|
||||
<nodes>cacofonix</nodes>
|
||||
<svr_id>rfsim5g_ue</svr_id>
|
||||
<svr_node>cacofonix</svr_node>
|
||||
<ping_args>-c 20 -i 0.25</ping_args>
|
||||
<ping_packetloss_threshold>5</ping_packetloss_threshold>
|
||||
</testCase>
|
||||
|
||||
<testCase id="100001">
|
||||
<class>Undeploy_Object</class>
|
||||
<always_exec>true</always_exec>
|
||||
<desc>Undeploy all OAI 5G stack</desc>
|
||||
<yaml_path>ci-scripts/yaml_files/5g_rfsimulator_ntn_leo</yaml_path>
|
||||
<eNB_instance>0</eNB_instance>
|
||||
<eNB_serverId>0</eNB_serverId>
|
||||
</testCase>
|
||||
|
||||
<testCase id="222222">
|
||||
<class>Clean_Test_Server_Images</class>
|
||||
<always_exec>true</always_exec>
|
||||
<desc>Clean Test Images on Test Server</desc>
|
||||
<svr_id>0</svr_id>
|
||||
<images>oai-gnb-asan oai-nr-ue-asan</images>
|
||||
</testCase>
|
||||
|
||||
</testCaseList>
|
||||
@@ -44,7 +44,7 @@
|
||||
<testCase id="555000">
|
||||
<class>DeployCoreNetwork</class>
|
||||
<desc>Initialize 5G Core</desc>
|
||||
<cn_id>oc-cn5g-20897-aerial2</cn_id>
|
||||
<cn_id>oc-cn5g-20897-aerial</cn_id>
|
||||
</testCase>
|
||||
|
||||
<testCase id="111111">
|
||||
@@ -52,6 +52,7 @@
|
||||
<desc>Pull Images from Local Registry</desc>
|
||||
<svr_id>0</svr_id>
|
||||
<images>oai-gnb-aerial</images>
|
||||
<tag_prefix>arm_</tag_prefix>
|
||||
</testCase>
|
||||
|
||||
<testCase id="800813">
|
||||
@@ -89,16 +90,16 @@
|
||||
<class>Ping</class>
|
||||
<desc>Ping: 100pings in 20sec</desc>
|
||||
<id>up2-aerial</id>
|
||||
<svr_id>oc-cn5g-20897-aerial2</svr_id>
|
||||
<svr_id>oc-cn5g-20897-aerial</svr_id>
|
||||
<ping_args>-c 100 -i 0.2</ping_args>
|
||||
<ping_packetloss_threshold>5</ping_packetloss_threshold>
|
||||
</testCase>
|
||||
|
||||
<testCase id="000022">
|
||||
<class>Iperf</class>
|
||||
<desc>iperf (DL/UDP/600M)(30 sec)(single-ue profile)</desc>
|
||||
<iperf_args>-u -b 600M -t 30 -R</iperf_args>
|
||||
<svr_id>oc-cn5g-20897-aerial2</svr_id>
|
||||
<desc>iperf (DL/UDP/500M)(30 sec)(single-ue profile)</desc>
|
||||
<iperf_args>-u -b 500M -t 30 -R</iperf_args>
|
||||
<svr_id>oc-cn5g-20897-aerial</svr_id>
|
||||
<id>up2-aerial</id>
|
||||
<iperf_packetloss_threshold>25</iperf_packetloss_threshold>
|
||||
<iperf_bitrate_threshold>80</iperf_bitrate_threshold>
|
||||
@@ -106,9 +107,9 @@
|
||||
|
||||
<testCase id="000033">
|
||||
<class>Iperf</class>
|
||||
<desc>iperf (UL/UDP/50M)(30 sec)(single-ue profile)</desc>
|
||||
<iperf_args>-u -b 50M -t 30</iperf_args>
|
||||
<svr_id>oc-cn5g-20897-aerial2</svr_id>
|
||||
<desc>iperf (UL/UDP/40M)(30 sec)(single-ue profile)</desc>
|
||||
<iperf_args>-u -b 40M -t 30</iperf_args>
|
||||
<svr_id>oc-cn5g-20897-aerial</svr_id>
|
||||
<id>up2-aerial</id>
|
||||
<iperf_packetloss_threshold>25</iperf_packetloss_threshold>
|
||||
<iperf_bitrate_threshold>80</iperf_bitrate_threshold>
|
||||
@@ -144,7 +145,7 @@
|
||||
<class>UndeployCoreNetwork</class>
|
||||
<always_exec>true</always_exec>
|
||||
<desc>Terminate 5G Core</desc>
|
||||
<cn_id>oc-cn5g-20897-aerial2</cn_id>
|
||||
<cn_id>oc-cn5g-20897-aerial</cn_id>
|
||||
</testCase>
|
||||
</testCaseList>
|
||||
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
<!--
|
||||
|
||||
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>TEST-GH-AERIAL-SA</htmlTabRef>
|
||||
<htmlTabName>Gracehopper AERIAL 100 MHz TDD SA</htmlTabName>
|
||||
<htmlTabIcon>tasks</htmlTabIcon>
|
||||
<TestCaseRequestedList>
|
||||
111111
|
||||
333333
|
||||
</TestCaseRequestedList>
|
||||
<TestCaseExclusionList></TestCaseExclusionList>
|
||||
|
||||
<testCase id="111111">
|
||||
<class>Pull_Local_Registry</class>
|
||||
<desc>Pull Images from Local Registry</desc>
|
||||
<svr_id>0</svr_id>
|
||||
<images>oai-gnb-aerial</images>
|
||||
<tag_prefix>arm_</tag_prefix>
|
||||
</testCase>
|
||||
|
||||
<testCase id="333333">
|
||||
<class>Clean_Test_Server_Images</class>
|
||||
<always_exec>true</always_exec>
|
||||
<desc>Clean Test Images on Test Server</desc>
|
||||
<svr_id>0</svr_id>
|
||||
<images>oai-gnb-aerial</images>
|
||||
</testCase>
|
||||
</testCaseList>
|
||||
|
||||
@@ -110,7 +110,7 @@ services:
|
||||
- NET_ADMIN # for interface bringup
|
||||
- NET_RAW # for ping
|
||||
environment:
|
||||
USE_ADDITIONAL_OPTIONS: --band 254 -C 2488400000 --CO -873500000 -r 25 --numerology 0 --ssb 60 --rfsim --rfsimulator.prop_delay 238.74 --rfsimulator.serveraddr 192.168.71.140 --log_config.global_log_options level,nocolor,time
|
||||
USE_ADDITIONAL_OPTIONS: --band 254 -C 2488400000 --CO -873500000 -r 25 --numerology 0 --ssb 60 --rfsim --rfsimulator.prop_delay 238.74 --rfsimulator.serveraddr 192.168.71.140 --num-ul-actors 1 --log_config.global_log_options level,nocolor,time
|
||||
depends_on:
|
||||
- oai-gnb
|
||||
networks:
|
||||
|
||||
152
ci-scripts/yaml_files/5g_rfsimulator_ntn_leo/docker-compose.yaml
Normal file
152
ci-scripts/yaml_files/5g_rfsimulator_ntn_leo/docker-compose.yaml
Normal file
@@ -0,0 +1,152 @@
|
||||
services:
|
||||
mysql:
|
||||
container_name: "rfsim5g-mysql"
|
||||
image: mysql:8.0
|
||||
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"
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 30
|
||||
networks:
|
||||
public_net:
|
||||
ipv4_address: 192.168.71.131
|
||||
oai-amf:
|
||||
container_name: "rfsim5g-oai-amf"
|
||||
image: oaisoftwarealliance/oai-amf:v2.0.0
|
||||
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.71.132
|
||||
oai-smf:
|
||||
container_name: "rfsim5g-oai-smf"
|
||||
image: oaisoftwarealliance/oai-smf:v2.0.0
|
||||
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.71.133
|
||||
oai-upf:
|
||||
container_name: "rfsim5g-oai-upf"
|
||||
image: oaisoftwarealliance/oai-upf:v2.0.0
|
||||
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.71.134
|
||||
traffic_net:
|
||||
ipv4_address: 192.168.72.134
|
||||
oai-ext-dn:
|
||||
privileged: true
|
||||
container_name: rfsim5g-oai-ext-dn
|
||||
image: oaisoftwarealliance/trf-gen-cn5g:focal
|
||||
entrypoint: /bin/bash -c \
|
||||
"iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE;"\
|
||||
"ip route add 12.1.1.0/24 via 192.168.72.134 dev eth0; sleep infinity"
|
||||
depends_on:
|
||||
- oai-upf
|
||||
networks:
|
||||
traffic_net:
|
||||
ipv4_address: 192.168.72.135
|
||||
healthcheck:
|
||||
test: /bin/bash -c "ping -c 2 192.168.72.134"
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
oai-gnb:
|
||||
image: ${REGISTRY:-oaisoftwarealliance}/${GNB_IMG:-oai-gnb}:${TAG:-develop}
|
||||
container_name: rfsim5g-oai-gnb
|
||||
cap_drop:
|
||||
- ALL
|
||||
environment:
|
||||
USE_ADDITIONAL_OPTIONS: --rfsim --log_config.global_log_options level,nocolor,time
|
||||
ASAN_OPTIONS: detect_leaks=0
|
||||
depends_on:
|
||||
- oai-ext-dn
|
||||
networks:
|
||||
public_net:
|
||||
ipv4_address: 192.168.71.140
|
||||
volumes:
|
||||
- ../../conf_files/gnb.sa.band254.u0.25prb.rfsim.ntn-leo.conf:/opt/oai-gnb/etc/gnb.conf
|
||||
healthcheck:
|
||||
test: /bin/bash -c "pgrep nr-softmodem"
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
|
||||
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:
|
||||
--band 254 -C 2488400000 --CO -873500000 -r 25 --numerology 0 --ssb 60
|
||||
--rfsim --rfsimulator.prop_delay 20 --rfsimulator.options chanmod
|
||||
--rfsimulator.serveraddr 192.168.71.140
|
||||
--time-sync-I 0.1 --ntn-initial-time-drift -46
|
||||
--autonomous-ta --initial-fo 57340 --cont-fo-comp 2
|
||||
--log_config.global_log_options level,nocolor,time
|
||||
--num-ul-actors 1
|
||||
depends_on:
|
||||
- oai-gnb
|
||||
networks:
|
||||
public_net:
|
||||
ipv4_address: 192.168.71.150
|
||||
devices:
|
||||
- /dev/net/tun:/dev/net/tun
|
||||
volumes:
|
||||
- ../../conf_files/nrue.uicc.ntn-leo.conf:/opt/oai-nr-ue/etc/nr-ue.conf
|
||||
healthcheck:
|
||||
test: /bin/bash -c "pgrep nr-uesoftmodem"
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
|
||||
networks:
|
||||
public_net:
|
||||
driver: bridge
|
||||
name: rfsim5g-oai-public-net
|
||||
ipam:
|
||||
config:
|
||||
- subnet: 192.168.71.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.72.128/26
|
||||
driver_opts:
|
||||
com.docker.network.bridge.name: "rfsim5g-traffic"
|
||||
@@ -24,7 +24,7 @@ sudo -E echo start_server -uid 0 | sudo -E nvidia-cuda-mps-control
|
||||
# Check if an argument is provided
|
||||
if [ $# -eq 0 ]; then
|
||||
# No argument provided, use default value
|
||||
argument="P5G_FXN"
|
||||
argument="P5G_FXN_GH"
|
||||
else
|
||||
# Argument provided, use it
|
||||
argument="$1"
|
||||
|
||||
@@ -23,7 +23,7 @@ services:
|
||||
- ../../../cmake_targets/share:/opt/cuBB/share
|
||||
userns_mode: host
|
||||
ipc: "shareable"
|
||||
image: cubb-build:24-1
|
||||
image: cubb-build:24-3
|
||||
environment:
|
||||
- cuBB_SDK=/opt/nvidia/cuBB
|
||||
command: bash -c "sudo rm -rf /tmp/phy.log && sudo chmod +x /opt/nvidia/cuBB/aerial_l1_entrypoint.sh && /opt/nvidia/cuBB/aerial_l1_entrypoint.sh"
|
||||
|
||||
@@ -107,3 +107,18 @@ or directly with
|
||||
")
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
function(run_asn1c ASN1C_GRAMMAR ASN1C_PREFIX)
|
||||
set(options "")
|
||||
set(oneValueArgs COMMENT)
|
||||
set(multiValueArgs OUTPUT OPTIONS)
|
||||
cmake_parse_arguments(ASN1C "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
|
||||
|
||||
get_filename_component(GRAMMAR_FILE ${ASN1C_GRAMMAR} NAME)
|
||||
set(LOGFILE "${CMAKE_CURRENT_BINARY_DIR}/${GRAMMAR_FILE}.log")
|
||||
add_custom_command(OUTPUT ${ASN1C_OUTPUT}
|
||||
COMMAND ASN1C_PREFIX=${ASN1C_PREFIX} ${ASN1C_EXEC} ${ASN1C_OPTIONS} -D ${CMAKE_CURRENT_BINARY_DIR} ${ASN1C_GRAMMAR} > ${LOGFILE} 2>&1 || cat ${LOGFILE}
|
||||
DEPENDS ${ASN1C_GRAMMAR}
|
||||
COMMENT "Generating ${ASN1C_COMMENT} from ${GRAMMAR_FILE}"
|
||||
)
|
||||
endfunction()
|
||||
|
||||
@@ -24,6 +24,12 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct plmn_id_s {
|
||||
uint16_t mcc;
|
||||
uint16_t mnc;
|
||||
uint8_t mnc_digit_length;
|
||||
} plmn_id_t;
|
||||
|
||||
typedef struct nssai_s {
|
||||
uint8_t sst;
|
||||
uint32_t sd;
|
||||
|
||||
@@ -167,4 +167,20 @@ typedef struct paramlist_def {
|
||||
int numelt ;
|
||||
} paramlist_def_t;
|
||||
|
||||
/* Macros to get parameters with the config module API */
|
||||
#define GET_PARAMS(param_def, param_desc, prefix) \
|
||||
printf("Reading '%s' section from the config file\n", #param_def); \
|
||||
paramdef_t param_def[] = param_desc; \
|
||||
config_get(config_get_if(), param_def, sizeofArray(param_def), prefix);
|
||||
|
||||
/* Macros to get params lists with the config module API */
|
||||
#define GET_PARAMS_LIST(param_list, param_def, param_desc, list_name, prefix, ...) \
|
||||
paramdef_t param_def[] = param_desc; \
|
||||
paramlist_def_t param_list = {list_name, NULL, 0}; \
|
||||
__VA_OPT__(checkedparam_t config_check_##param_def[] = __VA_ARGS__; \
|
||||
static_assert(sizeofArray(config_check_##param_def) == sizeofArray(param_def), \
|
||||
"param_def_t array and corresponding checkedparam_t array should have the same size"); \
|
||||
for (int i = 0; i < sizeofArray(param_def); ++i) param_def[i].chkPptr = &(config_check_##param_def[i]);) \
|
||||
config_getlist(config_get_if(), ¶m_list, param_def, sizeofArray(param_def), prefix);
|
||||
|
||||
#endif /* INCLUDE_CONFIG_PARAMDESC_H */
|
||||
|
||||
@@ -80,6 +80,8 @@
|
||||
#define NB_RAB_MAX 11 /* from LTE_maxDRB in LTE_asn_constant.h */
|
||||
#define RAB_OFFSET 0x000F
|
||||
|
||||
#define MAX_NUM_SLICES 1024
|
||||
|
||||
// RLC Entity
|
||||
#define RLC_TX_MAXSIZE 10000000
|
||||
#define RLC_RX_MAXSIZE 10000000
|
||||
@@ -93,5 +95,6 @@
|
||||
#define RETURNerror (-1)
|
||||
#define DEFAULT_NAS_PATH "PWD"
|
||||
#define UNUSED_VARIABLE(vARIABLE) (void)(vARIABLE)
|
||||
#define NUM_PRACH_RX_FOR_NOISE_ESTIMATE 100
|
||||
|
||||
#endif /* __PLATFORM_CONSTANTS_H__ */
|
||||
|
||||
@@ -13,6 +13,7 @@ add_subdirectory(T)
|
||||
add_subdirectory(nr)
|
||||
add_subdirectory(LOG)
|
||||
add_subdirectory(threadPool)
|
||||
add_subdirectory(time_manager)
|
||||
add_library(utils utils.c system.c time_meas.c time_stat.c tun_if.c)
|
||||
target_include_directories(utils PUBLIC .)
|
||||
target_link_libraries(utils PRIVATE ${T_LIB})
|
||||
|
||||
@@ -157,14 +157,19 @@ int write_file_matlab(const char *fname, const char *vname, void *data, int leng
|
||||
|
||||
//printf("Writing %d elements of type %d to %s\n",length,format,fname);
|
||||
|
||||
const int fname_len = strlen(fname);
|
||||
char write_file_name[fname_len + 10];
|
||||
const char *fn_format = (format & MATLAB_RAW) ? "%s.bin" : "%s";
|
||||
snprintf(write_file_name, sizeof(write_file_name), fn_format, fname);
|
||||
|
||||
if (format == 10 || format ==11 || format == 12 || format == 13 || format == 14 || multiVec) {
|
||||
fp = fopen(fname,"a+");
|
||||
fp = fopen(write_file_name, "a+");
|
||||
} else if (format != 10 && format !=11 && format != 12 && format != 13 && format != 14) {
|
||||
fp = fopen(fname,"w+");
|
||||
fp = fopen(write_file_name, "w+");
|
||||
}
|
||||
|
||||
if (fp== NULL) {
|
||||
printf("[OPENAIR][FILE OUTPUT] Cannot open file %s\n",fname);
|
||||
printf("[OPENAIR][FILE OUTPUT] Cannot open file %s\n", write_file_name);
|
||||
return(-1);
|
||||
}
|
||||
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
#include "common/utils/LOG/log.h"
|
||||
#include "nr_common.h"
|
||||
#include <limits.h>
|
||||
#include <math.h>
|
||||
|
||||
#define C_SRS_NUMBER (64)
|
||||
#define B_SRS_NUMBER (4)
|
||||
@@ -1427,3 +1428,15 @@ frequency_range_t get_freq_range_from_band(uint16_t band)
|
||||
{
|
||||
return band <= 256 ? FR1 : FR2;
|
||||
}
|
||||
|
||||
float get_beta_dmrs_pusch(int num_cdm_groups_no_data, pusch_dmrs_type_t dmrs_type)
|
||||
{
|
||||
float beta_dmrs_pusch = 1.0;
|
||||
if (num_cdm_groups_no_data == 2) {
|
||||
beta_dmrs_pusch = powf(10.0, 3.0 / 20.0);
|
||||
} else if (num_cdm_groups_no_data == 3) {
|
||||
if (dmrs_type == pusch_dmrs_type2)
|
||||
beta_dmrs_pusch = powf(10.0, 4.77 / 20.0);
|
||||
}
|
||||
return beta_dmrs_pusch;
|
||||
}
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
#include "assertions.h"
|
||||
#include "common/utils/utils.h"
|
||||
|
||||
#define MAX_SI_GROUPS 3
|
||||
#define NR_MAX_PDSCH_TBS 3824
|
||||
#define MAX_NUM_BEAM_PERIODS 4
|
||||
#define MAX_BWP_SIZE 275
|
||||
@@ -93,6 +94,12 @@ static inline const char *rnti_types(nr_rnti_type_t rr)
|
||||
// the total shift is 2 * 15, in dB scale thats 10log10(2^(15*2))
|
||||
#define SQ15_SQUARED_NORM_FACTOR_DB 90.3089986992
|
||||
|
||||
typedef struct {
|
||||
uint8_t *SIB_buffer;
|
||||
int SIB_size;
|
||||
int SIB_type;
|
||||
} nr_SIBs_t;
|
||||
|
||||
typedef struct nr_bandentry_s {
|
||||
int16_t band;
|
||||
uint64_t ul_min;
|
||||
@@ -123,6 +130,11 @@ typedef enum frequency_range_e {
|
||||
FR2
|
||||
} frequency_range_t;
|
||||
|
||||
typedef enum {
|
||||
pusch_dmrs_type1 = 0,
|
||||
pusch_dmrs_type2 = 1
|
||||
} pusch_dmrs_type_t;
|
||||
|
||||
#define MAX_NUM_SLOTS_ALLOWED 80 // up to numerology 3 (120 KHz SCS) is supported
|
||||
enum slot_type { TDD_NR_DOWNLINK_SLOT, TDD_NR_UPLINK_SLOT, TDD_NR_MIXED_SLOT };
|
||||
|
||||
@@ -295,6 +307,17 @@ frequency_range_t get_freq_range_from_freq(uint64_t freq);
|
||||
frequency_range_t get_freq_range_from_arfcn(uint32_t arfcn);
|
||||
frequency_range_t get_freq_range_from_band(uint16_t band);
|
||||
|
||||
/**
|
||||
* @brief Calculates the scaling factor for the ratio of PUSCH EPRE to DMRS EPRE.
|
||||
*
|
||||
* @param num_cdm_groups_no_data The number of CDM groups without data.
|
||||
* @param dmrs_type The DMRS type.
|
||||
* @return The calculated beta scaling factor for the ratio of PUSCH EPRE to DMRS EPRE.
|
||||
*
|
||||
* @note The values are derived from TS 38.214 Table 6.2.2-1.
|
||||
*/
|
||||
float get_beta_dmrs_pusch(int num_cdm_groups_no_data, pusch_dmrs_type_t dmrs_type);
|
||||
|
||||
#define CEILIDIV(a,b) ((a+b-1)/b)
|
||||
#define ROUNDIDIV(a,b) (((a<<1)+b)/(b<<1))
|
||||
|
||||
|
||||
14
common/utils/time_manager/CMakeLists.txt
Normal file
14
common/utils/time_manager/CMakeLists.txt
Normal file
@@ -0,0 +1,14 @@
|
||||
add_library(time_management STATIC
|
||||
time_manager.c)
|
||||
|
||||
add_library(time_management_core OBJECT
|
||||
time_source.c
|
||||
time_server.c
|
||||
time_client.c)
|
||||
|
||||
target_link_libraries(time_management PUBLIC time_management_core)
|
||||
target_link_libraries(time_management_core PRIVATE ${T_LIB})
|
||||
|
||||
if(ENABLE_TESTS)
|
||||
add_subdirectory(tests)
|
||||
endif()
|
||||
11
common/utils/time_manager/tests/CMakeLists.txt
Normal file
11
common/utils/time_manager/tests/CMakeLists.txt
Normal file
@@ -0,0 +1,11 @@
|
||||
add_executable(test_time_manager_manual test_manual.c)
|
||||
target_link_libraries(test_time_manager_manual time_management_core)
|
||||
target_link_libraries(test_time_manager_manual LOG CONFIG_LIB)
|
||||
|
||||
add_executable(test_time_manager_auto test_auto.c)
|
||||
target_link_libraries(test_time_manager_auto time_management)
|
||||
target_link_libraries(test_time_manager_auto LOG CONFIG_LIB)
|
||||
|
||||
add_dependencies(tests test_time_manager_auto)
|
||||
add_test(NAME time_management_tests
|
||||
COMMAND ./test_time_manager_auto)
|
||||
297
common/utils/time_manager/tests/test_auto.c
Normal file
297
common/utils/time_manager/tests/test_auto.c
Normal file
@@ -0,0 +1,297 @@
|
||||
/*
|
||||
* 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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include "common/utils/time_manager/time_manager.h"
|
||||
#include "common/utils/LOG/log.h"
|
||||
#include "common/config/config_userapi.h"
|
||||
|
||||
configmodule_interface_t *uniqCfg = NULL;
|
||||
|
||||
void exit_function(const char *file, const char *function, const int line, const char *s, const int assert)
|
||||
{
|
||||
if (s != NULL) {
|
||||
printf("%s:%d %s() Exiting OAI softmodem: %s\n", file, line, function, s);
|
||||
}
|
||||
if (assert)
|
||||
abort();
|
||||
else
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static int rlc_tick_count = 0;
|
||||
static int pdcp_tick_count = 0;
|
||||
static int x2ap_tick_count = 0;
|
||||
|
||||
void nr_rlc_ms_tick(void)
|
||||
{
|
||||
rlc_tick_count++;
|
||||
}
|
||||
|
||||
void nr_pdcp_ms_tick(void)
|
||||
{
|
||||
pdcp_tick_count++;
|
||||
}
|
||||
|
||||
void x2ap_ms_tick(void)
|
||||
{
|
||||
x2ap_tick_count++;
|
||||
}
|
||||
|
||||
/* return 1 if ok, 0 if error */
|
||||
static int standalone_realtime(void)
|
||||
{
|
||||
time_manager_tick_function_t tick_functions[] = {
|
||||
nr_pdcp_ms_tick,
|
||||
nr_rlc_ms_tick,
|
||||
x2ap_ms_tick
|
||||
};
|
||||
int tick_functions_count = sizeofArray(tick_functions);
|
||||
time_manager_start(tick_functions, tick_functions_count, TIME_SOURCE_REALTIME);
|
||||
|
||||
sleep(1);
|
||||
|
||||
time_manager_finish();
|
||||
|
||||
LOG_I(UTIL,
|
||||
"standalone realtime: rlc ticks: %d pdcp ticks: %d x2ap ticks: %d\n",
|
||||
rlc_tick_count,
|
||||
pdcp_tick_count,
|
||||
x2ap_tick_count);
|
||||
|
||||
/* let's accept 1% deviation from the 1000 counts we expect */
|
||||
return abs(rlc_tick_count-1000) < 10
|
||||
&& abs(pdcp_tick_count - 1000) < 10
|
||||
&& abs(x2ap_tick_count - 1000) < 10;
|
||||
}
|
||||
|
||||
/* return 1 if ok, 0 if error */
|
||||
static int standalone_iq_samples(void)
|
||||
{
|
||||
time_manager_tick_function_t tick_functions[] = {
|
||||
nr_pdcp_ms_tick,
|
||||
nr_rlc_ms_tick,
|
||||
x2ap_ms_tick
|
||||
};
|
||||
int tick_functions_count = sizeofArray(tick_functions);
|
||||
time_manager_start(tick_functions, tick_functions_count, TIME_SOURCE_IQ_SAMPLES);
|
||||
|
||||
/* let's pretend we have 2000 samples per second */
|
||||
for (int i = 0; i < 1000; i++) {
|
||||
time_manager_iq_samples(1, 2000);
|
||||
usleep(10);
|
||||
time_manager_iq_samples(1, 2000);
|
||||
usleep(10);
|
||||
}
|
||||
|
||||
time_manager_finish();
|
||||
|
||||
LOG_I(UTIL,
|
||||
"standalone iq-samples: rlc ticks: %d pdcp ticks: %d x2ap ticks: %d\n",
|
||||
rlc_tick_count,
|
||||
pdcp_tick_count,
|
||||
x2ap_tick_count);
|
||||
|
||||
/* exact count is required */
|
||||
return rlc_tick_count == 1000
|
||||
&& pdcp_tick_count == 1000
|
||||
&& x2ap_tick_count == 1000;
|
||||
}
|
||||
|
||||
/* return 1 if ok, 0 if error */
|
||||
static int client_server(char *program_name, bool iq_samples_time_source)
|
||||
{
|
||||
LOG_I(UTIL, "client/server %s: launch sub-processes\n", iq_samples_time_source ? "iq-samples" : "realtime");
|
||||
|
||||
pid_t server;
|
||||
pid_t client;
|
||||
|
||||
/* start server */
|
||||
server = fork();
|
||||
DevAssert(server >= 0);
|
||||
if (server == 0) {
|
||||
/* run as server */
|
||||
if (iq_samples_time_source)
|
||||
execl(program_name, program_name, "--time_management.mode", "server", "--time_management.time_source", "iq_samples", NULL);
|
||||
else
|
||||
execl(program_name, program_name, "--time_management.mode", "server", NULL);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* wait a little bit so that server is ready to accept clients
|
||||
* (this is hackish)
|
||||
*/
|
||||
usleep(100);
|
||||
|
||||
/* start client */
|
||||
client = fork();
|
||||
DevAssert(client >= 0);
|
||||
if (client == 0) {
|
||||
/* run as client */
|
||||
execl(program_name, program_name, "--time_management.mode", "client", NULL);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* wait for completion */
|
||||
int ret = 1;
|
||||
|
||||
int status;
|
||||
pid_t r = waitpid(server, &status, 0);
|
||||
DevAssert(r == server);
|
||||
if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
|
||||
ret = 0;
|
||||
|
||||
r = waitpid(client, &status, 0);
|
||||
DevAssert(r == client);
|
||||
if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
|
||||
ret = 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* return 1 if ok, 0 if error */
|
||||
static int run_sub_client_server(bool iq_samples_time_source)
|
||||
{
|
||||
time_manager_tick_function_t tick_functions[] = {
|
||||
nr_pdcp_ms_tick,
|
||||
nr_rlc_ms_tick,
|
||||
x2ap_ms_tick
|
||||
};
|
||||
int tick_functions_count = sizeofArray(tick_functions);
|
||||
/* last argument doesn't matter, overwritten by args of execl in client_server() */
|
||||
time_manager_start(tick_functions, tick_functions_count, TIME_SOURCE_REALTIME);
|
||||
|
||||
if (iq_samples_time_source) {
|
||||
/* 'iq_samples_time_source' is true only for server
|
||||
* wait a bit for client to be there otherwise server
|
||||
* may finish too early
|
||||
*/
|
||||
usleep(100);
|
||||
|
||||
/* let's pretend we have 2000 samples per second */
|
||||
for (int i = 0; i < 1000; i++) {
|
||||
time_manager_iq_samples(1, 2000);
|
||||
usleep(10);
|
||||
time_manager_iq_samples(1, 2000);
|
||||
usleep(10);
|
||||
}
|
||||
} else {
|
||||
sleep(1);
|
||||
}
|
||||
|
||||
time_manager_finish();
|
||||
|
||||
LOG_I(UTIL, "client/server: rlc ticks: %d pdcp ticks: %d x2ap ticks: %d\n", rlc_tick_count, pdcp_tick_count, x2ap_tick_count);
|
||||
|
||||
if (iq_samples_time_source)
|
||||
return rlc_tick_count == 1000
|
||||
&& pdcp_tick_count == 1000
|
||||
&& x2ap_tick_count == 1000;
|
||||
else
|
||||
/* let's accept 1% deviation from the 1000 counts we expect */
|
||||
return abs(rlc_tick_count-1000) < 10
|
||||
&& abs(pdcp_tick_count - 1000) < 10
|
||||
&& abs(x2ap_tick_count - 1000) < 10;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
if ((uniqCfg = load_configmodule(argc, argv, CONFIG_ENABLECMDLINEONLY)) == NULL) {
|
||||
exit_fun("[SOFTMODEM] Error, configuration module init failed\n");
|
||||
}
|
||||
logInit();
|
||||
|
||||
/* for client/server tests, we use sub-processes with command line parameters */
|
||||
if (argc > 1) {
|
||||
/* if there are command line parameters then it's a sub-process */
|
||||
rlc_tick_count = 0;
|
||||
pdcp_tick_count = 0;
|
||||
x2ap_tick_count = 0;
|
||||
/* return value to the main test program
|
||||
* let's do as for the shell: 0 means success and 1 means error
|
||||
*/
|
||||
/* we know we are in iq-samples time source mode if the last argument is "iq_samples" */
|
||||
int success = run_sub_client_server(!strcmp(argv[argc - 1], "iq_samples")) == 1;
|
||||
return 1 - success;
|
||||
}
|
||||
|
||||
int err = 0;
|
||||
|
||||
/* test standalone realtime */
|
||||
rlc_tick_count = 0;
|
||||
pdcp_tick_count = 0;
|
||||
x2ap_tick_count = 0;
|
||||
int ret = standalone_realtime();
|
||||
if (ret == 1)
|
||||
LOG_I(UTIL, "standalone realtime: OK\n");
|
||||
else {
|
||||
LOG_E(UTIL, "standalone realtime: ERROR\n");
|
||||
err = 1;
|
||||
}
|
||||
|
||||
/* test standalone iq-samples */
|
||||
rlc_tick_count = 0;
|
||||
pdcp_tick_count = 0;
|
||||
x2ap_tick_count = 0;
|
||||
ret = standalone_iq_samples();
|
||||
if (ret == 1)
|
||||
LOG_I(UTIL, "standalone iq-samples: OK\n");
|
||||
else {
|
||||
LOG_E(UTIL, "standalone iq-samples: ERROR\n");
|
||||
err = 1;
|
||||
}
|
||||
|
||||
/* client/server tests are not written in a robust way
|
||||
* they may fail depending on realtime on the machine
|
||||
* de-activate if needed (if CI fails)
|
||||
*/
|
||||
/* test client/server realtime */
|
||||
rlc_tick_count = 0;
|
||||
pdcp_tick_count = 0;
|
||||
x2ap_tick_count = 0;
|
||||
ret = client_server(argv[0], false);
|
||||
if (ret == 1)
|
||||
LOG_I(UTIL, "client-server realtime: OK\n");
|
||||
else {
|
||||
LOG_E(UTIL, "client-server realtime: ERROR\n");
|
||||
err = 1;
|
||||
}
|
||||
|
||||
/* test client/server iq-samples */
|
||||
rlc_tick_count = 0;
|
||||
pdcp_tick_count = 0;
|
||||
x2ap_tick_count = 0;
|
||||
ret = client_server(argv[0], true);
|
||||
if (ret == 1)
|
||||
LOG_I(UTIL, "client-server iq-samples: OK\n");
|
||||
else {
|
||||
LOG_E(UTIL, "client-server iq-samples: ERROR\n");
|
||||
err = 1;
|
||||
}
|
||||
|
||||
logTerm();
|
||||
|
||||
return err;
|
||||
}
|
||||
175
common/utils/time_manager/tests/test_manual.c
Normal file
175
common/utils/time_manager/tests/test_manual.c
Normal file
@@ -0,0 +1,175 @@
|
||||
/*
|
||||
* 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 "../time_source.h"
|
||||
#include "../time_server.h"
|
||||
#include "../time_client.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
#include <stdbool.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include "common/utils/system.h"
|
||||
#include "common/utils/LOG/log.h"
|
||||
|
||||
#include "common/config/config_userapi.h"
|
||||
|
||||
configmodule_interface_t *uniqCfg = NULL;
|
||||
|
||||
void exit_function(const char *file, const char *function, const int line, const char *s, const int assert)
|
||||
{
|
||||
printf("%s:%d:%s: %s\n", file, line, function, s);
|
||||
fflush(stdout);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
_Atomic bool test_exit;
|
||||
|
||||
static void *iq_generate_thread(void *ts)
|
||||
{
|
||||
time_source_t *time_source = ts;
|
||||
|
||||
while (!test_exit) {
|
||||
printf("iq_generate_thread calls time_source_iq_add(time_source, 100, 10000)\n");
|
||||
time_source_iq_add(time_source, 100, 10000);
|
||||
sleep(1);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#define STANDALONE 0
|
||||
#define SERVER 1
|
||||
#define CLIENT 2
|
||||
|
||||
static void usage(void)
|
||||
{
|
||||
printf("options:\n");
|
||||
printf(" -client\n");
|
||||
printf(" run as client (default is standalone)\n");
|
||||
printf(" -server\n");
|
||||
printf(" run as server (default is standalone)\n");
|
||||
printf(" -ip <ip address (default 127.0.0.1)>\n");
|
||||
printf(" use this ip address for server\n");
|
||||
printf(" -port <port (default 7473)\n");
|
||||
printf(" use this port for server\n");
|
||||
printf(" -realtime\n");
|
||||
printf(" run with realtime clock (default is simulated iq samples)\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
static void server_callback(void *callback_data)
|
||||
{
|
||||
printf("server_callback called (callback_data %p)\n", callback_data);
|
||||
DevAssert(callback_data == (void *)1);
|
||||
}
|
||||
|
||||
static void client_callback(void *callback_data)
|
||||
{
|
||||
printf("client_callback called (callback_data %p)\n", callback_data);
|
||||
DevAssert(callback_data == (void *)2);
|
||||
}
|
||||
|
||||
/* dummy sig handler to quit immediately when pressing enter
|
||||
* (we send a signal to iq_generate_thread to interrupt sleep())
|
||||
*/
|
||||
static void sig_handle(int n)
|
||||
{
|
||||
/* nothing */
|
||||
}
|
||||
|
||||
int main(int n, char **v)
|
||||
{
|
||||
time_source_t *ts = NULL;
|
||||
time_server_t *server = NULL;
|
||||
time_client_t *client = NULL;
|
||||
int mode = STANDALONE;
|
||||
char *server_ip = "127.0.0.1";
|
||||
int server_port = 7473;
|
||||
time_source_type_t time_source_type = TIME_SOURCE_IQ_SAMPLES;
|
||||
pthread_t iq_thread;
|
||||
|
||||
for (int i = 1; i < n; i++) {
|
||||
if (!strcmp(v[i], "-client")) { mode = CLIENT; continue; }
|
||||
if (!strcmp(v[i], "-server")) { mode = SERVER; continue; }
|
||||
if (!strcmp(v[i], "-ip")) { if (i>n-2) usage(); server_ip = v[++i]; continue; }
|
||||
if (!strcmp(v[i], "-port")) { if (i>n-2) usage(); server_port = atoi(v[++i]); continue; }
|
||||
if (!strcmp(v[i], "-realtime")) { time_source_type = TIME_SOURCE_REALTIME; continue; }
|
||||
usage();
|
||||
}
|
||||
|
||||
logInit();
|
||||
/* hack: set log to info (logInit doesn't do it because we don't call load_configmodule()) */
|
||||
for (int i = 0; i < MAX_LOG_COMPONENTS; i++)
|
||||
g_log->log_component[i].level = OAILOG_INFO;
|
||||
|
||||
if (mode != CLIENT) {
|
||||
ts = new_time_source(time_source_type);
|
||||
if (time_source_type == TIME_SOURCE_IQ_SAMPLES) {
|
||||
void *ret = signal(SIGHUP, sig_handle);
|
||||
DevAssert(ret != SIG_ERR);
|
||||
threadCreate(&iq_thread, iq_generate_thread, ts, "iq samples generator", -1, SCHED_OAI);
|
||||
}
|
||||
}
|
||||
|
||||
if (mode == SERVER) {
|
||||
/* (void*)1 to check if callback data is passed correctly */
|
||||
server = new_time_server(server_ip, server_port, server_callback, (void *)1);
|
||||
time_server_attach_time_source(server, ts);
|
||||
}
|
||||
|
||||
if (mode == CLIENT) {
|
||||
/* (void*)2 to check if callback data is passed correctly */
|
||||
client = new_time_client(server_ip, server_port, client_callback, (void *)2);
|
||||
}
|
||||
|
||||
printf("main: press enter to quit\n");
|
||||
getchar();
|
||||
|
||||
test_exit = true;
|
||||
|
||||
if (mode != CLIENT)
|
||||
if (time_source_type == TIME_SOURCE_IQ_SAMPLES) {
|
||||
(void)pthread_kill(iq_thread, SIGHUP);
|
||||
int ret = pthread_join(iq_thread, NULL);
|
||||
DevAssert(ret == 0);
|
||||
}
|
||||
|
||||
if (mode != CLIENT) {
|
||||
free_time_source(ts);
|
||||
}
|
||||
|
||||
if (mode == SERVER) {
|
||||
free_time_server(server);
|
||||
}
|
||||
|
||||
if (mode == CLIENT) {
|
||||
free_time_client(client);
|
||||
}
|
||||
|
||||
logTerm();
|
||||
|
||||
return 0;
|
||||
}
|
||||
232
common/utils/time_manager/time_client.c
Normal file
232
common/utils/time_manager/time_client.c
Normal file
@@ -0,0 +1,232 @@
|
||||
/*
|
||||
* 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 "time_client.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <stdbool.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <poll.h>
|
||||
#include <sys/eventfd.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "common/utils/assertions.h"
|
||||
#include "common/utils/LOG/log.h"
|
||||
#include "common/utils/system.h"
|
||||
|
||||
typedef struct {
|
||||
pthread_t thread_id;
|
||||
int exit_fd;
|
||||
struct sockaddr_in server_ip;
|
||||
int server_port;
|
||||
void (*callback)(void *);
|
||||
void *callback_data;
|
||||
} time_client_private_t;
|
||||
|
||||
static int connect_to_server(time_client_private_t *time_client)
|
||||
{
|
||||
int sock = -1;
|
||||
int opts;
|
||||
int r;
|
||||
struct pollfd fds[2];
|
||||
|
||||
/* try forever (or exit requested) until we succeed */
|
||||
while (1) {
|
||||
sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||
AssertFatal(sock != -1, "socket() failed: %s\n", strerror(errno));
|
||||
int v = 1;
|
||||
r = setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &v, sizeof(v));
|
||||
AssertFatal(r == 0, "setsockopt() failed: %s\n", strerror(errno));
|
||||
/* unblock socket */
|
||||
opts = fcntl(sock, F_GETFL);
|
||||
AssertFatal(opts >= 0, "fcntl() failed: %s\n", strerror(errno));
|
||||
opts |= O_NONBLOCK;
|
||||
r = fcntl(sock, F_SETFL, opts);
|
||||
AssertFatal(r == 0, "fctnl() failed: %s\n", strerror(errno));
|
||||
if (connect(sock, (struct sockaddr *)&time_client->server_ip, sizeof(time_client->server_ip)) == 0)
|
||||
break;
|
||||
if (errno == EINPROGRESS) {
|
||||
/* connection not completed yet, we need to wait */
|
||||
fds[0].fd = sock;
|
||||
fds[0].events = POLLOUT;
|
||||
fds[1].fd = time_client->exit_fd;
|
||||
fds[1].events = POLLIN;
|
||||
r = poll(fds, 2, -1);
|
||||
AssertFatal(r >= 0, "poll() failed: %s\n", strerror(errno));
|
||||
/* do we need to exit? */
|
||||
if (fds[1].revents) {
|
||||
shutdown(sock, SHUT_RDWR);
|
||||
close(sock);
|
||||
sock = -1;
|
||||
break;
|
||||
}
|
||||
/* check if connection is successful */
|
||||
if (fds[0].revents & POLLOUT) {
|
||||
int so_error;
|
||||
socklen_t so_error_len = sizeof(so_error);
|
||||
r = getsockopt(sock, SOL_SOCKET, SO_ERROR, &so_error, &so_error_len);
|
||||
AssertFatal(r == 0 && so_error_len == sizeof(so_error),
|
||||
"getsockopt() failed (r = %d) or so_error_len (= %d) is not %ld\n",
|
||||
r, so_error_len, sizeof(so_error));
|
||||
if (so_error == 0)
|
||||
/* success */
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* connection failed, try again in 1s (or stop if exit requested) */
|
||||
close(sock);
|
||||
sock = -1;
|
||||
char server_address[256];
|
||||
const char *ret = inet_ntop(AF_INET, &time_client->server_ip.sin_addr, server_address, sizeof(server_address));
|
||||
AssertFatal(ret != NULL, "inet_ntop() failed: %s\n", strerror(errno));
|
||||
LOG_W(UTIL, "time client: connection to %s:%d failed, try again in 1s\n", server_address, time_client->server_port);
|
||||
/* sleep 1s (or exit requested) */
|
||||
fds[0].fd = time_client->exit_fd;
|
||||
fds[0].events = POLLIN;
|
||||
r = poll(fds, 1, 1000);
|
||||
AssertFatal(r >= 0, "poll() failed: %s\n", strerror(errno));
|
||||
/* exit requested? */
|
||||
if (fds[0].revents) {
|
||||
shutdown(sock, SHUT_RDWR);
|
||||
close(sock);
|
||||
sock = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (sock != -1) {
|
||||
/* reblock socket */
|
||||
opts &= ~O_NONBLOCK;
|
||||
r = fcntl(sock, F_SETFL, opts);
|
||||
AssertFatal(r == 0, "fcntl() failed: %s\n", strerror(errno));
|
||||
}
|
||||
return sock;
|
||||
}
|
||||
|
||||
static void *time_client_thread(void *tc)
|
||||
{
|
||||
time_client_private_t *time_client = tc;
|
||||
int ret;
|
||||
int socket = connect_to_server(time_client);
|
||||
/* if socket is -1 at this point, it means that exit was requested */
|
||||
if (socket == -1)
|
||||
return NULL;
|
||||
|
||||
while (1) {
|
||||
struct pollfd polls[2];
|
||||
/* polls[0] is for the socket */
|
||||
polls[0].fd = socket;
|
||||
polls[0].events = POLLIN;
|
||||
|
||||
/* polls[1] is for exit_fd */
|
||||
polls[1].fd = time_client->exit_fd;
|
||||
polls[1].events = POLLIN;
|
||||
|
||||
ret = poll(polls, 2, -1);
|
||||
AssertFatal(ret >= 0, "poll() failed: %s\n", strerror(errno));
|
||||
|
||||
/* whatever is in revents for exit_fd means exit */
|
||||
if (polls[1].revents)
|
||||
break;
|
||||
|
||||
/* is socket fine? */
|
||||
if (polls[0].revents & (POLLERR | POLLHUP)) {
|
||||
reconnect:
|
||||
/* socket not fine, reconnect */
|
||||
shutdown(socket, SHUT_RDWR);
|
||||
close(socket);
|
||||
socket = connect_to_server(time_client);
|
||||
/* connect only fails if exit requested, we can safely 'continue' */
|
||||
continue;
|
||||
}
|
||||
|
||||
/* here we only accept POLLIN */
|
||||
AssertFatal(polls[0].revents == POLLIN, "poll() did not return expected POLLIN\n");
|
||||
|
||||
/* get the ticks from server */
|
||||
uint8_t tick_count;
|
||||
ret = read(socket, &tick_count, 1);
|
||||
/* any error => reconnect */
|
||||
if (ret == -1) {
|
||||
LOG_E(UTIL, "time client: error %s, reconnect\n", strerror(errno));
|
||||
goto reconnect;
|
||||
}
|
||||
/* if 0 is returned, it means socket has been closed by other end */
|
||||
if (ret == 0) {
|
||||
LOG_E(UTIL, "time client: socket closed by other end, reconnect\n");
|
||||
goto reconnect;
|
||||
}
|
||||
DevAssert(ret == 1);
|
||||
|
||||
/* call callback once for each tick */
|
||||
for (int i = 0; i < tick_count; i++)
|
||||
time_client->callback(time_client->callback_data);
|
||||
}
|
||||
|
||||
shutdown(socket, SHUT_RDWR);
|
||||
close(socket);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
time_client_t *new_time_client(const char *server_ip,
|
||||
int server_port,
|
||||
void (*callback)(void *),
|
||||
void *callback_data)
|
||||
{
|
||||
time_client_private_t *tc;
|
||||
int ret;
|
||||
|
||||
tc = calloc_or_fail(1, sizeof(*tc));
|
||||
|
||||
tc->exit_fd = eventfd(0, 0);
|
||||
AssertFatal(tc->exit_fd != -1, "eventfd() failed: %s\n", strerror(errno));
|
||||
|
||||
ret = inet_aton(server_ip, &tc->server_ip.sin_addr);
|
||||
AssertFatal(ret != 0, "inet_aton() failed: %s\n", strerror(errno));
|
||||
tc->server_ip.sin_family = AF_INET;
|
||||
tc->server_ip.sin_port = htons(server_port);
|
||||
tc->server_port = server_port;
|
||||
tc->callback = callback;
|
||||
tc->callback_data = callback_data;
|
||||
|
||||
threadCreate(&tc->thread_id, time_client_thread, tc, "time client", -1, SCHED_OAI);
|
||||
|
||||
return tc;
|
||||
}
|
||||
|
||||
void free_time_client(time_client_t *tc)
|
||||
{
|
||||
time_client_private_t *time_client = tc;
|
||||
|
||||
uint64_t v = 1;
|
||||
int ret = write(time_client->exit_fd, &v, 8);
|
||||
DevAssert(ret == 8);
|
||||
|
||||
ret = pthread_join(time_client->thread_id, NULL);
|
||||
DevAssert(ret == 0);
|
||||
|
||||
close(time_client->exit_fd);
|
||||
free(time_client);
|
||||
}
|
||||
36
common/utils/time_manager/time_client.h
Normal file
36
common/utils/time_manager/time_client.h
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* 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 COMMON_UTIL_TIME_MANAGER_TIME_CLIENT
|
||||
#define COMMON_UTIL_TIME_MANAGER_TIME_CLIENT
|
||||
|
||||
/* opaque data type */
|
||||
typedef void time_client_t;
|
||||
|
||||
time_client_t *new_time_client(const char *server_ip,
|
||||
int server_port,
|
||||
void (*callback)(void *),
|
||||
void *callback_data);
|
||||
|
||||
void free_time_client(time_client_t *time_client);
|
||||
|
||||
|
||||
#endif /* COMMON_UTIL_TIME_MANAGER_TIME_CLIENT */
|
||||
205
common/utils/time_manager/time_manager.c
Normal file
205
common/utils/time_manager/time_manager.c
Normal file
@@ -0,0 +1,205 @@
|
||||
/*
|
||||
* 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 "time_manager.h"
|
||||
|
||||
#include "time_source.h"
|
||||
#include "time_server.h"
|
||||
#include "time_client.h"
|
||||
|
||||
#include "common/config/config_userapi.h"
|
||||
#include "common/utils/assertions.h"
|
||||
#include "common/utils/LOG/log.h"
|
||||
|
||||
/* global variables (some may be ununsed, depends on configuration) */
|
||||
static time_source_t *time_source = NULL;
|
||||
static time_server_t *time_server = NULL;
|
||||
static time_client_t *time_client = NULL;
|
||||
|
||||
/* tick functions registered at initialization of the time manager */
|
||||
static time_manager_tick_function_t *tick_functions;
|
||||
static int tick_functions_count;
|
||||
|
||||
/* tick callback, called by time_source every 'millisecond' (can be
|
||||
* actual millisecond or simulated millisecond)
|
||||
*/
|
||||
static void tick(void *unused)
|
||||
{
|
||||
for (int i = 0; i < tick_functions_count; i++)
|
||||
tick_functions[i]();
|
||||
}
|
||||
|
||||
#define TIME_SOURCE "time_source"
|
||||
#define MODE "mode"
|
||||
#define SERVER_IP "server_ip"
|
||||
#define SERVER_PORT "server_port"
|
||||
|
||||
static paramdef_t config_parameters[] = {
|
||||
{TIME_SOURCE, "time source", 0, .strptr = NULL, .defstrval = NULL, TYPE_STRING, 0},
|
||||
{MODE, "time mode", 0, .strptr = NULL, .defstrval = NULL, TYPE_STRING, 0},
|
||||
{SERVER_IP, "server ip", 0, .strptr = NULL, .defstrval = NULL, TYPE_STRING, 0},
|
||||
{SERVER_PORT, "server port", 0, .iptr = NULL, .defintval = -1, TYPE_INT, 0},
|
||||
};
|
||||
|
||||
static char *get_param_str(char *name)
|
||||
{
|
||||
int idx = config_paramidx_fromname(config_parameters, sizeofArray(config_parameters), name);
|
||||
|
||||
char *param;
|
||||
if (config_parameters[idx].strptr != NULL)
|
||||
param = *config_parameters[idx].strptr;
|
||||
else
|
||||
param = NULL;
|
||||
|
||||
return param;
|
||||
}
|
||||
|
||||
static int get_param_int(char *name)
|
||||
{
|
||||
int idx = config_paramidx_fromname(config_parameters, sizeofArray(config_parameters), name);
|
||||
|
||||
return *config_parameters[idx].iptr;
|
||||
}
|
||||
|
||||
void time_manager_start(time_manager_tick_function_t *_tick_functions,
|
||||
int _tick_functions_count,
|
||||
time_source_type_t time_source_type)
|
||||
{
|
||||
bool has_time_server = false;
|
||||
bool has_time_client = false;
|
||||
char *default_server_ip = "127.0.0.1";
|
||||
int default_server_port = 7374;
|
||||
char *server_ip = NULL;
|
||||
int server_port = -1;
|
||||
|
||||
tick_functions_count = _tick_functions_count;
|
||||
tick_functions = calloc_or_fail(tick_functions_count, sizeof(*tick_functions));
|
||||
memcpy(tick_functions, _tick_functions, tick_functions_count * sizeof(*tick_functions));
|
||||
|
||||
/* retrieve configuration */
|
||||
int ret = config_get(config_get_if(), config_parameters, sizeofArray(config_parameters), "time_management");
|
||||
if (ret >= 0) {
|
||||
char *param;
|
||||
|
||||
/* time source */
|
||||
param = get_param_str(TIME_SOURCE);
|
||||
if (param != NULL) {
|
||||
if (!strcmp(param, "realtime")) {
|
||||
time_source_type = TIME_SOURCE_REALTIME;
|
||||
} else if (!strcmp(param, "iq_samples")) {
|
||||
time_source_type = TIME_SOURCE_IQ_SAMPLES;
|
||||
} else {
|
||||
AssertFatal(0, "bad parameter 'time_source' in section 'time_management', unknown value \"%s\". Valid values are \"realtime\" and \"iq_samples\"\n", param);
|
||||
}
|
||||
}
|
||||
|
||||
/* mode */
|
||||
param = get_param_str(MODE);
|
||||
if (param != NULL) {
|
||||
if (!strcmp(param, "standalone")) {
|
||||
has_time_server = false;
|
||||
has_time_client = false;
|
||||
} else if (!strcmp(param, "server")) {
|
||||
has_time_server = true;
|
||||
has_time_client = false;
|
||||
} else if (!strcmp(param, "client")) {
|
||||
has_time_server = false;
|
||||
has_time_client = true;
|
||||
} else {
|
||||
AssertFatal(0, "bad parameter 'mode' in section 'time_management', unknown value \"%s\". Valid values are \"standalone\", \"server\" and \"client\"\n", param);
|
||||
}
|
||||
}
|
||||
|
||||
/* server ip */
|
||||
param = get_param_str(SERVER_IP);
|
||||
if (param != NULL) {
|
||||
server_ip = param;
|
||||
}
|
||||
|
||||
/* server port */
|
||||
int port = get_param_int(SERVER_PORT);
|
||||
if (port != -1) {
|
||||
server_port = port;
|
||||
}
|
||||
}
|
||||
|
||||
if (server_ip == NULL)
|
||||
server_ip = default_server_ip;
|
||||
|
||||
if (server_port == -1)
|
||||
server_port = default_server_port;
|
||||
|
||||
/* create entities, according to selected configuration */
|
||||
if (!has_time_client) {
|
||||
time_source = new_time_source(time_source_type);
|
||||
time_source_set_callback(time_source, tick, NULL);
|
||||
}
|
||||
|
||||
if (has_time_server) {
|
||||
time_server = new_time_server(server_ip, server_port, tick, NULL);
|
||||
time_server_attach_time_source(time_server, time_source);
|
||||
}
|
||||
|
||||
if (has_time_client) {
|
||||
time_client = new_time_client(server_ip, server_port, tick, NULL);
|
||||
/* for the log below, there is no time source, we want to print 'server' as time source */
|
||||
time_source_type = 2;
|
||||
}
|
||||
|
||||
LOG_I(UTIL,
|
||||
"time manager configuration: [time source: %s] [mode: %s] [server IP: %s} [server port: %d]%s\n",
|
||||
(char *[]){"reatime", "iq_samples", "server"}[time_source_type],
|
||||
has_time_server ? "server"
|
||||
: has_time_client ? "client"
|
||||
: "standalone",
|
||||
server_ip,
|
||||
server_port,
|
||||
has_time_server || has_time_client ? "" : " (server IP/port not used)");
|
||||
}
|
||||
|
||||
void time_manager_iq_samples(uint64_t iq_samples_count,
|
||||
uint64_t iq_samples_per_second)
|
||||
{
|
||||
time_source_iq_add(time_source, iq_samples_count, iq_samples_per_second);
|
||||
}
|
||||
|
||||
void time_manager_finish(void)
|
||||
{
|
||||
/* time source has to be shutdown first */
|
||||
if (time_source != NULL) {
|
||||
free_time_source(time_source);
|
||||
time_source = NULL;
|
||||
}
|
||||
|
||||
if (time_server != NULL) {
|
||||
free_time_server(time_server);
|
||||
time_server = NULL;
|
||||
}
|
||||
|
||||
if (time_client != NULL) {
|
||||
free_time_client(time_client);
|
||||
time_client = NULL;
|
||||
}
|
||||
|
||||
free(tick_functions);
|
||||
tick_functions = NULL;
|
||||
tick_functions_count = 0;
|
||||
}
|
||||
@@ -19,40 +19,20 @@
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
/*! \file FGSRegistrationResult.c
|
||||
#ifndef COMMON_UTIL_TIME_MANAGER_TIME_MANAGER
|
||||
#define COMMON_UTIL_TIME_MANAGER_TIME_MANAGER
|
||||
|
||||
\brief 5GS Registration result for registration request procedures
|
||||
\author Yoshio INOUE, Masayuki HARADA
|
||||
\email: yoshio.inoue@fujitsu.com,masayuki.harada@fujitsu.com
|
||||
\date 2020
|
||||
\version 0.1
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "TLVEncoder.h"
|
||||
#include "TLVDecoder.h"
|
||||
#include "FGSRegistrationResult.h"
|
||||
#include "time_source.h"
|
||||
|
||||
int decode_fgs_registration_result(FGSRegistrationResult *fgsregistrationresult, uint8_t iei, uint16_t value, uint32_t len)
|
||||
{
|
||||
int decoded = 0;
|
||||
uint16_t *buffer = &value;
|
||||
fgsregistrationresult->registrationresult = *buffer & 0x7;
|
||||
fgsregistrationresult->smsallowed = *buffer & 0x8;
|
||||
decoded = decoded + 2;
|
||||
return decoded;
|
||||
}
|
||||
typedef void (*time_manager_tick_function_t)(void);
|
||||
|
||||
uint16_t encode_fgs_registration_result(const FGSRegistrationResult *fgsregistrationresult)
|
||||
{
|
||||
uint16_t bufferReturn;
|
||||
uint16_t *buffer = &bufferReturn;
|
||||
uint8_t encoded = 0;
|
||||
*(buffer + encoded) = 0x00 | (fgsregistrationresult->smsallowed & 0x8) | (fgsregistrationresult->registrationresult & 0x7);
|
||||
encoded = encoded + 2;
|
||||
void time_manager_start(time_manager_tick_function_t *tick_functions,
|
||||
int tick_functions_count,
|
||||
time_source_type_t time_source);
|
||||
void time_manager_iq_samples(uint64_t iq_samples_count,
|
||||
uint64_t iq_samples_per_second);
|
||||
void time_manager_finish(void);
|
||||
|
||||
return bufferReturn;
|
||||
}
|
||||
#endif /* COMMON_UTIL_TIME_MANAGER_TIME_MANAGER */
|
||||
249
common/utils/time_manager/time_server.c
Normal file
249
common/utils/time_manager/time_server.c
Normal file
@@ -0,0 +1,249 @@
|
||||
/*
|
||||
* 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 "time_server.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <poll.h>
|
||||
#include <errno.h>
|
||||
#include <sys/eventfd.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "common/utils/system.h"
|
||||
#include "common/utils/LOG/log.h"
|
||||
|
||||
typedef struct {
|
||||
pthread_t thread_id;
|
||||
_Atomic bool exit;
|
||||
int server_socket;
|
||||
int tick_fd;
|
||||
void (*callback)(void *);
|
||||
void *callback_data;
|
||||
} time_server_private_t;
|
||||
|
||||
static void *time_server_thread(void *ts)
|
||||
{
|
||||
time_server_private_t *time_server = ts;
|
||||
struct pollfd *polls = NULL;
|
||||
int *socket_fds = NULL;
|
||||
int client_count = 0;
|
||||
|
||||
polls = calloc_or_fail(2, sizeof(struct pollfd));
|
||||
|
||||
while (!time_server->exit) {
|
||||
/* polls[0] is to receive ticks */
|
||||
polls[0].fd = time_server->tick_fd;
|
||||
polls[0].events = POLLIN;
|
||||
/* polls[1] is to accept connections from clients */
|
||||
polls[1].fd = time_server->server_socket;
|
||||
polls[1].events = POLLIN;
|
||||
|
||||
/* add clients */
|
||||
for (int i = 0; i < client_count; i++) {
|
||||
polls[i + 2].fd = socket_fds[i];
|
||||
polls[i + 2].events = POLLIN;
|
||||
}
|
||||
|
||||
int ret = poll(polls, client_count + 2, -1);
|
||||
AssertFatal(ret >= 1 || (ret == -1 && errno == EINTR), "poll() failed\n");
|
||||
|
||||
if (time_server->exit)
|
||||
break;
|
||||
|
||||
/* check tick */
|
||||
if (polls[0].revents) {
|
||||
/* do not accept errors */
|
||||
AssertFatal(polls[0].revents == POLLIN, "poll() failed\n");
|
||||
uint64_t ticks;
|
||||
int ret = read(time_server->tick_fd, &ticks, 8);
|
||||
DevAssert(ret == 8);
|
||||
/* call the callback ticks time */
|
||||
for (int i = 0; i < ticks; i++)
|
||||
time_server->callback(time_server->callback_data);
|
||||
/* send ticks by blocks of 255 max (what fits in a uint8_t) */
|
||||
while (ticks) {
|
||||
/* get min(ticks, 255) */
|
||||
uint8_t count = ticks < 255 ? ticks : 255;
|
||||
/* send to all clients */
|
||||
for (int i = 0; i < client_count; i++) {
|
||||
if (write(socket_fds[i], &count, 1) == 1)
|
||||
continue;
|
||||
|
||||
/* error writing - remove client */
|
||||
LOG_W(UTIL, "time server: client disconnects\n");
|
||||
shutdown(socket_fds[i], SHUT_RDWR);
|
||||
close(socket_fds[i]);
|
||||
client_count--;
|
||||
i--;
|
||||
if (client_count == 0) {
|
||||
free(socket_fds);
|
||||
socket_fds = NULL;
|
||||
} else {
|
||||
memmove(&socket_fds[i + 1], &socket_fds[i + 2], sizeof(int) * (client_count - i - 1));
|
||||
socket_fds = realloc(socket_fds, sizeof(int) * client_count);
|
||||
}
|
||||
polls = realloc(polls, sizeof(struct pollfd) * (client_count + 2));
|
||||
AssertFatal(polls != NULL, "realloc() failed\n");
|
||||
}
|
||||
ticks -= count;
|
||||
}
|
||||
}
|
||||
|
||||
/* check new client */
|
||||
if (polls[1].revents) {
|
||||
/* do not accept errors */
|
||||
AssertFatal(polls[1].revents == POLLIN, "poll() failed\n");
|
||||
|
||||
int new_socket = accept(time_server->server_socket, NULL, NULL);
|
||||
AssertFatal(new_socket != -1, "accept() failed: %s\n", strerror(errno));
|
||||
|
||||
/* add client */
|
||||
client_count++;
|
||||
socket_fds = realloc(socket_fds, sizeof(int) * client_count);
|
||||
AssertFatal(socket_fds != NULL, "realloc() failed\n");
|
||||
socket_fds[client_count - 1] = new_socket;
|
||||
polls = realloc(polls, sizeof(struct pollfd) * (client_count + 2));
|
||||
AssertFatal(polls != NULL, "realloc() failed\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
/* any event on a client socket is to be considered as an error */
|
||||
for (int i = 0; i < client_count; i++) {
|
||||
if (polls[i + 2].revents == 0)
|
||||
continue;
|
||||
|
||||
LOG_W(UTIL,
|
||||
"time server: error on client's socket, removing client (revents is %d, fd is %d i is %d)\n",
|
||||
polls[i + 2].revents,
|
||||
polls[i + 2].fd,
|
||||
i);
|
||||
shutdown(socket_fds[i], SHUT_RDWR);
|
||||
close(socket_fds[i]);
|
||||
client_count--;
|
||||
i--;
|
||||
if (client_count == 0) {
|
||||
free(socket_fds);
|
||||
socket_fds = NULL;
|
||||
} else {
|
||||
memmove(&socket_fds[i + 1], &socket_fds[i + 2], sizeof(int) * (client_count - i - 1));
|
||||
socket_fds = realloc(socket_fds, sizeof(int) * client_count);
|
||||
AssertFatal(socket_fds != NULL, "realloco() failed\n");
|
||||
}
|
||||
if (client_count)
|
||||
memmove(&polls[i + 2 + 1], &polls[i + 2 + 2], sizeof(struct pollfd) * (client_count - i - 1));
|
||||
polls = realloc(polls, sizeof(struct pollfd) * (client_count + 2));
|
||||
AssertFatal(polls != NULL, "realloc() failed\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* close all clients' sockets */
|
||||
for (int i = 0; i < client_count; i++) {
|
||||
shutdown(socket_fds[i], SHUT_RDWR);
|
||||
close(socket_fds[i]);
|
||||
}
|
||||
|
||||
free(polls);
|
||||
free(socket_fds);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
time_server_t *new_time_server(const char *ip,
|
||||
int port,
|
||||
void (*callback)(void *),
|
||||
void *callback_data)
|
||||
{
|
||||
time_server_private_t *ts;
|
||||
int ret;
|
||||
|
||||
ts = calloc_or_fail(1, sizeof(*ts));
|
||||
|
||||
ts->server_socket = socket(AF_INET, SOCK_STREAM, 0);
|
||||
AssertFatal(ts->server_socket != -1, "socket() failed: %s\n", strerror(errno));
|
||||
|
||||
int v = 1;
|
||||
ret = setsockopt(ts->server_socket, SOL_SOCKET, SO_REUSEADDR, &v, sizeof(v));
|
||||
AssertFatal(ret == 0, "setsockopt() failed: %s\n", strerror(errno));
|
||||
v = 1;
|
||||
ret = setsockopt(ts->server_socket, IPPROTO_TCP, TCP_NODELAY, &v, sizeof(v));
|
||||
AssertFatal(ret == 0, "setsockopt() failed: %s\n", strerror(errno));
|
||||
ts->tick_fd = eventfd(0, 0);
|
||||
AssertFatal(ts->tick_fd != -1, "eventfd() failed: %s\n", strerror(errno));
|
||||
|
||||
struct sockaddr_in ip_addr;
|
||||
ip_addr.sin_family = AF_INET;
|
||||
ip_addr.sin_port = htons(port);
|
||||
ret = inet_aton(ip, &ip_addr.sin_addr);
|
||||
AssertFatal(ret != 0, "inet_aton() failed: %s\n", strerror(errno));
|
||||
ret = bind(ts->server_socket, (struct sockaddr *)&ip_addr, sizeof(ip_addr));
|
||||
AssertFatal(ret == 0, "bind() failed: %s\n", strerror(errno));
|
||||
|
||||
ret = listen(ts->server_socket, 10); /* 10: arbitrary value */
|
||||
AssertFatal(ret == 0, "listen() failed: %s\n", strerror(errno));
|
||||
|
||||
ts->callback = callback;
|
||||
ts->callback_data = callback_data;
|
||||
|
||||
threadCreate(&ts->thread_id, time_server_thread, ts, "time server", -1, SCHED_OAI);
|
||||
return ts;
|
||||
}
|
||||
|
||||
void free_time_server(time_server_t *ts)
|
||||
{
|
||||
time_server_private_t *time_server = ts;
|
||||
|
||||
/* flag exit */
|
||||
time_server->exit = true;
|
||||
|
||||
/* send a fake tick to wake up the server thread */
|
||||
uint64_t v = 1;
|
||||
int ret = write(time_server->tick_fd, &v, 8);
|
||||
DevAssert(ret == 8);
|
||||
|
||||
/* wait for thread termination */
|
||||
void *retval;
|
||||
ret = pthread_join(time_server->thread_id, &retval);
|
||||
|
||||
/* free memory */
|
||||
shutdown(time_server->server_socket, SHUT_RDWR);
|
||||
close(time_server->server_socket);
|
||||
close(time_server->tick_fd);
|
||||
free(time_server);
|
||||
}
|
||||
|
||||
static void time_server_tick_callback(void *ts)
|
||||
{
|
||||
time_server_private_t *time_server = ts;
|
||||
uint64_t v = 1;
|
||||
int ret = write(time_server->tick_fd, &v, 8);
|
||||
DevAssert(ret == 8);
|
||||
}
|
||||
|
||||
void time_server_attach_time_source(time_server_t *time_server,
|
||||
time_source_t *time_source)
|
||||
{
|
||||
time_source_set_callback(time_source, time_server_tick_callback, time_server);
|
||||
}
|
||||
40
common/utils/time_manager/time_server.h
Normal file
40
common/utils/time_manager/time_server.h
Normal file
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* 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 COMMON_UTIL_TIME_MANAGER_TIME_SERVER
|
||||
#define COMMON_UTIL_TIME_MANAGER_TIME_SERVER
|
||||
|
||||
#include "time_source.h"
|
||||
|
||||
/* opaque data type */
|
||||
typedef void time_server_t;
|
||||
|
||||
time_server_t *new_time_server(const char *ip,
|
||||
int port,
|
||||
void (*callback)(void *),
|
||||
void *callback_data);
|
||||
void free_time_server(time_server_t *time_server);
|
||||
|
||||
void time_server_attach_time_source(time_server_t *time_server,
|
||||
time_source_t *time_source);
|
||||
|
||||
#endif /* COMMON_UTIL_TIME_MANAGER_TIME_SERVER */
|
||||
|
||||
263
common/utils/time_manager/time_source.c
Normal file
263
common/utils/time_manager/time_source.c
Normal file
@@ -0,0 +1,263 @@
|
||||
/*
|
||||
* 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 "time_source.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <stdbool.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "common/utils/assertions.h"
|
||||
#include "common/utils/system.h"
|
||||
#include "common/utils/utils.h"
|
||||
|
||||
typedef void (*callback_function_t)(void *callback_data);
|
||||
typedef void * callback_data_t;
|
||||
|
||||
typedef struct {
|
||||
time_source_type_t type;
|
||||
volatile callback_function_t callback;
|
||||
volatile callback_data_t callback_data;
|
||||
_Atomic bool exit;
|
||||
void (*terminate)(void *this);
|
||||
pthread_t thread_id;
|
||||
pthread_mutex_t mutex;
|
||||
pthread_cond_t cond;
|
||||
} time_source_common_t;
|
||||
|
||||
typedef struct {
|
||||
time_source_common_t common;
|
||||
} time_source_realtime_t;
|
||||
|
||||
typedef struct {
|
||||
time_source_common_t common;
|
||||
volatile uint64_t iq_samples_count;
|
||||
volatile uint64_t iq_samples_per_second;
|
||||
} time_source_iq_t;
|
||||
|
||||
static void init_mutex(time_source_common_t *t)
|
||||
{
|
||||
int ret = pthread_mutex_init(&t->mutex, NULL);
|
||||
DevAssert(ret == 0);
|
||||
}
|
||||
|
||||
static void init_cond(time_source_common_t *t)
|
||||
{
|
||||
int ret = pthread_cond_init(&t->cond, NULL);
|
||||
DevAssert(ret == 0);
|
||||
}
|
||||
|
||||
static void lock(time_source_common_t *t)
|
||||
{
|
||||
int ret = pthread_mutex_lock(&t->mutex);
|
||||
DevAssert(ret == 0);
|
||||
}
|
||||
|
||||
static void unlock(time_source_common_t *t)
|
||||
{
|
||||
int ret = pthread_mutex_unlock(&t->mutex);
|
||||
DevAssert(ret == 0);
|
||||
}
|
||||
|
||||
static void condwait(time_source_common_t *t)
|
||||
{
|
||||
int ret = pthread_cond_wait(&t->cond, &t->mutex);
|
||||
DevAssert(ret == 0);
|
||||
}
|
||||
|
||||
static void condsignal(time_source_common_t *t)
|
||||
{
|
||||
int ret = pthread_cond_signal(&t->cond);
|
||||
DevAssert(ret == 0);
|
||||
}
|
||||
|
||||
static void wait_thread_termination(time_source_common_t *t)
|
||||
{
|
||||
void *retval;
|
||||
int ret = pthread_join(t->thread_id, &retval);
|
||||
DevAssert(ret == 0);
|
||||
}
|
||||
|
||||
static struct timespec next_ms(struct timespec t)
|
||||
{
|
||||
/* go to next millisecond */
|
||||
t.tv_nsec += 1000000;
|
||||
if (t.tv_nsec > 999999999) {
|
||||
t.tv_nsec -= 1000000000;
|
||||
t.tv_sec++;
|
||||
}
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
static void *time_source_realtime_thread(void *ts)
|
||||
{
|
||||
time_source_realtime_t *time_source = ts;
|
||||
|
||||
struct timespec now;
|
||||
if (clock_gettime(CLOCK_MONOTONIC, &now) == -1)
|
||||
AssertFatal(0, "clock_gettime failed\n");
|
||||
|
||||
/* go to next millisecond */
|
||||
now = next_ms(now);
|
||||
|
||||
while (!time_source->common.exit) {
|
||||
/* sleep */
|
||||
if (clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &now, NULL) == -1) {
|
||||
/* accept interruption by signals and then simply restart the sleep */
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
AssertFatal(0, "clock_nanosleep failed\n");
|
||||
}
|
||||
|
||||
if (time_source->common.exit)
|
||||
break;
|
||||
|
||||
/* tick */
|
||||
lock(&time_source->common);
|
||||
void (*callback)(void *callback_data) = time_source->common.callback;
|
||||
void *callback_data = time_source->common.callback_data;
|
||||
unlock(&time_source->common);
|
||||
if (callback != NULL)
|
||||
callback(callback_data);
|
||||
|
||||
/* go to next millisecond */
|
||||
now = next_ms(now);
|
||||
}
|
||||
|
||||
return (void *)0;
|
||||
}
|
||||
|
||||
static void *time_source_iq_samples_thread(void *ts)
|
||||
{
|
||||
time_source_iq_t *time_source = ts;
|
||||
|
||||
while (!time_source->common.exit) {
|
||||
/* wait until we have at least 1ms of IQ samples */
|
||||
lock(&time_source->common);
|
||||
while (!time_source->common.exit
|
||||
&& (time_source->iq_samples_per_second == 0
|
||||
|| time_source->iq_samples_count < time_source->iq_samples_per_second / 1000))
|
||||
condwait(&time_source->common);
|
||||
time_source->iq_samples_count -= time_source->iq_samples_per_second / 1000;
|
||||
unlock(&time_source->common);
|
||||
|
||||
if (time_source->common.exit)
|
||||
break;
|
||||
|
||||
/* tick */
|
||||
lock(&time_source->common);
|
||||
void (*callback)(void *callback_data) = time_source->common.callback;
|
||||
void *callback_data = time_source->common.callback_data;
|
||||
unlock(&time_source->common);
|
||||
if (callback != NULL)
|
||||
callback(callback_data);
|
||||
}
|
||||
|
||||
return (void *)0;
|
||||
}
|
||||
|
||||
static void time_source_iq_samples_terminate(void *ts)
|
||||
{
|
||||
time_source_iq_t *time_source = ts;
|
||||
condsignal(&time_source->common);
|
||||
}
|
||||
|
||||
time_source_t *new_time_source(time_source_type_t type)
|
||||
{
|
||||
time_source_t *ret = NULL;
|
||||
void *(*thread_function)(void *) = NULL;
|
||||
void (*terminate_function)(void *) = NULL;
|
||||
char *thread_function_name = NULL;
|
||||
|
||||
switch (type) {
|
||||
case TIME_SOURCE_REALTIME: {
|
||||
time_source_realtime_t *ts = calloc_or_fail(1, sizeof(*ts));
|
||||
thread_function = time_source_realtime_thread;
|
||||
thread_function_name = "time source realtime";
|
||||
ret = ts;
|
||||
break;
|
||||
}
|
||||
case TIME_SOURCE_IQ_SAMPLES: {
|
||||
time_source_iq_t *ts = calloc_or_fail(1, sizeof(*ts));
|
||||
thread_function = time_source_iq_samples_thread;
|
||||
terminate_function = time_source_iq_samples_terminate;
|
||||
thread_function_name = "time source iq samples";
|
||||
ret = ts;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
time_source_common_t *c = ret;
|
||||
c->type = type;
|
||||
init_mutex(c);
|
||||
init_cond(c);
|
||||
c->terminate = terminate_function;
|
||||
threadCreate(&c->thread_id, thread_function, c, thread_function_name, -1, SCHED_OAI);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void free_time_source(time_source_t *ts)
|
||||
{
|
||||
time_source_common_t *time_source = ts;
|
||||
time_source->exit = true;
|
||||
if (time_source->terminate != NULL)
|
||||
time_source->terminate(time_source);
|
||||
wait_thread_termination(time_source);
|
||||
free(time_source);
|
||||
}
|
||||
|
||||
void time_source_set_callback(time_source_t *ts,
|
||||
void (*callback)(void *),
|
||||
void *callback_data)
|
||||
{
|
||||
time_source_common_t *time_source = ts;
|
||||
lock(time_source);
|
||||
time_source->callback = callback;
|
||||
time_source->callback_data = callback_data;
|
||||
unlock(time_source);
|
||||
}
|
||||
|
||||
void time_source_iq_add(time_source_t *ts,
|
||||
uint64_t iq_samples_count,
|
||||
uint64_t iq_samples_per_second)
|
||||
{
|
||||
if (ts == NULL)
|
||||
return;
|
||||
|
||||
time_source_iq_t *time_source = ts;
|
||||
|
||||
if (time_source->common.type != TIME_SOURCE_IQ_SAMPLES)
|
||||
return;
|
||||
|
||||
lock(&time_source->common);
|
||||
|
||||
time_source->iq_samples_count += iq_samples_count;
|
||||
|
||||
if (time_source->iq_samples_per_second == 0)
|
||||
time_source->iq_samples_per_second = iq_samples_per_second;
|
||||
AssertFatal(time_source->iq_samples_per_second == iq_samples_per_second, "unsupported change of value 'IQ samples per second'\n");
|
||||
|
||||
condsignal(&time_source->common);
|
||||
unlock(&time_source->common);
|
||||
}
|
||||
@@ -19,37 +19,29 @@
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
/*! \file FGSRegistrationResult.h
|
||||
#ifndef COMMON_UTIL_TIME_MANAGER_TIME_SOURCE
|
||||
#define COMMON_UTIL_TIME_MANAGER_TIME_SOURCE
|
||||
|
||||
\brief 5GS Registration result for registration request procedures
|
||||
\author Yoshio INOUE, Masayuki HARADA
|
||||
\email: yoshio.inoue@fujitsu.com,masayuki.harada@fujitsu.com
|
||||
\date 2020
|
||||
\version 0.1
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "OctetString.h"
|
||||
/* opaque data type */
|
||||
typedef void time_source_t;
|
||||
|
||||
#ifndef FGS_REGISTRATION_RESULT_H_
|
||||
#define FGS_REGISTRATION_RESULT_H_
|
||||
#define FGS_REGISTRATION_RESULT_3GPP 0b001
|
||||
#define FGS_REGISTRATION_RESULT_NON_3GPP 0b010
|
||||
#define FGS_REGISTRATION_RESULT_3GPP_AND_NON_3GPP 0b011
|
||||
typedef enum {
|
||||
TIME_SOURCE_REALTIME,
|
||||
TIME_SOURCE_IQ_SAMPLES
|
||||
} time_source_type_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t iei;
|
||||
uint8_t resultlength;
|
||||
uint8_t spare: 4;
|
||||
uint8_t smsallowed: 1;
|
||||
uint8_t registrationresult: 3;
|
||||
} FGSRegistrationResult;
|
||||
time_source_t *new_time_source(time_source_type_t type);
|
||||
|
||||
uint16_t encode_fgs_registration_result(const FGSRegistrationResult *fgsregistrationresult);
|
||||
void free_time_source(time_source_t *time_source);
|
||||
|
||||
int decode_fgs_registration_result(FGSRegistrationResult *fgsregistrationresult, uint8_t iei, uint16_t value, uint32_t len);
|
||||
void time_source_set_callback(time_source_t *time_source,
|
||||
void (*callback)(void *),
|
||||
void *callback_data);
|
||||
|
||||
#endif /* FGS REGISTRATION RESULT_H_*/
|
||||
void time_source_iq_add(time_source_t *time_source,
|
||||
uint64_t iq_samples_count,
|
||||
uint64_t iq_samples_per_second);
|
||||
|
||||
#endif /* COMMON_UTIL_TIME_MANAGER_TIME_SOURCE */
|
||||
@@ -38,7 +38,7 @@
|
||||
int nas_sock_fd[MAX_MOBILES_PER_ENB * 2]; // Allocated for both LTE UE and NR UE.
|
||||
int nas_sock_mbms_fd;
|
||||
|
||||
static int tun_alloc(const char *dev)
|
||||
int tun_alloc(const char *dev)
|
||||
{
|
||||
struct ifreq ifr;
|
||||
int fd, err;
|
||||
@@ -157,13 +157,14 @@ static bool setInterfaceParameter(int sock_fd, const char *ifn, int af, const ch
|
||||
return success;
|
||||
}
|
||||
|
||||
/*
|
||||
* \brief bring interface up (up != 0) or down (up == 0)
|
||||
*/
|
||||
|
||||
typedef enum { INTERFACE_DOWN, INTERFACE_UP } if_action_t;
|
||||
/*
|
||||
* \brief bring interface up (up != 0) or down (up == 0)
|
||||
*/
|
||||
static bool change_interface_state(int sock_fd, const char *ifn, if_action_t if_action)
|
||||
{
|
||||
const char* action = if_action == INTERFACE_DOWN ? "DOWN" : "UP";
|
||||
const char *action = if_action == INTERFACE_DOWN ? "DOWN" : "UP";
|
||||
|
||||
struct ifreq ifr = {0};
|
||||
strncpy(ifr.ifr_name, ifn, sizeof(ifr.ifr_name));
|
||||
@@ -189,6 +190,7 @@ fail_interface_state:
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool tun_config(const char* ifname, const char *ipv4, const char *ipv6)
|
||||
{
|
||||
AssertFatal(ipv4 != NULL || ipv6 != NULL, "need to have IP address, but none given\n");
|
||||
@@ -262,3 +264,19 @@ int tun_generate_ifname(char *ifname, const char *ifprefix, int instance_id)
|
||||
{
|
||||
return snprintf(ifname, IFNAMSIZ, "%s%d", ifprefix, instance_id + 1);
|
||||
}
|
||||
|
||||
int tun_generate_ue_ifname(char *ifname, int instance_id, int pdu_session_id)
|
||||
{
|
||||
char pdu_session_string[10];
|
||||
snprintf(pdu_session_string, sizeof(pdu_session_string), "p%d", pdu_session_id);
|
||||
return snprintf(ifname, IFNAMSIZ, "%s%d%s", "oaitun_ue", instance_id + 1, pdu_session_id == -1 ? "" : pdu_session_string);
|
||||
}
|
||||
|
||||
void tun_destroy(const char *dev, int fd) {
|
||||
if (change_interface_state(fd, dev, INTERFACE_DOWN) == 0) {
|
||||
LOG_I(UTIL, "Interface %s is now down.\n", dev);
|
||||
} else {
|
||||
LOG_E(UTIL, "Could not bring interface %s down.\n", dev);
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
* \param[in] instance_id unique instance number
|
||||
*/
|
||||
int tun_generate_ifname(char *ifname, const char *ifprefix, int instance_id);
|
||||
int tun_generate_ue_ifname(char *ifname, int instance_id, int pdu_session_id);
|
||||
|
||||
/*!
|
||||
* \brief This function initializes the TUN interface
|
||||
@@ -73,4 +74,18 @@ bool tun_config(const char* ifname, const char *ipv4, const char *ipv6);
|
||||
*/
|
||||
void setup_ue_ipv4_route(const char* ifname, int instance_id, const char *ipv4);
|
||||
|
||||
/*!
|
||||
* \brief This function allocates a TUN interface
|
||||
* \param[in] dev name of the interface
|
||||
* \return file descriptor of the allocated interface
|
||||
*/
|
||||
int tun_alloc(const char *dev);
|
||||
|
||||
/*!
|
||||
* \brief This function destroys the TUN interface
|
||||
* \param[in] dev name of the interface
|
||||
* \param[in] fd file descriptor of the allocated interface
|
||||
*/
|
||||
void tun_destroy(const char *dev, int fd);
|
||||
|
||||
#endif /*TUN_IF_H_*/
|
||||
|
||||
@@ -24,8 +24,11 @@ The hardware on which we have tried this tutorial:
|
||||
|----------------------------------------------------------------------------|----------------------------------|--------------------------------------------------|
|
||||
| Gigabyte Edge E251-U70 (Intel Xeon Gold 6240R, 2.4GHz, 24C48T, 96GB DDR4) |Ubuntu 22.04.3 LTS (5.15.0-72-lowlatency)| NVIDIA ConnectX®-6 Dx 22.38.1002 |
|
||||
| Dell PowerEdge R750 (Dual Intel Xeon Gold 6336Y CPU @ 2.4G, 24C/48T (185W), 512GB RDIMM, 3200MT/s) |Ubuntu 22.04.3 LTS (5.15.0-72-lowlatency)| NVIDIA Converged Accelerator A100X (24.39.2048) |
|
||||
| Supermicro Grace Hopper MGX ARS-111GL-NHR (Neoverse-V2, 3.4GHz, 72C/72T, 576GB LPDDR5) | Ubuntu 22.04.5 LTS (6.5.0-1019-nvidia-64k) |NVIDIA BlueField3 (32.41.1000)|
|
||||
|
||||
**NOTE**: These are not minimum hardware requirements. This is the configuration of our servers. The NIC card should support hardware PTP time stamping.
|
||||
**NOTE**:
|
||||
- These are not minimum hardware requirements. This is the configuration of our servers. The NIC card should support hardware PTP time stamping.
|
||||
- Starting from tag [2025.w13](https://gitlab.eurecom.fr/oai/openairinterface5g/-/tree/2025.w13?ref_type=tags) of OAI, we are only testing with the Grace Hopper server.
|
||||
|
||||
PTP enabled switches and grandmaster clock we have tested with:
|
||||
|
||||
@@ -42,6 +45,7 @@ These are the radio units we've used for testing:
|
||||
|-------------|------------------|
|
||||
| Foxconn RPQN-7801E RU | 2.6.9r254 |
|
||||
| Foxconn RPQN-7801E RU | 3.1.15_0p4 |
|
||||
| Foxconn RPQN-7801E RU | v3.2.0q.551.12.E.rc2.srs-AIO |
|
||||
|
||||
|
||||
The UEs that have been tested and confirmed working with Aerial are the following:
|
||||
@@ -54,35 +58,30 @@ The UEs that have been tested and confirmed working with Aerial are the followin
|
||||
| Apaltec | Tributo 5G-Dongle |
|
||||
| OnePlus | Nord (AC2003) |
|
||||
| Apple iPhone | 14 Pro (MQ0G3RX/A) (iOS 17.3) |
|
||||
| Samsung | S23 Ultra |
|
||||
|
||||
|
||||
## Configure your server
|
||||
|
||||
The first step is to obtain the NVIDIA Aerial SDK, you'll need to request access [here](https://catalog.ngc.nvidia.com/orgs/nvidia/containers/aerial-sdk).
|
||||
|
||||
After obtaining access to the SDK, you can refer to [this instructions page](https://docs.nvidia.com/aerial/aerial-ran-colab-ota/current/index.html) to setup the L1 components using NVIDIAs' SDK manager, or to [this instructions page](https://docs.nvidia.com/aerial/cuda-accelerated-ran/index.html) in order to setup and install the components manually.
|
||||
|
||||
The currently used Aerial Version is 24-1, which is also the one currently used by the SDK Manager.
|
||||
To set up the L1 and install the components manually refer to this [instructions page](https://docs.nvidia.com/aerial/cuda-accelerated-ran/index.html).
|
||||
|
||||
**Note**:
|
||||
- To configure the Gigabyte server please refer to these [instructions](https://gitlab.eurecom.fr/oai/openairinterface5g/-/blob/2025.w13/doc/Aerial_FAPI_Split_Tutorial.md)
|
||||
- The last release to support the Gigabyte server is **Aerial CUDA-Accelerated RAN 24-1**.
|
||||
|
||||
### CPU allocation
|
||||
|
||||
Currently, the CPU isolation is setup the following:
|
||||
| Server brand | Model | Nº of CPU Cores | Isolated CPUs |
|
||||
|------------------|---------------|:---------------:|:--------------:|
|
||||
| Grace Hopper MGX | ARS-111GL-NHR | 72 | 4-64 |
|
||||
|
||||
| Server brand | Model | Nº of CPU Cores | Isolated CPUs |
|
||||
|--------------|-----------|:---------------:|:--------------:|
|
||||
| Gigabyte | Edge E251-U70 | 24 | 2-10 |
|
||||
|
||||
|
||||
**Gigabyte Edge E251-U70**
|
||||
**Grace Hopper MGX ARS-111GL-NHR**
|
||||
|
||||
| Applicative Threads | Allocated CPUs |
|
||||
|------------------------|----------------|
|
||||
| Aerial L1 | 2,3,4,5,6,7,8 |
|
||||
| PTP & PHC2SYS Services | 9 |
|
||||
| PTP & PHC2SYS Services | 41 |
|
||||
| OAI `nr-softmodem` | 13-20 |
|
||||
|
||||
|
||||
## PTP configuration
|
||||
|
||||
1. You need to install the `linuxptp` debian package. It will install both ptp4l and phc2sys.
|
||||
@@ -99,14 +98,10 @@ Once installed you can use this configuration file for ptp4l (`/etc/ptp4l.conf`)
|
||||
domainNumber 24
|
||||
slaveOnly 1
|
||||
time_stamping hardware
|
||||
tx_timestamp_timeout 1
|
||||
logging_level 6
|
||||
summary_interval 0
|
||||
#priority1 127
|
||||
tx_timestamp_timeout 30
|
||||
|
||||
[your_PTP_ENABLED_NIC]
|
||||
network_transport L2
|
||||
hybrid_e2e 0
|
||||
|
||||
```
|
||||
|
||||
@@ -120,7 +115,7 @@ Documentation=man:ptp4l
|
||||
Restart=always
|
||||
RestartSec=5s
|
||||
Type=simple
|
||||
ExecStart=taskset -c 9 /usr/sbin/ptp4l -f /etc/ptp.conf
|
||||
ExecStart=taskset -c 41 /usr/sbin/ptp4l -f /etc/ptp.conf
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
@@ -149,17 +144,16 @@ WantedBy=multi-user.target
|
||||
|
||||
# Build OAI gNB
|
||||
|
||||
If installing with the Aerial SDK, you should already have the repository cloned in `~/openairinterface5g`, if
|
||||
Clone OAI code base in a suitable repository, here we are cloning in `~/openairinterface5g` directory,
|
||||
|
||||
If it's not already cloned, the first step is to clone OAI repository
|
||||
```bash
|
||||
git clone https://gitlab.eurecom.fr/oai/openairinterface5g.git ~/openairinterface5g
|
||||
cd ~/openairinterface5g/
|
||||
```
|
||||
|
||||
## Get nvIPC sources from the L1 container
|
||||
The library used for communication between L1 and L2 components is called nvIPC, and was developed by NVIDIA, as such, it is not open-source and can't be freely distributed.
|
||||
In order to be able to use this library to achieve communication, we need to obtain the nvIPC source files from the L1 container (cuBB) and place it in out gNB project directory `~/openairinterface5g`.
|
||||
|
||||
The library used for communication between L1 and L2 components is called nvIPC, and is developed by NVIDIA. It is not open-source and can't be freely distributed.
|
||||
In order to achieve this communication, we need to obtain the nvIPC source files from the L1 container (cuBB) and place it in the gNB project directory `~/openairinterface5g`.
|
||||
This allows us to build and install this library when building the L2 docker container.
|
||||
|
||||
Check whether your L1 container is running:
|
||||
@@ -177,7 +171,7 @@ cuBB
|
||||
aerial@c_aerial_aerial:/opt/nvidia/cuBB#
|
||||
```
|
||||
|
||||
After logging into the container, we need to pack the nvIPC sources and copy them to the host ( the command creates a tar.gz file with the following name format: nvipc_src.YYYY.MM.DD.tar.gz)
|
||||
After logging into the container, you need to pack the nvIPC sources and copy them to the host ( the command creates a `tar.gz` file with the following name format: `nvipc_src.YYYY.MM.DD.tar.gz`)
|
||||
```bash
|
||||
~$ docker exec -it cuBB bash
|
||||
aerial@c_aerial_aerial:/opt/nvidia/cuBB# cd cuPHY-CP/gt_common_libs
|
||||
@@ -216,7 +210,7 @@ With the nvIPC sources in the project directory, the docker image can be built.
|
||||
|
||||
## Building OAI gNB docker image
|
||||
|
||||
In order to build the final image, there is an intermediary image to be built (ran-base)
|
||||
In order to build the target image (`oai-gnb-aerial`), first you should build a common shared image (`ran-base`)
|
||||
```bash
|
||||
~$ cd ~/openairinterface5g/
|
||||
~/openairinterface5g$ docker build . -f docker/Dockerfile.base.ubuntu22 --tag ran-base:latest
|
||||
@@ -224,21 +218,23 @@ In order to build the final image, there is an intermediary image to be built (r
|
||||
```
|
||||
|
||||
|
||||
## Running the setup
|
||||
In order to use Docker compose to automatically start and stop the setup, we need to first create a ready-made image of the L1, after compiling the L1 software and making the necessary adjustments to its configuration files.
|
||||
The process of preparing the L1 is covered on NVIDIAs' documentation, and falls outside the scope of this document.
|
||||
# Running the setup
|
||||
|
||||
### Prepare the L1 image
|
||||
After preparing the L1 software, the container needs to be committed in order for an image in which the L1 is ready to be executed, and that can be referenced by a docker-compose.yaml file later:
|
||||
*Note:* In preparing the L1 image, the default L1 configuration file is cuphycontroller_P5G_FXN.yaml, located in `/opt/nvidia/cuBB/cuPHY-CP/cuphycontroller/config/`.
|
||||
This is the file where the RU MAC address needs to be applied before commiting the image
|
||||
In order to use Docker Compose to automatically start and stop the setup, we first need to create a pre-built image of L1 after compiling the L1 software and making the necessary adjustments to its configuration files.
|
||||
The process of preparing L1 is covered in NVIDIA's documentation and falls outside the scope of this document.
|
||||
|
||||
## Prepare the L1 image
|
||||
After preparing the L1 software, the container needs to be committed to create an image where L1 is ready for execution, which can later be referenced by a `docker-compose.yaml` file.
|
||||
|
||||
*Note:* The default L1 configuration file is `cuphycontroller_P5G_FXN_GH.yaml`, located in `/opt/nvidia/cuBB/cuPHY-CP/cuphycontroller/config/`.
|
||||
In this file the RU MAC address needs to be specified before commiting the image.
|
||||
|
||||
```bash
|
||||
~$ docker commit nv-cubb cubb-build:24-1
|
||||
~$ docker commit nv-cubb cubb-build:24-3
|
||||
~$ docker image ls
|
||||
..
|
||||
cubb-build 24-1 824156e0334c 2 weeks ago 40.1GB
|
||||
..
|
||||
cubb-build 24-3 824156e0334c 2 weeks ago 23.9GB
|
||||
-..
|
||||
```
|
||||
|
||||
## Adapt the OAI-gNB configuration file to your system/workspace
|
||||
@@ -255,14 +251,12 @@ The default amf_ip_address:ipv4 value is 192.168.70.132, when installing the CN5
|
||||
Both 'GNB_IPV4_ADDRESS_FOR_NG_AMF' and 'GNB_IPV4_ADDRESS_FOR_NGU' need to be set to the IP address of the NIC referenced previously.
|
||||
|
||||
|
||||
### Running docker compose
|
||||
#### Aerial L1 entrypoint script
|
||||
Before running docker-compose, we can check which L1 configuration file is to be used by cuphycontroller_scf.
|
||||
This is set in the script [`aerial_l1_entrypoint.sh`](../ci-scripts/yaml_files/sa_gnb_aerial/aerial_l1_entrypoint.sh), which is used by the L1 container in order to start the L1 software.
|
||||
The script begins by setting up some environment variables, restarting NVIDIA MPS, and finally running cuphycontroller_scf.
|
||||
The L1 software is run with an argument that indicates which configuration file is to be used.
|
||||
This argument may be changed by providing an argument to the [`aerial_l1_entrypoint.sh`](../ci-scripts/yaml_files/sa_gnb_aerial/aerial_l1_entrypoint.sh) call in [`docker-compose.yaml`](../ci-scripts/yaml_files/sa_gnb_aerial/docker-compose.yaml).
|
||||
When no argument is provided (this is the default behaviour), it uses "P5G_FXN" as the cuphycontroller_scf argument.
|
||||
## Running docker compose
|
||||
### Aerial L1 entrypoint script
|
||||
The `aerial_l1_entrypoint` script is used by the L1 container to start the L1 software and is called in the Docker Compose file.
|
||||
It begins by setting up environment variables, restarting NVIDIA MPS, and finally running `cuphycontroller_scf`.
|
||||
|
||||
The L1 software is executed with an argument that specifies which configuration file to use. If not modified, the default argument is set to `P5G_FXN_GH`.
|
||||
|
||||
After building the gNB image, and preparing the configuration file, the setup can be run with the following command:
|
||||
|
||||
@@ -271,17 +265,18 @@ cd ci-scripts/yaml_files/sa_gnb_aerial/
|
||||
docker compose up -d
|
||||
|
||||
```
|
||||
This will start both containers, beginning with 'nv-cubb' and only after it being ready it starts 'oai-gnb-aerial'.
|
||||
This will start both containers, beginning with `nv-cubb`, and `oai-gnb-aerial` will start only after it is ready.
|
||||
|
||||
The gNB logs can be followed with:
|
||||
The logs can be followed using these commands:
|
||||
|
||||
```bash
|
||||
docker logs -f oai-gnb-aerial
|
||||
docker logs -f nv-cubb
|
||||
```
|
||||
#### Running with multiple L2s
|
||||
### Running with multiple L2s
|
||||
One L1 instance can support multiple L2 instances. See also the [aerial documentation](https://developer.nvidia.com/docs/gputelecom/aerial-sdk/text/cubb_quickstart/running_cubb-end-to-end.html#run-multiple-l2-instances-with-single-l1-instance) for more details.
|
||||
|
||||
In OAI the share memory prefix must be configured in the configuration file.
|
||||
In OAI the shared memory prefix must be configured in the configuration file.
|
||||
|
||||
```bash
|
||||
tr_s_preference = "aerial";
|
||||
@@ -289,9 +284,9 @@ In OAI the share memory prefix must be configured in the configuration file.
|
||||
```
|
||||
|
||||
|
||||
### Stopping the setup
|
||||
## Stopping the setup
|
||||
|
||||
Running the following command, will stop both containers, leaving the system ready to be run later:
|
||||
Run the following command to stop and remove both containers, leaving the system ready to be restarted later:
|
||||
```bash
|
||||
cd ci-scripts/yaml_files/sa_gnb_aerial/
|
||||
docker compose down
|
||||
|
||||
@@ -105,7 +105,7 @@ These modes of operation are supported:
|
||||
|
||||
- MAC -> PHY configuration using NR FAPI P5 interface
|
||||
- MAC <-> PHY data interface using FAPI P7 interface for BCH PDU, DCI PDU, PDSCH PDU
|
||||
- Scheduler procedures for SIB1
|
||||
- Generation of and scheduler procedures for MIB/SIB1
|
||||
- Scheduler procedures for RA
|
||||
- 4-Step RA
|
||||
- Contention Free RA procedure
|
||||
@@ -140,6 +140,7 @@ These modes of operation are supported:
|
||||
- MAC scheduling of SR reception
|
||||
- Intra-frequency handover
|
||||
- Initial support for RedCap
|
||||
- Scheduling of SIBs (2, 19)
|
||||
|
||||
## gNB RLC
|
||||
|
||||
@@ -174,7 +175,7 @@ These modes of operation are supported:
|
||||
|
||||
- NR RRC (38.331) Rel 17 messages using new [asn1c](https://github.com/mouse07410/asn1c)
|
||||
- LTE RRC (36.331) also updated to Rel 15
|
||||
- Generation of MIB/SIB1 (received from DU)
|
||||
- Generation of system information (SIB2)
|
||||
- RRC can configure PDCP, RLC, MAC
|
||||
- Interface with GTP-U (tunnel creation/handling for S1-U (NSA), N3 (SA), F1 interfaces)
|
||||
- Integration of RRC messages and procedures supporting UE 5G SA connection
|
||||
|
||||
@@ -232,7 +232,9 @@ In the `MACRLCs` section of the gNB/DU configuration file:
|
||||
|
||||
In the `gNBs` section of the gNB/DU configuration file: some of the parameters
|
||||
affect RRC configuration (CellGroupConfig) of a UE, and are therefore listed
|
||||
here, *also they pertain to the DU*, i.e., the scheduler.
|
||||
here, *also they pertain to the DU*, i.e., the scheduler. Note also that some
|
||||
SIBs are configured at the DU and some at the CU; please consult the [RRC
|
||||
configuration](../RRC/rrc-usage.md) as well for SIB configuration.
|
||||
|
||||
* `pdsch_AntennaPorts_XP` (default 1): number of XP logical antenna
|
||||
ports in PDSCH (see also [`RUNMODEM.md`](../RUNMODEM.md))
|
||||
@@ -248,6 +250,8 @@ here, *also they pertain to the DU*, i.e., the scheduler.
|
||||
* `do_CSIRS` (default 0): flag whether to use channel-state information
|
||||
reference signal (CSI-RS)
|
||||
* `do_SRS` (default 0): flag whether to use sounding reference signal (SRS)
|
||||
* `do_SINR` (default 0): flag whether to enable CSI reporting of SSB-SINR (introduced in rel16)
|
||||
Default setting of CSI reporting quantity is SSB-RSRP.
|
||||
* `min_rxtxtime` (default 2): minimum feedback time for UE to respond to
|
||||
transmissions (k1 and k2 in 3GPP spec)
|
||||
* `ul_prbblacklist`: PRBs that should not be used for UL scheduling. Cf with
|
||||
@@ -267,6 +271,20 @@ here, *also they pertain to the DU*, i.e., the scheduler.
|
||||
options are 2, 4, 6, 8, 10, 12, 32; **32 is a Rel-17 features**)
|
||||
* `num_ulharq` (default 16): as `num_dlharq` for UL (other valid option is 32;
|
||||
**32 is i Rel-17 feature**)
|
||||
- `du_sibs` (default `[]`): list of SIBs to transmit in the cell. Currently,
|
||||
SIB19 (for NTN) is supported.
|
||||
|
||||
| DL MIMO |`do_CSIRS`|`do_SINR`| CSI report Quantity |
|
||||
| ---------------------------- | -------- | ------- | --------------------------------------------------|
|
||||
| OFF (pdsch_AntennaPorts = 1) | 0 | 0 | SSB-RSRP |
|
||||
| OFF (pdsch_AntennaPorts = 1) | 0 | 1 | SSB-SINR |
|
||||
| OFF (pdsch_AntennaPorts = 1) | 1 | 0 | CSI-Reference signal RSRP |
|
||||
| OFF (pdsch_AntennaPorts = 1) | 1 | 1 | CSI-Reference signal SINR (not supported yet) |
|
||||
| ON (pdsch_AntennaPorts > 1) | 1 | 0 | cri-RI-PMI-CQI |
|
||||
|
||||
DL-MIMO is configured using following parameters:
|
||||
`pdsch_AntennaPorts_XP` , `pdsch_AntennaPorts_N1` , `pdsch_AntennaPorts_N2`, `maxMIMO_layers`
|
||||
(see also [`RUNMODEM.md`](../RUNMODEM.md))
|
||||
|
||||
## ServingCellConfigCommon parameters
|
||||
|
||||
|
||||
@@ -108,6 +108,7 @@ Legacy unmaintained files:
|
||||
- The [shared object loader](../common/utils/DOC/loader.md)
|
||||
- The [threadpool](../common/utils/threadPool/thread-pool.md) used in L1
|
||||
- The [LDPC implementation](../openair1/PHY/CODING/DOC/LDPCImplementation.md) is a shared library
|
||||
- The [time management](time_management.md) module
|
||||
|
||||
## Radios
|
||||
|
||||
|
||||
@@ -67,6 +67,9 @@ RRC-specific configuration
|
||||
|
||||
### cell-specific options
|
||||
|
||||
Note that some SIBS are configured at the CU and some at the DU; please consult
|
||||
the [MAC configuration](../MAC/mac-usage.md) as well for SIB configuration.
|
||||
|
||||
- `gNB_ID` and `gNB_name`: ID and name of the gNB
|
||||
- `tracking_area_code`: the current tracking area code in the range `[0x0001,
|
||||
0xfffd]`
|
||||
@@ -84,6 +87,8 @@ RRC-specific configuration
|
||||
- `enable_sdap` (default: false): enable the use of the SDAP layer. If
|
||||
deactivated, a transparent SDAP header is prepended to packets, but no
|
||||
further processing is being done.
|
||||
- `cu_sibs` (default: `[]`) list of SIBs to give to the DU for transmission.
|
||||
Currently, SIB2 is supported.
|
||||
|
||||
### UE-specific configuration
|
||||
|
||||
|
||||
@@ -136,7 +136,15 @@ Here are some useful command line options for the NR UE:
|
||||
| Parameter | Description |
|
||||
|--------------------------|---------------------------------------------------------------------------------------------------------------|
|
||||
| `--ue-scan-carrier` | Scan for cells in current bandwidth. This option can be used if the SSB position of the gNB is unknown. If multiple cells are detected, the UE will try to connect to the first cell. By default, this option is disabled and the UE attempts to only decode SSB given by `--ssb`. |
|
||||
| `--ue-fo-compensation` | Enables the frequency offset compensation at the UE. Useful when running over the air and/or without an external clock/time source. |
|
||||
| `--ue-fo-compensation` | Enables the initial frequency offset compensation at the UE. Useful when running over the air and/or without an external clock/time source. |
|
||||
| `--cont-fo-comp` | Enables the continuous frequency offset (FO) estimation and compensation. Parameter value `1` specifies that the main FO contribution comes from the local oscillator's (LO) accuracy. Parameter value `2` specifies that the main FO contribution comes from Doppler shift. |
|
||||
| `--initial-fo` | Sets the known initial frequency offset. Useful especially with large Doppler frequency, e.g. LEO satellite. |
|
||||
| `--freq-sync-P` | Sets the coefficient for the Proportional part of the PI-controller for the continuous frequency offset compensation. Default value 0.01. |
|
||||
| `--freq-sync-I` | Sets the coefficient for the Integrating part of the PI-controller for the continuous frequency offset compensation. Default value 0.001. |
|
||||
| `--ntn-initial-time-drift` | Sets the initial NTN DL time drift (feeder link and service link), given in µs/s. |
|
||||
| `--autonomous-ta` | Enables the autonomous TA update, based on DL drift (useful if main contribution to DL drift is movement, e.g. LEO satellite). |
|
||||
| `--time-sync-P` | Sets the coefficient for the Proportional part of the PI-controller for the time synchronization. Default value 0.5. |
|
||||
| `--time-sync-I` | Sets the coefficient for the Integrating part of the PI-controller for the time synchronization. Default value 0.0. |
|
||||
| `--usrp-args` | Equivalent to the `sdr_addrs` field in the gNB config file. Used to identify the USRP and set some basic parameters (like the clock source). |
|
||||
| `--clock-source` | Sets the clock source (internal or external). |
|
||||
| `--time-source` | Sets the time source (internal or external). |
|
||||
@@ -349,10 +357,16 @@ For LEO satellite scenarios, the parameter `--ntn-initial-time-drift` must be pr
|
||||
This parameter provides the drift rate of the complete DL timing (incl. feeder link and service link) in µs/s.
|
||||
Also, to perform an autonomous TA update based on the DL drift, the boolean parameter `--autonomous-ta` should be added in case of a LEO satellite scenario.
|
||||
|
||||
For LEO satellite scenario we assume the LO to be very accurate and the main FO contribution comes from Doppler shift.
|
||||
Therefore, we use the command line parameter `--cont-fo-comp 2` to continuously compensate the DL Doppler and pre-compensate the UL Doppler.
|
||||
The initial Doppler frequency offset must be provided via command line with the parameter `--initial-fo`.
|
||||
|
||||
For other information on optional NR UE command line options, please refer [here](#optional-nr-ue-command-line-options).
|
||||
|
||||
So an example NR UE command for FDD, 5MHz BW, 15 kHz SCS, transparent LEO satellite 5G NR NTN is this:
|
||||
```
|
||||
cd cmake_targets
|
||||
sudo ./ran_build/build/nr-uesoftmodem -O ../targets/PROJECTS/GENERIC-NR-5GC/CONF/ue.conf --band 254 -C 2488400000 --CO -873500000 -r 25 --numerology 0 --ssb 60 --rfsim --rfsimulator.prop_delay 20 --rfsimulator.options chanmod --time-sync-I 0.1 --ntn-initial-time-drift -46 --autonomous-ta
|
||||
sudo ./ran_build/build/nr-uesoftmodem -O ../targets/PROJECTS/GENERIC-NR-5GC/CONF/ue.conf --band 254 -C 2488400000 --CO -873500000 -r 25 --numerology 0 --ssb 60 --rfsim --rfsimulator.prop_delay 20 --rfsimulator.options chanmod --time-sync-I 0.1 --ntn-initial-time-drift -46 --autonomous-ta --initial-fo 57340 --cont-fo-comp 2
|
||||
```
|
||||
|
||||
# Specific OAI modes
|
||||
|
||||
@@ -298,7 +298,7 @@ Even, a future evolution could remove this global rlc layer: rlc can be only a l
|
||||
When adding a UE, external code have to call `add_rlc_srb()` and/or `add_rlc_drb()`, to remove it: `rrc_rlc_remove_ue()`
|
||||
Inside UE, channels called drd or srb can be created: ??? and deleted: rrc_rlc_config_req()
|
||||
|
||||
nr_rlc_tick() must be called periodically to manage the internal timers
|
||||
nr_rlc_ms_tick() must be called periodically to manage the internal timers
|
||||
|
||||
successful_delivery() and max_retx_reached(): in ??? trigger, the RLC sends a itti message to RRC: RLC_SDU_INDICATION (neutralized by #if 0 right now)
|
||||
|
||||
@@ -329,7 +329,7 @@ To manage UE connections, `nr_pdcp_add_srbs()` is employed for adding UE SRBs in
|
||||
|
||||
## PDCP Tx flow
|
||||
|
||||
On the Tx side (downlink in gNB), the entry functions `nr_pdcp_data_req_drb()` and `nr_pdcp_data_req_srb()` are called by the upper layer. The upper layer could be GTP or a PDCP internal thread like `enb_tun_read_thread()`, which reads directly from the Linux socket if the 3GPP core implementation is skipped. The PDCP internals for `nr_pdcp_data_req_srb()` and `nr_pdcp_data_req_drb()` are thread-safe. Within these functions, the PDCP manager protects access to the SDU receiving function of PDCP (`recv_sdu()` callback, corresponding to `nr_pdcp_entity_recv_pdu()` for DRBs) using mutex. When necessary, the PDCP layer pushes this data to RLC by calling `rlc_data_req()`.
|
||||
On the Tx side (downlink in gNB), the entry functions `nr_pdcp_data_req_drb()` and `nr_pdcp_data_req_srb()` are called by the upper layer. The upper layer could be GTP or a PDCP internal thread like `gnb_tun_read_thread()`, which reads directly from the Linux socket if the 3GPP core implementation is skipped. The PDCP internals for `nr_pdcp_data_req_srb()` and `nr_pdcp_data_req_drb()` are thread-safe. Within these functions, the PDCP manager protects access to the SDU receiving function of PDCP (`recv_sdu()` callback, corresponding to `nr_pdcp_entity_recv_pdu()` for DRBs) using mutex. When necessary, the PDCP layer pushes this data to RLC by calling `rlc_data_req()`.
|
||||
|
||||
## PDCP Rx flow
|
||||
|
||||
|
||||
@@ -19,10 +19,10 @@
|
||||
| starsky | Starsky | eNB (B40) | b200mini (30A3E3C) |
|
||||
| carabe | Carabe | UE (B7UE) | B200mini (30AE8C9) |
|
||||
| avra | Avra | gNB (n78) | AW2S Jaguar (192.168.80.239) |
|
||||
| aerial2 | Aerial2 | gNB (PNF/Nvidia CUBB + VNF) | Foxconn RU, _Nvidia Aerial SDK integrated_ |
|
||||
| cacofonix | Cacofonix | gNB (n78, FHI7.2) | -- |
|
||||
| matix | Matix | gNB (n77) | N310 |
|
||||
| gracehopper1-oai | Gracehopper1 | build, gNB/Aerial | _Nvidia Aerial SDK integrated_ |
|
||||
| gracehopper1-oai | Gracehopper1 | gNB (n78, PNF/Nvidia CUBB + VNF) | Foxconn RU, _Nvidia Aerial integration_ |
|
||||
| gracehopper3-oai | Gracehopper3 | build | -- |
|
||||
|
||||
Note: The available resources, and their current usage, is indicated here:
|
||||
- [Lockable resources of jenkins-oai](https://jenkins-oai.eurecom.fr/lockable-resources/):
|
||||
@@ -127,7 +127,7 @@ information on how the images are built.
|
||||
- build unit tests from `ci-scripts/docker/Dockerfile.unittest.ubuntu22`, and run them
|
||||
- [RAN-Ubuntu-ARM-Image-Builder](https://jenkins-oai.eurecom.fr/job/RAN-Ubuntu-ARM-Image-Builder/)
|
||||
~BUILD-ONLY ~4G-LTE ~5G-NR
|
||||
- gracehopper1-oai: ARM Ubuntu 22 image build using docker
|
||||
- gracehopper3-oai: ARM Ubuntu 22 image build using docker
|
||||
- base image from `Dockerfile.base.ubuntu22`
|
||||
- build image from `Dockerfile.build.ubuntu22`, followed by
|
||||
- target image from `Dockerfile.gNB.ubuntu22`
|
||||
@@ -199,7 +199,7 @@ information on how the images are built.
|
||||
- OpenShift cluster for CN deployment and container images for gNB and UE deployment
|
||||
- [RAN-SA-AERIAL-CN5G](https://jenkins-oai.eurecom.fr/job/RAN-SA-AERIAL-CN5G/)
|
||||
~5G-NR
|
||||
- 5G-NR SA test setup: OAI VNF + PNF/NVIDIA CUBB on Aerial2 + Foxconn RU, up2 + COTS UE (Quectel RM520N), OAI CN5G
|
||||
- 5G-NR SA test setup: OAI VNF + PNF/NVIDIA CUBB on gracehopper1-oai + Foxconn RU, up2 + COTS UE (Quectel RM520N), OAI CN5G
|
||||
- container images for gNB deployment
|
||||
- [RAN-SA-2x2-Module-CN5G](https://jenkins-oai.eurecom.fr/view/RAN/job/RAN-SA-2x2-Module-CN5G/)
|
||||
~5G-NR
|
||||
|
||||
@@ -29,6 +29,25 @@ cd cmake_targets/ran_build/build
|
||||
sudo LD_LIBRARY_PATH=. ./nr-softmodem ...
|
||||
```
|
||||
|
||||
### Possible problems
|
||||
|
||||
On some systems with specific ASan versions, executing a program compiled with
|
||||
ASan might fail with an error `DEADLYSIGNAL`, or simply a segmentation fault.
|
||||
Note that since OAI compiles and runs some programs _during compilation_ (for
|
||||
code generation), typically already the build is impacted.
|
||||
|
||||
The issue is related to Address Space Layout Randomization (ASLR) settings
|
||||
in Linux, a security feature designed to make it more difficult for attackers
|
||||
to predict the locations of processes in memory. In this case, it is possible
|
||||
to avoid the bug by running
|
||||
|
||||
```
|
||||
sudo sysctl vm.mmap_rnd_bits=30
|
||||
```
|
||||
|
||||
which reduces the number of bits for memory mappings used to randomize mmap
|
||||
base addresses. _This reduces the security of the system._
|
||||
|
||||
## Undefined Behavior Sanitizer (UBSAN)
|
||||
[Undefined Behavior Sanitizer](https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html) (UBSAN) is a runtime undefined behavior checker. It uses compile-time instrumentation to catch undefined behavior by inserting code that performs specific checks before operations that may cause it. UBSAN can be activated with the `--sanitize-undefined` option or `-fsanitize=undefined`.
|
||||
|
||||
|
||||
BIN
doc/testbenches_doc_resources/5g-ota-bench.pdf
Normal file
BIN
doc/testbenches_doc_resources/5g-ota-bench.pdf
Normal file
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 92 KiB After Width: | Height: | Size: 80 KiB |
@@ -13,15 +13,15 @@
|
||||
duplexer/.style={draw,fill=white},
|
||||
]
|
||||
|
||||
\node[label=above:porcepix] (porcepix)
|
||||
\node[label=above:cluster] (cluster)
|
||||
{\includegraphics[width=1.2cm]{server}};
|
||||
|
||||
\node[above right=-0.8cm and 2cm of porcepix, label=above:aerial2] (aerial2)
|
||||
\node[above right=-0.6cm and 2cm of cluster, label=above:gracehopper1-oai] (gracehopper1-oai)
|
||||
{\includegraphics[width=1.2cm]{server}}
|
||||
edge (porcepix);
|
||||
\node[right=0.3cm of aerial2, label=above:Foxconn, draw,
|
||||
edge (cluster);
|
||||
\node[right=0.3cm of gracehopper1-oai, label=above:Foxconn, draw,
|
||||
minimum width=1.7cm, minimum height=0.8cm] (foxconn)
|
||||
{O-RU} edge (aerial2);
|
||||
{O-RU} edge (gracehopper1-oai);
|
||||
\node[below right=+0.45cm and 0.35cm of foxconn.east] (antf1)
|
||||
{\includegraphics[width=0.3cm]{antenna}} edge (foxconn.east);
|
||||
\node[below right=-0.1cm and 0.35cm of foxconn.east] (antf2)
|
||||
@@ -31,7 +31,7 @@
|
||||
\node[above right=+0.45cm and 0.35cm of foxconn.east] (antf4)
|
||||
{\includegraphics[width=0.3cm]{antenna}} edge (foxconn.east);
|
||||
|
||||
\node[above right=+1.3cm and 2cm of porcepix, label=above:matix] (matix)
|
||||
\node[above right=+1.5cm and 2cm of cluster, label=above:matix] (matix)
|
||||
{\includegraphics[width=1.2cm]{server}};
|
||||
\node[right=0.3cm of matix, label=above:N310] (n310a)
|
||||
{\includegraphics[width=1.5cm]{n310}} edge (matix);
|
||||
@@ -41,22 +41,9 @@
|
||||
\node[above right=-0.1cm and 0.35cm of b77o.east] (anto2)
|
||||
{\includegraphics[width=0.3cm]{antenna}} edge (b77o);
|
||||
|
||||
\node[below right=-0.6cm and 2cm of porcepix, label=above:obelix] (obelix)
|
||||
\node[below right=-0.4cm and 2cm of cluster, label=above:cacofonix] (cacofonix)
|
||||
{\includegraphics[width=1.2cm]{server}}
|
||||
edge (porcepix);
|
||||
\node[right=0.3cm of obelix, label=above:N310] (n310o)
|
||||
{\includegraphics[width=1.5cm]{n310}} edge (obelix);
|
||||
\node[right=.2cm of n310o, duplexer] (b78o) {n40} edge (n310o);
|
||||
\node[below right=-0.1cm and 0.35cm of b78o.east] (anto1)
|
||||
{\includegraphics[width=0.3cm]{antenna}} edge (b78o);
|
||||
\node[above right=-0.1cm and 0.35cm of b78o.east] (anto2)
|
||||
{\includegraphics[width=0.3cm]{antenna}} edge (b78o);
|
||||
|
||||
\node[below=2cm of porcepix, label=above:Cluster] (cluster)
|
||||
{\includegraphics[width=1.2cm]{server}};
|
||||
\node[right=2cm of cluster, label=above:cacofonix] (cacofonix)
|
||||
{\includegraphics[width=1.2cm]{server}}
|
||||
edge (cluster);
|
||||
edge (cluster);
|
||||
\node[right=0.3cm of cacofonix, label=above:VVDN, draw,
|
||||
minimum width=1.7cm, minimum height=0.8cm] (vvdn)
|
||||
{O-RU} edge (cacofonix);
|
||||
@@ -69,7 +56,28 @@
|
||||
\node[above right=+0.45cm and 0.35cm of vvdn.east] (antv4)
|
||||
{\includegraphics[width=0.3cm]{antenna}} edge (vvdn.east);
|
||||
|
||||
\node[above right=+0.0cm and 5.0cm of n310o.east, label=above:RM520N-GL] (quectel)
|
||||
\node[below=2cm of cluster, label=above:porcepix] (porcepix)
|
||||
{\includegraphics[width=1.2cm]{server}};
|
||||
\node[right=2cm of porcepix, label=above:obelix] (obelix)
|
||||
{\includegraphics[width=1.2cm]{server}}
|
||||
edge (porcepix);
|
||||
\node[right=0.3cm of obelix, label=above:N310] (n310o)
|
||||
{\includegraphics[width=1.5cm]{n310}} edge (obelix);
|
||||
\node[right=.2cm of n310o, duplexer] (b78o) {n40} edge (n310o);
|
||||
\node[below right=-0.1cm and 0.35cm of b78o.east] (anto1)
|
||||
{\includegraphics[width=0.3cm]{antenna}} edge (b78o);
|
||||
\node[above right=-0.1cm and 0.35cm of b78o.east] (anto2)
|
||||
{\includegraphics[width=0.3cm]{antenna}} edge (b78o);
|
||||
|
||||
%\node[right=0.3cm of cacofonix, label=above:N310] (n310o)
|
||||
% {\includegraphics[width=1.5cm]{n310}} edge (cacofonix);
|
||||
\node[right=.2cm of n310o, duplexer] (b78o) {n40} edge (n310o);
|
||||
\node[below right=-0.1cm and 0.35cm of b78o.east] (anto1)
|
||||
{\includegraphics[width=0.3cm]{antenna}} edge (b78o);
|
||||
\node[above right=-0.1cm and 0.35cm of b78o.east] (anto2)
|
||||
{\includegraphics[width=0.3cm]{antenna}} edge (b78o);
|
||||
|
||||
\node[above right=+0.0cm and 5.0cm of vvdn.east, label=above:RM520N-GL] (quectel)
|
||||
{\includegraphics[height=1.2cm]{quectel}};
|
||||
\node[above left=-0.1cm and 0.8cm of quectel.west] (aq2)
|
||||
{\includegraphics[width=0.3cm]{antenna}} edge (quectel);
|
||||
|
||||
286
doc/time_management.md
Normal file
286
doc/time_management.md
Normal file
@@ -0,0 +1,286 @@
|
||||
# Time management module
|
||||
|
||||
[[_TOC_]]
|
||||
|
||||
## Introduction
|
||||
|
||||
Several parts of the 4G/5G protocol stack keep track of time, for example
|
||||
for timeout events (in RRC, PDCP, or RLC for example).
|
||||
|
||||
The obvious simple way to deal with time is to use the computer's realtime
|
||||
clock. This works well when we run the stack in realtime, with real
|
||||
radio equipment. But in simulation the system may run faster or slower
|
||||
than realtime, so we need another way to deal with time. A good solution
|
||||
is then to base time on the current IQ data processed by the system. So time
|
||||
becomes "IQ samples" based, not realtime.
|
||||
|
||||
The system may be decomposed into various components (CU, DU, RU, various
|
||||
UEs) running either in realtime or simulation. Time may be distributed
|
||||
to all these components from only one time source for accurate execution
|
||||
of the scenario, or each component may have its own time source, either
|
||||
based on realtime or IQ samples.
|
||||
|
||||
## Overall structure
|
||||
|
||||
The time management module is made of three main parts. The first one
|
||||
is the time source. It can either be realtime or "IQ samples" based.
|
||||
In one running scenario of the system, there can be one or more time
|
||||
sources (imagine one for the gNB, and one per each UE). There can also
|
||||
be only one time source, shared between various users of the time
|
||||
manager.
|
||||
|
||||
The second part is the server. One server is attached to one time source
|
||||
and receives a tick every millisecond (real or simulated) from the time
|
||||
source. It distributes the tick to the various connected clients.
|
||||
|
||||
And finally the last part is the client, which connects to a single server
|
||||
and receives ticks from it. The client does not have a time source attached
|
||||
to it. It gets the time from the server.
|
||||
|
||||
It is possible for a program (monolithic gNB for example) to have only
|
||||
a time source, without server or client.
|
||||
|
||||
## Configuration
|
||||
|
||||
To configure the time management module, add the following section in
|
||||
the configuration file.
|
||||
|
||||
```
|
||||
time_management = {
|
||||
#valid time sources: realtime, iq_samples
|
||||
time_source = realtime
|
||||
|
||||
#valid modes: standalone, server, client
|
||||
mode = standalone
|
||||
|
||||
#set ip/port of server (for server mode, this is the address/port to bind to;
|
||||
#for client mode, this is the address/port to connect to)
|
||||
server_ip = "127.0.0.1"
|
||||
server_port = 7374
|
||||
}
|
||||
```
|
||||
|
||||
If not set in the configuration file, some default is applied, depending
|
||||
on the program run. (See the function `time_manager_start()` for details.)
|
||||
|
||||
It is also possible to pass configuration parameters on the command line.
|
||||
For example add `--time_manager.time_source iq_samples` to the command line
|
||||
to set the time source to `iq_samples`. The same syntax is applicable to the
|
||||
other parameters.
|
||||
|
||||
## Examples
|
||||
|
||||
Here come some examples of configuration for typical use cases of OAI.
|
||||
|
||||
### Monolithic gNB realtime
|
||||
|
||||
This is a very simple example. The gNB runs in `standalone` mode with
|
||||
a `realtime` time source.
|
||||
|
||||
```
|
||||
time_management = {
|
||||
time_source = realtime
|
||||
mode = standalone
|
||||
}
|
||||
```
|
||||
### Monolithic gNB "IQ samples time"
|
||||
|
||||
For this configuration, it's the same as the previous example, but the
|
||||
time source is now `iq_samples`.
|
||||
|
||||
```
|
||||
time_management = {
|
||||
time_source = iq_samples
|
||||
mode = standalone
|
||||
}
|
||||
```
|
||||
### RF simulator CU/DU "IQ samples time"
|
||||
|
||||
Let's suppose the CU runs on a machine with IP address 1.2.3.4 and the DU
|
||||
runs on a machine with IP address 10.11.12.13.
|
||||
|
||||
The DU has the time source and so is the server. The CU acts as a client.
|
||||
|
||||
Here comes the configuration for the CU.
|
||||
|
||||
```
|
||||
time_management = {
|
||||
mode = client
|
||||
server_ip = "10.11.12.13"
|
||||
server_port = 7374
|
||||
}
|
||||
```
|
||||
And here is the configuration for the DU.
|
||||
|
||||
```
|
||||
time_management = {
|
||||
time_source = iq_samples
|
||||
mode = server
|
||||
server_ip = "10.11.12.13"
|
||||
server_port = 7374
|
||||
}
|
||||
```
|
||||
|
||||
### RF simulator CU/DU "realtime"
|
||||
|
||||
Let's suppose the CU runs on a machine with IP address 1.2.3.4 and the DU
|
||||
runs on a machine with IP address 10.11.12.13.
|
||||
|
||||
CU and DU can both run in standalone mode, with no exchange between them.
|
||||
Any one of them can also acts as a server and the other one as a client.
|
||||
|
||||
Let's suppose for this example that the CU and the DU run in client/server
|
||||
mode. Let's set the CU as the time source and so as the server. The DU acts
|
||||
as a client.
|
||||
|
||||
Here comes the configuration for the CU.
|
||||
|
||||
```
|
||||
time_management = {
|
||||
time_source = realtime
|
||||
mode = server
|
||||
server_ip = "1.2.3.4"
|
||||
server_port = 7374
|
||||
}
|
||||
```
|
||||
And here is the configuration for the DU.
|
||||
|
||||
```
|
||||
time_management = {
|
||||
mode = client
|
||||
server_ip = "1.2.3.4"
|
||||
server_port = 7374
|
||||
}
|
||||
```
|
||||
|
||||
Note that the time management module is flexible. It's possible to
|
||||
configure more complex setups. For example the time source can be a gNB
|
||||
and several UEs can be connected as client.
|
||||
|
||||
One could also write a simple program acting as a time source and distributing
|
||||
time to everyone (one or several gNB, several UEs).
|
||||
|
||||
## Programming API
|
||||
|
||||
Here comes the internal API of the time manager module. The (simpler) OAI
|
||||
API is described afterwards.
|
||||
|
||||
### Time source
|
||||
|
||||
- opaque type: `time_source_t`
|
||||
- create a time source:
|
||||
```
|
||||
time_source_t *new_time_source(time_source_type_t type)
|
||||
```
|
||||
where `type` is one of:
|
||||
* `TIME_SOURCE_REALTIME`
|
||||
* `TIME_SOURCE_IQ_SAMPLES`
|
||||
- delete a time source:
|
||||
```
|
||||
void free_time_source(time_source_t *time_source)
|
||||
```
|
||||
- set millisecond callback:
|
||||
```
|
||||
void time_source_set_callback(time_source_t *time_source,
|
||||
void (*callback)(void *),
|
||||
void *callback_data)
|
||||
```
|
||||
where `callback` is a function that will be called for each millisecond using
|
||||
the provided `callback_data`
|
||||
- for IQ samples time management, the user of the time source must call
|
||||
this function when it processes IQ samples:
|
||||
```
|
||||
void time_source_iq_add(time_source_t *time_source,
|
||||
uint64_t iq_samples_count,
|
||||
uint64_t iq_samples_per_second)
|
||||
```
|
||||
then the time source will generate a tick for each block for IQ samples
|
||||
lasting one millisecond. (If you pass `iq_samples_count` lasting several
|
||||
milliseconds then the time source will generate several ticks in a row,
|
||||
one for each millisecond.)
|
||||
|
||||
### Server
|
||||
|
||||
- opaque type: `time_server_t`
|
||||
- create a server:
|
||||
```
|
||||
time_server_t *new_time_server(const char *ip,
|
||||
int port,
|
||||
void (*callback)(void *),
|
||||
void *callback_data)
|
||||
```
|
||||
where ip/port is the IP adress and port the server will listen to
|
||||
and `callback` is a function that will be called for each millisecond using
|
||||
the provided `callback_data`
|
||||
- delete a server:
|
||||
```
|
||||
void free_time_server(time_server_t *time_server)
|
||||
```
|
||||
- attach a time source:
|
||||
```
|
||||
void time_server_attach_time_source(time_server_t *time_server,
|
||||
time_source_t *time_source)
|
||||
```
|
||||
|
||||
### Client
|
||||
|
||||
- opaque type: `time_client_t`
|
||||
- create a client:
|
||||
```
|
||||
time_client_t *new_time_client(const char *server_ip,
|
||||
int server_port,
|
||||
void (*callback)(void *),
|
||||
void *callback_data)
|
||||
```
|
||||
the client will connect on given server ip/port
|
||||
and use the `callback` with `callback_data` for each tick received
|
||||
- delete a client:
|
||||
```
|
||||
void free_time_client(time_client_t *time_client)
|
||||
```
|
||||
|
||||
### Threading
|
||||
|
||||
Each component (time source, server, client) runs its own thread which will
|
||||
be the one calling the configured callback. Be careful of using proper
|
||||
synchronization techniques in your callback to have correct behavior with
|
||||
the other threads of the program.
|
||||
|
||||
## OAI API
|
||||
|
||||
OAI uses the time manager through a simplified API. All the code is contained
|
||||
in `time_manager.c`, together with some global variables (so that there is no
|
||||
need to pass objects around, to limit risks of misuse).
|
||||
|
||||
Each program (for example: gnb, ue, cu, du) calls the `time_manager_start()`
|
||||
function, passing the callback functions to be called when a tick is generated
|
||||
(several callbacks can be passed) and a default time source. Based on this,
|
||||
`time_manager_start()` initializes what is needed.
|
||||
|
||||
The function `time_manager_iq_samples()` is to be called by programs that
|
||||
read IQ samples. It is called unconditionally. It may do nothing if the
|
||||
configuration is to use realtime ticks and not IQ samples ticks.
|
||||
|
||||
When the program exits, it calls `timer_manager_finish()` which in turns stops
|
||||
the various threads created by `time_manager_start()` and releases all the
|
||||
allocated data.
|
||||
|
||||
Here comes the API.
|
||||
|
||||
- init the time manager:
|
||||
```
|
||||
void time_manager_start(time_manager_tick_function_t *tick_functions,
|
||||
int tick_functions_count,
|
||||
time_source_type_t time_source);
|
||||
```
|
||||
(for valid values of `client_type` and `running_mode` see in
|
||||
`time_manager.h`)
|
||||
- update IQ samples' based time manager:
|
||||
```
|
||||
void time_manager_iq_samples(uint64_t iq_samples_count,
|
||||
uint64_t iq_samples_per_second)
|
||||
```
|
||||
- terminate the time manager:
|
||||
```
|
||||
void time_manager_finish(void)
|
||||
```
|
||||
@@ -31,6 +31,7 @@
|
||||
#include "openair2/F1AP/f1ap_ids.h"
|
||||
#include "openair2/GNB_APP/gnb_config.h"
|
||||
#include "nr_pdcp/nr_pdcp_oai_api.h"
|
||||
#include "common/utils/time_manager/time_manager.h"
|
||||
|
||||
RAN_CONTEXT_t RC;
|
||||
THREAD_STRUCT thread_struct;
|
||||
@@ -139,6 +140,16 @@ int main(int argc, char **argv)
|
||||
exit_fun("[SOFTMODEM] Error, configuration module init failed\n");
|
||||
}
|
||||
logInit();
|
||||
|
||||
// start time manager with some reasonable default for the running mode
|
||||
// (may be overwritten in configuration file or command line)
|
||||
void nr_pdcp_ms_tick(void);
|
||||
time_manager_tick_function_t tick_functions[] = {
|
||||
nr_pdcp_ms_tick
|
||||
};
|
||||
int tick_functions_count = 1;
|
||||
time_manager_start(tick_functions, tick_functions_count, TIME_SOURCE_REALTIME);
|
||||
|
||||
// strdup to put the sring in the core file for post mortem identification
|
||||
LOG_I(HW, "Version: %s\n", strdup(OAI_PACKAGE_VERSION));
|
||||
set_softmodem_sighandler();
|
||||
@@ -177,6 +188,8 @@ int main(int argc, char **argv)
|
||||
printf("TYPE <CTRL-C> TO TERMINATE\n");
|
||||
itti_wait_tasks_end(NULL);
|
||||
|
||||
time_manager_finish();
|
||||
|
||||
logClean();
|
||||
printf("Bye.\n");
|
||||
return 0;
|
||||
|
||||
@@ -31,54 +31,45 @@
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <pthread.h>
|
||||
#undef MALLOC //there are two conflicting definitions, so we better make sure we don't use it at all
|
||||
|
||||
#include "assertions.h"
|
||||
#include <common/utils/LOG/log.h>
|
||||
#include <common/utils/system.h>
|
||||
|
||||
#include "PHY/types.h"
|
||||
|
||||
#include "PHY/INIT/nr_phy_init.h"
|
||||
|
||||
#include "PHY/defs_gNB.h"
|
||||
#include "SCHED_NR/sched_nr.h"
|
||||
#include "SCHED_NR/fapi_nr_l1.h"
|
||||
#include "PHY/NR_TRANSPORT/nr_transport_proto.h"
|
||||
#include "PHY/MODULATION/nr_modulation.h"
|
||||
#include "PHY/NR_TRANSPORT/nr_dlsch.h"
|
||||
#include "openair2/NR_PHY_INTERFACE/nr_sched_response.h"
|
||||
#include "LAYER2/NR_MAC_gNB/mac_proto.h"
|
||||
|
||||
#include "radio/COMMON/common_lib.h"
|
||||
#include "PHY/LTE_TRANSPORT/if4_tools.h"
|
||||
|
||||
#include "PHY/phy_extern.h"
|
||||
|
||||
#include "common/ran_context.h"
|
||||
#include "RRC/LTE/rrc_extern.h"
|
||||
#include "PHY_INTERFACE/phy_interface.h"
|
||||
#include <fcntl.h> // for SEEK_SET
|
||||
#include <pthread.h> // for pthread_join
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include "common/utils/LOG/log.h"
|
||||
#include "common/utils/system.h"
|
||||
#include "PHY/NR_ESTIMATION/nr_ul_estimation.h"
|
||||
#include "openair1/PHY/NR_TRANSPORT/nr_dlsch.h"
|
||||
#include "openair1/PHY/NR_TRANSPORT/nr_ulsch.h"
|
||||
#include "NR_PHY_INTERFACE/NR_IF_Module.h"
|
||||
#include "PHY/INIT/nr_phy_init.h"
|
||||
#include "PHY/MODULATION/nr_modulation.h"
|
||||
#include "PHY/NR_TRANSPORT/nr_transport_proto.h"
|
||||
#include "PHY/TOOLS/tools_defs.h"
|
||||
#include "PHY/defs_RU.h"
|
||||
#include "PHY/defs_common.h"
|
||||
#include "PHY/defs_gNB.h"
|
||||
#include "PHY/defs_nr_common.h"
|
||||
#include "PHY/impl_defs_nr.h"
|
||||
#include "SCHED_NR/fapi_nr_l1.h"
|
||||
#include "SCHED_NR/phy_frame_config_nr.h"
|
||||
#include "SCHED_NR/sched_nr.h"
|
||||
#include "assertions.h"
|
||||
#include "common/ran_context.h"
|
||||
#include "common/utils/LOG/log.h"
|
||||
#include "UTIL/OTG/otg_tx.h"
|
||||
#include "UTIL/OTG/otg_externs.h"
|
||||
#include "common/utils/LOG/vcd_signal_dumper.h"
|
||||
#include "UTIL/OPT/opt.h"
|
||||
#include "gnb_paramdef.h"
|
||||
|
||||
#include <executables/softmodem-common.h>
|
||||
|
||||
#include "T.h"
|
||||
#include "nfapi/oai_integration/vendor_ext.h"
|
||||
#include "executables/softmodem-common.h"
|
||||
#include <nfapi/oai_integration/nfapi_pnf.h>
|
||||
#include <openair1/PHY/NR_TRANSPORT/nr_ulsch.h>
|
||||
#include <openair1/PHY/NR_TRANSPORT/nr_dlsch.h>
|
||||
#include <PHY/NR_ESTIMATION/nr_ul_estimation.h>
|
||||
#include "nfapi/oai_integration/vendor_ext.h"
|
||||
#include "nfapi_nr_interface_scf.h"
|
||||
#include "notified_fifo.h"
|
||||
#include "openair2/NR_PHY_INTERFACE/nr_sched_response.h"
|
||||
#include "thread-pool.h"
|
||||
#include "time_meas.h"
|
||||
#include "utils.h"
|
||||
|
||||
// #define USRP_DEBUG 1
|
||||
#include "executables/thread-common.h"
|
||||
|
||||
//#define TICK_TO_US(ts) (ts.diff)
|
||||
#define TICK_TO_US(ts) (ts.trials==0?0:ts.diff/ts.trials)
|
||||
#define L1STATSSTRLEN 16384
|
||||
static void rx_func(processingData_L1_t *param);
|
||||
|
||||
@@ -47,6 +47,7 @@
|
||||
#include "SCHED_NR/sched_nr.h"
|
||||
|
||||
#include "common/utils/LOG/log.h"
|
||||
#include "common/utils/time_manager/time_manager.h"
|
||||
#include "common/utils/LOG/vcd_signal_dumper.h"
|
||||
|
||||
#include <executables/softmodem-common.h>
|
||||
@@ -1249,6 +1250,10 @@ void *ru_thread(void *param)
|
||||
slot++;
|
||||
}
|
||||
|
||||
// pretend we have 1 iq sample per slot
|
||||
// and so slots_per_frame * 100 iq samples per second (1 frame being 10ms)
|
||||
time_manager_iq_samples(1, fp->slots_per_frame * 100);
|
||||
|
||||
// synchronization on input FH interface, acquire signals/data and block
|
||||
LOG_D(PHY,"[RU_thread] read data: frame_rx = %d, tti_rx = %d\n", frame, slot);
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include "PHY/TOOLS/smbv.h"
|
||||
unsigned short config_frames[4] = {2,9,11,13};
|
||||
#endif
|
||||
#include "common/utils/time_manager/time_manager.h"
|
||||
#ifdef ENABLE_AERIAL
|
||||
#include "nfapi/oai_integration/aerial/fapi_nvIPC.h"
|
||||
#endif
|
||||
@@ -85,6 +86,7 @@ unsigned short config_frames[4] = {2,9,11,13};
|
||||
#include "utils.h"
|
||||
#include "x2ap_eNB.h"
|
||||
#include "openair1/SCHED_NR/sched_nr.h"
|
||||
#include "openair2/SDAP/nr_sdap/nr_sdap.h"
|
||||
|
||||
pthread_cond_t nfapi_sync_cond;
|
||||
pthread_mutex_t nfapi_sync_mutex;
|
||||
@@ -464,23 +466,14 @@ int start_L1L2(module_id_t gnb_id)
|
||||
|
||||
NR_BCCH_BCH_Message_t *mib = mac->common_channels[0].mib;
|
||||
const NR_BCCH_DL_SCH_Message_t *sib1 = mac->common_channels[0].sib1;
|
||||
|
||||
/* update existing config in F1 Setup request structures */
|
||||
f1ap_setup_req_t *sr = mac->f1_config.setup_req;
|
||||
DevAssert(sr->num_cells_available == 1);
|
||||
f1ap_served_cell_info_t *info = &sr->cell[0].info;
|
||||
DevAssert(info->mode == F1AP_MODE_TDD);
|
||||
/* update existing config in F1 Setup request structures */
|
||||
DevAssert(scc->tdd_UL_DL_ConfigurationCommon != NULL);
|
||||
info->tdd = read_tdd_config(scc); /* updates radio config */
|
||||
/* send gNB-DU configuration update to RRC */
|
||||
f1ap_gnb_du_configuration_update_t update = {
|
||||
.transaction_id = 1,
|
||||
.num_cells_to_modify = 1,
|
||||
};
|
||||
update.cell_to_modify[0].old_nr_cellid = info->nr_cellid;
|
||||
update.cell_to_modify[0].info = *info;
|
||||
update.cell_to_modify[0].sys_info = get_sys_info(mib, sib1);
|
||||
mac->mac_rrc.gnb_du_configuration_update(&update);
|
||||
prepare_du_configuration_update(mac, info, mib, sib1);
|
||||
|
||||
init_NR_RU(config_get_if(), NULL);
|
||||
|
||||
@@ -506,11 +499,8 @@ static void wait_nfapi_init(char *thread_name)
|
||||
}
|
||||
|
||||
void init_pdcp(void) {
|
||||
uint32_t pdcp_initmask = IS_SOFTMODEM_NOS1 ? ENB_NAS_USE_TUN_BIT : LINK_ENB_PDCP_TO_GTPV1U_BIT;
|
||||
|
||||
if (!NODE_IS_DU(get_node_type())) {
|
||||
nr_pdcp_layer_init();
|
||||
nr_pdcp_module_init(pdcp_initmask, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -529,9 +519,9 @@ static void initialize_agent(ngran_node_t node_type, e2_agent_args_t oai_args)
|
||||
const gNB_RRC_INST* rrc = RC.nrrrc[0];
|
||||
assert(rrc != NULL && "rrc cannot be NULL");
|
||||
|
||||
const int mcc = rrc->configuration.mcc[0];
|
||||
const int mnc = rrc->configuration.mnc[0];
|
||||
const int mnc_digit_len = rrc->configuration.mnc_digit_length[0];
|
||||
const int mcc = rrc->configuration.plmn[0].mcc;
|
||||
const int mnc = rrc->configuration.plmn[0].mnc;
|
||||
const int mnc_digit_len = rrc->configuration.plmn[0].mnc_digit_length;
|
||||
// const ngran_node_t node_type = rrc->node_type;
|
||||
int nb_id = 0;
|
||||
int cu_du_id = 0;
|
||||
@@ -608,8 +598,6 @@ int main( int argc, char **argv ) {
|
||||
char *pckg = strdup(OAI_PACKAGE_VERSION);
|
||||
LOG_I(HW, "Version: %s\n", pckg);
|
||||
|
||||
// don't create if node doesn't connect to RRC/S1/GTP
|
||||
const ngran_node_t node_type = get_node_type();
|
||||
// Init RAN context
|
||||
if (!(CONFIG_ISFLAGSET(CONFIG_ABORT)))
|
||||
NRRCConfig();
|
||||
@@ -624,6 +612,9 @@ int main( int argc, char **argv ) {
|
||||
RCconfig_nr_prs();
|
||||
}
|
||||
|
||||
// don't create if node doesn't connect to RRC/S1/GTP
|
||||
const ngran_node_t node_type = get_node_type();
|
||||
|
||||
if (NFAPI_MODE != NFAPI_MODE_PNF) {
|
||||
int ret = create_gNB_tasks(node_type, uniqCfg);
|
||||
AssertFatal(ret == 0, "cannot create ITTI tasks\n");
|
||||
@@ -638,6 +629,38 @@ int main( int argc, char **argv ) {
|
||||
pthread_mutex_init(&sync_mutex, NULL);
|
||||
}
|
||||
|
||||
// start time manager with some reasonable default for the running mode
|
||||
// (may be overwritten in configuration file or command line)
|
||||
void nr_pdcp_ms_tick(void);
|
||||
void x2ap_ms_tick();
|
||||
void nr_rlc_ms_tick(void);
|
||||
time_manager_tick_function_t tick_functions[3];
|
||||
int tick_functions_count = 0;
|
||||
if (NODE_IS_MONOLITHIC(node_type)) {
|
||||
/* monolithic */
|
||||
tick_functions[tick_functions_count++] = nr_pdcp_ms_tick;
|
||||
tick_functions[tick_functions_count++] = nr_rlc_ms_tick;
|
||||
/* x2ap is enabled when in NSA mode */
|
||||
if (get_softmodem_params()->nsa)
|
||||
tick_functions[tick_functions_count++] = x2ap_ms_tick;
|
||||
} else if (NODE_IS_CU(node_type)) {
|
||||
/* CU */
|
||||
tick_functions[tick_functions_count++] = nr_pdcp_ms_tick;
|
||||
/* x2ap is enabled when in NSA mode */
|
||||
if (get_softmodem_params()->nsa)
|
||||
tick_functions[tick_functions_count++] = x2ap_ms_tick;
|
||||
} else {
|
||||
/* DU */
|
||||
tick_functions[tick_functions_count++] = nr_rlc_ms_tick;
|
||||
}
|
||||
time_manager_start(tick_functions, tick_functions_count,
|
||||
// iq_samples time source for monolithic/du with rfsim,
|
||||
// realtime time source for other cases
|
||||
IS_SOFTMODEM_RFSIM
|
||||
&& (NODE_IS_MONOLITHIC(node_type) || NODE_IS_DU(node_type))
|
||||
? TIME_SOURCE_IQ_SAMPLES
|
||||
: TIME_SOURCE_REALTIME);
|
||||
|
||||
// start the main threads
|
||||
number_of_cards = 1;
|
||||
|
||||
@@ -740,6 +763,8 @@ int main( int argc, char **argv ) {
|
||||
pthread_cond_destroy(&nfapi_sync_cond);
|
||||
pthread_mutex_destroy(&nfapi_sync_mutex);
|
||||
|
||||
time_manager_finish();
|
||||
|
||||
free(pckg);
|
||||
logClean();
|
||||
printf("Bye.\n");
|
||||
|
||||
@@ -41,6 +41,8 @@
|
||||
#include "instrumentation.h"
|
||||
#include "common/utils/threadPool/notified_fifo.h"
|
||||
#include "position_interface.h"
|
||||
#include "nr_phy_common.h"
|
||||
#include "common/utils/time_manager/time_manager.h"
|
||||
|
||||
/*
|
||||
* NR SLOT PROCESSING SEQUENCE
|
||||
@@ -104,7 +106,9 @@ static void *NRUE_phy_stub_standalone_pnf_task(void *arg);
|
||||
static void start_process_slot_tx(void* arg) {
|
||||
notifiedFIFO_elt_t *newTx = arg;
|
||||
nr_rxtx_thread_data_t *curMsgTx = NotifiedFifoData(newTx);
|
||||
pushNotifiedFIFO(&curMsgTx->UE->ul_actor.fifo, newTx);
|
||||
int num_ul_actors_to_use =
|
||||
get_nrUE_params()->num_ul_actors == 0 ? NUM_UL_ACTORS : min(get_nrUE_params()->num_ul_actors, NUM_UL_ACTORS);
|
||||
pushNotifiedFIFO(&curMsgTx->UE->ul_actors[curMsgTx->proc.nr_slot_tx % num_ul_actors_to_use].fifo, newTx);
|
||||
}
|
||||
|
||||
static size_t dump_L1_UE_meas_stats(PHY_VARS_NR_UE *ue, char *output, size_t max_len)
|
||||
@@ -436,9 +440,13 @@ static void UE_synch(void *arg) {
|
||||
((ret.rx_offset << 1) / fp->samples_per_subframe * fp->slots_per_subframe)
|
||||
+ round((float)((ret.rx_offset << 1) % fp->samples_per_subframe) / fp->samples_per_slot0);
|
||||
|
||||
// rerun with new cell parameters and frequency-offset
|
||||
// todo: the freq_offset computed on DL shall be scaled before being applied to UL
|
||||
nr_rf_card_config_freq(cfg0, ul_carrier, dl_carrier, freq_offset);
|
||||
if (get_nrUE_params()->cont_fo_comp) {
|
||||
UE->freq_offset = freq_offset;
|
||||
} else {
|
||||
// rerun with new cell parameters and frequency-offset
|
||||
nr_rf_card_config_freq(cfg0, ul_carrier, dl_carrier, freq_offset);
|
||||
UE->rfdevice.trx_set_freq_func(&UE->rfdevice, cfg0);
|
||||
}
|
||||
|
||||
if (get_nrUE_params()->agc) {
|
||||
nr_ue_adjust_rx_gain(UE, cfg0, UE->adjust_rxgain);
|
||||
@@ -452,7 +460,6 @@ static void UE_synch(void *arg) {
|
||||
cfg0->rx_freq[0],
|
||||
cfg0->tx_freq[0]);
|
||||
|
||||
UE->rfdevice.trx_set_freq_func(&UE->rfdevice, cfg0);
|
||||
UE->is_synchronized = 1;
|
||||
} else {
|
||||
int gain_change = 0;
|
||||
@@ -551,6 +558,15 @@ static void RU_write(nr_rxtx_thread_data_t *rxtxD, bool sl_tx_action)
|
||||
writeBlockSize -= dummyBlockSize;
|
||||
}
|
||||
|
||||
// pre-compensate UL frequency offset
|
||||
if (flags != TX_BURST_INVALID && get_nrUE_params()->cont_fo_comp) {
|
||||
double ul_freq_offset = -UE->freq_offset * ((double)fp->ul_CarrierFreq / (double)fp->dl_CarrierFreq);
|
||||
if (get_nrUE_params()->cont_fo_comp == 2) // different from LO frequency error compensation, Doppler UL pre-compensation has to be negative
|
||||
ul_freq_offset = -ul_freq_offset;
|
||||
for (int i = 0; i < fp->nb_antennas_tx; i++)
|
||||
nr_fo_compensation(ul_freq_offset, fp->samples_per_subframe, writeTimestamp, txp[i], txp[i], writeBlockSize);
|
||||
}
|
||||
|
||||
int tmp = openair0_write_reorder(&UE->rfdevice, writeTimestamp, txp, writeBlockSize, fp->nb_antennas_tx, flags);
|
||||
AssertFatal(tmp == writeBlockSize, "");
|
||||
}
|
||||
@@ -585,6 +601,7 @@ void processSlotTX(void *arg)
|
||||
UE->if_inst->sl_indication(&sl_indication);
|
||||
stop_meas(&UE->ue_ul_indication_stats);
|
||||
}
|
||||
dynamic_barrier_join(rxtxD->next_barrier);
|
||||
|
||||
if (phy_data.sl_tx_action) {
|
||||
|
||||
@@ -611,12 +628,14 @@ void processSlotTX(void *arg)
|
||||
UE->if_inst->ul_indication(&ul_indication);
|
||||
stop_meas(&UE->ue_ul_indication_stats);
|
||||
}
|
||||
dynamic_barrier_join(rxtxD->next_barrier);
|
||||
|
||||
phy_procedures_nrUE_TX(UE, proc, &phy_data);
|
||||
}
|
||||
} else {
|
||||
dynamic_barrier_join(rxtxD->next_barrier);
|
||||
}
|
||||
RU_write(rxtxD, sl_tx_action);
|
||||
dynamic_barrier_join(rxtxD->next_barrier);
|
||||
TracyCZoneEnd(ctx);
|
||||
}
|
||||
|
||||
@@ -656,7 +675,9 @@ static int handle_sync_req_from_mac(PHY_VARS_NR_UE *UE)
|
||||
for (int i = 0; i < NUM_DL_ACTORS; i++) {
|
||||
flush_actor(UE->dl_actors + i);
|
||||
}
|
||||
flush_actor(&UE->ul_actor);
|
||||
for (int i = 0; i < NUM_UL_ACTORS; i++) {
|
||||
flush_actor(UE->ul_actors + i);
|
||||
}
|
||||
|
||||
clean_UE_harq(UE);
|
||||
UE->is_synchronized = 0;
|
||||
@@ -686,16 +707,6 @@ static int UE_dl_preprocessing(PHY_VARS_NR_UE *UE,
|
||||
process_msg_rcc_to_mac(msg);
|
||||
} while (msg);
|
||||
|
||||
if (IS_SOFTMODEM_NOS1 || IS_SA_MODE(get_softmodem_params())) {
|
||||
/* send tick to RLC and PDCP every ms */
|
||||
if (proc->nr_slot_rx % fp->slots_per_subframe == 0) {
|
||||
void nr_rlc_tick(int frame, int subframe);
|
||||
void nr_pdcp_tick(int frame, int subframe);
|
||||
nr_rlc_tick(proc->frame_rx, proc->nr_slot_rx / fp->slots_per_subframe);
|
||||
nr_pdcp_tick(proc->frame_rx, proc->nr_slot_rx / fp->slots_per_subframe);
|
||||
}
|
||||
}
|
||||
|
||||
if (UE->if_inst)
|
||||
UE->if_inst->slot_indication(UE->Mod_id, false);
|
||||
|
||||
@@ -861,13 +872,12 @@ static inline int get_readBlockSize(uint16_t slot, NR_DL_FRAME_PARMS *fp) {
|
||||
static inline void apply_ntn_config(PHY_VARS_NR_UE *UE,
|
||||
NR_DL_FRAME_PARMS *fp,
|
||||
int slot_nr,
|
||||
bool *update_ntn_system_information,
|
||||
int *duration_rx_to_tx,
|
||||
int *timing_advance,
|
||||
int *ntn_koffset)
|
||||
{
|
||||
if (*update_ntn_system_information) {
|
||||
*update_ntn_system_information = false;
|
||||
if (UE->ntn_config_message->update) {
|
||||
UE->ntn_config_message->update = false;
|
||||
|
||||
double total_ta_ms = UE->ntn_config_message->ntn_config_params.ntn_total_time_advance_ms;
|
||||
UE->timing_advance = fp->samples_per_subframe * total_ta_ms;
|
||||
@@ -913,6 +923,8 @@ void *UE_thread(void *arg)
|
||||
if (usrp_tx_thread == 1)
|
||||
UE->rfdevice.trx_write_init(&UE->rfdevice);
|
||||
|
||||
InitSinLUT();
|
||||
|
||||
notifiedFIFO_t nf;
|
||||
initNotifiedFIFO(&nf);
|
||||
|
||||
@@ -947,13 +959,9 @@ void *UE_thread(void *arg)
|
||||
|
||||
double ntn_init_time_drift = get_nrUE_params()->ntn_init_time_drift;
|
||||
int ntn_koffset = 0;
|
||||
|
||||
int duration_rx_to_tx = NR_UE_CAPABILITY_SLOT_RX_TO_TX;
|
||||
int nr_slot_tx_offset = 0;
|
||||
bool update_ntn_system_information = false;
|
||||
|
||||
while (!oai_exit) {
|
||||
nr_slot_tx_offset = 0;
|
||||
if (syncRunning) {
|
||||
notifiedFIFO_elt_t *res = pollNotifiedFIFO(&nf);
|
||||
|
||||
@@ -1078,11 +1086,9 @@ void *UE_thread(void *arg)
|
||||
absolute_slot++;
|
||||
TracyCFrameMark;
|
||||
|
||||
if (UE->ntn_config_message->update) {
|
||||
UE->ntn_config_message->update = false;
|
||||
update_ntn_system_information = true;
|
||||
nr_slot_tx_offset = UE->ntn_config_message->ntn_config_params.cell_specific_k_offset << fp->numerology_index;
|
||||
}
|
||||
// pretend we have 1 iq sample per slot
|
||||
// and so nb_slot_frame * 100 iq samples per second (1 frame being 10ms)
|
||||
time_manager_iq_samples(1, nb_slot_frame * 100);
|
||||
|
||||
int slot_nr = absolute_slot % nb_slot_frame;
|
||||
nr_rxtx_thread_data_t curMsg = {0};
|
||||
@@ -1173,8 +1179,8 @@ void *UE_thread(void *arg)
|
||||
shiftForNextFrame = ret;
|
||||
pushNotifiedFIFO(&UE->dl_actors[curMsg.proc.nr_slot_rx % NUM_DL_ACTORS].fifo, newRx);
|
||||
|
||||
// apply new duration next run to avoid thread dead lock
|
||||
apply_ntn_config(UE, fp, slot_nr, &update_ntn_system_information, &duration_rx_to_tx, &timing_advance, &ntn_koffset);
|
||||
// apply new NTN timing information
|
||||
apply_ntn_config(UE, fp, slot_nr, &duration_rx_to_tx, &timing_advance, &ntn_koffset);
|
||||
|
||||
// Start TX slot processing here. It runs in parallel with RX slot processing
|
||||
// in current code, DURATION_RX_TO_TX constant is the limit to get UL data to encode from a RX slot
|
||||
@@ -1185,7 +1191,6 @@ void *UE_thread(void *arg)
|
||||
curMsgTx->writeBlockSize = writeBlockSize;
|
||||
curMsgTx->proc.timestamp_tx = writeTimestamp;
|
||||
curMsgTx->UE = UE;
|
||||
curMsgTx->proc.nr_slot_tx_offset = nr_slot_tx_offset;
|
||||
|
||||
int slot = curMsgTx->proc.nr_slot_tx;
|
||||
int slot_and_frame = slot + curMsgTx->proc.frame_tx * UE->frame_parms.slots_per_frame;
|
||||
|
||||
@@ -60,6 +60,7 @@
|
||||
unsigned short config_frames[4] = {2,9,11,13};
|
||||
#endif
|
||||
#include "common/utils/LOG/log.h"
|
||||
#include "common/utils/time_manager/time_manager.h"
|
||||
#include "common/utils/LOG/vcd_signal_dumper.h"
|
||||
|
||||
#include "UTIL/OPT/opt.h"
|
||||
@@ -224,6 +225,8 @@ void set_options(int CC_id, PHY_VARS_NR_UE *UE){
|
||||
UE->chest_freq = nrUE_params.chest_freq;
|
||||
UE->chest_time = nrUE_params.chest_time;
|
||||
UE->no_timing_correction = nrUE_params.no_timing_correction;
|
||||
UE->initial_fo = nrUE_params.initial_fo;
|
||||
UE->cont_fo_comp = nrUE_params.cont_fo_comp;
|
||||
|
||||
LOG_I(PHY,"Set UE_fo_compensation %d, UE_scan_carrier %d, UE_no_timing_correction %d \n, chest-freq %d, chest-time %d\n",
|
||||
UE->UE_fo_compensation, UE->UE_scan_carrier, UE->no_timing_correction, UE->chest_freq, UE->chest_time);
|
||||
@@ -299,25 +302,10 @@ void init_openair0()
|
||||
|
||||
static void init_pdcp(int ue_id)
|
||||
{
|
||||
uint32_t pdcp_initmask = (!IS_SOFTMODEM_NOS1) ? LINK_ENB_PDCP_TO_GTPV1U_BIT : LINK_ENB_PDCP_TO_GTPV1U_BIT;
|
||||
|
||||
/*if (IS_SOFTMODEM_RFSIM || (nfapi_getmode()==NFAPI_UE_STUB_PNF)) {
|
||||
pdcp_initmask = pdcp_initmask | UE_NAS_USE_TUN_BIT;
|
||||
}*/
|
||||
|
||||
// previous code was:
|
||||
// if (IS_SOFTMODEM_NOKRNMOD)
|
||||
// pdcp_initmask = pdcp_initmask | UE_NAS_USE_TUN_BIT;
|
||||
// The kernel module (KRNMOD) has been removed from the project, so the 'if'
|
||||
// was removed but the flag 'pdcp_initmask' was kept, as "no kernel module"
|
||||
// was always set. further refactoring could take it out
|
||||
pdcp_initmask = pdcp_initmask | UE_NAS_USE_TUN_BIT;
|
||||
|
||||
if (get_softmodem_params()->nsa && nr_rlc_module_init(0) != 0) {
|
||||
LOG_I(RLC, "Problem at RLC initiation \n");
|
||||
}
|
||||
nr_pdcp_layer_init();
|
||||
nr_pdcp_module_init(pdcp_initmask, ue_id);
|
||||
}
|
||||
|
||||
// Stupid function addition because UE itti messages queues definition is common with eNB
|
||||
@@ -447,6 +435,11 @@ int main(int argc, char **argv)
|
||||
}
|
||||
}
|
||||
|
||||
if (create_tasks_nrue(1) < 0) {
|
||||
printf("cannot create ITTI tasks\n");
|
||||
exit(-1); // need a softer mode
|
||||
}
|
||||
|
||||
int mode_offset = get_softmodem_params()->nsa ? NUMBER_OF_UE_MAX : 1;
|
||||
uint16_t node_number = get_softmodem_params()->node_number;
|
||||
ue_id_g = (node_number == 0) ? 0 : node_number - 2;
|
||||
@@ -465,9 +458,20 @@ int main(int argc, char **argv)
|
||||
get_channel_model_mode(uniqCfg);
|
||||
}
|
||||
|
||||
// Delay to allow the convergence of the IIR filter on PRACH noise measurements at gNB side
|
||||
if (IS_SOFTMODEM_RFSIM && !get_softmodem_params()->phy_test)
|
||||
sleep(3);
|
||||
// start time manager with some reasonable default for the running mode
|
||||
// (may be overwritten in configuration file or command line)
|
||||
void nr_pdcp_ms_tick(void);
|
||||
void nr_rlc_ms_tick(void);
|
||||
time_manager_tick_function_t tick_functions[] = {
|
||||
nr_pdcp_ms_tick,
|
||||
nr_rlc_ms_tick
|
||||
};
|
||||
int tick_functions_count = 2;
|
||||
time_manager_start(tick_functions, tick_functions_count,
|
||||
// iq_samples time source for rfsim,
|
||||
// realtime time source if not
|
||||
IS_SOFTMODEM_RFSIM ? TIME_SOURCE_IQ_SAMPLES
|
||||
: TIME_SOURCE_REALTIME);
|
||||
|
||||
if (!get_softmodem_params()->nsa && get_softmodem_params()->emulate_l1)
|
||||
start_oai_nrue_threads();
|
||||
@@ -508,7 +512,9 @@ int main(int argc, char **argv)
|
||||
for (int i = 0; i < NUM_DL_ACTORS; i++) {
|
||||
init_actor(&UE[CC_id]->dl_actors[i], "DL_", -1);
|
||||
}
|
||||
init_actor(&UE[CC_id]->ul_actor, "UL_", -1);
|
||||
for (int i = 0; i < NUM_UL_ACTORS; i++) {
|
||||
init_actor(&UE[CC_id]->ul_actors[i], "UL_", -1);
|
||||
}
|
||||
init_nr_ue_vars(UE[CC_id], inst);
|
||||
|
||||
if (UE[CC_id]->sl_mode) {
|
||||
@@ -553,11 +559,6 @@ int main(int argc, char **argv)
|
||||
// wait for end of program
|
||||
printf("TYPE <CTRL-C> TO TERMINATE\n");
|
||||
|
||||
if (create_tasks_nrue(1) < 0) {
|
||||
printf("cannot create ITTI tasks\n");
|
||||
exit(-1); // need a softer mode
|
||||
}
|
||||
|
||||
// Sleep a while before checking all parameters have been used
|
||||
// Some are used directly in external threads, asynchronously
|
||||
sleep(2);
|
||||
@@ -578,7 +579,9 @@ int main(int argc, char **argv)
|
||||
for (int CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) {
|
||||
PHY_VARS_NR_UE *phy_vars = PHY_vars_UE_g[0][CC_id];
|
||||
if (phy_vars) {
|
||||
shutdown_actor(&phy_vars->ul_actor);
|
||||
for (int i = 0; i < NUM_UL_ACTORS; i++) {
|
||||
shutdown_actor(&phy_vars->ul_actors[i]);
|
||||
}
|
||||
for (int i = 0; i < NUM_DL_ACTORS; i++) {
|
||||
shutdown_actor(&phy_vars->dl_actors[i]);
|
||||
}
|
||||
@@ -595,6 +598,9 @@ int main(int argc, char **argv)
|
||||
}
|
||||
|
||||
free_nrLDPC_coding_interface(&nrLDPC_coding_interface);
|
||||
|
||||
time_manager_finish();
|
||||
|
||||
free(pckg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -14,7 +14,12 @@
|
||||
#define CONFIG_HLP_TIME_SYNC_I "coefficient for Integrating part of time sync PI controller\n"
|
||||
#define CONFIG_HLP_NTN_INIT_TIME_DRIFT "Initial NTN DL time drift (feeder link and service link), given in µs/s\n"
|
||||
#define CONFIG_HLP_AUTONOMOUS_TA "Autonomously update TA based on DL drift (useful if main contribution to DL drift is movement, e.g. LEO satellite)\n"
|
||||
#define CONFIG_HLP_INITIAL_FO "Initially compensated DL frequency offset (e.g. known Doppler shift in NTN LEO scenario)\n"
|
||||
#define CONFIG_HLP_FREQ_SYNC_P "coefficient for Proportional part of continuous frequency offset compensation PI controller\n"
|
||||
#define CONFIG_HLP_FREQ_SYNC_I "coefficient for Integrating part of continuous frequency offset compensation PI controller\n"
|
||||
#define CONFIG_HLP_CONT_FO_COMP "Enable continuous frequency offset (FO) estimation and compensation and specify main FO source (1 = local oscillator, 2 = Doppler shift)\n"
|
||||
#define CONFIG_HLP_AGC "Rx Gain control used for UE\n"
|
||||
#define CONFIG_HLP_NUM_UL_ACTORS "Number of UL actors to use. Set to 0 to use the default value\n"
|
||||
|
||||
/***************************************************************************************************************************************/
|
||||
/* command line options definitions, CMDLINE_XXXX_DESC macros are used to initialize paramdef_t arrays which are then used as argument
|
||||
@@ -65,7 +70,12 @@
|
||||
{"time-sync-I", CONFIG_HLP_TIME_SYNC_I, 0, .dblptr=&(nrUE_params.time_sync_I), .defdblval=0.0, TYPE_DOUBLE, 0}, \
|
||||
{"ntn-initial-time-drift", CONFIG_HLP_NTN_INIT_TIME_DRIFT, 0, .dblptr=&(nrUE_params.ntn_init_time_drift), .defdblval=0.0, TYPE_DOUBLE, 0}, \
|
||||
{"autonomous-ta", CONFIG_HLP_AUTONOMOUS_TA, PARAMFLAG_BOOL, .iptr=&(nrUE_params.autonomous_ta), .defintval=0, TYPE_INT, 0}, \
|
||||
{"initial-fo", CONFIG_HLP_INITIAL_FO, 0, .dblptr=&(nrUE_params.initial_fo), .defdblval=0.0, TYPE_DOUBLE, 0}, \
|
||||
{"freq-sync-P", CONFIG_HLP_FREQ_SYNC_P, 0, .dblptr=&(nrUE_params.freq_sync_P), .defdblval=0.01, TYPE_DOUBLE, 0}, \
|
||||
{"freq-sync-I", CONFIG_HLP_FREQ_SYNC_I, 0, .dblptr=&(nrUE_params.freq_sync_I), .defdblval=0.001, TYPE_DOUBLE, 0}, \
|
||||
{"cont-fo-comp", CONFIG_HLP_CONT_FO_COMP, 0, .iptr=&(nrUE_params.cont_fo_comp), .defintval=0, TYPE_INT, 0}, \
|
||||
{"agc", CONFIG_HLP_AGC, PARAMFLAG_BOOL, .iptr=&(nrUE_params.agc), .defintval=0, TYPE_INT, 0}, \
|
||||
{"num-ul-actors", CONFIG_HLP_NUM_UL_ACTORS, 0, .iptr=&nrUE_params.num_ul_actors, .defintval=0, TYPE_INT, 0}, \
|
||||
}
|
||||
// clang-format on
|
||||
|
||||
@@ -89,6 +99,10 @@ typedef struct {
|
||||
double time_sync_I;
|
||||
double ntn_init_time_drift;
|
||||
int autonomous_ta;
|
||||
double initial_fo;
|
||||
double freq_sync_P;
|
||||
double freq_sync_I;
|
||||
int cont_fo_comp;
|
||||
int agc;
|
||||
char *usrp_args;
|
||||
char *tx_subdev;
|
||||
@@ -101,6 +115,7 @@ typedef struct {
|
||||
double rx_gain_off;
|
||||
int vcdflag;
|
||||
int tx_max_power;
|
||||
int num_ul_actors;
|
||||
} nrUE_params_t;
|
||||
extern uint64_t get_nrUE_optmask(void);
|
||||
extern uint64_t set_nrUE_optmask(uint64_t bitmask);
|
||||
|
||||
@@ -144,6 +144,7 @@ extern "C"
|
||||
#define EMULATE_L1 softmodem_params.emulate_l1
|
||||
#define CONTINUOUS_TX softmodem_params.continuous_tx
|
||||
#define SYNC_REF softmodem_params.sync_ref
|
||||
#define DEFAULT_PDU_ID softmodem_params.default_pdu_session_id
|
||||
|
||||
#define DEFAULT_RFCONFIG_FILE "/usr/local/etc/syriq/ue.band7.tm1.PRB100.NR40.dat";
|
||||
|
||||
@@ -188,6 +189,7 @@ extern int usrp_tx_thread;
|
||||
{"E" , CONFIG_HLP_TQFS, PARAMFLAG_BOOL, .iptr=&softmodem_params.threequarter_fs, .defintval=0, TYPE_INT, 0}, \
|
||||
{"imscope" , CONFIG_HLP_IMSCOPE, PARAMFLAG_BOOL, .uptr=&enable_imscope, .defintval=0, TYPE_UINT, 0}, \
|
||||
{"imscope-record" , CONFIG_HLP_IMSCOPE_RECORD,PARAMFLAG_BOOL, .uptr=&enable_imscope_record, .defintval=0, TYPE_UINT, 0}, \
|
||||
{"default_pdu_id", NULL, 0, .iptr=&DEFAULT_PDU_ID, .defintval=10, TYPE_INT, 0}, \
|
||||
}
|
||||
// clang-format on
|
||||
|
||||
@@ -234,6 +236,7 @@ extern int usrp_tx_thread;
|
||||
{ .s5 = { NULL } }, \
|
||||
{ .s5 = { NULL } }, \
|
||||
{ .s5 = { NULL } }, \
|
||||
{ .s5 = { NULL } }, \
|
||||
}
|
||||
// clang-format on
|
||||
|
||||
@@ -343,6 +346,7 @@ typedef struct {
|
||||
uint32_t sync_ref;
|
||||
int no_itti;
|
||||
int threequarter_fs;
|
||||
int default_pdu_session_id;
|
||||
} softmodem_params_t;
|
||||
|
||||
#define IS_SA_MODE(sM_params) (!(sM_params)->phy_test && !(sM_params)->do_ra && !(sM_params)->nsa)
|
||||
|
||||
@@ -129,6 +129,8 @@ typedef struct {
|
||||
short rsrp_dBm;
|
||||
long arfcn;
|
||||
rlm_t radiolink_monitoring; // -1 no monitoring, 0 out_of_sync, 1 in_sync
|
||||
// SINR value times 10 as reporting granularity is 0.5
|
||||
float sinr_dB;
|
||||
} fapi_nr_ssb_pdu_t;
|
||||
|
||||
typedef struct {
|
||||
|
||||
@@ -350,7 +350,7 @@ int32_t LDPCdecoder(t_nrLDPC_dec_params *p_decParams,
|
||||
uint16_t Zc = p_decParams->Z;
|
||||
uint8_t BG = p_decParams->BG;
|
||||
// uint8_t numMaxIter = p_decParams->numMaxIter;
|
||||
int block_length = p_decParams->block_length;
|
||||
int block_length = p_decParams->Kprime;
|
||||
// e_nrLDPC_outMode outMode = p_decParams->outMode;
|
||||
uint8_t row,col;
|
||||
if(BG == 1){
|
||||
|
||||
@@ -171,7 +171,6 @@ int init_nr_ue_signal(PHY_VARS_NR_UE *ue, int nb_connected_gNB)
|
||||
NR_DL_FRAME_PARMS *const fp = &ue->frame_parms;
|
||||
NR_UE_COMMON *const common_vars = &ue->common_vars;
|
||||
NR_UE_PRACH **const prach_vars = ue->prach_vars;
|
||||
NR_UE_SRS **const srs_vars = ue->srs_vars;
|
||||
|
||||
LOG_I(PHY, "Initializing UE vars for gNB TXant %u, UE RXant %u\n", fp->nb_antennas_tx, fp->nb_antennas_rx);
|
||||
|
||||
@@ -181,8 +180,10 @@ int init_nr_ue_signal(PHY_VARS_NR_UE *ue, int nb_connected_gNB)
|
||||
AssertFatal( nb_connected_gNB <= NUMBER_OF_CONNECTED_gNB_MAX, "n_connected_gNB is too large" );
|
||||
// init phy_vars_ue
|
||||
|
||||
for (int i = 0; i < fp->Lmax; i++)
|
||||
for (int i = 0; i < fp->Lmax; i++) {
|
||||
ue->measurements.ssb_rsrp_dBm[i] = INT_MIN;
|
||||
ue->measurements.ssb_sinr_dB[i] = INT_MIN;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
ue->rx_gain_max[i] = 135;
|
||||
@@ -257,8 +258,6 @@ int init_nr_ue_signal(PHY_VARS_NR_UE *ue, int nb_connected_gNB)
|
||||
// DLSCH
|
||||
for (int gNB_id = 0; gNB_id < ue->n_connected_gNB; gNB_id++) {
|
||||
prach_vars[gNB_id] = malloc16_clear(sizeof(NR_UE_PRACH));
|
||||
srs_vars[gNB_id] = malloc16_clear(sizeof(NR_UE_SRS));
|
||||
srs_vars[gNB_id]->active = false;
|
||||
|
||||
// ceil((NB_RB*8(max allocation per RB)*2(QPSK))/32)
|
||||
ue->nr_csi_info = malloc16_clear(sizeof(nr_csi_info_t));
|
||||
@@ -318,8 +317,6 @@ void term_nr_ue_signal(PHY_VARS_NR_UE *ue, int nb_connected_gNB)
|
||||
|
||||
free_and_zero(ue->nr_srs_info);
|
||||
|
||||
free_and_zero(ue->srs_vars[gNB_id]);
|
||||
|
||||
free_and_zero(ue->prach_vars[gNB_id]);
|
||||
}
|
||||
|
||||
@@ -487,7 +484,6 @@ void clean_UE_harq(PHY_VARS_NR_UE *UE)
|
||||
for (int harq_pid = 0; harq_pid < NR_MAX_ULSCH_HARQ_PROCESSES; harq_pid++) {
|
||||
NR_UL_UE_HARQ_t *ul_harq_process = &UE->ul_harq_processes[harq_pid];
|
||||
ul_harq_process->tx_status = NEW_TRANSMISSION_HARQ;
|
||||
ul_harq_process->ULstatus = SCH_IDLE;
|
||||
ul_harq_process->round = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,15 +25,9 @@
|
||||
#include "nr_modulation.h"
|
||||
#include "PHY/LTE_ESTIMATION/lte_estimation.h"
|
||||
#include "PHY/NR_UE_ESTIMATION/nr_estimation.h"
|
||||
#include "PHY/nr_phy_common/inc/nr_phy_common.h"
|
||||
#include <common/utils/LOG/log.h>
|
||||
|
||||
//#define DEBUG_FEP
|
||||
|
||||
/*#ifdef LOG_I
|
||||
#undef LOG_I
|
||||
#define LOG_I(A,B...) printf(A)
|
||||
#endif*/
|
||||
|
||||
int nr_slot_fep(PHY_VARS_NR_UE *ue,
|
||||
const NR_DL_FRAME_PARMS *frame_parms,
|
||||
unsigned int slot,
|
||||
@@ -43,7 +37,6 @@ int nr_slot_fep(PHY_VARS_NR_UE *ue,
|
||||
uint32_t sample_offset,
|
||||
c16_t **rxdata)
|
||||
{
|
||||
|
||||
AssertFatal(symbol < frame_parms->symbols_per_slot, "slot_fep: symbol must be between 0 and %d\n", frame_parms->symbols_per_slot-1);
|
||||
AssertFatal(slot < frame_parms->slots_per_frame, "slot_fep: Ns must be between 0 and %d\n", frame_parms->slots_per_frame - 1);
|
||||
|
||||
@@ -67,7 +60,7 @@ int nr_slot_fep(PHY_VARS_NR_UE *ue,
|
||||
|
||||
dft_size_idx_t dftsize = get_dft(frame_parms->ofdm_symbol_size);
|
||||
// This is for misalignment issues
|
||||
int32_t tmp_dft_in[8192] __attribute__ ((aligned (32)));
|
||||
c16_t tmp_dft_in[frame_parms->ofdm_symbol_size] __attribute__ ((aligned (32)));
|
||||
|
||||
unsigned int rx_offset = frame_parms->get_samples_slot_timestamp(slot, frame_parms, 0);
|
||||
unsigned int abs_symbol = slot * frame_parms->symbols_per_slot + symbol;
|
||||
@@ -80,16 +73,10 @@ int nr_slot_fep(PHY_VARS_NR_UE *ue,
|
||||
// use OFDM symbol from within 1/8th of the CP to avoid ISI
|
||||
rx_offset -= (nb_prefix_samples / frame_parms->ofdm_offset_divisor);
|
||||
|
||||
#ifdef DEBUG_FEP
|
||||
// if (ue->frame <100)
|
||||
LOG_D(PHY,"slot_fep: slot %d, symbol %d, nb_prefix_samples %u, nb_prefix_samples0 %u, rx_offset %u energy %d\n",
|
||||
Ns, symbol, nb_prefix_samples, nb_prefix_samples0, rx_offset, dB_fixed(signal_energy((int32_t *)&common_vars->rxdata[0][rx_offset],frame_parms->ofdm_symbol_size)));
|
||||
#endif
|
||||
rx_offset %= total_samples;
|
||||
|
||||
for (unsigned char aa=0; aa<frame_parms->nb_antennas_rx; aa++) {
|
||||
int16_t *rxdata_ptr = (int16_t *)&rxdata[aa][rx_offset];
|
||||
|
||||
rx_offset %= total_samples;
|
||||
c16_t *rxdata_ptr = &rxdata[aa][rx_offset];
|
||||
|
||||
// This happens only during initial sync
|
||||
if (rx_offset + frame_parms->ofdm_symbol_size > total_samples) {
|
||||
@@ -100,19 +87,25 @@ int nr_slot_fep(PHY_VARS_NR_UE *ue,
|
||||
memcpy((void *)&tmp_dft_in[total_samples - rx_offset],
|
||||
(void *)&rxdata[aa][0],
|
||||
(frame_parms->ofdm_symbol_size - (total_samples - rx_offset)) * sizeof(int32_t));
|
||||
rxdata_ptr = (int16_t *)tmp_dft_in;
|
||||
rxdata_ptr = tmp_dft_in;
|
||||
|
||||
} else if ((rx_offset & 7) != 0) { // if input to dft is not 256-bit aligned
|
||||
memcpy((void *)&tmp_dft_in[0], (void *)&rxdata[aa][rx_offset], frame_parms->ofdm_symbol_size * sizeof(int32_t));
|
||||
rxdata_ptr = tmp_dft_in;
|
||||
}
|
||||
|
||||
rxdata_ptr = (int16_t *)tmp_dft_in;
|
||||
if (ue && ue->cont_fo_comp) {
|
||||
start_meas_nr_ue_phy(ue, RX_FO_COMPENSATION_STATS);
|
||||
nr_fo_compensation(ue->freq_offset, frame_parms->samples_per_subframe, rx_offset, rxdata_ptr, tmp_dft_in, frame_parms->ofdm_symbol_size);
|
||||
rxdata_ptr = tmp_dft_in;
|
||||
stop_meas_nr_ue_phy(ue, RX_FO_COMPENSATION_STATS);
|
||||
}
|
||||
|
||||
if (ue)
|
||||
start_meas_nr_ue_phy(ue, RX_DFT_STATS);
|
||||
|
||||
dft(dftsize,
|
||||
rxdata_ptr,
|
||||
(int16_t *)rxdata_ptr,
|
||||
(int16_t *)&rxdataF[aa][frame_parms->ofdm_symbol_size*symbol],
|
||||
1);
|
||||
|
||||
@@ -122,10 +115,6 @@ int nr_slot_fep(PHY_VARS_NR_UE *ue,
|
||||
apply_nr_rotation_RX(frame_parms, rxdataF[aa], frame_parms->symbol_rotation[linktype], slot, N_RB, 0, symbol, 1);
|
||||
}
|
||||
|
||||
#ifdef DEBUG_FEP
|
||||
printf("slot_fep: done\n");
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
#include "nr_common.h"
|
||||
#include <string.h>
|
||||
|
||||
#include "nr_ul_estimation.h"
|
||||
@@ -480,6 +481,9 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB,
|
||||
pusch_pdu->scid,
|
||||
Ns,
|
||||
symbol);
|
||||
pusch_dmrs_type_t dmrs_type = pusch_pdu->dmrs_config_type == NFAPI_NR_DMRS_TYPE1 ? pusch_dmrs_type1 : pusch_dmrs_type2;
|
||||
float beta_dmrs_pusch = get_beta_dmrs_pusch(pusch_pdu->num_dmrs_cdm_grps_no_data, dmrs_type);
|
||||
int16_t dmrs_scaling = (1 / beta_dmrs_pusch) * (1 << 14);
|
||||
nr_pusch_dmrs_rx(gNB,
|
||||
Ns,
|
||||
gold,
|
||||
@@ -488,7 +492,8 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB,
|
||||
0,
|
||||
nb_rb_pusch,
|
||||
(pusch_pdu->bwp_start + pusch_pdu->rb_start) * NR_NB_SC_PER_RB,
|
||||
pusch_pdu->dmrs_config_type);
|
||||
pusch_pdu->dmrs_config_type,
|
||||
dmrs_scaling);
|
||||
} else { // if transform precoding or SC-FDMA is enabled in Uplink
|
||||
// NR_SC_FDMA supports type1 DMRS so only 6 DMRS REs per RB possible
|
||||
const int index = get_index_for_dmrs_lowpapr_seq(nb_rb_pusch * (NR_NB_SC_PER_RB / 2));
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
//#define NR_PBCH_DMRS_LENGTH 144
|
||||
//#define DEBUG_PUSCH
|
||||
|
||||
#include "PHY/TOOLS/tools_defs.h"
|
||||
#include "refsig_defs_ue.h"
|
||||
#include "PHY/defs_nr_UE.h"
|
||||
#include "nr_refsig.h"
|
||||
@@ -73,7 +74,8 @@ int nr_pusch_dmrs_rx(PHY_VARS_gNB *gNB,
|
||||
unsigned char lp,
|
||||
unsigned short nb_pusch_rb,
|
||||
uint32_t re_offset,
|
||||
uint8_t dmrs_type)
|
||||
uint8_t dmrs_type,
|
||||
int16_t dmrs_scaling)
|
||||
{
|
||||
typedef int array_of_w[2];
|
||||
const array_of_w *wf = (dmrs_type == pusch_dmrs_type1) ? wf1 : wf2;
|
||||
@@ -91,6 +93,7 @@ int nr_pusch_dmrs_rx(PHY_VARS_gNB *gNB,
|
||||
int i = k + dmrs_offset;
|
||||
int w = (wf[p - 1000][i & 1]) * (wt[p - 1000][lp]);
|
||||
output[k] = get_modulated(nr_gold_pusch, i, w == 1);
|
||||
output[k] = c16mulRealShift(output[k], dmrs_scaling, 14);
|
||||
#ifdef DEBUG_PUSCH
|
||||
printf("nr_pusch_dmrs_rx dmrs config type %d port %d nb_pusch_rb %d\n", dmrs_type, p, nb_pusch_rb);
|
||||
printf("wf[%d] = %d wt[%d]= %d\n", i&1, wf[p-1000][i&1], lp, wt[p-1000][lp]);
|
||||
|
||||
@@ -36,7 +36,8 @@ int nr_pusch_dmrs_rx(PHY_VARS_gNB *gNB,
|
||||
unsigned char lp,
|
||||
unsigned short nb_pusch_rb,
|
||||
uint32_t re_offset,
|
||||
uint8_t dmrs_type);
|
||||
uint8_t dmrs_type,
|
||||
int16_t dmrs_scaling);
|
||||
|
||||
void nr_generate_csi_rs(const NR_DL_FRAME_PARMS *frame_parms,
|
||||
int32_t **dataF,
|
||||
|
||||
@@ -730,7 +730,7 @@ static int do_one_dlsch(unsigned char *input_ptr, PHY_VARS_gNB *gNB, NR_gNB_DLSC
|
||||
#endif
|
||||
}
|
||||
uint32_t dmrs_idx = rel15->rbStart;
|
||||
if (rel15->rnti != SI_RNTI)
|
||||
if (rel15->refPoint == 0)
|
||||
dmrs_idx += rel15->BWPStart;
|
||||
dmrs_idx *= dmrs_Type == NFAPI_NR_DMRS_TYPE1 ? 6 : 4;
|
||||
c16_t txdataF_precoding[rel15->nrOfLayers][symbol_sz] __attribute__((aligned(64)));
|
||||
|
||||
@@ -47,7 +47,7 @@ int nr_adjust_synch_ue(NR_DL_FRAME_PARMS *frame_parms,
|
||||
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_ADJUST_SYNCH, VCD_FUNCTION_IN);
|
||||
|
||||
// search for maximum position within the cyclic prefix
|
||||
for (int i = -frame_parms->nb_prefix_samples/2; i < frame_parms->nb_prefix_samples/2; i++) {
|
||||
for (int i = -frame_parms->nb_prefix_samples; i < frame_parms->nb_prefix_samples; i++) {
|
||||
int temp = 0;
|
||||
|
||||
int j = (i < 0) ? (i + frame_parms->ofdm_symbol_size) : i;
|
||||
|
||||
@@ -1081,7 +1081,6 @@ void NFAPI_NR_DMRS_TYPE1_linear_interp(NR_DL_FRAME_PARMS *frame_parms,
|
||||
c16_t *dl_ch,
|
||||
unsigned short bwp_start_subcarrier,
|
||||
unsigned short nb_rb_pdsch,
|
||||
int8_t delta,
|
||||
delay_t *delay,
|
||||
uint32_t *nvar)
|
||||
{
|
||||
@@ -1094,30 +1093,23 @@ void NFAPI_NR_DMRS_TYPE1_linear_interp(NR_DL_FRAME_PARMS *frame_parms,
|
||||
int nest_count = 0;
|
||||
uint64_t noise_amp2 = 0;
|
||||
|
||||
for (int pilot_cnt = 0; pilot_cnt < 6 * nb_rb_pdsch; pilot_cnt++) {
|
||||
if (pilot_cnt % 2 == 0) {
|
||||
c16_t ch = c16mulShift(*pil, rxF[re_offset], 15);
|
||||
pil++;
|
||||
re_offset = (re_offset + 2) % frame_parms->ofdm_symbol_size;
|
||||
ch = c16maddShift(*pil, rxF[re_offset], ch, 15);
|
||||
ch = c16Shift(ch, 1);
|
||||
pil++;
|
||||
re_offset = (re_offset + 2) % frame_parms->ofdm_symbol_size;
|
||||
for (int k = pilot_cnt << 1; k < (pilot_cnt << 1) + 4; k++) {
|
||||
dl_ls_est[k] = ch;
|
||||
}
|
||||
}
|
||||
|
||||
for (int pilot_cnt = 0; pilot_cnt < 6 * nb_rb_pdsch; pilot_cnt += 2) {
|
||||
c16_t ch_l = c16mulShift(*pil, rxF[re_offset], 15);
|
||||
#ifdef DEBUG_PDSCH
|
||||
printf("pilot %3d: pil -> (%6d,%6d), rxF -> (%4d,%4d), ch -> (%4d,%4d) \n",
|
||||
pilot_cnt,
|
||||
pil->r,
|
||||
pil->i,
|
||||
rxF[re_offset].r,
|
||||
rxF[re_offset].i,
|
||||
dl_ls_est[pilot_cnt << 1].r,
|
||||
dl_ls_est[pilot_cnt << 1].i);
|
||||
printf("pilot %3d: pil -> (%6d,%6d), rxF -> (%4d,%4d), ch -> (%4d,%4d) \n", pilot_cnt, pil->r, pil->i, rxF[re_offset].r, rxF[re_offset].i, ch_l.r, ch_l.i);
|
||||
#endif
|
||||
pil++;
|
||||
re_offset = (re_offset + 2) % frame_parms->ofdm_symbol_size;
|
||||
c16_t ch_r = c16mulShift(*pil, rxF[re_offset], 15);
|
||||
#ifdef DEBUG_PDSCH
|
||||
printf("pilot %3d: pil -> (%6d,%6d), rxF -> (%4d,%4d), ch -> (%4d,%4d) \n", pilot_cnt + 1, pil->r, pil->i, rxF[re_offset].r, rxF[re_offset].i, ch_r.r, ch_r.i);
|
||||
#endif
|
||||
c16_t ch = c16addShift(ch_l, ch_r, 1);
|
||||
pil++;
|
||||
re_offset = (re_offset + 2) % frame_parms->ofdm_symbol_size;
|
||||
for (int k = pilot_cnt << 1; k < (pilot_cnt << 1) + 4; k++) {
|
||||
dl_ls_est[k] = ch;
|
||||
}
|
||||
}
|
||||
|
||||
c16_t ch_estimates_time[frame_parms->ofdm_symbol_size] __attribute__((aligned(32)));
|
||||
@@ -1247,8 +1239,6 @@ void NFAPI_NR_DMRS_TYPE2_linear_interp(NR_DL_FRAME_PARMS *frame_parms,
|
||||
c16_t *dl_ch,
|
||||
unsigned short bwp_start_subcarrier,
|
||||
unsigned short nb_rb_pdsch,
|
||||
int8_t delta,
|
||||
unsigned short p,
|
||||
delay_t *delay,
|
||||
uint32_t *nvar)
|
||||
{
|
||||
@@ -1270,7 +1260,7 @@ void NFAPI_NR_DMRS_TYPE2_linear_interp(NR_DL_FRAME_PARMS *frame_parms,
|
||||
re_offset = (re_offset + 1) % frame_parms->ofdm_symbol_size;
|
||||
c16_t ch_r = c16mulShift(*pil, rxF[re_offset], 15);
|
||||
#ifdef DEBUG_PDSCH
|
||||
printf("pilot %3d: pil -> (%6d,%6d), rxF -> (%4d,%4d), ch -> (%4d,%4d) \n", pilot_cnt, pil->r, pil->i, rxF[re_offset].r, rxF[re_offset].i, ch_r.r, ch_r.i);
|
||||
printf("pilot %3d: pil -> (%6d,%6d), rxF -> (%4d,%4d), ch -> (%4d,%4d) \n", pilot_cnt + 1, pil->r, pil->i, rxF[re_offset].r, rxF[re_offset].i, ch_r.r, ch_r.i);
|
||||
#endif
|
||||
c16_t ch = c16addShift(ch_l, ch_r, 1);
|
||||
for (int k = 3 * pilot_cnt; k < (3 * pilot_cnt) + 6; k++) {
|
||||
@@ -1427,9 +1417,8 @@ int nr_pdsch_channel_estimation(PHY_VARS_NR_UE *ue,
|
||||
|
||||
#ifdef DEBUG_PDSCH
|
||||
printf(
|
||||
"PDSCH Channel Estimation : gNB_id %d ch_offset %d, symbol_offset %d OFDM size %d, Ncp=%d, Ns=%d, bwp_start_subcarrier=%d "
|
||||
"PDSCH Channel Estimation : ch_offset %d, symbol_offset %d OFDM size %d, Ncp=%d, Ns=%d, bwp_start_subcarrier=%d "
|
||||
"symbol %d\n",
|
||||
gNB_id,
|
||||
ch_offset,
|
||||
symbol_offset,
|
||||
fp->ofdm_symbol_size,
|
||||
@@ -1467,7 +1456,6 @@ int nr_pdsch_channel_estimation(PHY_VARS_NR_UE *ue,
|
||||
dl_ch,
|
||||
bwp_start_subcarrier,
|
||||
nb_rb_pdsch,
|
||||
delta,
|
||||
&delay,
|
||||
nvar);
|
||||
|
||||
@@ -1478,8 +1466,6 @@ int nr_pdsch_channel_estimation(PHY_VARS_NR_UE *ue,
|
||||
dl_ch,
|
||||
bwp_start_subcarrier,
|
||||
nb_rb_pdsch,
|
||||
delta,
|
||||
p,
|
||||
&delay,
|
||||
nvar);
|
||||
|
||||
|
||||
@@ -111,11 +111,11 @@ void nr_ue_measurements(PHY_VARS_NR_UE *ue,
|
||||
uint32_t pdsch_est_size,
|
||||
int32_t dl_ch_estimates[][pdsch_est_size]);
|
||||
|
||||
int nr_ue_calculate_ssb_rsrp(const NR_DL_FRAME_PARMS *fp,
|
||||
const UE_nr_rxtx_proc_t *proc,
|
||||
const c16_t rxdataF[][fp->samples_per_slot_wCP],
|
||||
int symbol_offset,
|
||||
int ssb_start_subcarrier);
|
||||
uint32_t nr_ue_calculate_ssb_rsrp(const NR_DL_FRAME_PARMS *fp,
|
||||
const UE_nr_rxtx_proc_t *proc,
|
||||
const c16_t rxdataF[][fp->samples_per_slot_wCP],
|
||||
int symbol_offset,
|
||||
int ssb_start_subcarrier);
|
||||
|
||||
void nr_ue_ssb_rsrp_measurements(PHY_VARS_NR_UE *ue,
|
||||
uint8_t gNB_index,
|
||||
|
||||
@@ -172,11 +172,11 @@ void nr_ue_measurements(PHY_VARS_NR_UE *ue,
|
||||
|
||||
// This function calculates:
|
||||
// - SS reference signal received digital power in dB/RE
|
||||
int nr_ue_calculate_ssb_rsrp(const NR_DL_FRAME_PARMS *fp,
|
||||
const UE_nr_rxtx_proc_t *proc,
|
||||
const c16_t rxdataF[][fp->samples_per_slot_wCP],
|
||||
int symbol_offset,
|
||||
int ssb_start_subcarrier)
|
||||
uint32_t nr_ue_calculate_ssb_rsrp(const NR_DL_FRAME_PARMS *fp,
|
||||
const UE_nr_rxtx_proc_t *proc,
|
||||
const c16_t rxdataF[][fp->samples_per_slot_wCP],
|
||||
int symbol_offset,
|
||||
int ssb_start_subcarrier)
|
||||
{
|
||||
int k_start = 56;
|
||||
int k_end = 183;
|
||||
@@ -209,9 +209,7 @@ int nr_ue_calculate_ssb_rsrp(const NR_DL_FRAME_PARMS *fp,
|
||||
|
||||
LOG_D(PHY, "In %s: RSRP/nb_re: %d nb_re :%d\n", __FUNCTION__, rsrp, nb_re);
|
||||
|
||||
int rsrp_db_per_re = 10 * log10(rsrp);
|
||||
|
||||
return rsrp_db_per_re;
|
||||
return rsrp;
|
||||
}
|
||||
|
||||
// This function implements:
|
||||
@@ -234,7 +232,8 @@ void nr_ue_ssb_rsrp_measurements(PHY_VARS_NR_UE *ue,
|
||||
if (fp->half_frame_bit)
|
||||
symbol_offset += (fp->slots_per_frame >> 1) * fp->symbols_per_slot;
|
||||
|
||||
int rsrp_db_per_re = nr_ue_calculate_ssb_rsrp(fp, proc, rxdataF, symbol_offset, fp->ssb_start_subcarrier);
|
||||
uint32_t rsrp_avg = nr_ue_calculate_ssb_rsrp(fp, proc, rxdataF, symbol_offset, fp->ssb_start_subcarrier);
|
||||
float rsrp_db_per_re = 10 * log10(rsrp_avg);
|
||||
|
||||
openair0_config_t *cfg0 = &openair0_cfg[0];
|
||||
|
||||
@@ -242,12 +241,18 @@ void nr_ue_ssb_rsrp_measurements(PHY_VARS_NR_UE *ue,
|
||||
- ((int)cfg0->rx_gain[0] - (int)cfg0->rx_gain_offset[0])
|
||||
- dB_fixed(fp->ofdm_symbol_size);
|
||||
|
||||
// to obtain non-integer dB value with a resoluion of 0.5dB
|
||||
uint32_t signal_pwr = rsrp_avg > ue->measurements.n0_power_avg ? rsrp_avg - ue->measurements.n0_power_avg : 0;
|
||||
int SNRtimes10 = dB_fixed_x10(signal_pwr) - dB_fixed_x10(ue->measurements.n0_power_avg);
|
||||
ue->measurements.ssb_sinr_dB[ssb_index] = SNRtimes10 / 10.0;
|
||||
|
||||
LOG_D(PHY,
|
||||
"[UE %d] ssb %d SS-RSRP: %d dBm/RE (%d dB/RE)\n",
|
||||
"[UE %d] ssb %d SS-RSRP: %d dBm/RE (%f dB/RE), SS-SINR: %f dB\n",
|
||||
ue->Mod_id,
|
||||
ssb_index,
|
||||
ue->measurements.ssb_rsrp_dBm[ssb_index],
|
||||
rsrp_db_per_re);
|
||||
rsrp_db_per_re,
|
||||
ue->measurements.ssb_sinr_dB[ssb_index]);
|
||||
}
|
||||
|
||||
// This function computes the received noise power
|
||||
|
||||
@@ -640,6 +640,9 @@ void nr_dci_decoding_procedure(PHY_VARS_NR_UE *ue,
|
||||
{
|
||||
int e_rx_cand_idx = 0;
|
||||
*dci_ind = (fapi_nr_dci_indication_t){.SFN = proc->frame_rx, .slot = proc->nr_slot_rx};
|
||||
// if DCI for SIB we don't break after finding 1st DCI with that RNTI
|
||||
// there might be SIB1 and otherSIB in the same slot with the same length
|
||||
bool is_SI = rel15->rnti == SI_RNTI;
|
||||
|
||||
for (int j = 0; j < rel15->number_of_candidates; j++) {
|
||||
int CCEind = rel15->CCE[j];
|
||||
@@ -653,7 +656,7 @@ void nr_dci_decoding_procedure(PHY_VARS_NR_UE *ue,
|
||||
int dci_length = rel15->dci_length_options[k];
|
||||
int ind;
|
||||
for (ind = 0; ind < dci_ind->number_of_dcis; ind++) {
|
||||
if (rel15->rnti == dci_ind->dci_list[ind].rnti && dci_length == dci_ind->dci_list[ind].payloadSize) {
|
||||
if (!is_SI && rel15->rnti == dci_ind->dci_list[ind].rnti && dci_length == dci_ind->dci_list[ind].payloadSize) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -576,6 +576,25 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue,
|
||||
*log2_maxh,
|
||||
ue->phy_cpu_stats.cpu_time_stats[DLSCH_CHANNEL_COMPENSATION_STATS].p_time / (cpuf * 1000.0));
|
||||
}
|
||||
// Please keep it: useful for debugging
|
||||
#ifdef DEBUG_PDSCH_RX
|
||||
char filename[50];
|
||||
|
||||
snprintf(filename, 50, "rxdataF0_symb_%d_nr_slot_rx_%d.m", symbol, nr_slot_rx);
|
||||
write_output(filename, "rxdataF0", &rxdataF[0][symbol * frame_parms->ofdm_symbol_size], frame_parms->ofdm_symbol_size, 1, 1);
|
||||
|
||||
snprintf(filename, 50, "dl_ch_estimates0_symb_%d_nr_slot_rx_%d.m", symbol, nr_slot_rx);
|
||||
write_output(filename, "dl_ch_estimates0", &dl_ch_estimates[0][symbol * frame_parms->ofdm_symbol_size], frame_parms->ofdm_symbol_size, 1, 1);
|
||||
|
||||
snprintf(filename, 50, "rxdataF_ext0_symb_%d_nr_slot_rx_%d.m", symbol, nr_slot_rx);
|
||||
write_output(filename, "rxdataF_ext0", &rxdataF_ext[0][0], rx_size_symbol, 1, 1);
|
||||
|
||||
snprintf(filename, 50, "dl_ch_estimates_ext0_symb_%d_nr_slot_rx_%d.m", symbol, nr_slot_rx);
|
||||
write_output(filename, "dl_ch_estimates_ext0", &dl_ch_estimates_ext[0][0], rx_size_symbol, 1, 1);
|
||||
|
||||
snprintf(filename, 50, "rxdataF_comp00_symb_%d_nr_slot_rx_%d.m", symbol, nr_slot_rx);
|
||||
write_output(filename, "rxdataF_comp00", &rxdataF_comp[0][0][symbol * rx_size_symbol], rx_size_symbol, 1, 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
start_meas_nr_ue_phy(ue, DLSCH_MRC_MMSE_STATS);
|
||||
@@ -694,32 +713,12 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue,
|
||||
rx_llr_layer_size,
|
||||
layer_llr);
|
||||
stop_meas_nr_ue_phy(ue, DLSCH_LAYER_DEMAPPING);
|
||||
// Please keep it: useful for debugging
|
||||
#ifdef DEBUG_PDSCH_RX
|
||||
char filename[50];
|
||||
uint8_t aa = 0;
|
||||
|
||||
snprintf(filename, 50, "rxdataF0_symb_%d_nr_slot_rx_%d.m", symbol, nr_slot_rx);
|
||||
write_output(filename, "rxdataF0", &rxdataF[0][0], NR_SYMBOLS_PER_SLOT*frame_parms->ofdm_symbol_size, 1, 1);
|
||||
|
||||
snprintf(filename, 50, "dl_ch_estimates0%d_symb_%d_nr_slot_rx_%d.m", aa, symbol, nr_slot_rx);
|
||||
write_output(filename, "dl_ch_estimates", &dl_ch_estimates[aa][0], NR_SYMBOLS_PER_SLOT*frame_parms->ofdm_symbol_size, 1, 1);
|
||||
|
||||
snprintf(filename, 50, "rxdataF_ext0%d_symb_%d_nr_slot_rx_%d.m", aa, symbol, nr_slot_rx);
|
||||
write_output(filename, "rxdataF_ext", &rxdataF_ext[aa][0], NR_SYMBOLS_PER_SLOT*frame_parms->N_RB_DL*NR_NB_SC_PER_RB, 1, 1);
|
||||
|
||||
snprintf(filename, 50, "dl_ch_estimates_ext0%d_symb_%d_nr_slot_rx_%d.m", aa, symbol, nr_slot_rx);
|
||||
write_output(filename, "dl_ch_estimates_ext00", &dl_ch_estimates_ext[aa][0], NR_SYMBOLS_PER_SLOT*frame_parms->N_RB_DL*NR_NB_SC_PER_RB, 1, 1);
|
||||
|
||||
snprintf(filename, 50, "rxdataF_comp0%d_symb_%d_nr_slot_rx_%d.m", aa, symbol, nr_slot_rx);
|
||||
write_output(filename, "rxdataF_comp00", &rxdataF_comp[aa][0], NR_SYMBOLS_PER_SLOT*frame_parms->N_RB_DL*NR_NB_SC_PER_RB, 1, 1);
|
||||
/*
|
||||
for (int i=0; i < 2; i++){
|
||||
snprintf(filename, 50, "llr%d_symb_%d_nr_slot_rx_%d.m", i, symbol, nr_slot_rx);
|
||||
write_output(filename,"llr", &llr[i][0], (NR_SYMBOLS_PER_SLOT*nb_rb_pdsch*NR_NB_SC_PER_RB*dlsch1_harq->Qm) - 4*(nb_rb_pdsch*4*dlsch1_harq->Qm), 1, 0);
|
||||
}
|
||||
*/
|
||||
#endif
|
||||
if (UEScopeHasTryLock(ue)) {
|
||||
metadata mt = {.frame = proc->frame_rx, .slot = proc->nr_slot_rx };
|
||||
int total_valid_res = 0;
|
||||
@@ -766,10 +765,12 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue,
|
||||
for (int a = 0; a < nbRx; a++) {
|
||||
int offset = (void *)rxdataF_comp[0][a] - (void *)rxdataF_comp[0] + symbol * rx_size_symbol * sizeof(c16_t);
|
||||
memcpy(ue->phy_sim_pdsch_rxdataF_comp + offset, rxdataF_comp[0][a] + symbol * rx_size_symbol, sizeof(c16_t) * rx_size_symbol);
|
||||
memcpy(ue->phy_sim_pdsch_dl_ch_estimates + offset, dl_ch_estimates, pdsch_est_size * sizeof(c16_t));
|
||||
memcpy((c16_t *)ue->phy_sim_pdsch_dl_ch_estimates + pdsch_est_size * a, dl_ch_estimates, pdsch_est_size * sizeof(c16_t));
|
||||
}
|
||||
if (ue->phy_sim_pdsch_dl_ch_estimates_ext)
|
||||
memcpy(ue->phy_sim_pdsch_dl_ch_estimates_ext + symbol * rx_size_symbol, dl_ch_estimates_ext, sizeof(dl_ch_estimates_ext));
|
||||
memcpy((c16_t *)ue->phy_sim_pdsch_dl_ch_estimates_ext + symbol * rx_size_symbol,
|
||||
dl_ch_estimates_ext,
|
||||
sizeof(dl_ch_estimates_ext));
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
@@ -199,6 +199,9 @@ void nr_scan_ssb(void *arg)
|
||||
// initial sync performed on two successive frames, if pbch passes on first frame, no need to process second frame
|
||||
// only one frame is used for simulation tools
|
||||
for (int frame_id = 0; frame_id < ssbInfo->nFrames && !ssbInfo->syncRes.cell_detected; frame_id++) {
|
||||
if (ssbInfo->freqOffset)
|
||||
compensate_freq_offset(rxdata, fp, ssbInfo->freqOffset, frame_id);
|
||||
|
||||
/* process pss search on received buffer */
|
||||
ssbInfo->syncRes.frame_id = frame_id;
|
||||
int nid2;
|
||||
@@ -268,7 +271,7 @@ void nr_scan_ssb(void *arg)
|
||||
phase_tdd_ncp,
|
||||
ssbInfo->syncRes.rx_offset);
|
||||
#endif
|
||||
ssbInfo->freqOffset = freq_offset_pss + freq_offset_sss;
|
||||
ssbInfo->freqOffset += freq_offset_pss + freq_offset_sss;
|
||||
|
||||
if (ssbInfo->syncRes.cell_detected) { // we got sss channel
|
||||
ssbInfo->syncRes.cell_detected = nr_pbch_detection(ssbInfo->proc,
|
||||
@@ -282,7 +285,8 @@ void nr_scan_ssb(void *arg)
|
||||
&ssbInfo->pbchResult,
|
||||
rxdataF); // start pbch detection at first symbol after pss
|
||||
if (ssbInfo->syncRes.cell_detected) {
|
||||
int rsrp_db_per_re = nr_ue_calculate_ssb_rsrp(ssbInfo->fp, ssbInfo->proc, rxdataF, 0, ssbInfo->gscnInfo.ssbFirstSC);
|
||||
uint32_t rsrp_avg = nr_ue_calculate_ssb_rsrp(ssbInfo->fp, ssbInfo->proc, rxdataF, 0, ssbInfo->gscnInfo.ssbFirstSC);
|
||||
int rsrp_db_per_re = 10 * log10(rsrp_avg);
|
||||
ssbInfo->adjust_rxgain = TARGET_RX_POWER - rsrp_db_per_re;
|
||||
LOG_I(PHY, "pbch rx ok. rsrp:%d dB/RE, adjust_rxgain:%d dB\n", rsrp_db_per_re, ssbInfo->adjust_rxgain);
|
||||
}
|
||||
@@ -319,6 +323,7 @@ nr_initial_sync_t nr_initial_sync(UE_nr_rxtx_proc_t *proc,
|
||||
.syncRes.cell_detected = false,
|
||||
.nFrames = n_frames,
|
||||
.foFlag = ue->UE_fo_compensation,
|
||||
.freqOffset = ue->initial_fo,
|
||||
.targetNidCell = ue->target_Nid_cell};
|
||||
ssbInfo->rxdata = malloc16_clear(fp->nb_antennas_rx * sizeof(c16_t *));
|
||||
for (int ant = 0; ant < fp->nb_antennas_rx; ant++) {
|
||||
|
||||
@@ -525,3 +525,21 @@ int nr_rx_pbch(PHY_VARS_NR_UE *ue,
|
||||
TracyCZoneEnd(ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
double nr_ue_pbch_freq_offset(const NR_DL_FRAME_PARMS *frame_parms,
|
||||
int estimateSz,
|
||||
const c16_t dl_ch_estimates[][estimateSz])
|
||||
{
|
||||
const int i_ssb = frame_parms->ssb_index;
|
||||
const int symbol_offset = nr_get_ssb_start_symbol(frame_parms, i_ssb) % frame_parms->symbols_per_slot;
|
||||
const c16_t *dl_ch_est_symb1 = &dl_ch_estimates[0][(symbol_offset + 1) * frame_parms->ofdm_symbol_size];
|
||||
const c16_t *dl_ch_est_symb3 = &dl_ch_estimates[0][(symbol_offset + 3) * frame_parms->ofdm_symbol_size];
|
||||
const int nb_re = 240;
|
||||
const c32_t dot_prod_res = dot_product(dl_ch_est_symb1, dl_ch_est_symb3, nb_re, 8);
|
||||
const double res_phase = atan2(dot_prod_res.i, dot_prod_res.r);
|
||||
const int samples_per_symbol = frame_parms->ofdm_symbol_size + frame_parms->nb_prefix_samples;
|
||||
const double t_ofdm = samples_per_symbol / (frame_parms->samples_per_subframe * 1000.0); // symbol duration in sec
|
||||
const double freq_offset = res_phase / (2 * M_PI * (3 - 1) * t_ofdm);
|
||||
|
||||
return freq_offset;
|
||||
}
|
||||
|
||||
@@ -68,7 +68,7 @@ int32_t generate_nr_prach(PHY_VARS_NR_UE *ue, uint8_t gNB_id, int frame, uint8_t
|
||||
int Ncp = 0;
|
||||
int prach_start, prach_sequence_length, prach_len, dftlen, mu, n_ra_prb, k, prachStartSymbol, sample_offset_slot;
|
||||
|
||||
fd_occasion = 0;
|
||||
fd_occasion = prach_pdu->num_ra;
|
||||
prach_len = 0;
|
||||
dftlen = 0;
|
||||
first_nonzero_root_idx = 0;
|
||||
|
||||
@@ -204,6 +204,10 @@ int nr_rx_pbch(PHY_VARS_NR_UE *ue,
|
||||
int rxdataFSize,
|
||||
const struct complex16 rxdataF[][rxdataFSize]);
|
||||
|
||||
double nr_ue_pbch_freq_offset(const NR_DL_FRAME_PARMS *frame_parms,
|
||||
int estimateSz,
|
||||
const c16_t dl_ch_estimates[][estimateSz]);
|
||||
|
||||
#ifndef modOrder
|
||||
#define modOrder(I_MCS,I_TBS) ((I_MCS-I_TBS)*2+2) // Find modulation order from I_TBS and I_MCS
|
||||
#endif
|
||||
|
||||
@@ -46,8 +46,6 @@ typedef enum {
|
||||
typedef struct {
|
||||
/// HARQ tx status
|
||||
harq_result_t tx_status;
|
||||
/// Status Flag indicating for this ULSCH (idle,active,disabled)
|
||||
SCH_status_t ULstatus;
|
||||
/// Last TPC command
|
||||
uint8_t TPC;
|
||||
/// Length of ACK information (bits)
|
||||
@@ -87,6 +85,7 @@ typedef struct {
|
||||
} NR_UL_UE_HARQ_t;
|
||||
|
||||
typedef struct {
|
||||
SCH_status_t status;
|
||||
/// NDAPI struct for UE
|
||||
nfapi_nr_ue_pusch_pdu_t pusch_pdu;
|
||||
// UL number of harq processes
|
||||
|
||||
@@ -392,13 +392,15 @@ static void dmrs_amp_mult(const uint32_t dmrs_port,
|
||||
const c16_t *mod_dmrs,
|
||||
c16_t *mod_dmrs_out,
|
||||
const uint32_t n_dmrs,
|
||||
const pusch_dmrs_type_t dmrs_type)
|
||||
const pusch_dmrs_type_t dmrs_type,
|
||||
const unsigned int num_cdm_groups_no_data)
|
||||
{
|
||||
float beta_dmrs_pusch = get_beta_dmrs_pusch(num_cdm_groups_no_data, dmrs_type);
|
||||
/* short array that hold amplitude for k_prime = 0 and k_prime = 1 */
|
||||
int32_t alpha_dmrs[2] __attribute((aligned(16)));
|
||||
for (int_fast8_t i = 0; i < sizeofArray(alpha_dmrs); i++) {
|
||||
const int32_t a = Wf[i] * Wt * AMP;
|
||||
alpha_dmrs[i] = a;
|
||||
alpha_dmrs[i] = a * beta_dmrs_pusch;
|
||||
}
|
||||
|
||||
/* multiply amplitude with complex DMRS vector */
|
||||
@@ -440,9 +442,9 @@ static void map_symbols(const nr_phy_pxsch_params_t p,
|
||||
c16_t mod_dmrs[ALNARS_16_4(n_dmrs)] __attribute((aligned(16)));
|
||||
if (p.transform_precoding == transformPrecoder_disabled) {
|
||||
nr_modulation(gold, n_dmrs * 2, DMRS_MOD_ORDER, (int16_t *)mod_dmrs);
|
||||
dmrs_amp_mult(p.dmrs_port, p.Wt, p.Wf, mod_dmrs, mod_dmrs_amp, n_dmrs, p.dmrs_type);
|
||||
dmrs_amp_mult(p.dmrs_port, p.Wt, p.Wf, mod_dmrs, mod_dmrs_amp, n_dmrs, p.dmrs_type, p.num_cdm_no_data);
|
||||
} else {
|
||||
dmrs_amp_mult(p.dmrs_port, p.Wt, p.Wf, dmrs_seq, mod_dmrs_amp, n_dmrs, p.dmrs_type);
|
||||
dmrs_amp_mult(p.dmrs_port, p.Wt, p.Wf, dmrs_seq, mod_dmrs_amp, n_dmrs, p.dmrs_type, p.num_cdm_no_data);
|
||||
}
|
||||
} else if ((p.pdu_bit_map & PUSCH_PDU_BITMAP_PUSCH_PTRS) && ptrs_symbol) {
|
||||
AssertFatal(p.transform_precoding == transformPrecoder_disabled, "PTRS NOT SUPPORTED IF TRANSFORM PRECODING IS ENABLED\n");
|
||||
@@ -471,7 +473,7 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE,
|
||||
|
||||
int harq_pid = phy_data->ulsch.pusch_pdu.pusch_data.harq_process_id;
|
||||
|
||||
if (UE->ul_harq_processes[harq_pid].ULstatus != ACTIVE)
|
||||
if (phy_data->ulsch.status != ACTIVE)
|
||||
return;
|
||||
|
||||
start_meas_nr_ue_phy(UE, PUSCH_PROC_STATS);
|
||||
@@ -542,8 +544,6 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE,
|
||||
/////////////////////////ULSCH coding/////////////////////////
|
||||
|
||||
if (nr_ulsch_encoding(UE, &phy_data->ulsch, frame, slot, G, 1, ULSCH_ids) == -1) {
|
||||
NR_UL_UE_HARQ_t *harq_process_ulsch = &UE->ul_harq_processes[harq_pid];
|
||||
harq_process_ulsch->ULstatus = SCH_IDLE;
|
||||
stop_meas_nr_ue_phy(UE, PUSCH_PROC_STATS);
|
||||
return;
|
||||
}
|
||||
@@ -820,12 +820,7 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE,
|
||||
} // symbol loop
|
||||
} // port loop
|
||||
|
||||
NR_UL_UE_HARQ_t *harq_process_ulsch = NULL;
|
||||
harq_process_ulsch = &UE->ul_harq_processes[harq_pid];
|
||||
harq_process_ulsch->ULstatus = SCH_IDLE;
|
||||
|
||||
stop_meas_nr_ue_phy(UE, PUSCH_PROC_STATS);
|
||||
|
||||
}
|
||||
|
||||
uint8_t nr_ue_pusch_common_procedures(PHY_VARS_NR_UE *UE,
|
||||
|
||||
@@ -426,14 +426,15 @@ int generate_srs_nr(nfapi_nr_srs_pdu_t *srs_config_pdu,
|
||||
int ue_srs_procedures_nr(PHY_VARS_NR_UE *ue,
|
||||
const UE_nr_rxtx_proc_t *proc,
|
||||
c16_t **txdataF,
|
||||
nr_phy_data_tx_t *phy_data,
|
||||
bool was_symbol_used[NR_NUMBER_OF_SYMBOLS_PER_SLOT])
|
||||
{
|
||||
if(!ue->srs_vars[0]->active) {
|
||||
if(phy_data->srs_vars.active == false) {
|
||||
return -1;
|
||||
}
|
||||
ue->srs_vars[0]->active = false;
|
||||
|
||||
nfapi_nr_srs_pdu_t *srs_config_pdu = (nfapi_nr_srs_pdu_t*)&ue->srs_vars[0]->srs_config_pdu;
|
||||
// TODO: This is wrong: casting from UE fapi to gNB NFAPI srs pdu
|
||||
nfapi_nr_srs_pdu_t *srs_config_pdu = (nfapi_nr_srs_pdu_t *)&phy_data->srs_vars.srs_config_pdu;
|
||||
|
||||
int first_srs_symbol = ue->frame_parms.symbols_per_slot - 1 - srs_config_pdu->time_start_position;
|
||||
// Num consecutive SRS symbols according to 38.211 6.4.1.4.1
|
||||
|
||||
@@ -78,7 +78,10 @@ int is_srs_period_nr(SRS_Resource_t *p_SRS_Resource,
|
||||
@param rxtx context
|
||||
@param current gNB_id identifier
|
||||
@returns 0 if srs is transmitted -1 otherwise */
|
||||
|
||||
int ue_srs_procedures_nr(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, c16_t **txdataF, bool was_symbol_used[14]);
|
||||
int ue_srs_procedures_nr(PHY_VARS_NR_UE *ue,
|
||||
const UE_nr_rxtx_proc_t *proc,
|
||||
c16_t **txdataF,
|
||||
nr_phy_data_tx_t *phy_data,
|
||||
bool was_symbol_used[NR_NUMBER_OF_SYMBOLS_PER_SLOT]);
|
||||
|
||||
#endif /* SRS_MODULATION_NR_H */
|
||||
|
||||
70
openair1/PHY/TOOLS/get_sin_cos.c
Normal file
70
openair1/PHY/TOOLS/get_sin_cos.c
Normal file
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* 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 <stdint.h>
|
||||
#include <math.h>
|
||||
#include "tools_defs.h"
|
||||
|
||||
#define LUT_SIN_RESOL 128
|
||||
// look-up table for the sine (cosine) function
|
||||
static uint16_t LUTSin[LUT_SIN_RESOL + 1];
|
||||
|
||||
void InitSinLUT(void)
|
||||
{
|
||||
for (int i = 0; i < (LUT_SIN_RESOL + 1); i++) {
|
||||
LUTSin[i] = round(sin((M_PI * i) / (2 * LUT_SIN_RESOL)) * (1 << 14)); // Format: Q14
|
||||
}
|
||||
}
|
||||
|
||||
// fast calculation of e^{i*2*pi*phase}
|
||||
// ret.r == cosinus << 14
|
||||
// ret.i == sinus << 14
|
||||
c16_t get_sin_cos(double phase)
|
||||
{
|
||||
int index;
|
||||
if (phase < 0) {
|
||||
index = (int)(-phase * 4 * LUT_SIN_RESOL + 0.5) % (4 * LUT_SIN_RESOL);
|
||||
index = 4 * LUT_SIN_RESOL - index;
|
||||
} else {
|
||||
index = (int)(phase * 4 * LUT_SIN_RESOL + 0.5) % (4 * LUT_SIN_RESOL);
|
||||
}
|
||||
|
||||
c16_t ret;
|
||||
if (index < 2 * LUT_SIN_RESOL) { // check for 1st and 2nd Quadrant
|
||||
if (index < LUT_SIN_RESOL) { // 1st Quadrant
|
||||
ret.r = LUTSin[LUT_SIN_RESOL - index];
|
||||
ret.i = LUTSin[index];
|
||||
} else { // 2nd Quadrant
|
||||
ret.r = -LUTSin[index - LUT_SIN_RESOL];
|
||||
ret.i = LUTSin[2 * LUT_SIN_RESOL - index];
|
||||
}
|
||||
} else { // 3rd and 4th Quadrant
|
||||
if (index < 3 * LUT_SIN_RESOL) { // 3rd Quadrant
|
||||
ret.r = -LUTSin[3 * LUT_SIN_RESOL - index];
|
||||
ret.i = -LUTSin[index - 2 * LUT_SIN_RESOL];
|
||||
} else { // 4th Quadrant
|
||||
ret.r = LUTSin[index - 3 * LUT_SIN_RESOL];
|
||||
ret.i = -LUTSin[4 * LUT_SIN_RESOL - index];
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -792,6 +792,13 @@ double interp(double x, double *xs, double *ys, int count);
|
||||
void simde_mm128_separate_real_imag_parts(simde__m128i *out_re, simde__m128i *out_im, simde__m128i in0, simde__m128i in1);
|
||||
void simde_mm256_separate_real_imag_parts(simde__m256i *out_re, simde__m256i *out_im, simde__m256i in0, simde__m256i in1);
|
||||
|
||||
void InitSinLUT(void);
|
||||
|
||||
// fast calculation of e^{i*2*pi*phase}
|
||||
// ret.r == cosinus << 14
|
||||
// ret.i == sinus << 14
|
||||
c16_t get_sin_cos(double phase);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -82,6 +82,7 @@
|
||||
/// suppress compiler warning for unused arguments
|
||||
#define UNUSED(x) (void)x;
|
||||
#define NUM_DL_ACTORS 4
|
||||
#define NUM_UL_ACTORS 2
|
||||
|
||||
// Set the number of barriers for processSlotTX to 512. This value has to be at least 483 for NTN where
|
||||
// DL-to-UL offset is up to 483. The selected value is also half of the frame range so that
|
||||
@@ -139,6 +140,7 @@ typedef struct {
|
||||
uint32_t rsrp[7];
|
||||
short rsrp_dBm[7];
|
||||
int ssb_rsrp_dBm[64];
|
||||
float ssb_sinr_dB[64];
|
||||
// common measurements
|
||||
//! estimated noise power (linear)
|
||||
unsigned int n0_power[NB_ANTENNAS_RX];
|
||||
@@ -401,7 +403,6 @@ typedef struct PHY_VARS_NR_UE_s {
|
||||
nr_synch_request_t synch_request;
|
||||
|
||||
NR_UE_PRACH *prach_vars[NUMBER_OF_CONNECTED_gNB_MAX];
|
||||
NR_UE_SRS *srs_vars[NUMBER_OF_CONNECTED_gNB_MAX];
|
||||
NR_UE_PRS *prs_vars[NR_MAX_PRS_COMB_SIZE];
|
||||
uint8_t prs_active_gNBs;
|
||||
NR_DL_UE_HARQ_t dl_harq_processes[2][NR_MAX_DLSCH_HARQ_PROCESSES];
|
||||
@@ -460,6 +461,11 @@ typedef struct PHY_VARS_NR_UE_s {
|
||||
int64_t max_pos_iir; /// Timing offset IIR filter
|
||||
int max_pos_acc; /// Timing offset accumuluated error for PI filter
|
||||
|
||||
double initial_fo; /// initial frequency offset provided by the user
|
||||
int cont_fo_comp; /// flag enabling the continuous frequency offset estimation and compensation
|
||||
double freq_offset; /// currently compensated frequency offset
|
||||
double freq_off_acc; /// accumulated frequency error (for PI controller)
|
||||
|
||||
/// Timing Advance updates variables
|
||||
/// Timing advance update computed from the TA command signalled from gNB
|
||||
int timing_advance;
|
||||
@@ -514,7 +520,7 @@ typedef struct PHY_VARS_NR_UE_s {
|
||||
sl_nr_ue_phy_params_t SL_UE_PHY_PARAMS;
|
||||
Actor_t sync_actor;
|
||||
Actor_t dl_actors[NUM_DL_ACTORS];
|
||||
Actor_t ul_actor;
|
||||
Actor_t ul_actors[NUM_UL_ACTORS];
|
||||
ntn_config_message_t* ntn_config_message;
|
||||
pthread_t main_thread;
|
||||
pthread_t stat_thread;
|
||||
@@ -525,10 +531,6 @@ typedef struct {
|
||||
int gNB_id;
|
||||
/// NR slot index within frame_tx [0 .. slots_per_frame - 1] to act upon for transmission
|
||||
int nr_slot_tx;
|
||||
/// NR slot index tx offset to resume
|
||||
/// in case of NTN, tx_offset can be changed dynamically via SIB19
|
||||
/// we need to notify the right tx thread slot based on TX offset change
|
||||
int nr_slot_tx_offset;
|
||||
int rx_slot_type;
|
||||
/// NR slot index within frame_rx [0 .. slots_per_frame - 1] to act upon for transmission
|
||||
int nr_slot_rx;
|
||||
@@ -571,6 +573,7 @@ typedef struct {
|
||||
typedef struct nr_phy_data_tx_s {
|
||||
NR_UE_ULSCH_t ulsch;
|
||||
NR_UE_PUCCH pucch_vars;
|
||||
NR_UE_SRS srs_vars;
|
||||
|
||||
// Sidelink Rx action decided by MAC
|
||||
sl_nr_tx_config_type_enum_t sl_tx_action;
|
||||
@@ -597,7 +600,7 @@ typedef struct nr_rxtx_thread_data_s {
|
||||
PHY_VARS_NR_UE *UE;
|
||||
int writeBlockSize;
|
||||
nr_phy_data_t phy_data;
|
||||
dynamic_barrier_t *next_barrier;
|
||||
dynamic_barrier_t* next_barrier;
|
||||
} nr_rxtx_thread_data_t;
|
||||
|
||||
typedef struct LDPCDecode_ue_s {
|
||||
|
||||
@@ -344,12 +344,6 @@ typedef enum {
|
||||
* DESCRIPTION : configuration for PUSCH
|
||||
*
|
||||
************************************************************************/
|
||||
|
||||
typedef enum {
|
||||
pusch_dmrs_type1 = 0,
|
||||
pusch_dmrs_type2 = 1
|
||||
} pusch_dmrs_type_t;
|
||||
|
||||
typedef enum {
|
||||
txConfig_codebook = 1,
|
||||
txConfig_nonCodebook = 2
|
||||
|
||||
@@ -80,4 +80,6 @@ void nr_256qam_llr(int32_t *rxdataF_comp, int32_t *ch_mag, int32_t *ch_mag2, int
|
||||
void freq2time(uint16_t ofdm_symbol_size, int16_t *freq_signal, int16_t *time_signal);
|
||||
void nr_est_delay(int ofdm_symbol_size, const c16_t *ls_est, c16_t *ch_estimates_time, delay_t *delay);
|
||||
unsigned int nr_get_tx_amp(int power_dBm, int power_max_dBm, int total_nb_rb, int nb_rb);
|
||||
void nr_fo_compensation(double fo_Hz, int samples_per_ms, int sample_offset, const c16_t *rxdata_in, c16_t *rxdata_out, int size);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#define FOREACH_NR_PHY_CPU_MEAS(FN) \
|
||||
FN(RX_PDSCH_STATS),\
|
||||
FN(DLSCH_RX_PDCCH_STATS),\
|
||||
FN(RX_FO_COMPENSATION_STATS),\
|
||||
FN(RX_DFT_STATS),\
|
||||
FN(DLSCH_CHANNEL_ESTIMATION_STATS),\
|
||||
FN(DLSCH_DECODING_STATS),\
|
||||
|
||||
@@ -453,3 +453,41 @@ unsigned int nr_get_tx_amp(int power_dBm, int power_max_dBm, int total_nb_rb, in
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
void nr_fo_compensation(double fo_Hz, int samples_per_ms, int sample_offset, const c16_t *rxdata_in, c16_t *rxdata_out, int size)
|
||||
{
|
||||
const double phase_inc = -fo_Hz / (samples_per_ms * 1000);
|
||||
double phase = sample_offset * phase_inc;
|
||||
phase -= (int)phase;
|
||||
#if 1
|
||||
// The bottleneck is the calculation of the complex rotation values using get_sin_cos().
|
||||
// This code path does not compute these values for the complete OFDM symbol, but only for a smaller CHUNK size.
|
||||
// After applying the rotation to a CHUNK size of the output, these rotation values are efficiently rotated further by `rot_vec`.
|
||||
// Unfortunately, this propagates small errors from one chunk to the next.
|
||||
// Therefore, there is a tradeoff between speed (better with small CHUNK sizes) and accuracy (better with large CHUNK sizes).
|
||||
#define CHUNK 128
|
||||
c16_t rot[CHUNK] __attribute__((aligned(32)));
|
||||
for (int i = 0; i < CHUNK; i++) {
|
||||
rot[i] = get_sin_cos(phase);
|
||||
phase += phase_inc;
|
||||
}
|
||||
const c16_t rot_vec = get_sin_cos(CHUNK * phase_inc);
|
||||
while (size > CHUNK) {
|
||||
mult_complex_vectors(rxdata_in, rot, rxdata_out, CHUNK, 14);
|
||||
rotate_cpx_vector(rot, &rot_vec, rot, CHUNK, 14);
|
||||
rxdata_in += CHUNK;
|
||||
rxdata_out += CHUNK;
|
||||
size -= CHUNK;
|
||||
}
|
||||
mult_complex_vectors(rxdata_in, rot, rxdata_out, size, 14);
|
||||
#else
|
||||
// This code path computes the complex rotation values for the complete OFDM symbol using get_sin_cos().
|
||||
// This is more accurate, but also slower than the code path above.
|
||||
c16_t rot[size] __attribute__((aligned(32)));
|
||||
for (int i = 0; i < size; i++) {
|
||||
rot[i] = get_sin_cos(phase);
|
||||
phase += phase_inc;
|
||||
}
|
||||
mult_complex_vectors(rxdata_in, rot, rxdata_out, size, 14);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -120,7 +120,8 @@ void prach_procedures(PHY_VARS_eNB *eNB,
|
||||
*/
|
||||
|
||||
if (eNB->frame_parms.prach_emtc_config_common.prach_ConfigInfo.prach_CElevel_enable[0] == 1) {
|
||||
if ((eNB->prach_energy_counter == 100) && (max_preamble_energy[0] > eNB->measurements.prach_I0 + eNB->prach_DTX_threshold_emtc[0])) {
|
||||
if ((eNB->prach_energy_counter == NUM_PRACH_RX_FOR_NOISE_ESTIMATE)
|
||||
&& (max_preamble_energy[0] > eNB->measurements.prach_I0 + eNB->prach_DTX_threshold_emtc[0])) {
|
||||
eNB->UL_INFO.rach_ind_br.rach_indication_body.number_of_preambles++;
|
||||
eNB->preamble_list_br[ind].preamble_rel8.timing_advance = max_preamble_delay[ind]; //
|
||||
eNB->preamble_list_br[ind].preamble_rel8.preamble = max_preamble[ind];
|
||||
@@ -142,7 +143,7 @@ void prach_procedures(PHY_VARS_eNB *eNB,
|
||||
}
|
||||
} */// ce_level
|
||||
} else {
|
||||
if ((eNB->prach_energy_counter == 100) &&
|
||||
if ((eNB->prach_energy_counter == NUM_PRACH_RX_FOR_NOISE_ESTIMATE) &&
|
||||
(max_preamble_energy[0] > eNB->measurements.prach_I0+eNB->prach_DTX_threshold)) {
|
||||
LOG_D(PHY,"[eNB %d/%d][RAPROC] Frame %d, subframe %d Initiating RA procedure with preamble %d, energy %d.%d dB, delay %d\n",
|
||||
eNB->Mod_id,
|
||||
@@ -186,7 +187,8 @@ void prach_procedures(PHY_VARS_eNB *eNB,
|
||||
|
||||
if (frame==0) LOG_D(PHY,"prach_I0 = %d.%d dB\n",eNB->measurements.prach_I0/10,eNB->measurements.prach_I0%10);
|
||||
|
||||
if (eNB->prach_energy_counter < 100) eNB->prach_energy_counter++;
|
||||
if (eNB->prach_energy_counter < NUM_PRACH_RX_FOR_NOISE_ESTIMATE)
|
||||
eNB->prach_energy_counter++;
|
||||
}
|
||||
} // else br_flag
|
||||
|
||||
|
||||
@@ -145,7 +145,8 @@ void L1_nr_prach_procedures(PHY_VARS_gNB *gNB, int frame, int slot, nfapi_nr_rac
|
||||
max_preamble_delay[0],
|
||||
gNB->prach_energy_counter);
|
||||
|
||||
if ((gNB->prach_energy_counter == 100) && (max_preamble_energy[0] > gNB->measurements.prach_I0 + gNB->prach_thres)
|
||||
if ((gNB->prach_energy_counter == NUM_PRACH_RX_FOR_NOISE_ESTIMATE)
|
||||
&& (max_preamble_energy[0] > gNB->measurements.prach_I0 + gNB->prach_thres)
|
||||
&& (rach_ind->number_of_pdus < MAX_NUM_NR_RX_RACH_PDUS)) {
|
||||
LOG_A(NR_PHY,
|
||||
"[RAPROC] %d.%d Initiating RA procedure with preamble %d, energy %d.%d dB (I0 %d, thres %d), delay %d start symbol "
|
||||
@@ -185,7 +186,8 @@ void L1_nr_prach_procedures(PHY_VARS_gNB *gNB, int frame, int slot, nfapi_nr_rac
|
||||
}
|
||||
gNB->measurements.prach_I0 = ((gNB->measurements.prach_I0*900)>>10) + ((max_preamble_energy[0]*124)>>10);
|
||||
if (frame==0) LOG_I(PHY,"prach_I0 = %d.%d dB\n",gNB->measurements.prach_I0/10,gNB->measurements.prach_I0%10);
|
||||
if (gNB->prach_energy_counter < 100) gNB->prach_energy_counter++;
|
||||
if (gNB->prach_energy_counter < NUM_PRACH_RX_FOR_NOISE_ESTIMATE)
|
||||
gNB->prach_energy_counter++;
|
||||
} //if prach_id>0
|
||||
rach_ind->slot = prach_start_slot;
|
||||
} // for NUMBER_OF_NR_PRACH_OCCASION_MAX
|
||||
|
||||
@@ -518,7 +518,7 @@ static void nr_ue_scheduled_response_ul(PHY_VARS_NR_UE *phy, fapi_nr_ul_config_r
|
||||
pdu->pusch_config_pdu.tx_request_body.pdu_length);
|
||||
}
|
||||
|
||||
harq_process_ul_ue->ULstatus = ACTIVE;
|
||||
phy_data->ulsch.status = ACTIVE;
|
||||
pdu->pdu_type = FAPI_NR_UL_CONFIG_TYPE_DONE; // not handle it any more
|
||||
} break;
|
||||
|
||||
@@ -549,8 +549,8 @@ static void nr_ue_scheduled_response_ul(PHY_VARS_NR_UE *phy, fapi_nr_ul_config_r
|
||||
|
||||
case FAPI_NR_UL_CONFIG_TYPE_SRS:
|
||||
// srs config pdu
|
||||
phy->srs_vars[0]->srs_config_pdu = pdu->srs_config_pdu;
|
||||
phy->srs_vars[0]->active = true;
|
||||
phy_data->srs_vars.srs_config_pdu = pdu->srs_config_pdu;
|
||||
phy_data->srs_vars.active = true;
|
||||
pdu->pdu_type = FAPI_NR_UL_CONFIG_TYPE_DONE; // not handle it any more
|
||||
break;
|
||||
|
||||
|
||||
@@ -175,6 +175,7 @@ void nr_fill_rx_indication(fapi_nr_rx_indication_t *rx_ind,
|
||||
rx->ssb_pdu.cell_id = frame_parms->Nid_cell;
|
||||
rx->ssb_pdu.ssb_start_subcarrier = frame_parms->ssb_start_subcarrier;
|
||||
rx->ssb_pdu.rsrp_dBm = ue->measurements.ssb_rsrp_dBm[frame_parms->ssb_index];
|
||||
rx->ssb_pdu.sinr_dB = ue->measurements.ssb_sinr_dB[frame_parms->ssb_index];
|
||||
rx->ssb_pdu.arfcn = get_ssb_arfcn(frame_parms);
|
||||
rx->ssb_pdu.radiolink_monitoring = RLM_in_sync; // TODO to be removed from here
|
||||
rx->ssb_pdu.decoded_pdu = true;
|
||||
@@ -290,7 +291,7 @@ void phy_procedures_nrUE_TX(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, n
|
||||
|
||||
nr_ue_ulsch_procedures(ue, frame_tx, slot_tx, phy_data, (c16_t **)&txdataF, was_symbol_used);
|
||||
|
||||
ue_srs_procedures_nr(ue, proc, (c16_t **)&txdataF, was_symbol_used);
|
||||
ue_srs_procedures_nr(ue, proc, (c16_t **)&txdataF, phy_data, was_symbol_used);
|
||||
|
||||
pucch_procedures_ue_nr(ue, proc, phy_data, (c16_t **)&txdataF, was_symbol_used);
|
||||
|
||||
@@ -485,6 +486,7 @@ static int nr_ue_pdsch_procedures(PHY_VARS_NR_UE *ue,
|
||||
c16_t rxdataF[][ue->frame_parms.samples_per_slot_wCP],
|
||||
int G)
|
||||
{
|
||||
int frame_rx = proc->frame_rx;
|
||||
int nr_slot_rx = proc->nr_slot_rx;
|
||||
|
||||
// We handle only one CW now
|
||||
@@ -496,9 +498,10 @@ static int nr_ue_pdsch_procedures(PHY_VARS_NR_UE *ue,
|
||||
NR_DL_UE_HARQ_t *dlsch0_harq = &ue->dl_harq_processes[0][harq_pid];
|
||||
|
||||
LOG_D(PHY,
|
||||
"[UE %d] nr_slot_rx %d, harq_pid %d (%d), BWP start %d, rb_start %d, nb_rb %d, symbol_start %d, nb_symbols %d, DMRS mask "
|
||||
"[UE %d] frame_rx %d, nr_slot_rx %d, harq_pid %d (%d), BWP start %d, rb_start %d, nb_rb %d, symbol_start %d, nb_symbols %d, DMRS mask "
|
||||
"%x, Nl %d\n",
|
||||
ue->Mod_id,
|
||||
frame_rx,
|
||||
nr_slot_rx,
|
||||
harq_pid,
|
||||
dlsch0_harq->status,
|
||||
@@ -558,10 +561,9 @@ static int nr_ue_pdsch_procedures(PHY_VARS_NR_UE *ue,
|
||||
nvar += nvar_tmp;
|
||||
#if 0
|
||||
///LOG_M: the channel estimation
|
||||
int nr_frame_rx = proc->frame_rx;
|
||||
char filename[100];
|
||||
for (uint8_t aarx=0; aarx<ue->frame_parms.nb_antennas_rx; aarx++) {
|
||||
sprintf(filename,"PDSCH_CHANNEL_frame%d_slot%d_sym%d_port%d_rx%d.m", nr_frame_rx, nr_slot_rx, m, nl, aarx);
|
||||
sprintf(filename,"PDSCH_CHANNEL_frame%d_slot%d_sym%d_port%d_rx%d.m", frame_rx, nr_slot_rx, m, nl, aarx);
|
||||
int **dl_ch_estimates = ue->pdsch_vars[gNB_id]->dl_ch_estimates;
|
||||
LOG_M(filename,"channel_F",&dl_ch_estimates[nl*ue->frame_parms.nb_antennas_rx+aarx][ue->frame_parms.ofdm_symbol_size*m],ue->frame_parms.ofdm_symbol_size, 1, 1);
|
||||
}
|
||||
@@ -929,6 +931,17 @@ int pbch_pdcch_processing(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, nr_
|
||||
sampleShift =
|
||||
nr_adjust_synch_ue(fp, ue, gNB_id, fp->ofdm_symbol_size, dl_ch_estimates_time, frame_rx, nr_slot_rx, 16384);
|
||||
}
|
||||
|
||||
if (get_nrUE_params()->cont_fo_comp && pbchSuccess == 0) {
|
||||
double freq_offset = nr_ue_pbch_freq_offset(fp, estimateSz, dl_ch_estimates);
|
||||
LOG_D(PHY,"compensated frequency offset = %.3f Hz, detected residual frequency offset = %.3f Hz, accumulated frequency offset = %.3f Hz\n", ue->freq_offset, freq_offset, ue->freq_off_acc);
|
||||
|
||||
// PI controller
|
||||
const double PID_P = get_nrUE_params()->freq_sync_P;
|
||||
const double PID_I = get_nrUE_params()->freq_sync_I;
|
||||
ue->freq_offset += freq_offset * PID_P + ue->freq_off_acc * PID_I;
|
||||
ue->freq_off_acc += freq_offset;
|
||||
}
|
||||
}
|
||||
LOG_D(PHY, "Doing N0 measurements in %s\n", __FUNCTION__);
|
||||
nr_ue_rrc_measurements(ue, proc, rxdataF);
|
||||
|
||||
@@ -958,6 +958,13 @@ printf("%d\n", slot);
|
||||
fprintf(csv_file,"avg_round,eff_rate,eff_throughput,TBS\n");
|
||||
}
|
||||
//---------------
|
||||
|
||||
Sched_INFO = malloc(sizeof(*Sched_INFO));
|
||||
if (Sched_INFO == NULL) {
|
||||
LOG_E(PHY, "out of memory\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
for (SNR = snr0; SNR < snr1 && !stop; SNR += .2) {
|
||||
|
||||
varArray_t *table_tx=initVarArray(1000,sizeof(double));
|
||||
@@ -988,6 +995,9 @@ printf("%d\n", slot);
|
||||
n_false_positive = 0;
|
||||
if (n_trials== 1) num_rounds = 1;
|
||||
|
||||
NR_gNB_DLSCH_t *gNB_dlsch = &msgDataTx->dlsch[0][0];
|
||||
nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15 = &gNB_dlsch->harq_process.pdsch_pdu.pdsch_pdu_rel15;
|
||||
|
||||
for (trial = 0; trial < n_trials && !stop; trial++) {
|
||||
|
||||
errors_bit = 0;
|
||||
@@ -1003,19 +1013,11 @@ printf("%d\n", slot);
|
||||
int harq_pid = slot;
|
||||
NR_DL_UE_HARQ_t *UE_harq_process = &UE->dl_harq_processes[0][harq_pid];
|
||||
|
||||
NR_gNB_DLSCH_t *gNB_dlsch = &msgDataTx->dlsch[0][0];
|
||||
nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15 = &gNB_dlsch->harq_process.pdsch_pdu.pdsch_pdu_rel15;
|
||||
|
||||
UE_harq_process->decodeResult = false;
|
||||
round = 0;
|
||||
UE_harq_process->DLround = round;
|
||||
UE_harq_process->first_rx = 1;
|
||||
|
||||
Sched_INFO = malloc(sizeof(*Sched_INFO));
|
||||
if (Sched_INFO == NULL) {
|
||||
LOG_E(PHY, "out of memory\n");
|
||||
exit(1);
|
||||
}
|
||||
memset(Sched_INFO, 0, sizeof(*Sched_INFO));
|
||||
Sched_INFO->sched_response_id = -1;
|
||||
|
||||
@@ -1109,10 +1111,10 @@ printf("%d\n", slot);
|
||||
sprintf(filename,"txsig%d.m", aa);//LOG_M
|
||||
LOG_M(filename,"txs", &txdata[aa][slot_offset +frame_parms->ofdm_symbol_size+frame_parms->nb_prefix_samples0],6*(frame_parms->ofdm_symbol_size+frame_parms->nb_prefix_samples),1,1);
|
||||
}
|
||||
}
|
||||
if (output_fd) {
|
||||
printf("writing txdata to binary file\n");
|
||||
fwrite(txdata[0],sizeof(int32_t),frame_length_complex_samples,output_fd);
|
||||
if (output_fd) {
|
||||
printf("writing txdata to binary file\n");
|
||||
fwrite(txdata[0], sizeof(int32_t), frame_length_complex_samples, output_fd);
|
||||
}
|
||||
}
|
||||
|
||||
int txlev[n_tx];
|
||||
@@ -1296,15 +1298,38 @@ printf("%d\n", slot);
|
||||
}
|
||||
|
||||
if (n_trials == 1) {
|
||||
unsigned int op_format = 1;
|
||||
unsigned int dec = 1;
|
||||
if (output_fd) { // Write in bin format
|
||||
op_format |= MATLAB_RAW;
|
||||
}
|
||||
|
||||
LOG_M("rxsig0.m","rxs0", UE->common_vars.rxdata[0], frame_length_complex_samples, 1, 1);
|
||||
LOG_M("rxsig0.m", "rxs0", UE->common_vars.rxdata[0], frame_length_complex_samples, dec, op_format);
|
||||
if (UE->frame_parms.nb_antennas_rx>1)
|
||||
LOG_M("rxsig1.m","rxs1", UE->common_vars.rxdata[1], frame_length_complex_samples, 1, 1);
|
||||
LOG_M("rxF0.m","rxF0", UE->phy_sim_rxdataF, frame_parms->samples_per_slot_wCP, 1, 1);
|
||||
LOG_M("rxF_ext.m","rxFe",UE->phy_sim_pdsch_rxdataF_ext,g_rbSize*12*14,1,1);
|
||||
LOG_M("chestF0.m","chF0",UE->phy_sim_pdsch_dl_ch_estimates_ext,g_rbSize*12*14,1,1);
|
||||
write_output("rxF_comp.m","rxFc",UE->phy_sim_pdsch_rxdataF_comp,N_RB_DL*12*14,1,1);
|
||||
LOG_M("rxF_llr.m","rxFllr",UE->phy_sim_pdsch_llr,available_bits,1,0);
|
||||
LOG_M("rxsig1.m", "rxs1", UE->common_vars.rxdata[1], frame_length_complex_samples, dec, op_format);
|
||||
LOG_M("rxF0.m", "rxF0", UE->phy_sim_rxdataF, frame_parms->samples_per_slot_wCP, dec, op_format);
|
||||
LOG_M("rxF_ext.m", "rxFe", UE->phy_sim_pdsch_rxdataF_ext, g_rbSize * 12 * 14, dec, op_format);
|
||||
const uint32_t numReSym = (g_rbSize * 12 + 15) & (~15);
|
||||
const uint32_t numValidReSym = g_rbSize * 12;
|
||||
{
|
||||
const int s = rel15->StartSymbolIndex;
|
||||
const int n = rel15->NrOfSymbols;
|
||||
for (int i = s; i < s + n; i++) {
|
||||
char fName[50];
|
||||
snprintf(fName, sizeof(fName), "chestF0_ext_s%d.m", i);
|
||||
LOG_M(fName,
|
||||
"chF0_ext",
|
||||
((c16_t *)UE->phy_sim_pdsch_dl_ch_estimates_ext) + (i * numReSym),
|
||||
numValidReSym,
|
||||
dec,
|
||||
op_format);
|
||||
snprintf(fName, sizeof(fName), "rxF_comp_s%d.m", i);
|
||||
LOG_M(fName, "rxFc", ((c16_t *)UE->phy_sim_pdsch_rxdataF_comp) + (i * numReSym), numValidReSym, dec, op_format);
|
||||
}
|
||||
}
|
||||
LOG_M("chestF0.m", "chF0", UE->phy_sim_pdsch_dl_ch_estimates, frame_parms->ofdm_symbol_size * 14, dec, op_format);
|
||||
op_format = (op_format & (~1));
|
||||
LOG_M("rxF_llr.m", "rxFllr", UE->phy_sim_pdsch_llr, available_bits, dec, op_format);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1316,6 +1341,8 @@ printf("%d\n", slot);
|
||||
n_errs = n_errors[0];
|
||||
} // NSR
|
||||
|
||||
free(Sched_INFO);
|
||||
|
||||
free_channel_desc_scm(gNB2UE);
|
||||
|
||||
for (i = 0; i < n_tx; i++) {
|
||||
|
||||
@@ -239,6 +239,7 @@ int main(int argc, char *argv[])
|
||||
int threadCnt=0;
|
||||
int max_ldpc_iterations = 5;
|
||||
int num_antennas_per_thread = 1;
|
||||
uint32_t log_format = 0;
|
||||
if ((uniqCfg = load_configmodule(argc, argv, CONFIG_ENABLECMDLINEONLY)) == 0) {
|
||||
exit_fun("[NR_ULSIM] Error, configuration module init failed\n");
|
||||
}
|
||||
@@ -250,8 +251,7 @@ int main(int argc, char *argv[])
|
||||
InitSinLUT();
|
||||
|
||||
int c;
|
||||
while ((c = getopt(argc, argv, "--:O:a:b:c:d:ef:g:h:i:k:m:n:p:q:r:s:t:u:v:w:y:z:A:C:F:G:H:I:M:N:PR:S:T:U:L:ZW:E:X:")) != -1) {
|
||||
|
||||
while ((c = getopt(argc, argv, "--:O:a:b:c:d:ef:g:h:i:jk:m:n:p:q:r:s:t:u:v:w:y:z:A:C:F:G:H:I:M:N:PR:S:T:U:L:ZW:E:X:")) != -1) {
|
||||
/* ignore long options starting with '--', option '-O' and their arguments that are handled by configmodule */
|
||||
/* with this opstring getopt returns 1 for non-option arguments, refer to 'man 3 getopt' */
|
||||
if (c == 1 || c == '-' || c == 'O')
|
||||
@@ -345,7 +345,11 @@ int main(int argc, char *argv[])
|
||||
i+=2;
|
||||
} while (optarg[i-1] == ',');
|
||||
break;
|
||||
|
||||
|
||||
case 'j':
|
||||
log_format |= MATLAB_RAW;
|
||||
break;
|
||||
|
||||
case 'k':
|
||||
printf("Setting threequarter_fs_flag\n");
|
||||
openair0_cfg[0].threequarter_fs= 1;
|
||||
@@ -523,6 +527,7 @@ int main(int argc, char *argv[])
|
||||
printf("-g Channel model configuration. Arguments list: Number of arguments = 3, {Channel model: [A] TDLA30, [B] TDLB100, [C] TDLC300}, {Correlation: [l] Low, [m] Medium, [h] High}, {Maximum Doppler shift} e.g. -g A,l,10\n");
|
||||
printf("-h This message\n");
|
||||
printf("-i Change channel estimation technique. Arguments list: Number of arguments=2, Frequency domain {0:Linear interpolation, 1:PRB based averaging}, Time domain {0:Estimates of last DMRS symbol, 1:Average of DMRS symbols}. e.g. -i 1,0\n");
|
||||
printf("-j Save signal buffers in binary format.");
|
||||
printf("-k 3/4 sampling\n");
|
||||
printf("-m MCS value\n");
|
||||
printf("-n Number of trials to simulate\n");
|
||||
@@ -559,7 +564,7 @@ int main(int argc, char *argv[])
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
logInit();
|
||||
set_glog(loglvl);
|
||||
|
||||
@@ -1214,12 +1219,12 @@ int main(int argc, char *argv[])
|
||||
phy_procedures_nrUE_TX(UE, &UE_proc, &phy_data);
|
||||
|
||||
if (n_trials == 1) {
|
||||
LOG_M("txsig0.m", "txs0", &UE->common_vars.txData[0][slot_offset], slot_length, 1, 1);
|
||||
LOG_M("txsig0.m", "txs0", &UE->common_vars.txData[0][slot_offset], slot_length, 1, 1 | log_format);
|
||||
if (precod_nbr_layers > 1) {
|
||||
LOG_M("txsig1.m", "txs1", &UE->common_vars.txData[1][slot_offset], slot_length, 1, 1);
|
||||
if (precod_nbr_layers == 4) {
|
||||
LOG_M("txsig2.m", "txs2", &UE->common_vars.txData[2][slot_offset], slot_length, 1, 1);
|
||||
LOG_M("txsig3.m", "txs3", &UE->common_vars.txData[3][slot_offset], slot_length, 1, 1);
|
||||
LOG_M("txsig1.m", "txs1", &UE->common_vars.txData[1][slot_offset], slot_length, 1, 1 | log_format);
|
||||
if (precod_nbr_layers == 4) {
|
||||
LOG_M("txsig2.m", "txs2", &UE->common_vars.txData[2][slot_offset], slot_length, 1, 1 | log_format);
|
||||
LOG_M("txsig3.m", "txs3", &UE->common_vars.txData[3][slot_offset], slot_length, 1, 1 | log_format);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1293,16 +1298,16 @@ int main(int argc, char *argv[])
|
||||
ul_proc_error = phy_procedures_gNB_uespec_RX(gNB, frame, slot, &UL_INFO);
|
||||
|
||||
if (n_trials == 1 && round == 0) {
|
||||
LOG_M("rxsig0.m", "rx0", &rxdata[0][slot_offset], slot_length, 1, 1);
|
||||
LOG_M("rxsigF0.m", "rxsF0", gNB->common_vars.rxdataF[0][0], 14 * frame_parms->ofdm_symbol_size, 1, 1);
|
||||
LOG_M("rxsig0.m", "rx0", &rxdata[0][slot_offset], slot_length, 1, 1 | log_format);
|
||||
LOG_M("rxsigF0.m", "rxsF0", gNB->common_vars.rxdataF[0][0], 14 * frame_parms->ofdm_symbol_size, 1, 1 | log_format);
|
||||
if (precod_nbr_layers > 1) {
|
||||
LOG_M("rxsig1.m", "rx1", &rxdata[1][slot_offset], slot_length, 1, 1);
|
||||
LOG_M("rxsigF1.m", "rxsF1", gNB->common_vars.rxdataF[0][1], 14 * frame_parms->ofdm_symbol_size, 1, 1);
|
||||
LOG_M("rxsigF1.m", "rxsF1", gNB->common_vars.rxdataF[0][1], 14 * frame_parms->ofdm_symbol_size, 1, 1 | log_format);
|
||||
if (precod_nbr_layers == 4) {
|
||||
LOG_M("rxsig2.m", "rx2", &rxdata[2][slot_offset], slot_length, 1, 1);
|
||||
LOG_M("rxsig3.m", "rx3", &rxdata[3][slot_offset], slot_length, 1, 1);
|
||||
LOG_M("rxsigF2.m", "rxsF2", gNB->common_vars.rxdataF[0][2], 14 * frame_parms->ofdm_symbol_size, 1, 1);
|
||||
LOG_M("rxsigF3.m", "rxsF3", gNB->common_vars.rxdataF[0][3], 14 * frame_parms->ofdm_symbol_size, 1, 1);
|
||||
LOG_M("rxsigF2.m", "rxsF2", gNB->common_vars.rxdataF[0][2], 14 * frame_parms->ofdm_symbol_size, 1, 1 | log_format);
|
||||
LOG_M("rxsigF3.m", "rxsF3", gNB->common_vars.rxdataF[0][3], 14 * frame_parms->ofdm_symbol_size, 1, 1 | log_format);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1316,71 +1321,69 @@ int main(int argc, char *argv[])
|
||||
&pusch_vars->ul_ch_estimates[0][start_symbol * frame_parms->ofdm_symbol_size],
|
||||
frame_parms->ofdm_symbol_size,
|
||||
1,
|
||||
1);
|
||||
1 | log_format);
|
||||
|
||||
LOG_M("rxsigF0_comp.m",
|
||||
"rxsF0_comp",
|
||||
&pusch_vars->rxdataF_comp[0][start_symbol * (off + (NR_NB_SC_PER_RB * pusch_pdu->rb_size))],
|
||||
nb_symb_sch * (off + (NR_NB_SC_PER_RB * pusch_pdu->rb_size)),
|
||||
1,
|
||||
1);
|
||||
1 | log_format);
|
||||
|
||||
if (precod_nbr_layers == 2) {
|
||||
|
||||
LOG_M("chestF3.m",
|
||||
"chF3",
|
||||
&pusch_vars->ul_ch_estimates[3][start_symbol * frame_parms->ofdm_symbol_size],
|
||||
frame_parms->ofdm_symbol_size,
|
||||
1,
|
||||
1);
|
||||
1 | log_format);
|
||||
|
||||
LOG_M("rxsigF2_comp.m",
|
||||
"rxsF2_comp",
|
||||
&pusch_vars->rxdataF_comp[2][start_symbol * (off + (NR_NB_SC_PER_RB * pusch_pdu->rb_size))],
|
||||
nb_symb_sch * (off + (NR_NB_SC_PER_RB * pusch_pdu->rb_size)),
|
||||
1,
|
||||
1);
|
||||
1 | log_format);
|
||||
}
|
||||
|
||||
if (precod_nbr_layers == 4) {
|
||||
|
||||
LOG_M("chestF5.m",
|
||||
"chF5",
|
||||
&pusch_vars->ul_ch_estimates[5][start_symbol * frame_parms->ofdm_symbol_size],
|
||||
frame_parms->ofdm_symbol_size,
|
||||
1,
|
||||
1);
|
||||
1 | log_format);
|
||||
LOG_M("chestF10.m",
|
||||
"chF10",
|
||||
&pusch_vars->ul_ch_estimates[10][start_symbol * frame_parms->ofdm_symbol_size],
|
||||
frame_parms->ofdm_symbol_size,
|
||||
1,
|
||||
1);
|
||||
1 | log_format);
|
||||
LOG_M("chestF15.m",
|
||||
"chF15",
|
||||
&pusch_vars->ul_ch_estimates[15][start_symbol * frame_parms->ofdm_symbol_size],
|
||||
frame_parms->ofdm_symbol_size,
|
||||
1,
|
||||
1);
|
||||
1 | log_format);
|
||||
|
||||
LOG_M("rxsigF4_comp.m",
|
||||
"rxsF4_comp",
|
||||
&pusch_vars->rxdataF_comp[4][start_symbol * (off + (NR_NB_SC_PER_RB * pusch_pdu->rb_size))],
|
||||
nb_symb_sch * (off + (NR_NB_SC_PER_RB * pusch_pdu->rb_size)),
|
||||
1,
|
||||
1);
|
||||
1 | log_format);
|
||||
LOG_M("rxsigF8_comp.m",
|
||||
"rxsF8_comp",
|
||||
&pusch_vars->rxdataF_comp[8][start_symbol * (off + (NR_NB_SC_PER_RB * pusch_pdu->rb_size))],
|
||||
nb_symb_sch * (off + (NR_NB_SC_PER_RB * pusch_pdu->rb_size)),
|
||||
1,
|
||||
1);
|
||||
1 | log_format);
|
||||
LOG_M("rxsigF12_comp.m",
|
||||
"rxsF12_comp",
|
||||
&pusch_vars->rxdataF_comp[12][start_symbol * (off + (NR_NB_SC_PER_RB * pusch_pdu->rb_size))],
|
||||
nb_symb_sch * (off + (NR_NB_SC_PER_RB * pusch_pdu->rb_size)),
|
||||
1,
|
||||
1);
|
||||
1 | log_format);
|
||||
}
|
||||
|
||||
LOG_M("rxsigF0_llr.m",
|
||||
@@ -1388,7 +1391,7 @@ int main(int argc, char *argv[])
|
||||
&pusch_vars->llr[0],
|
||||
precod_nbr_layers * (nb_symb_sch - 1) * NR_NB_SC_PER_RB * pusch_pdu->rb_size * mod_order,
|
||||
1,
|
||||
0);
|
||||
0 | log_format);
|
||||
}
|
||||
|
||||
if ((ulsch_gNB->last_iteration_cnt >= ulsch_gNB->max_ldpc_iterations) || ul_proc_error == 1) {
|
||||
|
||||
@@ -143,31 +143,6 @@ void __attribute__ ((no_sanitize_address)) multipath_channel(channel_desc_t *des
|
||||
|
||||
#else
|
||||
|
||||
void add_noise(c16_t **rxdata,
|
||||
const double **r_re,
|
||||
const double **r_im,
|
||||
const double sigma,
|
||||
const int length,
|
||||
const int slot_offset,
|
||||
const double ts,
|
||||
const int delay,
|
||||
const uint16_t pdu_bit_map,
|
||||
const uint16_t ptrs_bit_map,
|
||||
const uint8_t nb_antennas_rx)
|
||||
{
|
||||
for (int i = 0; i < length; i++) {
|
||||
for (int ap = 0; ap < nb_antennas_rx; ap++) {
|
||||
c16_t *rxd = &rxdata[ap][slot_offset + i + delay];
|
||||
rxd->r = r_re[ap][i] + sqrt(sigma / 2) * gaussZiggurat(0.0, 1.0); // convert to fixed point
|
||||
rxd->i = r_im[ap][i] + sqrt(sigma / 2) * gaussZiggurat(0.0, 1.0);
|
||||
/* Add phase noise if enabled */
|
||||
if (pdu_bit_map & ptrs_bit_map) {
|
||||
phase_noise(ts, &rxdata[ap][slot_offset + i + delay].r, &rxdata[ap][slot_offset + i + delay].i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void __attribute__ ((no_sanitize_address)) multipath_channel(channel_desc_t *desc,
|
||||
double *tx_sig_re[NB_ANTENNAS_TX],
|
||||
double *tx_sig_im[NB_ANTENNAS_TX],
|
||||
|
||||
@@ -23,47 +23,41 @@
|
||||
#include "sim.h"
|
||||
|
||||
|
||||
static uint16_t LUTSin[ResolSinCos+1];
|
||||
/* linear phase noise model */
|
||||
void phase_noise(double ts, int16_t * InRe, int16_t * InIm)
|
||||
void phase_noise(double ts, int16_t *InRe, int16_t *InIm)
|
||||
{
|
||||
static uint64_t i=0;
|
||||
int32_t x=0 ,y=0;
|
||||
double fd = 300;//0.01*30000
|
||||
int16_t SinValue = 0, CosValue= 0;
|
||||
double IdxDouble = (double)(i*fd * ts * ResolSinCos * 4);
|
||||
int16_t IdxModulo = ((int32_t)(IdxDouble>0 ? IdxDouble+0.5 : IdxDouble-0.5)) % (ResolSinCos*4);
|
||||
IdxModulo = IdxModulo<0 ? IdxModulo+ResolSinCos*4 : IdxModulo;
|
||||
|
||||
if(IdxModulo<2*ResolSinCos) {//< 2 check for 1st and 2nd
|
||||
if(IdxModulo < ResolSinCos) {// 1st Quadrant
|
||||
SinValue = LUTSin[IdxModulo];
|
||||
CosValue = LUTSin[ResolSinCos-IdxModulo];
|
||||
}
|
||||
else {// 2nd Quadrant
|
||||
SinValue = LUTSin[2*ResolSinCos-IdxModulo];
|
||||
CosValue = -LUTSin[IdxModulo-ResolSinCos];
|
||||
}
|
||||
}
|
||||
else {// 3rd and 4th Quadrant
|
||||
if(IdxModulo < 3*ResolSinCos) {// 3rd Quadrant
|
||||
SinValue = -LUTSin[IdxModulo-2*ResolSinCos];
|
||||
CosValue = -LUTSin[3*ResolSinCos-IdxModulo];
|
||||
}
|
||||
else {//4th Quadrant
|
||||
SinValue = -LUTSin[4*ResolSinCos-IdxModulo];
|
||||
CosValue = LUTSin[IdxModulo-3*ResolSinCos];
|
||||
}
|
||||
}
|
||||
x = ( ((int32_t)InRe[0] * CosValue) - ((int32_t)InIm[0] * SinValue ));
|
||||
y = ( ((int32_t)InIm[0] * CosValue) + ((int32_t)InRe[0] * SinValue ));
|
||||
InRe[0]= (int16_t)(x>>14);
|
||||
InIm[0]= (int16_t)(y>>14);
|
||||
double phase = (double)(i * fd * ts);
|
||||
c16_t rot = get_sin_cos(phase);
|
||||
c16_t val = {.r = *InRe, .i = *InIm};
|
||||
val = c16mulShift(val, rot, 14);
|
||||
*InRe = val.r;
|
||||
*InIm = val.i;
|
||||
i++;
|
||||
}
|
||||
/* Initialisation function for SIN table values */
|
||||
void InitSinLUT( void ) {
|
||||
for ( int i=0; i<(ResolSinCos+1); i++ ) {
|
||||
LUTSin[i] = sin((double)(M_PI*i)/(2*ResolSinCos)) * (1<<14); //Format: Q14
|
||||
|
||||
void add_noise(c16_t **rxdata,
|
||||
const double **r_re,
|
||||
const double **r_im,
|
||||
const double sigma,
|
||||
const int length,
|
||||
const int slot_offset,
|
||||
const double ts,
|
||||
const int delay,
|
||||
const uint16_t pdu_bit_map,
|
||||
const uint16_t ptrs_bit_map,
|
||||
const uint8_t nb_antennas_rx)
|
||||
{
|
||||
for (int i = 0; i < length; i++) {
|
||||
for (int ap = 0; ap < nb_antennas_rx; ap++) {
|
||||
c16_t *rxd = &rxdata[ap][slot_offset + i + delay];
|
||||
rxd->r = r_re[ap][i] + sqrt(sigma / 2) * gaussZiggurat(0.0, 1.0); // convert to fixed point
|
||||
rxd->i = r_im[ap][i] + sqrt(sigma / 2) * gaussZiggurat(0.0, 1.0);
|
||||
/* Add phase noise if enabled */
|
||||
if (pdu_bit_map & ptrs_bit_map) {
|
||||
phase_noise(ts, &rxdata[ap][slot_offset + i + delay].r, &rxdata[ap][slot_offset + i + delay].i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1663,7 +1663,7 @@ channel_desc_t *new_channel_desc_scm(uint8_t nb_tx,
|
||||
maxDoppler = 0;
|
||||
chan_desc->sat_height = 600e3;
|
||||
chan_desc->enable_dynamic_delay = true;
|
||||
chan_desc->enable_dynamic_Doppler = false; // TODO: requires UE to support continuous Doppler estimation, compensation and pre-compensation
|
||||
chan_desc->enable_dynamic_Doppler = true;
|
||||
fill_channel_desc(chan_desc,nb_tx,
|
||||
nb_rx,
|
||||
nb_taps,
|
||||
@@ -1762,6 +1762,11 @@ void set_channeldesc_name(channel_desc_t *cdesc,char *modelname) {
|
||||
cdesc->model_name=strdup(modelname);
|
||||
}
|
||||
|
||||
void set_channeldesc_direction(channel_desc_t *cdesc, bool is_uplink)
|
||||
{
|
||||
cdesc->is_uplink = is_uplink;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_CH_POWER
|
||||
double accumulated_ch_power = 0;
|
||||
int ch_power_count = 0;
|
||||
|
||||
@@ -139,6 +139,8 @@ typedef struct {
|
||||
float Doppler_phase_inc;
|
||||
/// current Doppler phase of each RX antenna (for continuous phase from one block to the next)
|
||||
float *Doppler_phase_cur;
|
||||
/// flag indicating if channel direction is UL or DL
|
||||
bool is_uplink;
|
||||
} channel_desc_t;
|
||||
|
||||
typedef struct {
|
||||
@@ -358,6 +360,7 @@ void free_channel_desc_scm(channel_desc_t *ch);
|
||||
\param module_id identifies the channel model. should be define as a macro in simu.h
|
||||
*/
|
||||
void set_channeldesc_owner(channel_desc_t *cdesc, channelmod_moduleid_t module_id);
|
||||
|
||||
/**
|
||||
\brief This function set a model name to a model descriptor, can be later used to identify a allocated channel model
|
||||
\param cdesc points to the model descriptor
|
||||
@@ -365,6 +368,13 @@ void set_channeldesc_owner(channel_desc_t *cdesc, channelmod_moduleid_t module_i
|
||||
*/
|
||||
void set_channeldesc_name(channel_desc_t *cdesc,char *modelname);
|
||||
|
||||
/**
|
||||
\brief This function set a channel model direction to either uplink or downlink
|
||||
\param cdesc points to the model descriptor
|
||||
\param is_uplink indicates if this channel is applied in uplink (not downlink) direction
|
||||
*/
|
||||
void set_channeldesc_direction(channel_desc_t *cdesc, bool is_uplink);
|
||||
|
||||
/** \fn void get_cexp_doppler(struct complexd *cexp_doppler, channel_desc_t *chan_desc, const uint32_t length)
|
||||
\brief This routine generates the complex exponential to apply the Doppler shift
|
||||
\param cexp_doppler Output with the complex exponential of Doppler shift
|
||||
@@ -379,32 +389,6 @@ void get_cexp_doppler(struct complexd *cexp_doppler, channel_desc_t *chan_desc,
|
||||
*/
|
||||
int random_channel(channel_desc_t *desc, uint8_t abstraction_flag);
|
||||
|
||||
/**
|
||||
\brief Add AWGN noise and phase noise if enabled
|
||||
\param rxdata output data with noise
|
||||
\param r_re real part of input data without noise
|
||||
\param r_im imaginary part of input data without noise
|
||||
\param sigma noise power
|
||||
\param length number of samples to apply the noise
|
||||
\param slot_offset slot offset to start applying the noise
|
||||
\param ts sampling time
|
||||
\param delay introduce delay in terms of number of samples
|
||||
\param pdu_bit_map bitmap indicating presence of optional PDUs
|
||||
\param ptrs_bit_map
|
||||
\param nb_antennas_rx number of receive antennas
|
||||
*/
|
||||
void add_noise(c16_t **rxdata,
|
||||
const double **r_re,
|
||||
const double **r_im,
|
||||
const double sigma,
|
||||
const int length,
|
||||
const int slot_offset,
|
||||
const double ts,
|
||||
const int delay,
|
||||
const uint16_t pdu_bit_map,
|
||||
const uint16_t ptrs_bit_map,
|
||||
const uint8_t nb_antennas_rx);
|
||||
|
||||
/**\fn void multipath_channel(channel_desc_t *desc,
|
||||
double tx_sig_re[NB_ANTENNAS_TX],
|
||||
double tx_sig_im[NB_ANTENANS_TX],
|
||||
@@ -570,16 +554,38 @@ double N_RB2sampling_rate(uint16_t N_RB);
|
||||
double N_RB2channel_bandwidth(uint16_t N_RB);
|
||||
|
||||
/* Linear phase noise model */
|
||||
/*!
|
||||
/**
|
||||
\brief This function produce phase noise and add to input signal
|
||||
\param ts Sampling time
|
||||
\param ts Sampling time
|
||||
\param *Re *Im Real and Imag part of the signal
|
||||
*/
|
||||
//look-up table for the sine (cosine) function
|
||||
#define ResolSinCos 100
|
||||
void InitSinLUT( void );
|
||||
void phase_noise(double ts, int16_t * InRe, int16_t * InIm);
|
||||
void phase_noise(double ts, int16_t *InRe, int16_t *InIm);
|
||||
|
||||
/**
|
||||
\brief Add AWGN noise and phase noise if enabled
|
||||
\param rxdata output data with noise
|
||||
\param r_re real part of input data without noise
|
||||
\param r_im imaginary part of input data without noise
|
||||
\param sigma noise power
|
||||
\param length number of samples to apply the noise
|
||||
\param slot_offset slot offset to start applying the noise
|
||||
\param ts sampling time
|
||||
\param delay introduce delay in terms of number of samples
|
||||
\param pdu_bit_map bitmap indicating presence of optional PDUs
|
||||
\param ptrs_bit_map
|
||||
\param nb_antennas_rx number of receive antennas
|
||||
*/
|
||||
void add_noise(c16_t **rxdata,
|
||||
const double **r_re,
|
||||
const double **r_im,
|
||||
const double sigma,
|
||||
const int length,
|
||||
const int slot_offset,
|
||||
const double ts,
|
||||
const int delay,
|
||||
const uint16_t pdu_bit_map,
|
||||
const uint16_t ptrs_bit_map,
|
||||
const uint8_t nb_antennas_rx);
|
||||
|
||||
void do_DL_sig(sim_t *sim,
|
||||
uint16_t subframe,
|
||||
|
||||
@@ -469,6 +469,10 @@ typedef ul_info_transfer_cnf_t dl_info_transfer_cnf_t;
|
||||
*/
|
||||
typedef ul_info_transfer_ind_t dl_info_transfer_ind_t;
|
||||
|
||||
typedef struct nas_nos1_msg_s {
|
||||
int dummy; // This dummy element is to avoid CLANG warning: empty struct has size 0 in C, size 1 in C++
|
||||
} nas_nos1_msg_t;
|
||||
|
||||
typedef struct nas_pdu_session_req_s {
|
||||
int pdusession_id;
|
||||
int pdusession_type;
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/sctp.h>
|
||||
#include "common/5g_platform_types.h"
|
||||
#include "common/platform_constants.h"
|
||||
|
||||
//-------------------------------------------------------------------------------------------//
|
||||
// Defines to access message fields.
|
||||
@@ -92,12 +93,6 @@ typedef struct f1ap_net_config_t {
|
||||
uint16_t DUport;
|
||||
} f1ap_net_config_t;
|
||||
|
||||
typedef struct f1ap_plmn_t {
|
||||
uint16_t mcc;
|
||||
uint16_t mnc;
|
||||
uint8_t mnc_digit_length;
|
||||
} f1ap_plmn_t;
|
||||
|
||||
typedef struct f1ap_cp_tnl_s {
|
||||
in_addr_t tl_address; // currently only IPv4 supported
|
||||
uint16_t port;
|
||||
@@ -129,7 +124,7 @@ typedef struct f1ap_tdd_info_t {
|
||||
|
||||
typedef struct f1ap_served_cell_info_t {
|
||||
// NR CGI
|
||||
f1ap_plmn_t plmn;
|
||||
plmn_id_t plmn;
|
||||
uint64_t nr_cellid; // NR Global Cell Id
|
||||
|
||||
// NR Physical Cell Ids
|
||||
@@ -140,7 +135,7 @@ typedef struct f1ap_served_cell_info_t {
|
||||
|
||||
// Number of slice support items (max 16, could be increased to as much as 1024)
|
||||
uint16_t num_ssi;
|
||||
nssai_t nssai[16];
|
||||
nssai_t nssai[MAX_NUM_SLICES];
|
||||
|
||||
f1ap_mode_t mode;
|
||||
union {
|
||||
@@ -192,7 +187,7 @@ typedef struct f1ap_sib_msg_t {
|
||||
} f1ap_sib_msg_t;
|
||||
|
||||
typedef struct served_cells_to_activate_s {
|
||||
f1ap_plmn_t plmn;
|
||||
plmn_id_t plmn;
|
||||
// NR Global Cell Id
|
||||
uint64_t nr_cellid;
|
||||
/// NRPCI [int 0..1007]
|
||||
@@ -239,7 +234,7 @@ typedef struct f1ap_gnb_cu_configuration_update_acknowledge_s {
|
||||
uint16_t num_cells_failed_to_be_activated;
|
||||
struct {
|
||||
// NR CGI
|
||||
f1ap_plmn_t plmn;
|
||||
plmn_id_t plmn;
|
||||
uint64_t nr_cellid;
|
||||
uint16_t cause;
|
||||
} cells_failed_to_be_activated[F1AP_MAX_NB_CELLS];
|
||||
@@ -256,7 +251,7 @@ typedef struct f1ap_gnb_cu_configuration_update_acknowledge_s {
|
||||
struct {
|
||||
uint32_t gNB_CU_ue_id;
|
||||
// NR CGI
|
||||
f1ap_plmn_t ue_plmn;
|
||||
plmn_id_t ue_plmn;
|
||||
uint64_t ue_nr_cellid;
|
||||
} dedicatedSIDeliveryNeededUEs[F1AP_MAX_NO_UE_ID];
|
||||
} f1ap_gnb_cu_configuration_update_acknowledge_t;
|
||||
@@ -283,7 +278,7 @@ typedef struct f1ap_gnb_du_configuration_update_s {
|
||||
/// int cells_to_modify
|
||||
uint16_t num_cells_to_modify;
|
||||
struct {
|
||||
f1ap_plmn_t old_plmn;
|
||||
plmn_id_t old_plmn;
|
||||
uint64_t old_nr_cellid; // NR Global Cell Id
|
||||
f1ap_served_cell_info_t info;
|
||||
f1ap_gnb_du_system_info_t *sys_info;
|
||||
@@ -293,7 +288,7 @@ typedef struct f1ap_gnb_du_configuration_update_s {
|
||||
uint16_t num_cells_to_delete;
|
||||
struct {
|
||||
// NR CGI
|
||||
f1ap_plmn_t plmn;
|
||||
plmn_id_t plmn;
|
||||
uint64_t nr_cellid; // NR Global Cell Id
|
||||
} cell_to_delete[F1AP_MAX_NB_CELLS];
|
||||
/// gNB-DU unique ID, at least within a gNB-CU (0 .. 2^36 - 1)
|
||||
@@ -333,7 +328,7 @@ typedef struct f1ap_dl_rrc_message_s {
|
||||
|
||||
typedef struct f1ap_initial_ul_rrc_message_s {
|
||||
uint32_t gNB_DU_ue_id;
|
||||
f1ap_plmn_t plmn;
|
||||
plmn_id_t plmn;
|
||||
/// nr cell id
|
||||
uint64_t nr_cellid;
|
||||
/// crnti
|
||||
@@ -475,7 +470,7 @@ typedef struct f1ap_ue_context_setup_s {
|
||||
uint32_t gNB_CU_ue_id;
|
||||
uint32_t gNB_DU_ue_id;
|
||||
// SpCell Info
|
||||
f1ap_plmn_t plmn;
|
||||
plmn_id_t plmn;
|
||||
uint64_t nr_cellid;
|
||||
uint8_t servCellIndex;
|
||||
uint8_t *cellULConfigured;
|
||||
@@ -549,7 +544,7 @@ typedef struct f1ap_paging_ind_s {
|
||||
uint16_t ueidentityindexvalue;
|
||||
uint64_t fiveg_s_tmsi;
|
||||
uint8_t fiveg_s_tmsi_length;
|
||||
f1ap_plmn_t plmn;
|
||||
plmn_id_t plmn;
|
||||
uint64_t nr_cellid;
|
||||
uint8_t paging_drx;
|
||||
} f1ap_paging_ind_t;
|
||||
|
||||
@@ -435,10 +435,8 @@ typedef enum ngap_paging_ind_present_s {
|
||||
} ngap_paging_ind_present_t;
|
||||
|
||||
typedef struct {
|
||||
uint16_t mcc;
|
||||
uint16_t mnc;
|
||||
uint8_t mnc_digit_length;
|
||||
uint8_t num_nssai;
|
||||
plmn_id_t plmn;
|
||||
uint16_t num_nssai;
|
||||
nssai_t s_nssai[8];
|
||||
} ngap_plmn_t;
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user