Commit 19c62290 authored by Laurent's avatar Laurent

merge develop, compile ok

parents 93550b1c 3a7ac982
......@@ -12,3 +12,9 @@ targets/bin/
# vscode
.vscode
# Tags for vim/global
GPATH
GRTAGS
GTAGS
tags
......@@ -34,7 +34,7 @@
import sys # arg
import re # reg
import yaml
import constants as CONST
#-----------------------------------------------------------
# Parsing Command Line Arguements
......
......@@ -27,61 +27,111 @@
# pexpect
#---------------------------------------------------------------------
#to use isfile
import os
import sys
#to use logging.info()
import logging
#to create a SSH object locally in the methods
import sshconnection
#time.sleep
import time
#to load cots_ue dictionary
import yaml
class CotsUe:
def __init__(self,model,UEIPAddr,UEUserName,UEPassWord):
self.model = model
self.UEIPAddr = UEIPAddr
self.UEUserName = UEUserName
self.UEPassWord = UEPassWord
self.runargs = '' #on of off to toggle airplane mode on/off
def __init__(self,ADBIPAddr,ADBUserName,ADBPassWord):
self.cots_id = '' #cots id from yaml oppo, s10 etc...
self.ADBIPAddr = ADBIPAddr
self.ADBUserName = ADBUserName
self.ADBPassWord = ADBPassWord
self.cots_run_mode = '' #on of off to toggle airplane mode on/off
self.__cots_cde_dict_file = 'cots_ue_ctl.yaml'
self.__SetAirplaneRetry = 3
#-----------------$
#PUBLIC Methods$
#-----------------$
def Check_Airplane(self):
mySSH = sshconnection.SSHConnection()
mySSH.open(self.UEIPAddr, self.UEUserName, self.UEPassWord)
status=mySSH.cde_check_value('sudo adb shell settings get global airplane_mode_on ', ['0','1'],5)
mySSH.open(self.ADBIPAddr, self.ADBUserName, self.ADBPassWord)
status=mySSH.cde_check_value('adb shell settings get global airplane_mode_on ', ['0','1'],5)
mySSH.close()
return status
#simply check if the device id exists in the dictionary
#returns true if it exists, false otherwise
def Check_Exists(self,target_id):
#load cots commands dictionary
if (os.path.isfile(self.__cots_cde_dict_file)):
yaml_file=self.__cots_cde_dict_file
elif (os.path.isfile('ci-scripts/'+self.__cots_cde_dict_file)):
yaml_file='ci-scripts/'+self.__cots_cde_dict_file
else:
logging.error("COTS UE dictionary yaml file cannot be found")
sys.exit("COTS UE dictionary yaml file cannot be found")
#load cots commands dictionary
with open(yaml_file,'r') as file:
cots_ue_ctl = yaml.load(file,Loader=yaml.FullLoader)
#check if ue id is in the dictionary
if target_id in cots_ue_ctl:
return True
else:
return False
def Set_Airplane(self, target_id, target_state_str):
#loading cots commands dictionary
def Set_Airplane(self,target_state_str):
mySSH = sshconnection.SSHConnection()
mySSH.open(self.UEIPAddr, self.UEUserName, self.UEPassWord)
mySSH.command('sudo adb start-server','$',5)
logging.info("Toggling COTS UE Airplane mode to : "+target_state_str)
current_state = self.Check_Airplane()
if target_state_str.lower()=="on":
target_state=1
if (os.path.isfile(self.__cots_cde_dict_file)):
yaml_file=self.__cots_cde_dict_file
elif (os.path.isfile('ci-scripts/'+self.__cots_cde_dict_file)):
yaml_file='ci-scripts/'+self.__cots_cde_dict_file
else:
target_state=0
if current_state != target_state:
#toggle state
retry = 0
while (current_state!=target_state) and (retry < self.__SetAirplaneRetry):
mySSH.command('sudo adb shell am start -a android.settings.AIRPLANE_MODE_SETTINGS', '\$', 5)
mySSH.command('sudo adb shell input keyevent 20', '\$', 5)
mySSH.command('sudo adb shell input tap 968 324', '\$', 5)
time.sleep(1)
current_state = self.Check_Airplane()
retry+=1
logging.error("COTS UE dictionary yaml file cannot be found")
sys.exit("COTS UE dictionary yaml file cannot be found")
#load cots commands dictionary
with open(yaml_file,'r') as file:
cots_ue_ctl = yaml.load(file,Loader=yaml.FullLoader)
#check if ue id is in the dictionary
if target_id in cots_ue_ctl:
mySSH = sshconnection.SSHConnection()
mySSH.open(self.ADBIPAddr, self.ADBUserName, self.ADBPassWord)
logging.info(str(self.ADBIPAddr)+' '+str(self.ADBUserName)+' '+str(self.ADBPassWord))
mySSH.command('adb start-server','\$',5)
mySSH.command('adb devices','\$',5)
logging.info("Toggling COTS UE Airplane mode to : "+target_state_str)
#get current state
current_state = self.Check_Airplane()
if target_state_str.lower()=="on":
target_state=1
else:
target_state=0
if current_state != target_state:
logging.error("ATTENTION : Could not toggle to : "+target_state_str)
logging.error("Current state is : "+ str(current_state))
#toggle state
retry = 0
while (current_state!=target_state) and (retry < self.__SetAirplaneRetry):
#loop over the command list from dictionary for the selected ue, to switch to required state
for i in range (0,len(cots_ue_ctl[target_id])):
mySSH.command(cots_ue_ctl[target_id][i], '\$', 5)
time.sleep(1)
current_state = self.Check_Airplane()
retry+=1
#could not toggle despite the retry
if current_state != target_state:
logging.error("ATTENTION : Could not toggle to : "+target_state_str)
logging.error("Current state is : "+ str(current_state))
else:
logging.info("Airplane mode is already "+ target_state_str)
mySSH.command('adb kill-server','\$',5)
mySSH.close()
#ue id is NOT in the dictionary
else:
print("Airplane mode is already "+ target_state_str)
mySSH.command('sudo adb kill-server','$',5)
mySSH.close()
logging.error("COTS UE Id from XML could not be found in UE YAML dictionary " + self.__cots_cde_dict_file)
sys.exit("COTS UE Id from XML could not be found in UE YAML dictionary " + self.__cots_cde_dict_file)
......
......@@ -71,6 +71,12 @@ gNBs =
initialDLBWPmappingType_2 = 0;
#this is SS=1,L=12
initialDLBWPstartSymbolAndLength_2 = 54;
initialDLBWPk0_3 = 0;
initialDLBWPmappingType_3 = 0;
#this is SS=1,L=4
initialDLBWPstartSymbolAndLength_3 = 57;
#uplinkConfigCommon
#frequencyInfoUL
ul_frequencyBand = 78;
......@@ -105,8 +111,8 @@ gNBs =
#1,2,4,8,10,20,40,80
ra_ResponseWindow = 4;
#ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR
#0=oneeighth,1=onefourth,2=half,3=one,4=two,5=four,6=eight,7=sixteen
ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 3;
#1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen
ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4;
#oneHalf (0..15) 4,8,12,16,...60,64
ssb_perRACH_OccasionAndCB_PreamblesPerSSB = 15;
#ra_ContentionResolutionTimer
......@@ -114,8 +120,8 @@ gNBs =
ra_ContentionResolutionTimer = 7;
rsrp_ThresholdSSB = 19;
#prach-RootSequenceIndex_PR
#0 = 839, 1 = 139
prach_RootSequenceIndex_PR = 1;
#1 = 839, 2 = 139
prach_RootSequenceIndex_PR = 2;
prach_RootSequenceIndex = 1;
# SCS for msg1, can only be 15 for 30 kHz < 6 GHz, takes precendence over the one derived from prach-ConfigIndex
#
......@@ -135,7 +141,11 @@ gNBs =
# this is SS=0 L=12
initialULBWPstartSymbolAndLength_1 = 69;
initialULBWPk2_2 = 7;
initialULBWPmappingType_2 = 1;
# this is SS=10 L=4
initialULBWPstartSymbolAndLength_2 = 52;
msg3_DeltaPreamble = 1;
p0_NominalWithGrant =-90;
......@@ -235,10 +245,14 @@ RUs = (
att_rx = 0;
bands = [7];
max_pdschReferenceSignalPower = -27;
max_rxgain = 114;
max_rxgain = 75;
eNB_instances = [0];
#sdr_addrs = "addr=192.168.10.2,second_addr=192.168.20.2";
clock_src = "internal";
#beamforming 1x4 matrix:
bf_weights = [0x00007fff, 0x0000, 0x0000, 0x0000];
sdr_addrs = "addr=192.168.10.2,second_addr=192.168.20.2";
clock_src = "external";
}
);
......
9d690a12: #oppo
- adb shell input keyevent KEYCODE_POWER
- adb shell input swipe 300 700 300 0
- adb shell am start -a android.settings.AIRPLANE_MODE_SETTINGS
- adb shell input keyevent 20
- adb shell input tap 968 324
002: #s10
- adb shell input keyevent KEYCODE_POWER
- adb shell input swipe 200 900 200 300
- adb shell am start -a android.settings.AIRPLANE_MODE_SETTINGS
- adb shell input tap 968 324
003: #s20
- adb shell input keyevent KEYCODE_POWER
- adb shell input swipe 200 900 200 300
- adb shell am start -a android.settings.AIRPLANE_MODE_SETTINGS
- adb shell input tap 968 324
004: #xperia
- tbd
- tbd
- tbd
......@@ -83,6 +83,10 @@ nullPointer:common/utils/T/tracer/multi.c:265
// the tests
arrayIndexOutOfBounds:openair2/LAYER2/rlc_v2/tests/test.c:401
//
//-----------------------------------------------------------------------------
// cppcheck does not understand the different lengths of arrays
arrayIndexOutOfBounds:openair1/SIMULATION/TOOLS/random_channel.c:705
arrayIndexOutOfBounds:openair1/SIMULATION/TOOLS/random_channel.c:706
//*****************************************************************************
//
// True problems we don't know how to fix, Suppression is commented out,
......
This diff is collapsed.
......@@ -90,6 +90,7 @@ class RANManagement():
self.epcPcapFile = ''
self.htmlObj = None
self.epcObj = None
self.runtime_stats= ''
......@@ -614,7 +615,7 @@ class RANManagement():
logging.debug('\u001B[1m Analyzing eNB replay logfile \u001B[0m')
logStatus = self.AnalyzeLogFile_eNB(extracted_log_file)
if self.htmlObj is not None:
self.htmlObj.CreateHtmlTestRow('N/A', 'OK', CONST.ALL_PROCESSES_OK)
self.htmlObj.CreateHtmlTestRow(self.runtime_stats, 'OK', CONST.ALL_PROCESSES_OK)
self.eNBLogFiles[int(self.eNB_instance)] = ''
else:
analyzeFile = False
......@@ -643,10 +644,10 @@ class RANManagement():
return
else:
if self.htmlObj is not None:
self.htmlObj.CreateHtmlTestRow('N/A', 'OK', CONST.ALL_PROCESSES_OK)
self.htmlObj.CreateHtmlTestRow(self.runtime_stats, 'OK', CONST.ALL_PROCESSES_OK)
else:
if self.htmlObj is not None:
self.htmlObj.CreateHtmlTestRow('N/A', 'OK', CONST.ALL_PROCESSES_OK)
self.htmlObj.CreateHtmlTestRow(self.runtime_stats, 'OK', CONST.ALL_PROCESSES_OK)
self.eNBmbmsEnables[int(self.eNB_instance)] = False
self.eNBstatuses[int(self.eNB_instance)] = -1
......@@ -712,16 +713,20 @@ class RANManagement():
if runTime != '':
result = re.search('Time executing user inst', str(line))
if result is not None:
userTime = 'to be decoded - 1'
fields=line.split(':')
userTime = 'userTime : ' + fields[1].replace('\n','')
result = re.search('Time executing system inst', str(line))
if result is not None:
systemTime = 'to be decoded - 2'
fields=line.split(':')
systemTime = 'systemTime : ' + fields[1].replace('\n','')
result = re.search('Max. Phy. memory usage:', str(line))
if result is not None:
maxPhyMemUsage = 'to be decoded - 3'
fields=line.split(':')
maxPhyMemUsage = 'maxPhyMemUsage : ' + fields[1].replace('\n','')
result = re.search('Number of context switch.*process origin', str(line))
if result is not None:
nbContextSwitches = 'to be decoded - 4'
fields=line.split(':')
nbContextSwitches = 'nbContextSwitches : ' + fields[1].replace('\n','')
if X2HO_state == CONST.X2_HO_REQ_STATE__IDLE:
result = re.search('target eNB Receives X2 HO Req X2AP_HANDOVER_REQ', str(line))
if result is not None:
......@@ -978,11 +983,12 @@ class RANManagement():
global_status = CONST.ENB_PROCESS_REALTIME_ISSUE
if self.htmlObj is not None:
self.htmlObj.htmleNBFailureMsg=htmleNBFailureMsg
# Runtime statistics
# Runtime statistics for console output and HTML
if runTime != '':
logging.debug(runTime)
logging.debug('Time executing user inst : ' + userTime)
logging.debug('Time executing system inst : ' + systemTime)
logging.debug('Max Physical Memory Usage : ' + maxPhyMemUsage)
logging.debug('Nb Context Switches : ' + nbContextSwitches)
logging.debug(userTime)
logging.debug(systemTime)
logging.debug(maxPhyMemUsage)
logging.debug(nbContextSwitches)
self.runtime_stats='<pre>'+runTime + '\n'+ userTime + '\n' + systemTime + '\n' + maxPhyMemUsage + '\n' + nbContextSwitches+'</pre>'
return global_status
- COTS_UE_Airplane
- Build_PhySim
- Run_PhySim
- Build_eNB
......
......@@ -21,19 +21,27 @@
-->
<testCaseList>
<htmlTabRef>test-airplane-mode</htmlTabRef>
<htmlTabName>AirplaneToggle</htmlTabName>
<htmlTabIcon>tasks</htmlTabIcon>
<htmlTabRef>epc-closure</htmlTabRef>
<htmlTabName>EPC-Closure</htmlTabName>
<htmlTabIcon>log-out</htmlTabIcon>
<TestCaseRequestedList>
010000
060000 060001 060002
</TestCaseRequestedList>
<TestCaseExclusionList></TestCaseExclusionList>
<testCase id="010000">
<class>COTS_UE_Airplane</class>
<desc>Toggle COTS Airplane mode ON</desc>
<cots_ue_airplane_args>ON</cots_ue_airplane_args>
<testCase id="060000">
<class>Terminate_HSS</class>
<desc>Terminate HSS</desc>
</testCase>
<testCase id="060001">
<class>Terminate_MME</class>
<desc>Terminate MME</desc>
</testCase>
<testCase id="060002">
<class>Terminate_SPGW</class>
<desc>Terminate SPGW</desc>
</testCase>
</testCaseList>
......@@ -21,30 +21,28 @@
-->
<testCaseList>
<htmlTabRef>test-fr1-tm1</htmlTabRef>
<htmlTabName>Test-FR1-TM1</htmlTabName>
<htmlTabIcon>tasks</htmlTabIcon>
<repeatCount>1</repeatCount>
<htmlTabRef>epc-start-tab</htmlTabRef>
<htmlTabName>EPC-Start</htmlTabName>
<htmlTabIcon>log-in</htmlTabIcon>
<TestCaseRequestedList>
070001
070000
000100 000101 000102
</TestCaseRequestedList>
<TestCaseExclusionList>
</TestCaseExclusionList>
<testCase id="070000">
<class>Terminate_eNB</class>
<desc>Terminate eNB</desc>
<eNB_instance>0</eNB_instance>
<eNB_serverId>0</eNB_serverId>
<testCase id="000100">
<class>Initialize_HSS</class>
<desc>Initialize HSS</desc>
</testCase>
<testCase id="070001">
<class>Terminate_eNB</class>
<desc>Terminate gNB</desc>
<eNB_instance>1</eNB_instance>
<eNB_serverId>1</eNB_serverId>
<testCase id="000101">
<class>Initialize_MME</class>
<desc>Initialize MME</desc>
</testCase>
</testCaseList>
<testCase id="000102">
<class>Initialize_SPGW</class>
<desc>Initialize SPGW</desc>
</testCase>
</testCaseList>
<!--
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-FR1-TM1</htmlTabRef>
<htmlTabName>FR1</htmlTabName>
<htmlTabIcon>tasks</htmlTabIcon>
<TestCaseRequestedList>
010000
030000
040000
010001
000001
050000
050001
070001
070000
010002
010003
</TestCaseRequestedList>
<TestCaseExclusionList></TestCaseExclusionList>
<testCase id="010000">
<class>Initialize_UE</class>
<desc>Initialize UE</desc>
</testCase>
<testCase id="010003">
<class>Terminate_UE</class>
<desc>Terminate UE</desc>
</testCase>
<testCase id="010001">
<class>Attach_UE</class>
<desc>Attach UE</desc>
</testCase>
<testCase id="010002">
<class>Detach_UE</class>
<desc>Detach UE</desc>
</testCase>
<testCase id="030000">
<class>Initialize_eNB</class>
<desc>Initialize eNB</desc>
<Initialize_eNB_args>-O ci-scripts/conf_files/enb.band7.tm1.fr1.25PRB.usrpb210.conf</Initialize_eNB_args>
<eNB_instance>0</eNB_instance>
<eNB_serverId>0</eNB_serverId>
<air_interface>lte</air_interface>
</testCase>
<testCase id="040000">
<class>Initialize_eNB</class>
<desc>Initialize gNB</desc>
<Initialize_eNB_args>-O ci-scripts/conf_files/gnb.band78.tm1.fr1.106PRB.usrpb210.conf -E</Initialize_eNB_args>
<eNB_instance>1</eNB_instance>
<eNB_serverId>1</eNB_serverId>
<air_interface>nr</air_interface>
</testCase>
<testCase id="000001">
<class>IdleSleep</class>
<desc>Sleep</desc>
<idle_sleep_time_in_sec>20</idle_sleep_time_in_sec>
</testCase>
<testCase id="050000">
<class>Ping</class>
<desc>Ping: 20pings in 20sec</desc>
<ping_args>-c 20</ping_args>
<ping_packetloss_threshold>0</ping_packetloss_threshold>
</testCase>
<testCase id="050001">
<class>Ping</class>
<desc>Ping: 5pings in 1sec</desc>
<ping_args>-c 5 -i 0.2</ping_args>
<ping_packetloss_threshold>0</ping_packetloss_threshold>
</testCase>
<testCase id="070000">
<class>Terminate_eNB</class>
<desc>Terminate eNB</desc>
<eNB_instance>0</eNB_instance>
<eNB_serverId>0</eNB_serverId>
</testCase>
<testCase id="070001">
<class>Terminate_eNB</class>
<desc>Terminate gNB</desc>
<eNB_instance>1</eNB_instance>
<eNB_serverId>1</eNB_serverId>
</testCase>
</testCaseList>
......@@ -52,7 +52,7 @@
<testCase id="090102">
<class>Initialize_OAI_UE</class>
<desc>Initialize NR UE USRP</desc>
<Initialize_OAI_UE_args>--phy-test --usrp-args "addr=192.168.30.2,second_addr=192.168.50.2,clock_source=external,time_source=external" --threadoffset 16 --rrc_config_path .</Initialize_OAI_UE_args>
<Initialize_OAI_UE_args>--phy-test --usrp-args "addr=192.168.30.2,second_addr=192.168.50.2,clock_source=external,time_source=external" --ue-rxgain 75 --threadoffset 16 --rrc_config_path .</Initialize_OAI_UE_args>
<air_interface>NR</air_interface>
</testCase>
......
......@@ -52,7 +52,7 @@
<testCase id="090104">
<class>Initialize_OAI_UE</class>
<desc>Initialize NR UE USRP</desc>
<Initialize_OAI_UE_args>--phy-test --usrp-args "addr=192.168.30.2,second_addr=192.168.50.2,clock_source=external,time_source=external" --threadoffset 16 --rrc_config_path .</Initialize_OAI_UE_args>
<Initialize_OAI_UE_args>--phy-test --usrp-args "addr=192.168.30.2,second_addr=192.168.50.2,clock_source=external,time_source=external" --ue-rxgain 75 --threadoffset 16 --rrc_config_path .</Initialize_OAI_UE_args>
<air_interface>NR</air_interface>
</testCase>
......
This diff is collapsed.
......@@ -1276,7 +1276,10 @@
(Test2: MCS 16 50 PRBs),
(Test3: MCS 28 50 PRBs),
(Test4: MCS 9 217 PRBs),
(Test5: MCS 9 273 PRBs)</desc>
(Test5: MCS 9 273 PRBs),
(Test6: DMRS Type A, 3 DMRS, 4 PTRS, 5 Interpolated Symbols),
(Test7: DMRS Type B, 3 DMRS, 2 PTRS, 7 Interpolated Symbols),
(Test8: DMRS Type B, 3 DMRS, 2 PTRS, 3 Interpolated Symbols)</desc>
<pre_compile_prog></pre_compile_prog>
<compile_prog>$OPENAIR_DIR/cmake_targets/build_oai</compile_prog>
<compile_prog_args> --phy_simulators -c </compile_prog_args>
......@@ -1287,8 +1290,11 @@
-n100 -m16 -s10
-n100 -m28 -s20
-n100 -m9 -R217 -r217 -s5
-n100 -m9 -R273 -r273 -s5</main_exec_args>
<tags>nr_ulsim.test1 nr_ulsim.test2 nr_ulsim.test3 nr_ulsim.test4 nr_ulsim.test5</tags>
-n100 -m9 -R273 -r273 -s5
-n100 -s5 -T 2 1 2 -U 2 0 2
-n100 -s5 -T 2 2 2 -U 2 1 2
-n100 -s5 -a4 -b8 -T 2 1 2 -U 2 1 3</main_exec_args>
<tags>nr_ulsim.test1 nr_ulsim.test2 nr_ulsim.test3 nr_ulsim.test4 nr_ulsim.test5 nr_ulsim.test6 nr_ulsim.test7 nr_ulsim.test8</tags>
<search_expr_true>PUSCH test OK</search_expr_true>
<search_expr_false>segmentation fault|assertion|exiting|fatal</search_expr_false>
<nruns>3</nruns>
......
......@@ -211,7 +211,7 @@ function main() {
GDB=0
CMAKE_BUILD_TYPE="RelWithDebInfo"
echo_info "Will Compile with gdb symbols"
CMAKE_CMD="$CMAKE_CMD -DCMAKE_BUILD_TYPE=RelWithDebInfo"
CMAKE_CMD="$CMAKE_CMD -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_EXPORT_COMPILE_COMMANDS=1"
shift
;;
"MinSizeRel")
......
......@@ -105,3 +105,9 @@ char *itoa(int i) {
return strdup(buffer);
}
void *memcpy1(void *dst,const void *src,size_t n) {
void *ret=dst;
asm volatile("rep movsb" : "+D" (dst) : "c"(n), "S"(src) : "cc","memory");
return(ret);
}
......@@ -15,6 +15,9 @@ int hex_char_to_hex_value (char c);
// Converts an hexadecimal ASCII coded string into its value.**
int hex_string_to_hex_value (uint8_t *hex_value, const char *hex_string, int size);
void *memcpy1(void *dst,const void *src,size_t n);
char *itoa(int i);
#define findInList(keY, result, list, element_type) {\
......
......@@ -16,6 +16,7 @@ This page is valid on tags starting from **`2019.w09`**.
# Soft Modem Build Script
The OAI EPC is developed in a distinct project with it's own [documentation](https://github.com/OPENAIRINTERFACE/openair-epc-fed/wiki) , it is not described here.
OAI softmodem sources, which aim to implement 3GPP compliant UEs, eNodeB and gNodeB can be downloaded from the Eurecom [gitlab repository](./GET_SOURCES.md).
......@@ -33,7 +34,7 @@ The main oai binaries, which are tested by the Continuous Integration process ar
Running the [build_oai](../cmake_targets/build_oai) script also generates some utilities required to build and/or run the oai softmodem binaries:
- `con2uedata`: a binary used to build the UE data from a configuration file. The created file emulates the sim card of a 3GPP compliant phone.
- `conf2uedata`: a binary used to build the UE data from a configuration file. The created file emulates the sim card of a 3GPP compliant phone.
- `nvram`: a binary used to build UE (IMEI...) and EMM (IMSI, registered PLMN) non volatile data.
- `rb_tool`: radio bearer utility
- `genids` T Tracer utility, used at build time to generate T_IDs.h include file. This binary is located in the [T Tracer source file directory](../common/utils/T) .
......
......@@ -33,12 +33,8 @@ holds the source code for (eNB RAN + UE RAN).
For legal issues (licenses), the core network (EPC) source code is now moved away from
the above openairinterface5g git repository.
* A very old version of the EPC is located under the same GitLab Eurecom server (splitted into 2 Git repos):
* [openair-cn](https://gitlab.eurecom.fr/oai/openair-cn.git) with apache license
* [xtables-addons-oai](https://gitlab.eurecom.fr/oai/xtables-addons-oai.git) with GPL license
* **These repositories are no more maintained.**
* A more recent version is available under our GitHub domain:
* [OAI GitHub openair-cn](https://github.com/OPENAIRINTERFACE/openair-cn)
* [OAI GitHub openair-cn domain](https://github.com/OPENAIRINTERFACE)
* Check its wiki pages for more details
Configure git with your name/email address (only important if you are developer and want to contribute/push code to Git Repository):
......@@ -80,8 +76,6 @@ you do not have account on gitlab.eurecom.fr, please register yourself to gitlab
* `git clone git@gitlab.eurecom.fr:oai/openairinterface5g.git`
* Clone with user name/password prompt:
* `git clone https://YOUR_USERNAME@gitlab.eurecom.fr/oai/openairinterface5g.git`
* `git clone https://YOUR_USERNAME@gitlab.eurecom.fr/oai/openair-cn.git`
* `git clone https://YOUR_USERNAME@gitlab.eurecom.fr/oai/xtables-addons-oai.git` (optional, openair-cn build script can do it for you)
# Which branch to checkout?
......
## Table of Contents ##
1. [Legacy 1 Bench](#legacy-1-bench)
2. [Legacy 2 Bench](#legacy-2-bench)
3. [Next Bench for DEV](#next-bench-for-dev)
4. [Next Bench for CI](#next-bench-for-ci)
5. [Indoor Live Network Bench](#indoor-live-network-bench)
6. [Outdoor Live Network Bench](#outdoor-live-network-bench)
## Legacy 1 Bench
**Purpose** : FDD Band 7 and Band 13, LTE-M
**Note** : Legacy1 and Legacy2 are duplicated so that they can run in parallel, thus avoiding a CI bottleneck
**Note** : Faraday Cages 1 and 2 are physically the same cage
![image info](./testbenches_doc_resources/legacy1.jpg)
## Legacy 2 Bench
**Purpose** : TDD Band 40, TM2 2xTX 2xRX
**Note** : CN can run in a container, could also run on Massive
![image info](./testbenches_doc_resources/legacy2.jpg)
## Next Bench for DEV
**Note** : Benetel CI can also run on this bench at night
![image info](./testbenches_doc_resources/next_dev.jpg)
## Next Bench for CI
**Note** : The current test running on Caracal could run on this bench with a N300/N300 setup
![image info](./testbenches_doc_resources/next_ci.jpg)
## Indoor Live Network Bench
![image info](./testbenches_doc_resources/indoor_live.jpg)
## Outdoor Live Network Bench
![image info](./testbenches_doc_resources/outdoor_live.jpg)
STATUS 2020/07/30 : under continuous improvement ; updated the configuration files links with CI approved reference files
STATUS 2020/09/10 : updated the status of interop (end to end UL/DL traffic)
## Table of Contents ##
......@@ -194,7 +194,7 @@ The order to run the different components is important:
1- first, CN
2- then, eNB
3- then, gNB
4- finally, switch UE from airplane mode OFF to ON
4- finally, switch UE from airplane mode ON to OFF (ie Radio from OFF to ON)
It is recommended to redirect the run commands to the same log file (fur further analysis and debug), using ```| tee **YOUR_LOG_FILE**``` especially for eNB and gNB.
It is not very useful for the CN.
......@@ -220,17 +220,16 @@ Execute:
- **gNB** (on the gNB host)
**ATTENTION** : for the gNB execution,
The **-E** option is required to enable the tri-quarter sampling rate when using a B2xx serie USRP
The **-E** option is **NOT supported** when using a a N300 USRP
Execute:
```
~/openairinterface5g/cmake_targets/ran_build/build$ sudo ./nr-softmodem -O **YOUR_GNB_CONF_FILE** -E | tee **YOUR_LOG_FILE**
```
**ATTENTION** : for the gNB execution,
The -E option is required to enable the tri-quarter sampling rate when using a B2xx serie USRP
The -E opton is not needed when using a a N300 USRP
## Test Case
......@@ -377,13 +376,11 @@ The following parts have been validated with FR1 COTS UE:
PDCCH DCI format 1_1 and correponding PDSCH are decoded correctlyby the phone
ACK/NACK (PUCCH format 0) are successfully received at gNB
- On going:
validation of HARQ procedures
Integration with higher layers to replace dummy data with real traffic
- **End-to end UL / DL traffic with HARQ procedures validated (ping, iperf)**
- Known limitations as of May 2020:
only dummy DL traffic
no UL traffic
no end-to-end traffic possible
- Known limitations as of September 2020:
DL traffic : 3Mbps
UL traffic : 1Mbps
some packet losses might still occur even in ideal channel conditions
#/*
# * 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
# */
#---------------------------------------------------------------------
#
# Dockerfile for the Open-Air-Interface eNB service
# Valid for RHEL7 in the OpenShift context (v4.4)
#
#---------------------------------------------------------------------
ARG REGISTRY=localhost
FROM $REGISTRY/oai-build-base:latest.el7 AS builder
ARG GIT_TAG=v1.1.1
WORKDIR /root
RUN if [ "$EURECOM_PROXY" == true ]; then git config --global http.proxy http://:@proxy.eurecom.fr:8080; fi
RUN git clone --depth=1 --branch=$GIT_TAG https://gitlab.eurecom.fr/oai/openairinterface5g.git
COPY patches patches/
RUN patch -p1 -d openairinterface5g < patches/disable_building_nasmesh_and_rbtool.patch \
&& patch -p1 -d openairinterface5g < patches/disable_sched_fifo_fail_exits.patch
RUN cd openairinterface5g/cmake_targets \
&& ln -sf /usr/local/bin/asn1c_oai /usr/local/bin/asn1c \
&& ln -sf /usr/local/share/asn1c_oai /usr/local/share/asn1c \
&& ./build_oai -c --eNB -w USRP --verbose-compile
FROM registry.redhat.io/ubi7/ubi
LABEL name="oai-enb" \
version="$GIT_TAG" \
maintainer="Frank A. Zdarsky <fzdarsky@redhat.com>" \
io.k8s.description="openairinterface5g eNB $GIT_TAG." \
io.openshift.tags="oai,enb" \
io.openshift.non-scalable="true"
RUN yum install -y https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm \
&& REPOLIST="rhel-7-server-optional-rpms" \
&& PKGLIST="boost libconfig lksctp-tools protobuf-c iproute iputils procps-ng bind-utils xforms nettle libyaml libusb" \
# && yum -y upgrade-minimal --setopt=tsflags=nodocs --security --sec-severity=Critical --sec-severity=Important && \
&& yum -y install --enablerepo ${REPOLIST} --setopt=tsflag=nodocs ${PKGLIST} \
&& yum -y clean all \
&& rm -rf /var/cache/yum
ENV APP_ROOT=/opt/oai-enb
ENV PATH=${APP_ROOT}:${PATH} HOME=${APP_ROOT}
COPY --from=builder /root/openairinterface5g/cmake_targets/lte_build_oai/build/lte-softmodem ${APP_ROOT}/bin/
COPY --from=builder /root/openairinterface5g/cmake_targets/lte_build_oai/build/*.so* /lib64
COPY --from=builder /usr/local/lib64 /lib64
COPY --from=builder /usr/local/bin/uhd_* /usr/local/bin
COPY --from=builder /usr/local/share/uhd /usr/local/share/uhd
RUN cd /lib64 \
&& ln -sf liboai_eth_transpro.so liboai_transpro.so \
&& ln -sf liboai_usrpdevif.so liboai_device.so \
&& ln -sf libuhd.so.3.13 libuhd.so.3 \
&& ln -sf libuhd.so.3 libuhd.so
COPY scripts ${APP_ROOT}/bin/
COPY configs ${APP_ROOT}/etc/
RUN chmod -R u+x ${APP_ROOT} && \
chgrp -R 0 ${APP_ROOT} && \
chmod -R g=u ${APP_ROOT} /etc/passwd
USER 10001
WORKDIR ${APP_ROOT}
EXPOSE 2152/udp # S1U, GTP/UDP
EXPOSE 22100/tcp # ?
EXPOSE 36412/udp # S1C, SCTP/UDP
EXPOSE 36422/udp # X2C, SCTP/UDP
EXPOSE 50000/udp # IF5 / ORI (control)
EXPOSE 50001/udp # IF5 / ECPRI (data)
CMD ["/opt/oai-enb/bin/lte-softmodem", "-O", "/opt/oai-enb/etc/enb.conf"]
ENTRYPOINT ["/opt/oai-enb/bin/entrypoint.sh"]
......@@ -180,6 +180,17 @@ int attach_rru(RU_t *ru)
((RRU_config_t *)&rru_config_msg.msg[0])->prach_ConfigIndex[0]);
AssertFatal((ru->ifdevice.trx_ctlsend_func(&ru->ifdevice,&rru_config_msg,rru_config_msg.len)!=-1),
"RU %d failed send configuration to remote radio\n",ru->idx);
if ((len = ru->ifdevice.trx_ctlrecv_func(&ru->ifdevice,
&rru_config_msg,
msg_len))<0) {
LOG_I(PHY,"Waiting for RRU %d\n",ru->idx);
} else if (rru_config_msg.type == RRU_config_ok) {
LOG_I(PHY, "RRU_config_ok received\n");
} else {
LOG_E(PHY,"Received incorrect message %d from RRU %d\n",rru_config_msg.type,ru->idx);
}
return 0;
}
......@@ -1442,6 +1453,8 @@ void *ru_thread( void *param ) {
LOG_I(PHY,"Starting RU %d (%s,%s),\n",ru->idx,NB_functions[ru->function],NB_timing[ru->if_timing]);
memcpy((void*)&ru->config,(void*)&RC.gNB[0]->gNB_config,sizeof(ru->config));
if(emulate_rf) {
fill_rf_config(ru,ru->rf_config_file);
nr_init_frame_parms(&ru->config, fp);
......@@ -1464,8 +1477,6 @@ void *ru_thread( void *param ) {
AssertFatal(ret==0,"Cannot connect to remote radio\n");
}
memcpy((void*)&ru->config,(void*)&RC.gNB[0]->gNB_config,sizeof(ru->config));
if (ru->if_south == LOCAL_RF) { // configure RF parameters only
nr_init_frame_parms(&ru->config, fp);
nr_dump_frame_parms(fp);
......@@ -1571,7 +1582,8 @@ void *ru_thread( void *param ) {
if (slot_type == NR_UPLINK_SLOT || slot_type == NR_MIXED_SLOT) {
//if (proc->tti_rx==8) {
if (ru->feprx) ru->feprx(ru,proc->tti_rx);
if (ru->feprx) {
ru->feprx(ru,proc->tti_rx);
//LOG_M("rxdata.m","rxs",ru->common.rxdata[0],1228800,1,1);
LOG_D(PHY,"RU proc: frame_rx = %d, tti_rx = %d\n", proc->frame_rx, proc->tti_rx);
......@@ -1591,6 +1603,7 @@ void *ru_thread( void *param ) {
proc->frame_rx,proc->tti_rx);
free_nr_ru_prach_entry(ru,prach_id);
}
}
}
// At this point, all information for subframe has been received on FH interface
......@@ -2131,26 +2144,29 @@ void set_function_spec_param(RU_t *ru) {
ru->fh_north_out = NULL; // no outgoing fronthaul to north
ru->nr_start_if = NULL; // no if interface
ru->rfdevice.host_type = RAU_HOST;
// FK this here looks messed up. The following lines should be part of the if (ru->function == gNodeB_3GPP), shouldn't they?
ru->fh_south_in = rx_rf; // local synchronous RF RX
ru->fh_south_out = tx_rf; // local synchronous RF TX
ru->start_rf = start_rf; // need to start the local RF interface
ru->stop_rf = stop_rf;
ru->start_write_thread = start_write_thread; // starting RF TX in different thread
printf("configuring ru_id %u (start_rf %p)\n", ru->idx, start_rf);
}
ru->fh_south_in = rx_rf; // local synchronous RF RX
ru->fh_south_out = tx_rf; // local synchronous RF TX
ru->start_rf = start_rf; // need to start the local RF interface
ru->stop_rf = stop_rf;
ru->start_write_thread = start_write_thread; // starting RF TX in different thread
printf("configuring ru_id %u (start_rf %p)\n", ru->idx, start_rf);
/*
if (ru->function == gNodeB_3GPP) { // configure RF parameters only for 3GPP eNodeB, we need to get them from RAU otherwise
fill_rf_config(ru,rf_config_file);
init_frame_parms(&ru->frame_parms,1);
nr_phy_init_RU(ru);
}
ret = openair0_device_load(&ru->rfdevice,&ru->openair0_cfg);
if (setup_RU_buffers(ru)!=0) {
printf("Exiting, cannot initialize RU Buffers\n");
exit(-1);
}*/
printf("configuring ru_id %u (start_rf %p)\n", ru->idx, start_rf);
fill_rf_config(ru,rf_config_file);
init_frame_parms(&ru->frame_parms,1);
nr_phy_init_RU(ru);
ret = openair0_device_load(&ru->rfdevice,&ru->openair0_cfg);
if (setup_RU_buffers(ru)!=0) {
printf("Exiting, cannot initialize RU Buffers\n");
exit(-1);
}
*/
break;
case REMOTE_IF5: // the remote unit is IF5 RRU
......@@ -2203,6 +2219,15 @@ void set_function_spec_param(RU_t *ru) {
exit(-1);
}
if (ru->ifdevice.get_internal_parameter != NULL) {
void *t = ru->ifdevice.get_internal_parameter("fh_if4p5_south_in");
if (t != NULL)
ru->fh_south_in = t;
t = ru->ifdevice.get_internal_parameter("fh_if4p5_south_out");
if (t != NULL)
ru->fh_south_out = t;
}
malloc_IF4p5_buffer(ru);
break;
......
......@@ -364,8 +364,6 @@ static void UE_synch(void *arg) {
}
void processSlotTX( PHY_VARS_NR_UE *UE, UE_nr_rxtx_proc_t *proc) {
fapi_nr_config_request_t *cfg = &UE->nrUE_config;
int tx_slot_type = nr_ue_slot_select(cfg, proc->frame_tx, proc->nr_tti_tx);
uint8_t gNB_id = 0;
......@@ -473,21 +471,22 @@ void UE_processing(void *arg) {
UE_nr_rxtx_proc_t *proc = &rxtxD->proc;
PHY_VARS_NR_UE *UE = rxtxD->UE;
uint8_t gNB_id = 0;
// params for UL time alignment procedure
NR_UL_TIME_ALIGNMENT_t *ul_time_alignment = &UE->ul_time_alignment[gNB_id];
uint8_t numerology = UE->frame_parms.numerology_index;
uint16_t bwp_ul_NB_RB = UE->frame_parms.N_RB_UL;
int slot_tx = proc->nr_tti_tx;
int frame_tx = proc->frame_tx;
processSlotRX(UE, proc);
processSlotTX(UE, proc);
/* UL time alignment
// If the current tx frame and slot match the TA configuration in ul_time_alignment
// then timing advance is processed and set to be applied in the next UL transmission */
if (UE->mac_enabled == 1) {
uint8_t gNB_id = 0;
NR_UL_TIME_ALIGNMENT_t *ul_time_alignment = &UE->ul_time_alignment[gNB_id];
int slot_tx = proc->nr_tti_tx;
int frame_tx = proc->frame_tx;
if (frame_tx == ul_time_alignment->ta_frame && slot_tx == ul_time_alignment->ta_slot) {
uint8_t numerology = UE->frame_parms.numerology_index;
uint16_t bwp_ul_NB_RB = UE->frame_parms.N_RB_UL;
LOG_D(PHY,"Applying timing advance -- frame %d -- slot %d\n", frame_tx, slot_tx);
//if (nfapi_mode!=3){
......@@ -497,9 +496,6 @@ void UE_processing(void *arg) {
//}
}
}
processSlotRX(UE, proc);
processSlotTX(UE, proc);
}
void dummyWrite(PHY_VARS_NR_UE *UE,openair0_timestamp timestamp, int writeBlockSize) {
......@@ -624,6 +620,7 @@ void *UE_thread(void *arg) {
notifiedFIFO_t freeBlocks;
initNotifiedFIFO_nothreadSafe(&freeBlocks);
NR_UE_MAC_INST_t *mac = get_mac_inst(0);
int timing_advance = UE->timing_advance;
for (int i=0; i<RX_NB_TH+1; i++) // RX_NB_TH working + 1 we are making to be pushed
pushNotifiedFIFO_nothreadSafe(&freeBlocks,
......@@ -728,21 +725,26 @@ void *UE_thread(void *arg) {
for (int i=0; i<UE->frame_parms.nb_antennas_tx; i++)
txp[i] = (void *)&UE->common_vars.txdata[i][UE->frame_parms.get_samples_slot_timestamp(
((curMsg->proc.nr_tti_rx + DURATION_RX_TO_TX -2)%nb_slot_frame),&UE->frame_parms,0)];
((slot_nr + DURATION_RX_TO_TX - RX_NB_TH)%nb_slot_frame),&UE->frame_parms,0)];
int readBlockSize, writeBlockSize;
if (slot_nr<(nb_slot_frame - 1)) {
readBlockSize=get_readBlockSize(slot_nr, &UE->frame_parms);
writeBlockSize=UE->frame_parms.get_samples_per_slot(curMsg->proc.nr_tti_tx,&UE->frame_parms);
writeBlockSize=UE->frame_parms.get_samples_per_slot((slot_nr + DURATION_RX_TO_TX - RX_NB_TH) % nb_slot_frame, &UE->frame_parms);
} else {
UE->rx_offset_diff = computeSamplesShift(UE);
readBlockSize=get_readBlockSize(slot_nr, &UE->frame_parms) -
UE->rx_offset_diff;
writeBlockSize=UE->frame_parms.get_samples_per_slot(curMsg->proc.nr_tti_tx,&UE->frame_parms) -
writeBlockSize=UE->frame_parms.get_samples_per_slot((slot_nr + DURATION_RX_TO_TX - RX_NB_TH) % nb_slot_frame, &UE->frame_parms)-
UE->rx_offset_diff;
}
if (UE->timing_advance != timing_advance) {
writeBlockSize -= UE->timing_advance - timing_advance;
timing_advance = UE->timing_advance;
}
AssertFatal(readBlockSize ==
UE->rfdevice.trx_read_func(&UE->rfdevice,
&timestamp,
......@@ -750,29 +752,19 @@ void *UE_thread(void *arg) {
readBlockSize,
UE->frame_parms.nb_antennas_rx),"");
AssertFatal( writeBlockSize ==
UE->rfdevice.trx_write_func(&UE->rfdevice,
timestamp+
UE->frame_parms.get_samples_slot_timestamp(slot_nr,
&UE->frame_parms,DURATION_RX_TO_TX -2) - firstSymSamp -
openair0_cfg[0].tx_sample_advance,
txp,
writeBlockSize,
UE->frame_parms.nb_antennas_tx,
1),"");
if( slot_nr==(nb_slot_frame-1)) {
// read in first symbol of next frame and adjust for timing drift
int first_symbols=UE->frame_parms.ofdm_symbol_size+UE->frame_parms.nb_prefix_samples0; // first symbol of every frames
if ( first_symbols > 0 )
if ( first_symbols > 0 ) {
openair0_timestamp ignore_timestamp;
AssertFatal(first_symbols ==
UE->rfdevice.trx_read_func(&UE->rfdevice,
&timestamp,
&ignore_timestamp,
(void **)UE->common_vars.rxdata,
first_symbols,
UE->frame_parms.nb_antennas_rx),"");
else
} else
LOG_E(PHY,"can't compensate: diff =%d\n", first_symbols);
}
......@@ -783,18 +775,15 @@ void *UE_thread(void *arg) {
notifiedFIFO_elt_t *res;
while (nbSlotProcessing >= RX_NB_TH) {
if ( (res=tryPullTpool(&nf, Tpool)) != NULL ) {
nbSlotProcessing--;
processingData_t *tmp=(processingData_t *)res->msgData;
if (tmp->proc.decoded_frame_rx != -1)
decoded_frame_rx=(((mac->mib->systemFrameNumber.buf[0] >> mac->mib->systemFrameNumber.bits_unused)<<4) | tmp->proc.decoded_frame_rx);
//decoded_frame_rx=tmp->proc.decoded_frame_rx;
res=pullTpool(&nf, Tpool);
nbSlotProcessing--;
processingData_t *tmp=(processingData_t *)res->msgData;
pushNotifiedFIFO_nothreadSafe(&freeBlocks,res);
}
if (tmp->proc.decoded_frame_rx != -1)
decoded_frame_rx=(((mac->mib->systemFrameNumber.buf[0] >> mac->mib->systemFrameNumber.bits_unused)<<4) | tmp->proc.decoded_frame_rx);
//decoded_frame_rx=tmp->proc.decoded_frame_rx;
usleep(200);
pushNotifiedFIFO_nothreadSafe(&freeBlocks,res);
}
if ( (decoded_frame_rx != curMsg->proc.frame_rx) &&
......@@ -803,6 +792,20 @@ void *UE_thread(void *arg) {
LOG_E(PHY,"Decoded frame index (%d) is not compatible with current context (%d), UE should go back to synch mode\n",
decoded_frame_rx, curMsg->proc.frame_rx );
AssertFatal( writeBlockSize ==
UE->rfdevice.trx_write_func(&UE->rfdevice,
timestamp+
UE->frame_parms.get_samples_slot_timestamp(slot_nr,
&UE->frame_parms,DURATION_RX_TO_TX - RX_NB_TH) - firstSymSamp -
openair0_cfg[0].tx_sample_advance - UE->N_TA_offset - UE->timing_advance,
txp,
writeBlockSize,
UE->frame_parms.nb_antennas_tx,
1),"");
for (int i=0; i<UE->frame_parms.nb_antennas_tx; i++)
memset(txp[i], 0, writeBlockSize);
nbSlotProcessing++;
msgToPush->key=slot_nr;
pushTpool(Tpool, msgToPush);
......
......@@ -38,13 +38,12 @@
#include "../../ARCH/ETHERNET/USERSPACE/LIB/if_defs.h"
//#undef FRAME_LENGTH_COMPLEX_SAMPLES //there are two conflicting definitions, so we better make sure we don't use it at all
#include "openair1/PHY/MODULATION/nr_modulation.h"
#include "PHY/phy_vars_nr_ue.h"
#include "PHY/LTE_TRANSPORT/transport_vars.h"
#include "SCHED/sched_common_vars.h"
#include "PHY/MODULATION/modulation_vars.h"
//#include "../../SIMU/USER/init_lte.h"
#include "PHY/NR_REFSIG/nr_mod_table.h"
#include "LAYER2/MAC/mac_vars.h"
#include "RRC/LTE/rrc_vars.h"
......@@ -585,7 +584,7 @@ void init_pdcp(void) {
LOG_I(RLC, "Problem at RLC initiation \n");
}
pdcp_layer_init();
nr_ip_over_LTE_DRB_preconfiguration();*/
nr_DRB_preconfiguration();*/
pdcp_module_init(pdcp_initmask);
pdcp_set_rlc_data_req_func((send_rlc_data_req_func_t) rlc_data_req);
pdcp_set_pdcp_data_ind_func((pdcp_data_ind_func_t) pdcp_data_ind);
......@@ -686,11 +685,14 @@ int main( int argc, char **argv ) {
fapi_nr_config_request_t *nrUE_config = &UE[CC_id]->nrUE_config;
nr_init_frame_parms_ue(frame_parms[CC_id],nrUE_config,NORMAL);
// Overwrite DL frequency (for FR2 testing)
if (downlink_frequency[0][0]!=0)
if (downlink_frequency[0][0]!=0) {
frame_parms[CC_id]->dl_CarrierFreq = downlink_frequency[0][0];
frame_parms[CC_id]->ul_CarrierFreq = downlink_frequency[0][0];
}
init_symbol_rotation(frame_parms[CC_id],frame_parms[CC_id]->dl_CarrierFreq);
init_nr_ue_vars(UE[CC_id],frame_parms[CC_id],0,abstraction_flag);
UE[CC_id]->mac_enabled = 1;
......@@ -767,13 +769,7 @@ int main( int argc, char **argv ) {
for(int CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) {
PHY_vars_UE_g[0][CC_id]->rf_map.card=0;
PHY_vars_UE_g[0][CC_id]->rf_map.chain=CC_id+chain_offset;
#if defined(OAI_USRP) || defined(OAI_ADRV9371_ZC706)
PHY_vars_UE_g[0][CC_id]->hw_timing_advance = timing_advance;
PHY_vars_UE_g[0][CC_id]->timing_advance = timing_advance;
#else
PHY_vars_UE_g[0][CC_id]->hw_timing_advance = 160;
#endif
}
init_NR_UE_threads(1);
......
......@@ -236,13 +236,12 @@ void nr_interleaving_ldpc(uint32_t E, uint8_t Qm, uint8_t *e,uint8_t *f)
}
*/
int j2=0;
fp=f;
switch (Qm) {
case 2:
e0=e;
e1=e0+EQm;
for (int j = 0; j< EQm; j++,j2+=2){
for (int j = 0, j2 = 0; j< EQm; j++,j2+=2){
fp=&f[j2];
fp[0] = e0[j];
fp[1] = e1[j];
......@@ -253,7 +252,7 @@ void nr_interleaving_ldpc(uint32_t E, uint8_t Qm, uint8_t *e,uint8_t *f)
e1=e0+EQm;
e2=e1+EQm;
e3=e2+EQm;
for (int j = 0; j< EQm; j++,j2+=4){
for (int j = 0, j2 = 0; j< EQm; j++,j2+=4){
fp=&f[j2];
fp[0] = e0[j];
fp[1] = e1[j];
......@@ -287,7 +286,7 @@ void nr_interleaving_ldpc(uint32_t E, uint8_t Qm, uint8_t *e,uint8_t *f)
e5=e4+EQm;
e6=e5+EQm;
e7=e6+EQm;
for (int j = 0; j< EQm; j++,j2+=8){
for (int j = 0, j2 = 0; j< EQm; j++,j2+=8){
fp=&f[j2];
fp[0] = e0[j];
fp[1] = e1[j];
......@@ -310,15 +309,67 @@ void nr_interleaving_ldpc(uint32_t E, uint8_t Qm, uint8_t *e,uint8_t *f)
void nr_deinterleaving_ldpc(uint32_t E, uint8_t Qm, int16_t *e,int16_t *f)
{
uint32_t EQm;
EQm = E/Qm;
for (int j = 0; j< EQm; j++){
for (int i = 0; i< Qm; i++){
e[(i*EQm + j)] = f[(i+j*Qm)];
}
int16_t *e1,*e2,*e3,*e4,*e5,*e6,*e7;
switch(Qm) {
case 2:
e1=e+(E/2);
for (int j = 0,j2=0; j< E/2; j+=2,j2+=4){
e[j] = f[j2];
e1[j] = f[j2+1];
e[j+1] = f[j2+2];
e1[j+1] = f[j2+3];
}
break;
case 4:
e1=e+(E/4);
e2=e1+(E/4);
e3=e2+(E/4);
for (int j = 0,j2=0; j< E/4; j++,j2+=4){
e[j] = f[j2];
e1[j] = f[j2+1];
e2[j] = f[j2+2];
e3[j] = f[j2+3];
}
break;
case 6:
e1=e+(E/6);
e2=e1+(E/6);
e3=e2+(E/6);
e4=e3+(E/6);
e5=e4+(E/6);
for (int j = 0,j2=0; j< E/6; j++,j2+=6){
e[j] = f[j2];
e1[j] = f[j2+1];
e2[j] = f[j2+2];
e3[j] = f[j2+3];
e4[j] = f[j2+4];
e5[j] = f[j2+5];
}
break;
case 8:
e1=e+(E/6);
e2=e1+(E/6);
e3=e2+(E/6);
e4=e3+(E/6);
e5=e4+(E/6);
e6=e5+(E/6);
e7=e6+(E/6);
for (int j = 0,j2=0; j< E/8; j++,j2+=8){
e[j] = f[j2];
e1[j] = f[j2+1];
e2[j] = f[j2+2];
e3[j] = f[j2+3];
e4[j] = f[j2+4];
e5[j] = f[j2+5];
e6[j] = f[j2+6];
e7[j] = f[j2+7];
}
break;
default:
AssertFatal(1==0,"Should not get here : Qm %d\n",Qm);
break;
}
}
......
......@@ -27,6 +27,7 @@
#include "PHY/CODING/nrPolar_tools/nr_polar_pbch_defs.h"
#include "PHY/NR_TRANSPORT/nr_transport_proto.h"
#include "PHY/NR_TRANSPORT/nr_transport_common_proto.h"
#include "openair1/PHY/MODULATION/nr_modulation.h"
/*#include "RadioResourceConfigCommonSIB.h"
#include "RadioResourceConfigDedicated.h"
#include "TDD-Config.h"
......@@ -200,6 +201,8 @@ int phy_init_nr_gNB(PHY_VARS_gNB *gNB,
common_vars->rxdataF[i] = (int32_t*)malloc16_clear(fp->samples_per_frame_wCP*sizeof(int32_t));
common_vars->rxdata[i] = (int32_t*)malloc16_clear(fp->samples_per_frame*sizeof(int32_t));
}
common_vars->debugBuff = (int32_t*)malloc16_clear(fp->samples_per_frame*sizeof(int32_t)*100);
common_vars->debugBuff_sample_offset = 0;
// Channel estimates for SRS
......@@ -248,10 +251,11 @@ int phy_init_nr_gNB(PHY_VARS_gNB *gNB,
pusch_vars[ULSCH_id]->ul_ch_estimates_ext = (int32_t **)malloc16(Prx*sizeof(int32_t *) );
pusch_vars[ULSCH_id]->ul_ch_ptrs_estimates = (int32_t **)malloc16(Prx*sizeof(int32_t *) );
pusch_vars[ULSCH_id]->ul_ch_ptrs_estimates_ext = (int32_t **)malloc16(Prx*sizeof(int32_t *) );
pusch_vars[ULSCH_id]->ptrs_phase_per_slot = (int32_t **)malloc16(Prx*sizeof(int32_t *) );
pusch_vars[ULSCH_id]->ul_ch_estimates_time = (int32_t **)malloc16(Prx*sizeof(int32_t *) );
pusch_vars[ULSCH_id]->rxdataF_comp = (int32_t **)malloc16(Prx*sizeof(int32_t *) );
pusch_vars[ULSCH_id]->ul_ch_mag0 = (int32_t **)malloc16(Prx*sizeof(int32_t *) );
pusch_vars[ULSCH_id]->ul_ch_magb0 = (int32_t **)malloc16(Prx*sizeof(int32_t *) );
pusch_vars[ULSCH_id]->ul_ch_mag0 = (int32_t **)malloc16(Prx*sizeof(int32_t *) );
pusch_vars[ULSCH_id]->ul_ch_magb0 = (int32_t **)malloc16(Prx*sizeof(int32_t *) );
pusch_vars[ULSCH_id]->ul_ch_mag = (int32_t **)malloc16(Prx*sizeof(int32_t *) );
pusch_vars[ULSCH_id]->ul_ch_magb = (int32_t **)malloc16(Prx*sizeof(int32_t *) );
pusch_vars[ULSCH_id]->rho = (int32_t **)malloc16_clear(Prx*sizeof(int32_t*) );
......@@ -265,16 +269,18 @@ int phy_init_nr_gNB(PHY_VARS_gNB *gNB,
pusch_vars[ULSCH_id]->ul_ch_estimates_time[i] = (int32_t *)malloc16_clear( 2*sizeof(int32_t)*fp->ofdm_symbol_size );
pusch_vars[ULSCH_id]->ul_ch_ptrs_estimates[i] = (int32_t *)malloc16_clear( sizeof(int32_t)*fp->ofdm_symbol_size*2*fp->symbols_per_slot ); // max intensity in freq is 1 sc every 2 RBs
pusch_vars[ULSCH_id]->ul_ch_ptrs_estimates_ext[i] = (int32_t *)malloc16_clear( sizeof(int32_t)*fp->ofdm_symbol_size*2*fp->symbols_per_slot );
pusch_vars[ULSCH_id]->ptrs_phase_per_slot[i] = (int32_t *)malloc16_clear( sizeof(int32_t)*fp->symbols_per_slot); // symbols per slot
pusch_vars[ULSCH_id]->rxdataF_comp[i] = (int32_t *)malloc16_clear( sizeof(int32_t)*N_RB_UL*12*fp->symbols_per_slot );
pusch_vars[ULSCH_id]->ul_ch_mag0[i] = (int32_t *)malloc16_clear( fp->symbols_per_slot*sizeof(int32_t)*N_RB_UL*12 );
pusch_vars[ULSCH_id]->ul_ch_magb0[i] = (int32_t *)malloc16_clear( fp->symbols_per_slot*sizeof(int32_t)*N_RB_UL*12 );
pusch_vars[ULSCH_id]->ul_ch_mag0[i] = (int32_t *)malloc16_clear( fp->symbols_per_slot*sizeof(int32_t)*N_RB_UL*12 );
pusch_vars[ULSCH_id]->ul_ch_magb0[i] = (int32_t *)malloc16_clear( fp->symbols_per_slot*sizeof(int32_t)*N_RB_UL*12 );
pusch_vars[ULSCH_id]->ul_ch_mag[i] = (int32_t *)malloc16_clear( fp->symbols_per_slot*sizeof(int32_t)*N_RB_UL*12 );
pusch_vars[ULSCH_id]->ul_ch_magb[i] = (int32_t *)malloc16_clear( fp->symbols_per_slot*sizeof(int32_t)*N_RB_UL*12 );
pusch_vars[ULSCH_id]->rho[i] = (int32_t *)malloc16_clear( sizeof(int32_t)*(fp->N_RB_UL*12*7*2) );
}
printf("ULSCH_id %d (before llr alloc) : %p\n",ULSCH_id,gNB->dlsch[0][0]->harq_processes[0]);
pusch_vars[ULSCH_id]->llr = (int16_t *)malloc16_clear( (8*((3*8*6144)+12))*sizeof(int16_t) ); // [hna] 6144 is LTE and (8*((3*8*6144)+12)) is not clear
printf("ULSCH_id %d (after llr alloc) : %p\n",ULSCH_id,gNB->dlsch[0][0]->harq_processes[0]);
printf("ULSCH_id %d (after llr alloc) : %p\n",ULSCH_id,gNB->dlsch[0][0]->harq_processes[0]);
pusch_vars[ULSCH_id]->ul_valid_re_per_slot = (int16_t *)malloc16_clear( sizeof(int16_t)*fp->symbols_per_slot);
} //ulsch_id
/*
for (ulsch_id=0; ulsch_id<NUMBER_OF_UE_MAX; ulsch_id++)
......@@ -335,6 +341,7 @@ void phy_free_nr_gNB(PHY_VARS_gNB *gNB)
free_and_zero(pusch_vars[ULSCH_id]->ul_ch_estimates_time[i]);
free_and_zero(pusch_vars[ULSCH_id]->ul_ch_ptrs_estimates[i]);
free_and_zero(pusch_vars[ULSCH_id]->ul_ch_ptrs_estimates_ext[i]);
free_and_zero(pusch_vars[ULSCH_id]->ptrs_phase_per_slot[i]);
free_and_zero(pusch_vars[ULSCH_id]->rxdataF_comp[i]);
free_and_zero(pusch_vars[ULSCH_id]->ul_ch_mag0[i]);
free_and_zero(pusch_vars[ULSCH_id]->ul_ch_magb0[i]);
......@@ -350,6 +357,8 @@ void phy_free_nr_gNB(PHY_VARS_gNB *gNB)
free_and_zero(pusch_vars[ULSCH_id]->ul_ch_ptrs_estimates);
free_and_zero(pusch_vars[ULSCH_id]->ul_ch_ptrs_estimates_ext);
free_and_zero(pusch_vars[ULSCH_id]->ul_ch_estimates_time);
free_and_zero(pusch_vars[ULSCH_id]->ptrs_phase_per_slot);
free_and_zero(pusch_vars[ULSCH_id]->ul_valid_re_per_slot);
free_and_zero(pusch_vars[ULSCH_id]->rxdataF_comp);
free_and_zero(pusch_vars[ULSCH_id]->ul_ch_mag0);
free_and_zero(pusch_vars[ULSCH_id]->ul_ch_magb0);
......@@ -494,6 +503,9 @@ void nr_phy_config_request(NR_PHY_Config_t *phy_config) {
compute_nr_prach_seq(short_sequence, num_sequences, rootSequenceIndex, RC.gNB[Mod_id]->X_u);
RC.gNB[Mod_id]->configured = 1;
init_symbol_rotation(fp,fp->dl_CarrierFreq);
LOG_I(PHY,"gNB %d configured\n",Mod_id);
}
......@@ -505,6 +517,15 @@ void init_nr_transport(PHY_VARS_gNB *gNB) {
LOG_I(PHY, "Initialise nr transport\n");
uint16_t grid_size = cfg->carrier_config.dl_grid_size[fp->numerology_index].value;
memset(gNB->num_pdsch_rnti, 0, sizeof(uint16_t)*80);
for (i=0; i <NUMBER_OF_NR_PDCCH_MAX; i++) {
LOG_I(PHY,"Initializing PDCCH list for PDCCH %d/%d\n",i,NUMBER_OF_NR_PDCCH_MAX);
gNB->pdcch_pdu[i].frame=-1;
LOG_I(PHY,"Initializing UL PDCCH list for UL PDCCH %d/%d\n",i,NUMBER_OF_NR_PDCCH_MAX);
gNB->ul_pdcch_pdu[i].frame=-1;
}
for (i=0; i<NUMBER_OF_NR_PUCCH_MAX; i++) {
LOG_I(PHY,"Allocating Transport Channel Buffers for PUCCH %d/%d\n",i,NUMBER_OF_NR_PUCCH_MAX);
gNB->pucch[i] = new_gNB_pucch();
......
......@@ -643,10 +643,6 @@ int init_nr_ue_signal(PHY_VARS_NR_UE *ue,
// create shortcuts
NR_DL_FRAME_PARMS *const fp = &ue->frame_parms;
NR_UE_COMMON *const common_vars = &ue->common_vars;
NR_UE_PDSCH **const pdsch_vars_SI = ue->pdsch_vars_SI;
NR_UE_PDSCH **const pdsch_vars_ra = ue->pdsch_vars_ra;
NR_UE_PDSCH **const pdsch_vars_p = ue->pdsch_vars_p;
NR_UE_PDSCH **const pdsch_vars_mch = ue->pdsch_vars_MCH;
NR_UE_PBCH **const pbch_vars = ue->pbch_vars;
NR_UE_PRACH **const prach_vars = ue->prach_vars;
int i,j,k,l,slot,symb,q;
......@@ -799,10 +795,6 @@ int init_nr_ue_signal(PHY_VARS_NR_UE *ue,
ue->pdcch_vars[th_id][eNB_id] = (NR_UE_PDCCH *)malloc16_clear(sizeof(NR_UE_PDCCH));
}
pdsch_vars_SI[eNB_id] = (NR_UE_PDSCH *)malloc16_clear(sizeof(NR_UE_PDSCH));
pdsch_vars_ra[eNB_id] = (NR_UE_PDSCH *)malloc16_clear(sizeof(NR_UE_PDSCH));
pdsch_vars_p[eNB_id] = (NR_UE_PDSCH *)malloc16_clear(sizeof(NR_UE_PDSCH));
pdsch_vars_mch[eNB_id] = (NR_UE_PDSCH *)malloc16_clear(sizeof(NR_UE_PDSCH));
prach_vars[eNB_id] = (NR_UE_PRACH *)malloc16_clear(sizeof(NR_UE_PRACH));
pbch_vars[eNB_id] = (NR_UE_PBCH *)malloc16_clear(sizeof(NR_UE_PBCH));
......@@ -864,11 +856,6 @@ int init_nr_ue_signal(PHY_VARS_NR_UE *ue,
}
}
phy_init_nr_ue__PDSCH( pdsch_vars_SI[eNB_id], fp );
phy_init_nr_ue__PDSCH( pdsch_vars_ra[eNB_id], fp );
phy_init_nr_ue__PDSCH( pdsch_vars_p[eNB_id], fp );
phy_init_nr_ue__PDSCH( pdsch_vars_mch[eNB_id], fp );
// 100 PRBs * 12 REs/PRB * 4 PDCCH SYMBOLS * 2 LLRs/RE
for (th_id=0; th_id<RX_NB_TH_MAX; th_id++) {
ue->pdcch_vars[th_id][eNB_id]->llr = (int16_t *)malloc16_clear( 2*4*100*12*sizeof(uint16_t) );
......@@ -932,10 +919,6 @@ int init_nr_ue_signal(PHY_VARS_NR_UE *ue,
ue->pdsch_vars[th_id][eNB_id] = (NR_UE_PDSCH *)malloc16_clear( sizeof(NR_UE_PDSCH) );
}
pdsch_vars_SI[eNB_id] = (NR_UE_PDSCH *)malloc16_clear( sizeof(NR_UE_PDSCH) );
pdsch_vars_ra[eNB_id] = (NR_UE_PDSCH *)malloc16_clear( sizeof(NR_UE_PDSCH) );
pdsch_vars_p[eNB_id] = (NR_UE_PDSCH *)malloc16_clear( sizeof(NR_UE_PDSCH) );
if (abstraction_flag == 0) {
for (th_id=0; th_id<RX_NB_TH_MAX; th_id++) {
//phy_init_lte_ue__PDSCH( ue->pdsch_vars[th_id][eNB_id], fp );
......
......@@ -500,3 +500,37 @@ void nr_dft(int32_t *z, int32_t *d, uint32_t Msc_PUSCH)
z[i] = dft_out0[ip];
}
}
void init_symbol_rotation(NR_DL_FRAME_PARMS *fp,uint64_t CarrierFreq) {
const int nsymb = fp->symbols_per_slot * fp->slots_per_frame/10;
const double Tc=(1/480e3/4096);
const double Nu=2048*64*.5;
const double f0= (double)CarrierFreq;
const double Ncp0=16*64 + (144*64*.5);
const double Ncp1=(144*64*.5);
double tl=0,poff,exp_re,exp_im;
double Ncp,Ncpm1=Ncp0;
poff = 2*M_PI*((Ncp0*Tc))*f0;
exp_re = cos(poff);
exp_im = sin(-poff);
fp->symbol_rotation[0]=(int16_t)floor(exp_re*32767);
fp->symbol_rotation[1]=(int16_t)floor(exp_im*32767);
LOG_I(PHY,"Doing symbol rotation calculation for gNB TX/RX, f0 %f Hz, Nsymb %d\n",f0,nsymb);
LOG_I(PHY,"Symbol rotation %d/%d => (%d,%d)\n",0,nsymb,fp->symbol_rotation[0],fp->symbol_rotation[1]);
for (int l=1;l<nsymb;l++) {
if (l==(7*(1<<fp->numerology_index))) Ncp=Ncp0;
else Ncp=Ncp1;
tl += (Nu+Ncpm1)*Tc;
poff = 2*M_PI*(tl + (Ncp*Tc))*f0;
exp_re = cos(poff);
exp_im = sin(-poff);
fp->symbol_rotation[l<<1]=(int16_t)floor(exp_re*32767);
fp->symbol_rotation[1+(l<<1)]=(int16_t)floor(exp_im*32767);
LOG_I(PHY,"Symbol rotation %d/%d => tl %f (%d,%d) (%f)\n",l,nsymb,tl,fp->symbol_rotation[l<<1],fp->symbol_rotation[1+(l<<1)],
(poff/2/M_PI)-floor(poff/2/M_PI));
Ncpm1=Ncp;
}
}
......@@ -103,4 +103,13 @@ int nr_beam_precoding(int32_t **txdataF,
int nb_antenna_ports
);
void apply_nr_rotation(NR_DL_FRAME_PARMS *fp,
int16_t* txdata,
int slot,
int first_symbol,
int nsymb,
int length);
void init_symbol_rotation(NR_DL_FRAME_PARMS *fp,uint64_t CarrierFreq);
#endif
......@@ -27,6 +27,7 @@
This section deals with basic functions for OFDM Modulation.
*/
#include "PHY/defs_eNB.h"
......@@ -47,6 +48,7 @@ void normal_prefix_mod(int32_t *txdataF,int32_t *txdata,uint8_t nsymb,LTE_DL_FRA
PHY_ofdm_mod(txdataF, // input
txdata, // output
frame_parms->ofdm_symbol_size,
1, // number of symbols
frame_parms->nb_prefix_samples0, // number of prefix samples
CYCLIC_PREFIX);
......@@ -191,7 +193,7 @@ void PHY_ofdm_mod(int *input, /// pointer to complex input
/*for (j=0; j<fftsize ; j++) {
output_ptr[j] = temp_ptr[j];
}*/
memcpy((void*)output_ptr,(void*)temp_ptr,fftsize<<2);
memcpy1((void*)output_ptr,(void*)temp_ptr,fftsize<<2);
}
j=fftsize;
......@@ -306,60 +308,23 @@ void do_OFDM_mod(int32_t **txdataF, int32_t **txdata, uint32_t frame,uint16_t ne
}
/*
// OFDM modulation for each symbol
void do_OFDM_mod_symbol(LTE_eNB_COMMON *eNB_common_vars, RU_COMMON *common, uint16_t next_slot, LTE_DL_FRAME_PARMS *frame_parms,int do_precoding)
{
int aa, l, slot_offset, slot_offsetF;
int32_t **txdataF = eNB_common_vars->txdataF;
int32_t **txdataF_BF = common->txdataF_BF;
int32_t **txdata = common->txdata;
slot_offset = (next_slot)*(frame_parms->samples_per_tti>>1);
slot_offsetF = (next_slot)*(frame_parms->ofdm_symbol_size)*((frame_parms->Ncp==EXTENDED) ? 6 : 7);
//printf("Thread %d starting ... aa %d (%llu)\n",omp_get_thread_num(),aa,rdtsc());
for (l=0; l<frame_parms->symbols_per_tti>>1; l++) {
for (aa=0; aa<frame_parms->nb_antennas_tx; aa++) {
//printf("do_OFDM_mod_l, slot=%d, l=%d, NUMBER_OF_OFDM_CARRIERS=%d,OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES=%d\n",next_slot, l,NUMBER_OF_OFDM_CARRIERS,OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES);
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_ENB_BEAM_PRECODING,1);
if (do_precoding==1) beam_precoding(txdataF,txdataF_BF,frame_parms,eNB_common_vars->beam_weights,next_slot,l,aa);
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_ENB_BEAM_PRECODING,0);
//PMCH case not implemented...
if (frame_parms->Ncp == EXTENDED)
PHY_ofdm_mod((do_precoding == 1)?txdataF_BF[aa]:&txdataF[aa][slot_offsetF+l*frame_parms->ofdm_symbol_size], // input
&txdata[aa][slot_offset+l*OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES], // output
frame_parms->ofdm_symbol_size,
1, // number of symbols
frame_parms->nb_prefix_samples, // number of prefix samples
CYCLIC_PREFIX);
else {
if (l==0) {
PHY_ofdm_mod((do_precoding==1)?txdataF_BF[aa]:&txdataF[aa][slot_offsetF+l*frame_parms->ofdm_symbol_size], // input
&txdata[aa][slot_offset], // output
frame_parms->ofdm_symbol_size,
1, // number of symbols
frame_parms->nb_prefix_samples0, // number of prefix samples
CYCLIC_PREFIX);
} else {
PHY_ofdm_mod((do_precoding==1)?txdataF_BF[aa]:&txdataF[aa][slot_offsetF+l*frame_parms->ofdm_symbol_size], // input
&txdata[aa][slot_offset+OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES0+(l-1)*OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES], // output
frame_parms->ofdm_symbol_size,
1, // number of symbols
frame_parms->nb_prefix_samples, // number of prefix samples
CYCLIC_PREFIX);
//printf("txdata[%d][%d]=%d\n",aa,slot_offset+OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES0+(l-1)*OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES,txdata[aa][slot_offset+OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES0+(l-1)*OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES]);
}
}
}
void apply_nr_rotation(NR_DL_FRAME_PARMS *fp,
int16_t* trxdata,
int slot,
int first_symbol,
int nsymb,
int length) {
int symb_offset = (slot%fp->slots_per_subframe)*fp->symbols_per_slot;
for (int sidx=0;sidx<nsymb;sidx++) {
LOG_D(PHY,"Rotating symbol %d, slot %d, symbol_subframe_index %d, length %d (%d,%d)\n",
first_symbol+sidx,slot,sidx+first_symbol+symb_offset,length,
fp->symbol_rotation[2*(sidx+first_symbol+symb_offset)],fp->symbol_rotation[1+2*(sidx+first_symbol+symb_offset)]);
rotate_cpx_vector(trxdata+(sidx*length*2),
&fp->symbol_rotation[2*(sidx+first_symbol+symb_offset)],
trxdata+(sidx*length*2),
length,
15);
}
}
*/
......@@ -133,8 +133,8 @@ int nr_slot_fep(PHY_VARS_NR_UE *ue,
#ifdef DEBUG_FEP
// if (ue->frame <100)
/*LOG_I(PHY,*/printf("slot_fep: frame %d: slot %d, symbol %d, nb_prefix_samples %u, nb_prefix_samples0 %u, slot_offset %u, sample_offset %d,rx_offset %u, frame_length_samples %u\n",
ue->proc.proc_rxtx[(Ns)&1].frame_rx, Ns, symbol, nb_prefix_samples, nb_prefix_samples0, slot_offset, sample_offset, rx_offset, frame_length_samples);
/*LOG_I(PHY,*/printf("slot_fep: slot %d, symbol %d, nb_prefix_samples %u, nb_prefix_samples0 %u, slot_offset %u, sample_offset %d,rx_offset %u, frame_length_samples %u\n",
Ns, symbol, nb_prefix_samples, nb_prefix_samples0, slot_offset, sample_offset, rx_offset, frame_length_samples);
#endif
abs_symbol = Ns * frame_parms->symbols_per_slot + symbol;
......@@ -198,12 +198,22 @@ int nr_slot_fep(PHY_VARS_NR_UE *ue,
}
#ifdef DEBUG_FEP
// if (ue->frame <100)
printf("slot_fep: frame %d: symbol %d rx_offset %u\n", ue->proc.proc_rxtx[(Ns)&1].frame_rx, symbol, rx_offset);
#endif
#ifdef DEBUG_FEP
// if (ue->frame <100)
printf("slot_fep: symbol %d rx_offset %u\n", symbol, rx_offset);
#endif
int symb_offset = (Ns%frame_parms->slots_per_subframe)*frame_parms->symbols_per_slot;
int32_t rot2 = ((uint32_t*)frame_parms->symbol_rotation)[symbol+symb_offset];
((int16_t*)&rot2)[1]=-((int16_t*)&rot2)[1];
rotate_cpx_vector((int16_t *)&common_vars->common_vars_rx_data_per_thread[ue->current_thread_id[Ns]].rxdataF[aa][frame_parms->ofdm_symbol_size*symbol],
(int16_t*)&rot2,
(int16_t *)&common_vars->common_vars_rx_data_per_thread[ue->current_thread_id[Ns]].rxdataF[aa][frame_parms->ofdm_symbol_size*symbol],
frame_parms->ofdm_symbol_size,
15);
}
#ifdef DEBUG_FEP
printf("slot_fep: done\n");
......@@ -308,8 +318,8 @@ int nr_slot_fep_init_sync(PHY_VARS_NR_UE *ue,
#ifdef DEBUG_FEP
// if (ue->frame <100)
/*LOG_I(PHY,*/printf("slot_fep: frame %d: slot %d, symbol %d, nb_prefix_samples %u, nb_prefix_samples0 %u, slot_offset %u, sample_offset %d,rx_offset %u, frame_length_samples %u\n",
ue->proc.proc_rxtx[(Ns)&1].frame_rx, Ns, symbol, nb_prefix_samples, nb_prefix_samples0, slot_offset, sample_offset, rx_offset, frame_length_samples);
/*LOG_I(PHY,*/printf("slot_fep: slot %d, symbol %d, nb_prefix_samples %u, nb_prefix_samples0 %u, slot_offset %u, sample_offset %d,rx_offset %u, frame_length_samples %u\n",
Ns, symbol, nb_prefix_samples, nb_prefix_samples0, slot_offset, sample_offset, rx_offset, frame_length_samples);
#endif
abs_symbol = Ns * frame_parms->symbols_per_slot + symbol;
......@@ -373,10 +383,22 @@ int nr_slot_fep_init_sync(PHY_VARS_NR_UE *ue,
}
#ifdef DEBUG_FEP
// if (ue->frame <100)
printf("slot_fep: frame %d: symbol %d rx_offset %u\n", ue->proc.proc_rxtx[(Ns)&1].frame_rx, symbol, rx_offset);
#endif
int symb_offset = (Ns%frame_parms->slots_per_subframe)*frame_parms->symbols_per_slot;
int32_t rot2 = ((uint32_t*)frame_parms->symbol_rotation)[symbol+symb_offset];
((int16_t*)&rot2)[1]=-((int16_t*)&rot2)[1];
#ifdef DEBUG_FEP
// if (ue->frame <100)
printf("slot_fep: slot %d, symbol %d rx_offset %u, rotation symbol %d %d.%d\n", Ns,symbol, rx_offset,
symbol+symb_offset,((int16_t*)&rot2)[0],((int16_t*)&rot2)[1]);
#endif
rotate_cpx_vector((int16_t *)&common_vars->common_vars_rx_data_per_thread[ue->current_thread_id[Ns]].rxdataF[aa][frame_parms->ofdm_symbol_size*symbol],
(int16_t*)&rot2,
(int16_t *)&common_vars->common_vars_rx_data_per_thread[ue->current_thread_id[Ns]].rxdataF[aa][frame_parms->ofdm_symbol_size*symbol],
frame_parms->ofdm_symbol_size,
15);
}
......@@ -450,11 +472,11 @@ int nr_slot_fep_ul(NR_DL_FRAME_PARMS *frame_parms,
rxdata_offset = slot_offset + nb_prefix_samples0 + (symbol * (frame_parms->ofdm_symbol_size + nb_prefix_samples)) - SOFFSET;
if(sample_offset>rxdata_offset) {
memcpy((void *)tmp_dft_in,
memcpy1((void *)tmp_dft_in,
(void *) &rxdata[frame_parms->samples_per_frame-sample_offset+rxdata_offset],
(sample_offset-rxdata_offset)*sizeof(int));
memcpy((void *)&tmp_dft_in[sample_offset-rxdata_offset],
memcpy1((void *)&tmp_dft_in[sample_offset-rxdata_offset],
(void *) &rxdata[0],
(frame_parms->ofdm_symbol_size-sample_offset+rxdata_offset)*sizeof(int));
......@@ -468,11 +490,16 @@ int nr_slot_fep_ul(NR_DL_FRAME_PARMS *frame_parms,
// clear DC carrier from OFDM symbols
rxdataF[symbol * frame_parms->ofdm_symbol_size] = 0;
LOG_T(PHY,"Ns: %d, symbol: %d dft of size: %d done from %d (energy %d) to %d offsets (energy (%d)\n",
Ns, symbol, dftsize,
rxdata_offset-sample_offset, signal_energy(&rxdata[rxdata_offset-sample_offset], dftsize),
symbol * frame_parms->ofdm_symbol_size, signal_energy(&rxdataF[symbol * frame_parms->ofdm_symbol_size], dftsize)
);
int symb_offset = (Ns%frame_parms->slots_per_subframe)*frame_parms->symbols_per_slot;
uint32_t rot2 = ((uint32_t*)frame_parms->symbol_rotation)[symbol+symb_offset];
((int16_t*)&rot2)[1]=-((int16_t*)&rot2)[1];
LOG_D(PHY,"slot %d, symb_offset %d rotating by %d.%d\n",Ns,symb_offset,((int16_t*)&rot2)[0],((int16_t*)&rot2)[1]);
rotate_cpx_vector((int16_t *)&rxdataF[frame_parms->ofdm_symbol_size*symbol],
(int16_t*)&rot2,
(int16_t *)&rxdataF[frame_parms->ofdm_symbol_size*symbol],
frame_parms->ofdm_symbol_size,
15);
return(0);
}
......@@ -19,7 +19,7 @@
* contact@openairinterface.org
*/
/*! \file PHY/NR_ESTIMATION/nr_adjust_sync_gNB.c
/*! \file PHY/NR_ESTIMATION/nr_measurements_gNB.c
* \brief TA estimation for TA updates
* \author Ahmed Hussein
* \date 2019
......@@ -69,3 +69,37 @@ int nr_est_timing_advance_pusch(PHY_VARS_gNB* gNB, int UE_id)
return max_pos - sync_pos;
}
void gNB_I0_measurements(PHY_VARS_gNB *gNB) {
NR_DL_FRAME_PARMS *frame_parms = &gNB->frame_parms;
NR_gNB_COMMON *common_vars = &gNB->common_vars;
PHY_MEASUREMENTS_gNB *measurements = &gNB->measurements;
uint32_t *rb_mask = gNB->rb_mask_ul;
int symbol = gNB->ulmask_symb;
int rb, offset, nb_rb;
uint32_t n0_power_tot, n0_subband_power_temp=0;
int32_t *ul_ch;
if (symbol>-1) {
n0_power_tot = 0;
for (int aarx=0; aarx<frame_parms->nb_antennas_rx; aarx++) {
nb_rb = 0;
for (rb=0; rb<frame_parms->N_RB_UL; rb++) {
if ((rb_mask[rb>>5]&(1<<(rb&31))) == 0) { // check that rb was not used in this subframe
nb_rb++;
offset = (frame_parms->first_carrier_offset + (rb*12))%frame_parms->ofdm_symbol_size;
offset += (symbol*frame_parms->ofdm_symbol_size);
ul_ch = &common_vars->rxdataF[aarx][offset];
//TODO what about DC?
n0_subband_power_temp += signal_energy_nodc(ul_ch,12);
}
}
measurements->n0_power[aarx] = n0_subband_power_temp/nb_rb;
measurements->n0_power_dB[aarx] = dB_fixed(measurements->n0_power[aarx]);
n0_power_tot += measurements->n0_power[aarx];
}
measurements->n0_power_tot_dB = dB_fixed(n0_power_tot);
}
}
......@@ -43,9 +43,38 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB,
unsigned char Ns,
unsigned short p,
unsigned char symbol,
int ul_id,
unsigned short bwp_start_subcarrier,
nfapi_nr_pusch_pdu_t *pusch_pdu);
void gNB_I0_measurements(PHY_VARS_gNB *gNB);
int nr_est_timing_advance_pusch(PHY_VARS_gNB* phy_vars_gNB, int UE_id);
void nr_pusch_ptrs_processing(PHY_VARS_gNB *gNB,
nfapi_nr_pusch_pdu_t *rel15_ul,
uint8_t ulsch_id,
uint8_t nr_tti_rx,
uint8_t dmrs_symbol_flag,
unsigned char symbol,
uint32_t nb_re_pusch);
void nr_pusch_phase_estimation(NR_DL_FRAME_PARMS *frame_parms,
nfapi_nr_pusch_pdu_t *rel15_ul,
int16_t *ptrs_ch_p,
unsigned char Ns,
unsigned char symbol,
int16_t *rxF_comp,
uint32_t ***ptrs_gold_seq,
int16_t *error_est,
uint16_t *ptrs_sc);
void nr_pusch_phase_interpolation(int16_t *error_est,
uint8_t start_symbol,
uint8_t end_symbol);
int nr_ptrs_find_next_estimate(int16_t *error_est,
uint8_t counter,
uint8_t end_symbol);
#endif
......@@ -362,4 +362,25 @@ void generate_dmrs_pbch(uint32_t dmrs_pbch_bitmap[DMRS_PBCH_I_SSB][DMRS_PBCH_N_H
free(dmrs_sequence);
#endif
}
/* return the position of next dmrs symbol in a slot */
int get_next_dmrs_symbol_in_slot(uint16_t ul_dmrs_symb_pos, uint8_t counter, uint8_t end_symbol)
{
for(uint8_t symbol = counter; symbol < end_symbol; symbol++)
if((ul_dmrs_symb_pos >>symbol)&0x01 )
{
return symbol;
}
return 0;
}
/* return the total number of dmrs symbol in a slot */
uint8_t get_dmrs_symbols_in_slot(uint16_t l_prime_mask, uint16_t nb_symb)
{
uint8_t tmp = 0;
for (int i = 0; i < nb_symb; i++)
{
tmp += (l_prime_mask >> i) & 0x01;
}
return tmp;
}
......@@ -223,3 +223,27 @@ int nr_pbch_dmrs_rx(int symbol,
return(0);
}
/*!
\brief This function generate gold ptrs sequence for each OFDM symbol
\param *in gold sequence for ptrs per OFDM symbol
\param length is number of RE in a OFDM symbol
\param *output pointer to all ptrs RE in a OFDM symbol
*/
void nr_gen_ref_conj_symbols(uint32_t *in, uint32_t length, int16_t *output, uint16_t offset, int mod_order)
{
uint8_t idx, b_idx;
for (int i=0; i<length/mod_order; i++)
{
idx = 0;
for (int j=0; j<mod_order; j++)
{
b_idx = (i*mod_order+j)&0x1f;
if (i && (!b_idx))
in++;
idx ^= (((*in)>>b_idx)&1)<<(mod_order-j-1);
}
output[i<<1] = nr_rx_mod_table[(offset+idx)<<1];
output[(i<<1)+1] = nr_rx_mod_table[((offset+idx)<<1)+1];
}
}
......@@ -52,10 +52,14 @@ int nr_pusch_dmrs_rx(PHY_VARS_gNB *gNB,
uint8_t dmrs_type);
void init_scrambling_luts(void);
void nr_gen_ref_conj_symbols(uint32_t *in, uint32_t length, int16_t *output, uint16_t offset, int mod_order);
uint8_t get_next_dmrs_symbol_in_slot(uint16_t ul_dmrs_symb_pos, uint8_t counter, uint8_t end_symbol);
uint8_t get_dmrs_symbols_in_slot(uint16_t l_prime_mask, uint16_t nb_symb);
void nr_generate_modulation_table(void);
extern __m64 byte2m64_re[256];
extern __m64 byte2m64_im[256];
extern __m128i byte2m128i[256];
#endif
......@@ -32,6 +32,8 @@
__m64 byte2m64_re[256];
__m64 byte2m64_im[256];
__m128i byte2m128i[256];
void init_byte2m64(void) {
for (int s=0;s<256;s++) {
......@@ -54,10 +56,24 @@ void init_byte2m64(void) {
}
}
void init_byte2m128i(void) {
for (int s=0;s<256;s++) {
byte2m128i[s] = _mm_insert_epi16(byte2m128i[s],(1-2*(s&1)),0);
byte2m128i[s] = _mm_insert_epi16(byte2m128i[s],(1-2*((s>>1)&1)),1);
byte2m128i[s] = _mm_insert_epi16(byte2m128i[s],(1-2*((s>>2)&1)),2);
byte2m128i[s] = _mm_insert_epi16(byte2m128i[s],(1-2*((s>>3)&1)),3);
byte2m128i[s] = _mm_insert_epi16(byte2m128i[s],(1-2*((s>>4)&1)),4);
byte2m128i[s] = _mm_insert_epi16(byte2m128i[s],(1-2*((s>>5)&1)),5);
byte2m128i[s] = _mm_insert_epi16(byte2m128i[s],(1-2*((s>>6)&1)),6);
byte2m128i[s] = _mm_insert_epi16(byte2m128i[s],(1-2*((s>>7)&1)),7);
}
}
void init_scrambling_luts(void) {
init_byte2m64();
init_byte2m128i();
}
#endif
......@@ -154,8 +154,10 @@ void nr_pdcch_scrambling(uint32_t *in,
}
uint8_t nr_generate_dci_top(nfapi_nr_dl_tti_pdcch_pdu *pdcch_pdu,
nfapi_nr_ul_dci_request_pdus_t *ul_dci_pdu,
uint8_t nr_generate_dci_top(PHY_VARS_gNB *gNB,
nfapi_nr_dl_tti_pdcch_pdu *pdcch_pdu,
nfapi_nr_dl_tti_pdcch_pdu *ul_dci_pdu,
uint32_t **gold_pdcch_dmrs,
int32_t *txdataF,
int16_t amp,
......@@ -180,15 +182,17 @@ uint8_t nr_generate_dci_top(nfapi_nr_dl_tti_pdcch_pdu *pdcch_pdu,
if (pdcch_pdu) pdcch_pdu_rel15 = &pdcch_pdu->pdcch_pdu_rel15;
else if (ul_dci_pdu) pdcch_pdu_rel15 = &ul_dci_pdu->pdcch_pdu.pdcch_pdu_rel15;
else if (ul_dci_pdu) pdcch_pdu_rel15 = &ul_dci_pdu->pdcch_pdu_rel15;
nr_fill_cce_list(gNB,0,pdcch_pdu_rel15);
get_coreset_rballoc(pdcch_pdu_rel15->FreqDomainResource,&n_rb,&rb_offset);
// compute rb_offset and n_prb based on frequency allocation
if (pdcch_pdu_rel15->CoreSetType == NFAPI_NR_CSET_CONFIG_MIB_SIB1) {
cset_start_sc = frame_parms.first_carrier_offset + (frame_parms.ssb_start_subcarrier/NR_NB_SC_PER_RB +
rb_offset)*NR_NB_SC_PER_RB;
cset_start_sc = frame_parms.first_carrier_offset +
(frame_parms.ssb_start_subcarrier/NR_NB_SC_PER_RB + rb_offset)*NR_NB_SC_PER_RB;
} else
cset_start_sc = frame_parms.first_carrier_offset + rb_offset*NR_NB_SC_PER_RB;
......@@ -324,6 +328,7 @@ uint8_t nr_generate_dci_top(nfapi_nr_dl_tti_pdcch_pdu *pdcch_pdu,
k -= frame_parms.ofdm_symbol_size;
} // m
} // reg_idx
} // for (int d=0;d<pdcch_pdu_rel15->numDlDci;d++)
return 0;
}
......
......@@ -29,9 +29,10 @@ uint16_t nr_get_dci_size(nfapi_nr_dci_format_e format,
nfapi_nr_rnti_type_e rnti_type,
uint16_t N_RB);
uint8_t nr_generate_dci_top(nfapi_nr_dl_tti_pdcch_pdu *pdcch_pdu,
nfapi_nr_ul_dci_request_pdus_t *ul_dci_pdu,
uint32_t **gold_pdcch_dmrs,
uint8_t nr_generate_dci_top(PHY_VARS_gNB *gNB,
nfapi_nr_dl_tti_pdcch_pdu *pdcch_pdu,
nfapi_nr_dl_tti_pdcch_pdu *ul_pdcch_pdu,
uint32_t **gold_pdcch_dmrs,
int32_t *txdataF,
int16_t amp,
NR_DL_FRAME_PARMS frame_parms);
......@@ -42,15 +43,21 @@ void nr_pdcch_scrambling(uint32_t *in,
uint32_t n_RNTI,
uint32_t *out);
int16_t find_nr_pdcch(int frame,int slot, PHY_VARS_gNB *gNB,find_type_t type);
void nr_fill_dci(PHY_VARS_gNB *gNB,
int frame,
int slot);
int slot,
nfapi_nr_dl_tti_pdcch_pdu *pdcch_pdu);
int16_t find_nr_ul_dci(int frame,int slot, PHY_VARS_gNB *gNB,find_type_t type);
void nr_fill_ul_dci(PHY_VARS_gNB *gNB,
int frame,
int slot);
int slot,
nfapi_nr_ul_dci_request_pdus_t *pdcch_pdu);
void nr_fill_cce_list(PHY_VARS_gNB *gNB, uint8_t m);
void nr_fill_cce_list(PHY_VARS_gNB *gNB, uint8_t m,nfapi_nr_dl_tti_pdcch_pdu_rel15_t *);
void get_coreset_rballoc(uint8_t *FreqDomainResource,int *n_rb,int *rb_offset);
......
......@@ -118,11 +118,11 @@ void nr_fill_cce_list(PHY_VARS_gNB *gNB, uint16_t n_shift, uint8_t m) {
*/
void nr_fill_cce_list(PHY_VARS_gNB *gNB, uint8_t m) {
void nr_fill_cce_list(PHY_VARS_gNB *gNB, uint8_t m, nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu_rel15) {
nr_cce_t* cce;
nr_reg_t* reg;
nfapi_nr_dl_tti_pdcch_pdu_rel15_t* pdcch_pdu_rel15 = &gNB->pdcch_pdu->pdcch_pdu_rel15;
int bsize = pdcch_pdu_rel15->RegBundleSize;
int R = pdcch_pdu_rel15->InterleaverSize;
int n_shift = pdcch_pdu_rel15->ShiftIndex;
......@@ -139,6 +139,8 @@ void nr_fill_cce_list(PHY_VARS_gNB *gNB, uint8_t m) {
int N_reg = n_rb * pdcch_pdu_rel15->DurationSymbols;
int C=-1;
AssertFatal(N_reg > 0,"N_reg cannot be 0\n");
for (int d=0;d<pdcch_pdu_rel15->numDlDci;d++) {
int L = pdcch_pdu_rel15->dci_pdu.AggregationLevel[d];
......@@ -200,14 +202,38 @@ void nr_fill_cce_list(PHY_VARS_gNB *gNB, uint8_t m) {
ret |= ((field>>i)&1)<<(size-i-1);
return ret;
}*/
int16_t find_nr_pdcch(int frame,int slot, PHY_VARS_gNB *gNB,find_type_t type) {
uint16_t i;
int16_t first_free_index=-1;
AssertFatal(gNB!=NULL,"gNB is null\n");
for (i=0; i<NUMBER_OF_NR_PDCCH_MAX; i++) {
LOG_D(PHY,"searching for frame.slot %d.%d : pdcch_index %d frame.slot %d.%d, first_free_index %d\n", frame,slot,i,gNB->pdcch_pdu[i].frame,gNB->pdcch_pdu[i].slot,first_free_index);
if ((gNB->pdcch_pdu[i].frame == frame) &&
(gNB->pdcch_pdu[i].slot==slot)) return i;
else if ( gNB->pdcch_pdu[i].frame==-1 && first_free_index==-1) first_free_index=i;
}
if (type == SEARCH_EXIST) return -1;
return first_free_index;
}
void nr_fill_dci(PHY_VARS_gNB *gNB,
int frame,
int slot) {
int slot,
nfapi_nr_dl_tti_pdcch_pdu *pdcch_pdu) {
nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu_rel15 = &gNB->pdcch_pdu->pdcch_pdu_rel15;
nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu_rel15 = &pdcch_pdu->pdcch_pdu_rel15;
NR_gNB_DLSCH_t *dlsch;
int pdcch_id = find_nr_pdcch(frame,slot,gNB,SEARCH_EXIST_OR_FREE);
AssertFatal(pdcch_id>=0 && pdcch_id<NUMBER_OF_NR_PDCCH_MAX,"Cannot find space for PDCCH, exiting\n");
memcpy((void*)&gNB->pdcch_pdu[pdcch_id].pdcch_pdu,(void*)pdcch_pdu,sizeof(*pdcch_pdu));
gNB->pdcch_pdu[pdcch_id].frame = frame;
gNB->pdcch_pdu[pdcch_id].slot = slot;
for (int i=0;i<pdcch_pdu_rel15->numDlDci;i++) {
//uint64_t *dci_pdu = (uint64_t*)pdcch_pdu_rel15->dci_pdu.Payload[i];
......@@ -230,7 +256,7 @@ void nr_fill_dci(PHY_VARS_gNB *gNB,
dlsch->harq_mask |= (1<<harq_pid);
dlsch->rnti = pdcch_pdu_rel15->dci_pdu.RNTI[i];
nr_fill_cce_list(gNB,0);
// nr_fill_cce_list(gNB,0);
/*
LOG_D(PHY, "DCI PDU: [0]->0x%lx \t [1]->0x%lx \n",dci_pdu[0], dci_pdu[1]);
LOG_D(PHY, "DCI type %d payload (size %d) generated on candidate %d\n", dci_alloc->pdcch_params.dci_format, dci_alloc->size, cand_idx);
......@@ -239,19 +265,45 @@ void nr_fill_dci(PHY_VARS_gNB *gNB,
}
}
int16_t find_nr_ul_dci(int frame,int slot, PHY_VARS_gNB *gNB,find_type_t type) {
uint16_t i;
int16_t first_free_index=-1;
AssertFatal(gNB!=NULL,"gNB is null\n");
for (i=0; i<NUMBER_OF_NR_PDCCH_MAX; i++) {
LOG_D(PHY,"searching for frame.slot %d.%d : ul_pdcch_index %d frame.slot %d.%d, first_free_index %d\n", frame,slot,i,gNB->ul_pdcch_pdu[i].frame,gNB->ul_pdcch_pdu[i].slot,first_free_index);
if ((gNB->ul_pdcch_pdu[i].frame == frame) &&
(gNB->ul_pdcch_pdu[i].slot==slot)) return i;
else if (gNB->ul_pdcch_pdu[i].frame==-1 && first_free_index==-1) first_free_index=i;
}
if (type == SEARCH_EXIST) return -1;
return first_free_index;
}
void nr_fill_ul_dci(PHY_VARS_gNB *gNB,
int frame,
int slot) {
int slot,
nfapi_nr_ul_dci_request_pdus_t *pdcch_pdu) {
nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu_rel15 = &gNB->ul_dci_pdu->pdcch_pdu.pdcch_pdu_rel15;
nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu_rel15 = &pdcch_pdu->pdcch_pdu.pdcch_pdu_rel15;
int pdcch_id = find_nr_ul_dci(frame,slot,gNB,SEARCH_EXIST_OR_FREE);
AssertFatal(pdcch_id>=0 && pdcch_id<NUMBER_OF_NR_PDCCH_MAX,"Cannot find space for UL PDCCH, exiting\n");
memcpy((void*)&gNB->ul_pdcch_pdu[pdcch_id].pdcch_pdu,(void*)pdcch_pdu,sizeof(*pdcch_pdu));
gNB->ul_pdcch_pdu[pdcch_id].frame = frame;
gNB->ul_pdcch_pdu[pdcch_id].slot = slot;
for (int i=0;i<pdcch_pdu_rel15->numDlDci;i++) {
//uint64_t *dci_pdu = (uint64_t*)pdcch_pdu_rel15->dci_pdu.Payload[i];
// if there's no DL DCI then generate CCE list
if (gNB->pdcch_pdu) nr_fill_cce_list(gNB,0);
// nr_fill_cce_list(gNB,0);
/*
LOG_D(PHY, "DCI PDU: [0]->0x%lx \t [1]->0x%lx \n",dci_pdu[0], dci_pdu[1]);
LOG_D(PHY, "DCI type %d payload (size %d) generated on candidate %d\n", dci_alloc->pdcch_params.dci_format, dci_alloc->size, cand_idx);
......
This diff is collapsed.
......@@ -69,27 +69,9 @@ void nr_fill_dlsch(PHY_VARS_gNB *gNB,
nfapi_nr_dl_tti_pdsch_pdu *pdsch_pdu,
unsigned char *sdu);
uint8_t nr_generate_pdsch(NR_gNB_DLSCH_t *dlsch,
uint32_t ***pdsch_dmrs,
int32_t** txdataF,
int16_t amp,
int frame,
uint8_t slot,
NR_DL_FRAME_PARMS *frame_parms,
int xOverhead,
time_stats_t *dlsch_encoding_stats,
time_stats_t *dlsch_scrambling_stats,
time_stats_t *dlsch_modulation_stats,
time_stats_t *tinput,
time_stats_t *tprep,
time_stats_t *tparity,
time_stats_t *toutput,
time_stats_t *dlsch_rate_matching_stats,
time_stats_t *dlsch_interleaving_stats,
time_stats_t *dlsch_segmentation_stats);
uint8_t nr_generate_pdsch(PHY_VARS_gNB *gNB,
int frame,
int slot);
void free_gNB_dlsch(NR_gNB_DLSCH_t **dlschptr, uint16_t N_RB);
void clean_gNB_dlsch(NR_gNB_DLSCH_t *dlsch);
......@@ -98,7 +80,10 @@ void clean_gNB_ulsch(NR_gNB_ULSCH_t *ulsch);
int16_t find_nr_dlsch(uint16_t rnti, PHY_VARS_gNB *gNB,find_type_t type);
int nr_dlsch_encoding(unsigned char *a,int frame,
NR_gNB_SCH_STATS_t *find_nr_dlsch_stats(uint16_t rnti, PHY_VARS_gNB *gNB,find_type_t type);
int nr_dlsch_encoding(PHY_VARS_gNB *gNB,
unsigned char *a,int frame,
uint8_t slot,
NR_gNB_DLSCH_t *dlsch,
NR_DL_FRAME_PARMS* frame_parms,
......@@ -113,4 +98,8 @@ int nr_dlsch_encoding(unsigned char *a,int frame,
void nr_emulate_dlsch_payload(uint8_t* payload, uint16_t size);
void dump_pdsch_stats(PHY_VARS_gNB *gNB);
void clear_pdsch_stats(PHY_VARS_gNB *gNB);
#endif
......@@ -61,7 +61,7 @@ void free_gNB_dlsch(NR_gNB_DLSCH_t **dlschptr, uint16_t N_RB)
if (N_RB != 273) {
a_segments = a_segments*N_RB;
a_segments = a_segments/273;
a_segments = a_segments/273 +1;
}
......@@ -150,7 +150,7 @@ NR_gNB_DLSCH_t *new_gNB_dlsch(NR_DL_FRAME_PARMS *frame_parms,
if (N_RB != 273) {
a_segments = a_segments*N_RB;
a_segments = (a_segments + 272) / 273;
a_segments = a_segments/273 +1;
}
uint16_t dlsch_bytes = a_segments*1056; // allocated bytes per segment
......@@ -309,7 +309,8 @@ void clean_gNB_dlsch(NR_gNB_DLSCH_t *dlsch)
}
}
int nr_dlsch_encoding(unsigned char *a,
int nr_dlsch_encoding(PHY_VARS_gNB *gNB,
unsigned char *a,
int frame,
uint8_t slot,
NR_gNB_DLSCH_t *dlsch,
......@@ -326,7 +327,8 @@ int nr_dlsch_encoding(unsigned char *a,
nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15 = &dlsch->harq_processes[harq_pid]->pdsch_pdu.pdsch_pdu_rel15;
uint16_t nb_rb = rel15->rbSize;
uint8_t nb_symb_sch = rel15->NrOfSymbols;
uint32_t A, Z, Kb, F=0;
uint32_t A, Kb, F=0;
static uint32_t Z = 0;
uint32_t *Zc = &Z;
uint8_t mod_order = rel15->qamModOrder[0];
uint16_t Kr=0,r;
......@@ -347,10 +349,34 @@ int nr_dlsch_encoding(unsigned char *a,
float Coderate = 0.0;
uint8_t Nl = 4;
dlsch->harq_processes[harq_pid]->round = nr_rv_round_map[rel15->rvIndex[0]];
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_gNB_DLSCH_ENCODING, VCD_FUNCTION_IN);
A = rel15->TBSize[0]<<3;
NR_gNB_SCH_STATS_t *stats=NULL;
int first_free=-1;
for (int i=0;i<NUMBER_OF_NR_SCH_STATS_MAX;i++) {
if (gNB->dlsch_stats[i].rnti == 0 && first_free == -1) {
first_free = i;
stats=&gNB->dlsch_stats[i];
}
if (gNB->dlsch_stats[i].rnti == dlsch->rnti) {
stats=&gNB->dlsch_stats[i];
break;
}
}
if (stats) {
stats->round_trials[dlsch->harq_processes[harq_pid]->round]++;
stats->rnti = dlsch->rnti;
if (dlsch->harq_processes[harq_pid]->round == 0){
stats->total_bytes_tx += rel15->TBSize[0];
stats->current_RI = rel15->nrOfLayers;
stats->current_Qm = rel15->qamModOrder[0];
}
}
G = nr_get_G(nb_rb, nb_symb_sch, nb_re_dmrs, length_dmrs,mod_order,rel15->nrOfLayers);
LOG_D(PHY,"dlsch coding A %d G %d mod_order %d\n", A,G, mod_order);
......
......@@ -255,27 +255,28 @@ void nr_emulate_dlsch_payload(uint8_t* pdu, uint16_t size) {
}
int16_t find_nr_dlsch(uint16_t rnti, PHY_VARS_gNB *gNB,find_type_t type) {
uint16_t i;
int16_t first_free_index=-1;
AssertFatal(gNB!=NULL,"gNB is null\n");
for (i=0; i<NUMBER_OF_NR_DLSCH_MAX; i++) {
AssertFatal(gNB->dlsch[i]!=NULL,"gNB->dlsch[%d] is null\n",i);
AssertFatal(gNB->dlsch[i][0]!=NULL,"gNB->dlsch[%d][0] is null\n",i);
LOG_D(PHY,"searching for rnti %x : dlsch_index %d=> harq_mask %x, rnti %x, first_free_index %d\n", rnti,i,gNB->dlsch[i][0]->harq_mask,gNB->dlsch[i][0]->rnti,first_free_index);
if ((gNB->dlsch[i][0]->harq_mask >0) &&
(gNB->dlsch[i][0]->rnti==rnti)) return i;
else if ((gNB->dlsch[i][0]->harq_mask == 0) && (first_free_index==-1)) first_free_index=i;
}
if (type == SEARCH_EXIST) return -1;
if (first_free_index != -1)
gNB->dlsch[first_free_index][0]->rnti = 0;
return first_free_index;
uint16_t i;
int16_t first_free_index=-1;
AssertFatal(gNB!=NULL,"gNB is null\n");
for (i=0; i<NUMBER_OF_NR_DLSCH_MAX; i++) {
AssertFatal(gNB->dlsch[i]!=NULL,"gNB->dlsch[%d] is null\n",i);
AssertFatal(gNB->dlsch[i][0]!=NULL,"gNB->dlsch[%d][0] is null\n",i);
LOG_D(PHY,"searching for rnti %x : dlsch_index %d=> harq_mask %x, rnti %x, first_free_index %d\n", rnti,i,
gNB->dlsch[i][0]->harq_mask,gNB->dlsch[i][0]->rnti,first_free_index);
if ((gNB->dlsch[i][0]->harq_mask >0) &&
(gNB->dlsch[i][0]->rnti==rnti)) return i;
else if ((gNB->dlsch[i][0]->harq_mask == 0) && (first_free_index==-1)) first_free_index=i;
}
if (type == SEARCH_EXIST) return -1;
if (first_free_index != -1)
gNB->dlsch[first_free_index][0]->rnti = 0;
return first_free_index;
}
void nr_fill_dlsch(PHY_VARS_gNB *gNB,
int frame,
int slot,
......@@ -291,7 +292,7 @@ void nr_fill_dlsch(PHY_VARS_gNB *gNB,
NR_DL_gNB_HARQ_t **harq = dlsch->harq_processes;
/// DLSCH struct
memcpy((void*)&harq[dlsch->harq_ids[frame%2][slot]]->pdsch_pdu, (void*)pdsch_pdu, sizeof(nfapi_nr_dl_tti_pdsch_pdu));
gNB->num_pdsch_rnti++;
gNB->num_pdsch_rnti[slot]++;
AssertFatal(sdu!=NULL,"sdu is null\n");
harq[dlsch->harq_ids[frame%2][slot]]->pdu = sdu;
......
......@@ -342,6 +342,11 @@ void nr_decode_pucch1(int32_t **rxdataF,
uint8_t timeDomainOCC,
uint8_t nr_bit);
void nr_decode_pucch2(PHY_VARS_gNB *gNB,
int slot,
nfapi_nr_uci_pucch_pdu_format_2_3_4_t* uci_pdu,
nfapi_nr_pucch_pdu_t* pucch_pdu);
void nr_decode_pucch0(PHY_VARS_gNB *gNB,
int slot,
nfapi_nr_uci_pucch_pdu_format_0_1_t* uci_pdu,
......
......@@ -33,7 +33,7 @@
#include <stdint.h>
#include "PHY/NR_TRANSPORT/nr_transport_common_proto.h"
#include "PHY/NR_TRANSPORT/nr_ulsch.h"
#include "PHY/LTE_REFSIG/lte_refsig.h"
#include "PHY/NR_REFSIG/nr_refsig.h"
int16_t find_nr_ulsch(uint16_t rnti, PHY_VARS_gNB *gNB,find_type_t type) {
......@@ -103,3 +103,62 @@ void nr_ulsch_unscrambling(int16_t* llr,
llr[i] = -llr[i];
}
}
void nr_ulsch_unscrambling_optim(int16_t* llr,
uint32_t size,
uint8_t q,
uint32_t Nid,
uint32_t n_RNTI) {
#if defined(__x86_64__) || defined(__i386__)
uint32_t x1, x2, s=0;
x2 = (n_RNTI<<15) + Nid;
uint8_t *s8=(uint8_t *)&s;
__m128i *llr128 = (__m128i*)llr;
int j=0;
s = lte_gold_generic(&x1, &x2, 1);
for (int i=0; i<((size>>5)+((size&0x1f) > 0 ? 1 : 0)); i++,j+=4) {
llr128[j] = _mm_mullo_epi16(llr128[j],byte2m128i[s8[0]]);
llr128[j+1] = _mm_mullo_epi16(llr128[j+1],byte2m128i[s8[1]]);
llr128[j+2] = _mm_mullo_epi16(llr128[j+2],byte2m128i[s8[2]]);
llr128[j+3] = _mm_mullo_epi16(llr128[j+3],byte2m128i[s8[3]]);
s = lte_gold_generic(&x1, &x2, 0);
}
#else
nr_ulsch_unscrambling(llr,
size,
q,
Nid,
n_RNTI);
#endif
}
void dump_pusch_stats(PHY_VARS_gNB *gNB) {
for (int i=0;i<NUMBER_OF_NR_ULSCH_MAX;i++)
if (gNB->ulsch_stats[i].rnti>0)
LOG_I(PHY,"ULSCH RNTI %x: round_trials %d(%1.1e):%d(%1.1e):%d(%1.1e):%d, current_Qm %d, current_RI %d, total_bytes RX/SCHED %d/%d\n",
gNB->ulsch_stats[i].rnti,
gNB->ulsch_stats[i].round_trials[0],
(double)gNB->ulsch_stats[i].round_trials[1]/gNB->ulsch_stats[i].round_trials[0],
gNB->ulsch_stats[i].round_trials[1],
(double)gNB->ulsch_stats[i].round_trials[2]/gNB->ulsch_stats[i].round_trials[0],
gNB->ulsch_stats[i].round_trials[2],
(double)gNB->ulsch_stats[i].round_trials[3]/gNB->ulsch_stats[i].round_trials[0],
gNB->ulsch_stats[i].round_trials[3],
gNB->ulsch_stats[i].current_Qm,
gNB->ulsch_stats[i].current_RI,
gNB->ulsch_stats[i].total_bytes_rx,
gNB->ulsch_stats[i].total_bytes_tx);
}
void clear_pusch_stats(PHY_VARS_gNB *gNB) {
for (int i=0;i<NUMBER_OF_NR_ULSCH_MAX;i++)
memset((void*)&gNB->ulsch_stats[i],0,sizeof(gNB->ulsch_stats[i]));
}
......@@ -75,9 +75,19 @@ void nr_ulsch_unscrambling(int16_t* llr,
uint32_t n_RNTI);
void nr_ulsch_unscrambling_optim(int16_t* llr,
uint32_t size,
uint8_t q,
uint32_t Nid,
uint32_t n_RNTI);
void nr_ulsch_procedures(PHY_VARS_gNB *gNB,
int frame_rx,
int slot_rx,
int UE_id,
uint8_t harq_pid);
int16_t find_nr_ulsch(uint16_t rnti, PHY_VARS_gNB *gNB,find_type_t type);
void dump_pusch_stats(PHY_VARS_gNB *gNB);
void clear_pusch_stats(PHY_VARS_gNB *gNB);
This diff is collapsed.
......@@ -68,7 +68,7 @@ void free_nr_ue_dlsch(NR_UE_DLSCH_t **dlschptr,uint8_t N_RB_DL)
if (dlsch) {
if (N_RB_DL != 273) {
a_segments = a_segments*N_RB_DL;
a_segments = a_segments/273;
a_segments = a_segments/273 +1;
}
......@@ -283,7 +283,7 @@ uint32_t nr_dlsch_decoding(PHY_VARS_NR_UE *phy_vars_ue,
__m128i *pl = (__m128i*)&l;
vcd_signal_dumper_dump_function_by_name(VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_SEGMENTATION, VCD_FUNCTION_IN);
//NR_DL_UE_HARQ_t *harq_process = dlsch->harq_processes[0];
if (!dlsch_llr) {
......@@ -415,7 +415,7 @@ uint32_t nr_dlsch_decoding(PHY_VARS_NR_UE *phy_vars_ue,
if (nb_rb != 273) {
a_segments = a_segments*nb_rb;
a_segments = (a_segments + 272) / 273;
a_segments = a_segments/273 +1;
}
if (harq_process->C > a_segments) {
......@@ -590,6 +590,9 @@ uint32_t nr_dlsch_decoding(PHY_VARS_NR_UE *phy_vars_ue,
// Fixme: correct type is unsigned, but nrLDPC_decoder and all called behind use signed int
if (check_crc((uint8_t*)llrProcBuf,length_dec,harq_process->F,crc_type)) {
LOG_D(PHY,"Segment %u CRC OK\n\033[0m",r);
if (r==0)
for (int i=0;i<10;i++) LOG_D(PHY,"byte %d : %x\n",i,((uint8_t*)llrProcBuf)[i]);
//Temporary hack
no_iteration_ldpc = dlsch->max_ldpc_iterations;
ret = no_iteration_ldpc;
......@@ -663,9 +666,8 @@ uint32_t nr_dlsch_decoding(PHY_VARS_NR_UE *phy_vars_ue,
harq_process->harq_ack.harq_id = harq_pid;
harq_process->harq_ack.send_harq_status = 1;
harq_process->errors[harq_process->round]++;
// harq_process->round++; // [hna] uncomment this line when HARQ is implemented
// printf("Rate: [UE %d] DLSCH: Setting NACK for subframe %d (pid %d, round %d)\n",phy_vars_ue->Mod_id,subframe,harq_pid,harq_process->round);
// printf("Rate: [UE %d] DLSCH: Setting NACK for slot %d (pid %d, round %d)\n",phy_vars_ue->Mod_id,nr_tti_rx,harq_pid,harq_process->round);
if (harq_process->round >= dlsch->Mlimit) {
harq_process->status = SCH_IDLE;
harq_process->round = 0;
......@@ -958,7 +960,7 @@ uint32_t nr_dlsch_decoding_mthread(PHY_VARS_NR_UE *phy_vars_ue,
if (nb_rb != 273) {
a_segments = a_segments*nb_rb;
a_segments = a_segments/273;
a_segments = a_segments/273 +1;
}
if (harq_process->C > a_segments) {
......@@ -1536,7 +1538,7 @@ void nr_dlsch_decoding_process(void *arg)
if (nb_rb != 273) {
a_segments = a_segments*nb_rb;
a_segments = a_segments/273;
a_segments = a_segments/273 +1;
}
if (harq_process->C > a_segments) {
......
......@@ -786,16 +786,16 @@ void nr_dlsch_16qam_llr(NR_DL_FRAME_PARMS *frame_parms,
//----------------------------------------------------------------------------------------------
void nr_dlsch_64qam_llr(NR_DL_FRAME_PARMS *frame_parms,
int32_t **rxdataF_comp,
int16_t *dlsch_llr,
int32_t **dl_ch_mag,
int32_t **dl_ch_magb,
uint8_t symbol,
uint32_t len,
uint8_t first_symbol_flag,
uint16_t nb_rb,
uint32_t llr_offset,
uint8_t beamforming_mode)
int32_t **rxdataF_comp,
int16_t *dlsch_llr,
int32_t **dl_ch_mag,
int32_t **dl_ch_magb,
uint8_t symbol,
uint32_t len,
uint8_t first_symbol_flag,
uint16_t nb_rb,
uint32_t llr_offset,
uint8_t beamforming_mode)
{
#if defined(__x86_64__) || defined(__i386__)
__m128i *rxF = (__m128i*)&rxdataF_comp[0][(symbol*nb_rb*12)];
......
This diff is collapsed.
......@@ -1074,11 +1074,9 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE,
*/
uint8_t nr_ue_pusch_common_procedures(PHY_VARS_NR_UE *UE,
uint8_t harq_pid,
uint8_t slot,
uint8_t thread_id,
uint8_t gNB_id,
NR_DL_FRAME_PARMS *frame_parms);
NR_DL_FRAME_PARMS *frame_parms,
uint8_t Nl);
......
This diff is collapsed.
......@@ -270,7 +270,6 @@ void generate_pss_nr(NR_DL_FRAME_PARMS *fp,int N_ID_2)
if (k>= fp->ofdm_symbol_size) k-=fp->ofdm_symbol_size;
for (int i=0; i < LENGTH_PSS_NR; i++) {
synchroF_tmp[2*k] = primary_synchro[2*i];
synchroF_tmp[2*k+1] = primary_synchro[2*i+1];
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment